mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 08:52:39 +01:00
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
This commit is contained in:
parent
4236952cdb
commit
994d2e8e15
5 changed files with 126 additions and 20 deletions
|
@ -3,6 +3,7 @@
|
|||
abstract class PhabricatorMailImplementationAdapter extends Phobject {
|
||||
|
||||
private $key;
|
||||
private $priority;
|
||||
private $options = array();
|
||||
|
||||
final public function getAdapterType() {
|
||||
|
@ -57,6 +58,15 @@ abstract class PhabricatorMailImplementationAdapter extends Phobject {
|
|||
return $this->key;
|
||||
}
|
||||
|
||||
final public function setPriority($priority) {
|
||||
$this->priority = $priority;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final public function getPriority() {
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
final public function getOption($key) {
|
||||
if (!array_key_exists($key, $this->options)) {
|
||||
throw new Exception(
|
||||
|
|
|
@ -8,14 +8,31 @@ final class PhabricatorMetaMTAMailgunReceiveController
|
|||
}
|
||||
|
||||
private function verifyMessage() {
|
||||
$api_key = PhabricatorEnv::getEnvConfig('mailgun.api-key');
|
||||
$request = $this->getRequest();
|
||||
$timestamp = $request->getStr('timestamp');
|
||||
$token = $request->getStr('token');
|
||||
$sig = $request->getStr('signature');
|
||||
$hash = hash_hmac('sha256', $timestamp.$token, $api_key);
|
||||
|
||||
return phutil_hashes_are_identical($sig, $hash);
|
||||
// An install may configure multiple Mailgun mailers, and we might receive
|
||||
// inbound mail from any of them. Test the signature to see if it matches
|
||||
// any configured Mailgun mailer.
|
||||
|
||||
$mailers = PhabricatorMetaMTAMail::newMailers();
|
||||
$mailgun_type = PhabricatorMailImplementationMailgunAdapter::ADAPTERTYPE;
|
||||
foreach ($mailers as $mailer) {
|
||||
if ($mailer->getAdapterType() != $mailgun_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$api_key = $mailer->getOption('api-key');
|
||||
|
||||
$hash = hash_hmac('sha256', $timestamp.$token, $api_key);
|
||||
if (phutil_hashes_are_identical($sig, $hash)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
|
|
|
@ -8,6 +8,26 @@ final class PhabricatorMetaMTASendGridReceiveController
|
|||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$mailers = PhabricatorMetaMTAMail::newMailers();
|
||||
$sendgrid_type = PhabricatorMailImplementationSendGridAdapter::ADAPTERTYPE;
|
||||
|
||||
// SendGrid doesn't sign payloads so we can't be sure that SendGrid
|
||||
// actually sent this request, but require a configured SendGrid mailer
|
||||
// before we activate this endpoint.
|
||||
|
||||
$has_sendgrid = false;
|
||||
foreach ($mailers as $mailer) {
|
||||
if ($mailer->getAdapterType() != $sendgrid_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$has_sendgrid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$has_sendgrid) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
// No CSRF for SendGrid.
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
|
|
|
@ -463,33 +463,85 @@ final class PhabricatorMetaMTAMail
|
|||
throw new Exception(pht('Trying to send an already-sent mail!'));
|
||||
}
|
||||
|
||||
$mailers = $this->newMailers();
|
||||
$mailers = self::newMailers();
|
||||
|
||||
return $this->sendWithMailers($mailers);
|
||||
}
|
||||
|
||||
private function newMailers() {
|
||||
public static function newMailers() {
|
||||
$mailers = array();
|
||||
|
||||
$mailer = PhabricatorEnv::newObjectFromConfig('metamta.mail-adapter');
|
||||
$config = PhabricatorEnv::getEnvConfig('cluster.mailers');
|
||||
if ($config === null) {
|
||||
$mailer = PhabricatorEnv::newObjectFromConfig('metamta.mail-adapter');
|
||||
|
||||
$defaults = $mailer->newDefaultOptions();
|
||||
$options = $mailer->newLegacyOptions();
|
||||
$defaults = $mailer->newDefaultOptions();
|
||||
$options = $mailer->newLegacyOptions();
|
||||
|
||||
$options = $options + $defaults;
|
||||
$options = $options + $defaults;
|
||||
|
||||
$mailer
|
||||
->setKey('default')
|
||||
->setOptions($options);
|
||||
$mailer
|
||||
->setKey('default')
|
||||
->setPriority(-1)
|
||||
->setOptions($options);
|
||||
|
||||
$mailer->prepareForSend();
|
||||
$mailers[] = $mailer;
|
||||
} else {
|
||||
$adapters = PhabricatorMailImplementationAdapter::getAllAdapters();
|
||||
$next_priority = -1;
|
||||
|
||||
$mailers[] = $mailer;
|
||||
foreach ($config as $spec) {
|
||||
$type = $spec['type'];
|
||||
if (!isset($adapters[$type])) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unknown mailer ("%s")!',
|
||||
$type));
|
||||
}
|
||||
|
||||
return $mailers;
|
||||
$key = $spec['key'];
|
||||
$mailer = id(clone $adapters[$type])
|
||||
->setKey($key);
|
||||
|
||||
$priority = idx($spec, 'priority');
|
||||
if (!$priority) {
|
||||
$priority = $next_priority;
|
||||
$next_priority--;
|
||||
}
|
||||
$mailer->setPriority($priority);
|
||||
|
||||
$defaults = $mailer->newDefaultOptions();
|
||||
$options = idx($spec, 'options', array()) + $defaults;
|
||||
$mailer->setOptions($options);
|
||||
}
|
||||
}
|
||||
|
||||
$sorted = array();
|
||||
$groups = mgroup($mailers, 'getPriority');
|
||||
ksort($groups);
|
||||
foreach ($groups as $group) {
|
||||
// Reorder services within the same priority group randomly.
|
||||
shuffle($group);
|
||||
foreach ($group as $mailer) {
|
||||
$sorted[] = $mailer;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($sorted as $mailer) {
|
||||
$mailer->prepareForSend();
|
||||
}
|
||||
|
||||
return $sorted;
|
||||
}
|
||||
|
||||
public function sendWithMailers(array $mailers) {
|
||||
if (!$mailers) {
|
||||
return $this
|
||||
->setStatus(PhabricatorMailOutboundStatus::STATUS_VOID)
|
||||
->setMessage(pht('No mailers are configured.'))
|
||||
->save();
|
||||
}
|
||||
|
||||
$exceptions = array();
|
||||
foreach ($mailers as $template_mailer) {
|
||||
$mailer = null;
|
||||
|
@ -865,6 +917,12 @@ final class PhabricatorMetaMTAMail
|
|||
$mailer->addCCs($add_cc);
|
||||
}
|
||||
|
||||
// Keep track of which mailer actually ended up accepting the message.
|
||||
$mailer_key = $mailer->getKey();
|
||||
if ($mailer_key !== null) {
|
||||
$this->setParam('mailer.key', $mailer_key);
|
||||
}
|
||||
|
||||
return $mailer;
|
||||
}
|
||||
|
||||
|
|
|
@ -2575,12 +2575,13 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
|
||||
$mail = $this->buildMailForTarget($object, $xactions, $target);
|
||||
|
||||
if ($this->mustEncrypt) {
|
||||
$mail
|
||||
->setMustEncrypt(true)
|
||||
->setMustEncryptReasons($this->mustEncrypt);
|
||||
if ($mail) {
|
||||
if ($this->mustEncrypt) {
|
||||
$mail
|
||||
->setMustEncrypt(true)
|
||||
->setMustEncryptReasons($this->mustEncrypt);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $ex) {
|
||||
$caught = $ex;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue