mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 16:52:41 +01:00
Add a rough "!history" email command to get an entire object history via email
Summary: See PHI505. Ref T13124. If you're an agent of a hostile state trying to exfiltrate corporate secrets, you might find yourself foiled if Phabricator is secured behind a VPN. To assist users in this situation, provide a "!history" command which will dump the entire history of an object in a nice text format and get through the troublesome VPN. Some issues with this: - You currently get all the "X added a comment." up top, and then all the comments below. This isn't terribly useful. - This goes through the "Must Encrypt" flag, but possibly should not? (On the other hand, this is a pretty willful way to bypass it the flag.) Test Plan: Used `bin/mail receive-test ...` to send `!history` commands, got somewhat-useful response mail. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13124 Differential Revision: https://secure.phabricator.com/D19372
This commit is contained in:
parent
b5f23b023e
commit
25965260c4
3 changed files with 75 additions and 4 deletions
|
@ -15,6 +15,7 @@ final class PhabricatorTransactions extends Phobject {
|
||||||
const TYPE_CREATE = 'core:create';
|
const TYPE_CREATE = 'core:create';
|
||||||
const TYPE_COLUMNS = 'core:columns';
|
const TYPE_COLUMNS = 'core:columns';
|
||||||
const TYPE_SUBTYPE = 'core:subtype';
|
const TYPE_SUBTYPE = 'core:subtype';
|
||||||
|
const TYPE_HISTORY = 'core:history';
|
||||||
|
|
||||||
const COLOR_RED = 'red';
|
const COLOR_RED = 'red';
|
||||||
const COLOR_ORANGE = 'orange';
|
const COLOR_ORANGE = 'orange';
|
||||||
|
|
|
@ -83,6 +83,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
private $webhookMap = array();
|
private $webhookMap = array();
|
||||||
|
|
||||||
private $transactionQueue = array();
|
private $transactionQueue = array();
|
||||||
|
private $sendHistory = false;
|
||||||
|
|
||||||
const STORAGE_ENCODING_BINARY = 'binary';
|
const STORAGE_ENCODING_BINARY = 'binary';
|
||||||
|
|
||||||
|
@ -300,6 +301,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
$types = array();
|
$types = array();
|
||||||
|
|
||||||
$types[] = PhabricatorTransactions::TYPE_CREATE;
|
$types[] = PhabricatorTransactions::TYPE_CREATE;
|
||||||
|
$types[] = PhabricatorTransactions::TYPE_HISTORY;
|
||||||
|
|
||||||
if ($this->object instanceof PhabricatorEditEngineSubtypeInterface) {
|
if ($this->object instanceof PhabricatorEditEngineSubtypeInterface) {
|
||||||
$types[] = PhabricatorTransactions::TYPE_SUBTYPE;
|
$types[] = PhabricatorTransactions::TYPE_SUBTYPE;
|
||||||
|
@ -377,6 +379,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
|
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case PhabricatorTransactions::TYPE_CREATE:
|
case PhabricatorTransactions::TYPE_CREATE:
|
||||||
|
case PhabricatorTransactions::TYPE_HISTORY:
|
||||||
return null;
|
return null;
|
||||||
case PhabricatorTransactions::TYPE_SUBTYPE:
|
case PhabricatorTransactions::TYPE_SUBTYPE:
|
||||||
return $object->getEditEngineSubtype();
|
return $object->getEditEngineSubtype();
|
||||||
|
@ -468,6 +471,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
case PhabricatorTransactions::TYPE_TOKEN:
|
case PhabricatorTransactions::TYPE_TOKEN:
|
||||||
case PhabricatorTransactions::TYPE_INLINESTATE:
|
case PhabricatorTransactions::TYPE_INLINESTATE:
|
||||||
case PhabricatorTransactions::TYPE_SUBTYPE:
|
case PhabricatorTransactions::TYPE_SUBTYPE:
|
||||||
|
case PhabricatorTransactions::TYPE_HISTORY:
|
||||||
return $xaction->getNewValue();
|
return $xaction->getNewValue();
|
||||||
case PhabricatorTransactions::TYPE_SPACE:
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
$space_phid = $xaction->getNewValue();
|
$space_phid = $xaction->getNewValue();
|
||||||
|
@ -520,6 +524,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
|
|
||||||
switch ($xaction->getTransactionType()) {
|
switch ($xaction->getTransactionType()) {
|
||||||
case PhabricatorTransactions::TYPE_CREATE:
|
case PhabricatorTransactions::TYPE_CREATE:
|
||||||
|
case PhabricatorTransactions::TYPE_HISTORY:
|
||||||
return true;
|
return true;
|
||||||
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
|
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
|
||||||
$field = $this->getCustomFieldForTransaction($object, $xaction);
|
$field = $this->getCustomFieldForTransaction($object, $xaction);
|
||||||
|
@ -604,6 +609,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
$field = $this->getCustomFieldForTransaction($object, $xaction);
|
$field = $this->getCustomFieldForTransaction($object, $xaction);
|
||||||
return $field->applyApplicationTransactionInternalEffects($xaction);
|
return $field->applyApplicationTransactionInternalEffects($xaction);
|
||||||
case PhabricatorTransactions::TYPE_CREATE:
|
case PhabricatorTransactions::TYPE_CREATE:
|
||||||
|
case PhabricatorTransactions::TYPE_HISTORY:
|
||||||
case PhabricatorTransactions::TYPE_SUBTYPE:
|
case PhabricatorTransactions::TYPE_SUBTYPE:
|
||||||
case PhabricatorTransactions::TYPE_TOKEN:
|
case PhabricatorTransactions::TYPE_TOKEN:
|
||||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||||
|
@ -665,6 +671,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
$field = $this->getCustomFieldForTransaction($object, $xaction);
|
$field = $this->getCustomFieldForTransaction($object, $xaction);
|
||||||
return $field->applyApplicationTransactionExternalEffects($xaction);
|
return $field->applyApplicationTransactionExternalEffects($xaction);
|
||||||
case PhabricatorTransactions::TYPE_CREATE:
|
case PhabricatorTransactions::TYPE_CREATE:
|
||||||
|
case PhabricatorTransactions::TYPE_HISTORY:
|
||||||
case PhabricatorTransactions::TYPE_SUBTYPE:
|
case PhabricatorTransactions::TYPE_SUBTYPE:
|
||||||
case PhabricatorTransactions::TYPE_EDGE:
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
case PhabricatorTransactions::TYPE_TOKEN:
|
case PhabricatorTransactions::TYPE_TOKEN:
|
||||||
|
@ -800,6 +807,9 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
case PhabricatorTransactions::TYPE_SPACE:
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
$this->scrambleFileSecrets($object);
|
$this->scrambleFileSecrets($object);
|
||||||
break;
|
break;
|
||||||
|
case PhabricatorTransactions::TYPE_HISTORY:
|
||||||
|
$this->sendHistory = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1317,6 +1327,13 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
$this->publishFeedStory($object, $xactions, $mailed);
|
$this->publishFeedStory($object, $xactions, $mailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->sendHistory) {
|
||||||
|
$history_mail = $this->buildHistoryMail($object);
|
||||||
|
if ($history_mail) {
|
||||||
|
$messages[] = $history_mail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: This actually sends the mail. We do this last to reduce the chance
|
// NOTE: This actually sends the mail. We do this last to reduce the chance
|
||||||
// that we send some mail, hit an exception, then send the mail again when
|
// that we send some mail, hit an exception, then send the mail again when
|
||||||
// retrying.
|
// retrying.
|
||||||
|
@ -2557,6 +2574,25 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
$unexpandable = array();
|
$unexpandable = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$messages = $this->buildMailWithRecipients(
|
||||||
|
$object,
|
||||||
|
$xactions,
|
||||||
|
$email_to,
|
||||||
|
$email_cc,
|
||||||
|
$unexpandable);
|
||||||
|
|
||||||
|
$this->runHeraldMailRules($messages);
|
||||||
|
|
||||||
|
return $messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildMailWithRecipients(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
array $xactions,
|
||||||
|
array $email_to,
|
||||||
|
array $email_cc,
|
||||||
|
array $unexpandable) {
|
||||||
|
|
||||||
$targets = $this->buildReplyHandler($object)
|
$targets = $this->buildReplyHandler($object)
|
||||||
->setUnexpandablePHIDs($unexpandable)
|
->setUnexpandablePHIDs($unexpandable)
|
||||||
->getMailTargets($email_to, $email_cc);
|
->getMailTargets($email_to, $email_cc);
|
||||||
|
@ -2603,8 +2639,6 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->runHeraldMailRules($messages);
|
|
||||||
|
|
||||||
return $messages;
|
return $messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3671,6 +3705,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
'mailMutedPHIDs',
|
'mailMutedPHIDs',
|
||||||
'webhookMap',
|
'webhookMap',
|
||||||
'silent',
|
'silent',
|
||||||
|
'sendHistory',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4328,4 +4363,32 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildHistoryMail(PhabricatorLiskDAO $object) {
|
||||||
|
$viewer = $this->requireActor();
|
||||||
|
$recipient_phid = $this->getActingAsPHID();
|
||||||
|
|
||||||
|
// Load every transaction so we can build a mail message with a complete
|
||||||
|
// history for the object.
|
||||||
|
$query = PhabricatorApplicationTransactionQuery::newQueryForObject($object);
|
||||||
|
$xactions = $query
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withObjectPHIDs(array($object->getPHID()))
|
||||||
|
->execute();
|
||||||
|
$xactions = array_reverse($xactions);
|
||||||
|
|
||||||
|
$mail_messages = $this->buildMailWithRecipients(
|
||||||
|
$object,
|
||||||
|
$xactions,
|
||||||
|
array($recipient_phid),
|
||||||
|
array(),
|
||||||
|
array());
|
||||||
|
$mail = head($mail_messages);
|
||||||
|
|
||||||
|
// Since the user explicitly requested "!history", force delivery of this
|
||||||
|
// message regardless of their other mail settings.
|
||||||
|
$mail->setForceDelivery(true);
|
||||||
|
|
||||||
|
return $mail;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -545,11 +545,18 @@ abstract class PhabricatorApplicationTransaction
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$xaction_type = $this->getTransactionType();
|
||||||
|
|
||||||
|
// Always hide requests for object history.
|
||||||
|
if ($xaction_type === PhabricatorTransactions::TYPE_HISTORY) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Hide creation transactions if the old value is empty. These are
|
// Hide creation transactions if the old value is empty. These are
|
||||||
// transactions like "alice set the task tile to: ...", which are
|
// transactions like "alice set the task title to: ...", which are
|
||||||
// essentially never interesting.
|
// essentially never interesting.
|
||||||
if ($this->getIsCreateTransaction()) {
|
if ($this->getIsCreateTransaction()) {
|
||||||
switch ($this->getTransactionType()) {
|
switch ($xaction_type) {
|
||||||
case PhabricatorTransactions::TYPE_CREATE:
|
case PhabricatorTransactions::TYPE_CREATE:
|
||||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||||
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
||||||
|
|
Loading…
Reference in a new issue