diff --git a/src/applications/metamta/management/PhabricatorMailManagementShowInboundWorkflow.php b/src/applications/metamta/management/PhabricatorMailManagementShowInboundWorkflow.php index 5226bd2dc2..ea2bf197dd 100644 --- a/src/applications/metamta/management/PhabricatorMailManagementShowInboundWorkflow.php +++ b/src/applications/metamta/management/PhabricatorMailManagementShowInboundWorkflow.php @@ -1,103 +1,106 @@ setName('show-inbound') ->setSynopsis('Show diagnostic details about inbound mail.') ->setExamples( "**show-inbound** --id 1 --id 2") ->setArguments( array( array( 'name' => 'id', 'param' => 'id', 'help' => 'Show details about inbound mail with given ID.', 'repeat' => true, ), )); } public function execute(PhutilArgumentParser $args) { $console = PhutilConsole::getConsole(); $ids = $args->getArg('id'); if (!$ids) { throw new PhutilArgumentUsageException( "Use the '--id' flag to specify one or more messages to show."); } $messages = id(new PhabricatorMetaMTAReceivedMail())->loadAllWhere( 'id IN (%Ld)', $ids); if ($ids) { $ids = array_fuse($ids); $missing = array_diff_key($ids, $messages); if ($missing) { throw new PhutilArgumentUsageException( "Some specified messages do not exist: ". implode(', ', array_keys($missing))); } } $last_key = last_key($messages); foreach ($messages as $message_key => $message) { $info = array(); $info[] = pht('PROPERTIES'); $info[] = pht('ID: %d', $message->getID()); $info[] = pht('Status: %s', $message->getStatus()); $info[] = pht('Related PHID: %s', $message->getRelatedPHID()); $info[] = pht('Author PHID: %s', $message->getAuthorPHID()); $info[] = pht('Message ID Hash: %s', $message->getMessageIDHash()); if ($message->getMessage()) { $info[] = null; $info[] = pht('MESSAGE'); $info[] = $message->getMessage(); } $info[] = null; $info[] = pht('HEADERS'); foreach ($message->getHeaders() as $key => $value) { + if (is_array($value)) { + $value = implode("\n", $value); + } $info[] = pht('%s: %s', $key, $value); } $bodies = $message->getBodies(); $last_body = last_key($bodies); $info[] = null; $info[] = pht('BODIES'); foreach ($bodies as $key => $value) { $info[] = pht('Body "%s"', $key); $info[] = $value; if ($key != $last_body) { $info[] = null; } } $attachments = $message->getAttachments(); $info[] = null; $info[] = pht('ATTACHMENTS'); if (!$attachments) { $info[] = pht('No attachments.'); } else { foreach ($attachments as $attachment) { $info[] = pht('File PHID: %s', $attachment); } } $console->writeOut("%s\n", implode("\n", $info)); if ($message_key != $last_key) { $console->writeOut("\n%s\n\n", str_repeat('-', 80)); } } } } diff --git a/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php b/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php index 9202e710f5..8c88e4e1f5 100644 --- a/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php +++ b/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php @@ -1,179 +1,181 @@ loadObjectFromMail($mail, $sender); $mail->setRelatedPHID($object->getPHID()); $this->processReceivedObjectMail($mail, $object, $sender); return $this; } abstract protected function processReceivedObjectMail( PhabricatorMetaMTAReceivedMail $mail, PhabricatorLiskDAO $object, PhabricatorUser $sender); public function loadMailReceiverObject($pattern, PhabricatorUser $viewer) { return $this->loadObject($pattern, $viewer); } public function validateSender( PhabricatorMetaMTAReceivedMail $mail, PhabricatorUser $sender) { parent::validateSender($mail, $sender); $parts = $this->matchObjectAddressInMail($mail); try { $object = $this->loadObjectFromMail($mail, $sender); } catch (PhabricatorPolicyException $policy_exception) { throw new PhabricatorMetaMTAReceivedMailProcessingException( MetaMTAReceivedMailStatus::STATUS_POLICY_PROBLEM, pht( "This mail is addressed to an object you are not permitted ". "to see: %s", $policy_exception->getMessage())); } if (!$object) { throw new PhabricatorMetaMTAReceivedMailProcessingException( MetaMTAReceivedMailStatus::STATUS_NO_SUCH_OBJECT, pht( "This mail is addressed to an object ('%s'), but that object ". "does not exist.", $parts['pattern'])); } $sender_identifier = $parts['sender']; if ($sender_identifier === 'public') { if (!PhabricatorEnv::getEnvConfig('metamta.public-replies')) { throw new PhabricatorMetaMTAReceivedMailProcessingException( MetaMTAReceivedMailStatus::STATUS_NO_PUBLIC_MAIL, pht( "This mail is addressed to an object's public address, but ". "public replies are not enabled (`metamta.public-replies`).")); } $check_phid = $object->getPHID(); } else { if ($sender_identifier != $sender->getID()) { throw new PhabricatorMetaMTAReceivedMailProcessingException( MetaMTAReceivedMailStatus::STATUS_USER_MISMATCH, pht( "This mail is addressed to an object's private address, but ". "the sending user and the private address owner are not the ". "same user.")); } $check_phid = $sender->getPHID(); } $expect_hash = self::computeMailHash($object->getMailKey(), $check_phid); if ($expect_hash != $parts['hash']) { throw new PhabricatorMetaMTAReceivedMailProcessingException( MetaMTAReceivedMailStatus::STATUS_HASH_MISMATCH, pht( "The hash in this object's address does not match the expected ". "value.")); } } final public function canAcceptMail(PhabricatorMetaMTAReceivedMail $mail) { if ($this->matchObjectAddressInMail($mail)) { return true; } return false; } private function matchObjectAddressInMail( PhabricatorMetaMTAReceivedMail $mail) { foreach ($mail->getToAddresses() as $address) { $parts = $this->matchObjectAddress($address); if ($parts) { return $parts; } } return null; } private function matchObjectAddress($address) { $regexp = $this->getAddressRegexp(); $address = self::stripMailboxPrefix($address); $local = id(new PhutilEmailAddress($address))->getLocalPart(); $matches = null; if (!preg_match($regexp, $local, $matches)) { return false; } return $matches; } private function getAddressRegexp() { $pattern = $this->getObjectPattern(); $regexp = '(^'. '(?P'.$pattern.')'. '\\+'. '(?P\w+)'. '\\+'. '(?P[a-f0-9]{16})'. - '$)U'; + '$)Ui'; return $regexp; } private function loadObjectFromMail( PhabricatorMetaMTAReceivedMail $mail, PhabricatorUser $sender) { $parts = $this->matchObjectAddressInMail($mail); - return $this->loadObject($parts['pattern'], $sender); + return $this->loadObject( + phutil_utf8_strtoupper($parts['pattern']), + $sender); } public static function computeMailHash($mail_key, $phid) { $global_mail_key = PhabricatorEnv::getEnvConfig('phabricator.mail-key'); $hash = PhabricatorHash::digest($mail_key.$global_mail_key.$phid); return substr($hash, 0, 16); } }