@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+75 -4
+1
src/applications/transactions/constants/PhabricatorTransactions.php
··· 15 15 const TYPE_CREATE = 'core:create'; 16 16 const TYPE_COLUMNS = 'core:columns'; 17 17 const TYPE_SUBTYPE = 'core:subtype'; 18 + const TYPE_HISTORY = 'core:history'; 18 19 19 20 const COLOR_RED = 'red'; 20 21 const COLOR_ORANGE = 'orange';
+65 -2
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 83 83 private $webhookMap = array(); 84 84 85 85 private $transactionQueue = array(); 86 + private $sendHistory = false; 86 87 87 88 const STORAGE_ENCODING_BINARY = 'binary'; 88 89 ··· 300 301 $types = array(); 301 302 302 303 $types[] = PhabricatorTransactions::TYPE_CREATE; 304 + $types[] = PhabricatorTransactions::TYPE_HISTORY; 303 305 304 306 if ($this->object instanceof PhabricatorEditEngineSubtypeInterface) { 305 307 $types[] = PhabricatorTransactions::TYPE_SUBTYPE; ··· 377 379 378 380 switch ($type) { 379 381 case PhabricatorTransactions::TYPE_CREATE: 382 + case PhabricatorTransactions::TYPE_HISTORY: 380 383 return null; 381 384 case PhabricatorTransactions::TYPE_SUBTYPE: 382 385 return $object->getEditEngineSubtype(); ··· 468 471 case PhabricatorTransactions::TYPE_TOKEN: 469 472 case PhabricatorTransactions::TYPE_INLINESTATE: 470 473 case PhabricatorTransactions::TYPE_SUBTYPE: 474 + case PhabricatorTransactions::TYPE_HISTORY: 471 475 return $xaction->getNewValue(); 472 476 case PhabricatorTransactions::TYPE_SPACE: 473 477 $space_phid = $xaction->getNewValue(); ··· 520 524 521 525 switch ($xaction->getTransactionType()) { 522 526 case PhabricatorTransactions::TYPE_CREATE: 527 + case PhabricatorTransactions::TYPE_HISTORY: 523 528 return true; 524 529 case PhabricatorTransactions::TYPE_CUSTOMFIELD: 525 530 $field = $this->getCustomFieldForTransaction($object, $xaction); ··· 604 609 $field = $this->getCustomFieldForTransaction($object, $xaction); 605 610 return $field->applyApplicationTransactionInternalEffects($xaction); 606 611 case PhabricatorTransactions::TYPE_CREATE: 612 + case PhabricatorTransactions::TYPE_HISTORY: 607 613 case PhabricatorTransactions::TYPE_SUBTYPE: 608 614 case PhabricatorTransactions::TYPE_TOKEN: 609 615 case PhabricatorTransactions::TYPE_VIEW_POLICY: ··· 665 671 $field = $this->getCustomFieldForTransaction($object, $xaction); 666 672 return $field->applyApplicationTransactionExternalEffects($xaction); 667 673 case PhabricatorTransactions::TYPE_CREATE: 674 + case PhabricatorTransactions::TYPE_HISTORY: 668 675 case PhabricatorTransactions::TYPE_SUBTYPE: 669 676 case PhabricatorTransactions::TYPE_EDGE: 670 677 case PhabricatorTransactions::TYPE_TOKEN: ··· 800 807 case PhabricatorTransactions::TYPE_SPACE: 801 808 $this->scrambleFileSecrets($object); 802 809 break; 810 + case PhabricatorTransactions::TYPE_HISTORY: 811 + $this->sendHistory = true; 812 + break; 803 813 } 804 814 } 805 815 ··· 1315 1325 } 1316 1326 1317 1327 $this->publishFeedStory($object, $xactions, $mailed); 1328 + } 1329 + 1330 + if ($this->sendHistory) { 1331 + $history_mail = $this->buildHistoryMail($object); 1332 + if ($history_mail) { 1333 + $messages[] = $history_mail; 1334 + } 1318 1335 } 1319 1336 1320 1337 // NOTE: This actually sends the mail. We do this last to reduce the chance ··· 2557 2574 $unexpandable = array(); 2558 2575 } 2559 2576 2577 + $messages = $this->buildMailWithRecipients( 2578 + $object, 2579 + $xactions, 2580 + $email_to, 2581 + $email_cc, 2582 + $unexpandable); 2583 + 2584 + $this->runHeraldMailRules($messages); 2585 + 2586 + return $messages; 2587 + } 2588 + 2589 + private function buildMailWithRecipients( 2590 + PhabricatorLiskDAO $object, 2591 + array $xactions, 2592 + array $email_to, 2593 + array $email_cc, 2594 + array $unexpandable) { 2595 + 2560 2596 $targets = $this->buildReplyHandler($object) 2561 2597 ->setUnexpandablePHIDs($unexpandable) 2562 2598 ->getMailTargets($email_to, $email_cc); ··· 2602 2638 $messages[] = $mail; 2603 2639 } 2604 2640 } 2605 - 2606 - $this->runHeraldMailRules($messages); 2607 2641 2608 2642 return $messages; 2609 2643 } ··· 3671 3705 'mailMutedPHIDs', 3672 3706 'webhookMap', 3673 3707 'silent', 3708 + 'sendHistory', 3674 3709 ); 3675 3710 } 3676 3711 ··· 4326 4361 // subscribers. 4327 4362 4328 4363 return true; 4364 + } 4365 + 4366 + private function buildHistoryMail(PhabricatorLiskDAO $object) { 4367 + $viewer = $this->requireActor(); 4368 + $recipient_phid = $this->getActingAsPHID(); 4369 + 4370 + // Load every transaction so we can build a mail message with a complete 4371 + // history for the object. 4372 + $query = PhabricatorApplicationTransactionQuery::newQueryForObject($object); 4373 + $xactions = $query 4374 + ->setViewer($viewer) 4375 + ->withObjectPHIDs(array($object->getPHID())) 4376 + ->execute(); 4377 + $xactions = array_reverse($xactions); 4378 + 4379 + $mail_messages = $this->buildMailWithRecipients( 4380 + $object, 4381 + $xactions, 4382 + array($recipient_phid), 4383 + array(), 4384 + array()); 4385 + $mail = head($mail_messages); 4386 + 4387 + // Since the user explicitly requested "!history", force delivery of this 4388 + // message regardless of their other mail settings. 4389 + $mail->setForceDelivery(true); 4390 + 4391 + return $mail; 4329 4392 } 4330 4393 4331 4394 }
+9 -2
src/applications/transactions/storage/PhabricatorApplicationTransaction.php
··· 545 545 return false; 546 546 } 547 547 548 + $xaction_type = $this->getTransactionType(); 549 + 550 + // Always hide requests for object history. 551 + if ($xaction_type === PhabricatorTransactions::TYPE_HISTORY) { 552 + return true; 553 + } 554 + 548 555 // Hide creation transactions if the old value is empty. These are 549 - // transactions like "alice set the task tile to: ...", which are 556 + // transactions like "alice set the task title to: ...", which are 550 557 // essentially never interesting. 551 558 if ($this->getIsCreateTransaction()) { 552 - switch ($this->getTransactionType()) { 559 + switch ($xaction_type) { 553 560 case PhabricatorTransactions::TYPE_CREATE: 554 561 case PhabricatorTransactions::TYPE_VIEW_POLICY: 555 562 case PhabricatorTransactions::TYPE_EDIT_POLICY: