mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 22:10:55 +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_COLUMNS = 'core:columns';
|
||||
const TYPE_SUBTYPE = 'core:subtype';
|
||||
const TYPE_HISTORY = 'core:history';
|
||||
|
||||
const COLOR_RED = 'red';
|
||||
const COLOR_ORANGE = 'orange';
|
||||
|
|
|
@ -83,6 +83,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
private $webhookMap = array();
|
||||
|
||||
private $transactionQueue = array();
|
||||
private $sendHistory = false;
|
||||
|
||||
const STORAGE_ENCODING_BINARY = 'binary';
|
||||
|
||||
|
@ -300,6 +301,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$types = array();
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_CREATE;
|
||||
$types[] = PhabricatorTransactions::TYPE_HISTORY;
|
||||
|
||||
if ($this->object instanceof PhabricatorEditEngineSubtypeInterface) {
|
||||
$types[] = PhabricatorTransactions::TYPE_SUBTYPE;
|
||||
|
@ -377,6 +379,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
|
||||
switch ($type) {
|
||||
case PhabricatorTransactions::TYPE_CREATE:
|
||||
case PhabricatorTransactions::TYPE_HISTORY:
|
||||
return null;
|
||||
case PhabricatorTransactions::TYPE_SUBTYPE:
|
||||
return $object->getEditEngineSubtype();
|
||||
|
@ -468,6 +471,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
case PhabricatorTransactions::TYPE_TOKEN:
|
||||
case PhabricatorTransactions::TYPE_INLINESTATE:
|
||||
case PhabricatorTransactions::TYPE_SUBTYPE:
|
||||
case PhabricatorTransactions::TYPE_HISTORY:
|
||||
return $xaction->getNewValue();
|
||||
case PhabricatorTransactions::TYPE_SPACE:
|
||||
$space_phid = $xaction->getNewValue();
|
||||
|
@ -520,6 +524,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorTransactions::TYPE_CREATE:
|
||||
case PhabricatorTransactions::TYPE_HISTORY:
|
||||
return true;
|
||||
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
|
||||
$field = $this->getCustomFieldForTransaction($object, $xaction);
|
||||
|
@ -604,6 +609,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$field = $this->getCustomFieldForTransaction($object, $xaction);
|
||||
return $field->applyApplicationTransactionInternalEffects($xaction);
|
||||
case PhabricatorTransactions::TYPE_CREATE:
|
||||
case PhabricatorTransactions::TYPE_HISTORY:
|
||||
case PhabricatorTransactions::TYPE_SUBTYPE:
|
||||
case PhabricatorTransactions::TYPE_TOKEN:
|
||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||
|
@ -665,6 +671,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$field = $this->getCustomFieldForTransaction($object, $xaction);
|
||||
return $field->applyApplicationTransactionExternalEffects($xaction);
|
||||
case PhabricatorTransactions::TYPE_CREATE:
|
||||
case PhabricatorTransactions::TYPE_HISTORY:
|
||||
case PhabricatorTransactions::TYPE_SUBTYPE:
|
||||
case PhabricatorTransactions::TYPE_EDGE:
|
||||
case PhabricatorTransactions::TYPE_TOKEN:
|
||||
|
@ -800,6 +807,9 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
case PhabricatorTransactions::TYPE_SPACE:
|
||||
$this->scrambleFileSecrets($object);
|
||||
break;
|
||||
case PhabricatorTransactions::TYPE_HISTORY:
|
||||
$this->sendHistory = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1317,6 +1327,13 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$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
|
||||
// that we send some mail, hit an exception, then send the mail again when
|
||||
// retrying.
|
||||
|
@ -2557,6 +2574,25 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$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)
|
||||
->setUnexpandablePHIDs($unexpandable)
|
||||
->getMailTargets($email_to, $email_cc);
|
||||
|
@ -2603,8 +2639,6 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
}
|
||||
}
|
||||
|
||||
$this->runHeraldMailRules($messages);
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
|
@ -3671,6 +3705,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
'mailMutedPHIDs',
|
||||
'webhookMap',
|
||||
'silent',
|
||||
'sendHistory',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4328,4 +4363,32 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
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;
|
||||
}
|
||||
|
||||
$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
|
||||
// transactions like "alice set the task tile to: ...", which are
|
||||
// transactions like "alice set the task title to: ...", which are
|
||||
// essentially never interesting.
|
||||
if ($this->getIsCreateTransaction()) {
|
||||
switch ($this->getTransactionType()) {
|
||||
switch ($xaction_type) {
|
||||
case PhabricatorTransactions::TYPE_CREATE:
|
||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
||||
|
|
Loading…
Reference in a new issue