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

Use "cluster.mailers" if it is configured

Summary:
Depends on D19004. Ref T13053. Ref T12677. If the new `cluster.mailers` is configured, make use of it. Also use it in the Sengrid/Mailgun inbound stuff.

Also fix a bug where "Must Encrypt" mail to no recipients could fatal because no `$mail` was returned.

Test Plan: Processed some mail locally. The testing on this is still pretty flimsy, but I plan to solidify it in an upcoming change.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13053, T12677

Differential Revision: https://secure.phabricator.com/D19005

+126 -20
+10
src/applications/metamta/adapter/PhabricatorMailImplementationAdapter.php
··· 3 3 abstract class PhabricatorMailImplementationAdapter extends Phobject { 4 4 5 5 private $key; 6 + private $priority; 6 7 private $options = array(); 7 8 8 9 final public function getAdapterType() { ··· 55 56 56 57 final public function getKey() { 57 58 return $this->key; 59 + } 60 + 61 + final public function setPriority($priority) { 62 + $this->priority = $priority; 63 + return $this; 64 + } 65 + 66 + final public function getPriority() { 67 + return $this->priority; 58 68 } 59 69 60 70 final public function getOption($key) {
+20 -3
src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php
··· 8 8 } 9 9 10 10 private function verifyMessage() { 11 - $api_key = PhabricatorEnv::getEnvConfig('mailgun.api-key'); 12 11 $request = $this->getRequest(); 13 12 $timestamp = $request->getStr('timestamp'); 14 13 $token = $request->getStr('token'); 15 14 $sig = $request->getStr('signature'); 16 - $hash = hash_hmac('sha256', $timestamp.$token, $api_key); 15 + 16 + // An install may configure multiple Mailgun mailers, and we might receive 17 + // inbound mail from any of them. Test the signature to see if it matches 18 + // any configured Mailgun mailer. 19 + 20 + $mailers = PhabricatorMetaMTAMail::newMailers(); 21 + $mailgun_type = PhabricatorMailImplementationMailgunAdapter::ADAPTERTYPE; 22 + foreach ($mailers as $mailer) { 23 + if ($mailer->getAdapterType() != $mailgun_type) { 24 + continue; 25 + } 26 + 27 + $api_key = $mailer->getOption('api-key'); 28 + 29 + $hash = hash_hmac('sha256', $timestamp.$token, $api_key); 30 + if (phutil_hashes_are_identical($sig, $hash)) { 31 + return true; 32 + } 33 + } 17 34 18 - return phutil_hashes_are_identical($sig, $hash); 35 + return false; 19 36 } 20 37 21 38 public function handleRequest(AphrontRequest $request) {
+20
src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php
··· 8 8 } 9 9 10 10 public function handleRequest(AphrontRequest $request) { 11 + $mailers = PhabricatorMetaMTAMail::newMailers(); 12 + $sendgrid_type = PhabricatorMailImplementationSendGridAdapter::ADAPTERTYPE; 13 + 14 + // SendGrid doesn't sign payloads so we can't be sure that SendGrid 15 + // actually sent this request, but require a configured SendGrid mailer 16 + // before we activate this endpoint. 17 + 18 + $has_sendgrid = false; 19 + foreach ($mailers as $mailer) { 20 + if ($mailer->getAdapterType() != $sendgrid_type) { 21 + continue; 22 + } 23 + 24 + $has_sendgrid = true; 25 + break; 26 + } 27 + 28 + if (!$has_sendgrid) { 29 + return new Aphront404Response(); 30 + } 11 31 12 32 // No CSRF for SendGrid. 13 33 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+70 -12
src/applications/metamta/storage/PhabricatorMetaMTAMail.php
··· 463 463 throw new Exception(pht('Trying to send an already-sent mail!')); 464 464 } 465 465 466 - $mailers = $this->newMailers(); 466 + $mailers = self::newMailers(); 467 467 468 468 return $this->sendWithMailers($mailers); 469 469 } 470 470 471 - private function newMailers() { 471 + public static function newMailers() { 472 472 $mailers = array(); 473 473 474 - $mailer = PhabricatorEnv::newObjectFromConfig('metamta.mail-adapter'); 474 + $config = PhabricatorEnv::getEnvConfig('cluster.mailers'); 475 + if ($config === null) { 476 + $mailer = PhabricatorEnv::newObjectFromConfig('metamta.mail-adapter'); 475 477 476 - $defaults = $mailer->newDefaultOptions(); 477 - $options = $mailer->newLegacyOptions(); 478 + $defaults = $mailer->newDefaultOptions(); 479 + $options = $mailer->newLegacyOptions(); 478 480 479 - $options = $options + $defaults; 481 + $options = $options + $defaults; 480 482 481 - $mailer 482 - ->setKey('default') 483 - ->setOptions($options); 483 + $mailer 484 + ->setKey('default') 485 + ->setPriority(-1) 486 + ->setOptions($options); 484 487 485 - $mailer->prepareForSend(); 488 + $mailers[] = $mailer; 489 + } else { 490 + $adapters = PhabricatorMailImplementationAdapter::getAllAdapters(); 491 + $next_priority = -1; 486 492 487 - $mailers[] = $mailer; 493 + foreach ($config as $spec) { 494 + $type = $spec['type']; 495 + if (!isset($adapters[$type])) { 496 + throw new Exception( 497 + pht( 498 + 'Unknown mailer ("%s")!', 499 + $type)); 500 + } 488 501 489 - return $mailers; 502 + $key = $spec['key']; 503 + $mailer = id(clone $adapters[$type]) 504 + ->setKey($key); 505 + 506 + $priority = idx($spec, 'priority'); 507 + if (!$priority) { 508 + $priority = $next_priority; 509 + $next_priority--; 510 + } 511 + $mailer->setPriority($priority); 512 + 513 + $defaults = $mailer->newDefaultOptions(); 514 + $options = idx($spec, 'options', array()) + $defaults; 515 + $mailer->setOptions($options); 516 + } 517 + } 518 + 519 + $sorted = array(); 520 + $groups = mgroup($mailers, 'getPriority'); 521 + ksort($groups); 522 + foreach ($groups as $group) { 523 + // Reorder services within the same priority group randomly. 524 + shuffle($group); 525 + foreach ($group as $mailer) { 526 + $sorted[] = $mailer; 527 + } 528 + } 529 + 530 + foreach ($sorted as $mailer) { 531 + $mailer->prepareForSend(); 532 + } 533 + 534 + return $sorted; 490 535 } 491 536 492 537 public function sendWithMailers(array $mailers) { 538 + if (!$mailers) { 539 + return $this 540 + ->setStatus(PhabricatorMailOutboundStatus::STATUS_VOID) 541 + ->setMessage(pht('No mailers are configured.')) 542 + ->save(); 543 + } 544 + 493 545 $exceptions = array(); 494 546 foreach ($mailers as $template_mailer) { 495 547 $mailer = null; ··· 863 915 $mailer->addTos($add_to); 864 916 if ($add_cc) { 865 917 $mailer->addCCs($add_cc); 918 + } 919 + 920 + // Keep track of which mailer actually ended up accepting the message. 921 + $mailer_key = $mailer->getKey(); 922 + if ($mailer_key !== null) { 923 + $this->setParam('mailer.key', $mailer_key); 866 924 } 867 925 868 926 return $mailer;
+6 -5
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 2575 2575 2576 2576 $mail = $this->buildMailForTarget($object, $xactions, $target); 2577 2577 2578 - if ($this->mustEncrypt) { 2579 - $mail 2580 - ->setMustEncrypt(true) 2581 - ->setMustEncryptReasons($this->mustEncrypt); 2578 + if ($mail) { 2579 + if ($this->mustEncrypt) { 2580 + $mail 2581 + ->setMustEncrypt(true) 2582 + ->setMustEncryptReasons($this->mustEncrypt); 2583 + } 2582 2584 } 2583 - 2584 2585 } catch (Exception $ex) { 2585 2586 $caught = $ex; 2586 2587 }