1
0
Fork 0
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:
epriestley 2018-04-16 07:09:44 -07:00
parent b5f23b023e
commit 25965260c4
3 changed files with 75 additions and 4 deletions

View file

@ -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';

View file

@ -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;
}
} }

View file

@ -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: