Path: blob/master/src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php
12256 views
<?php12final class PhabricatorMetaMTAMailgunReceiveController3extends PhabricatorMetaMTAController {45public function shouldRequireLogin() {6return false;7}89private function verifyMessage() {10$request = $this->getRequest();11$timestamp = $request->getStr('timestamp');12$token = $request->getStr('token');13$sig = $request->getStr('signature');1415// An install may configure multiple Mailgun mailers, and we might receive16// inbound mail from any of them. Test the signature to see if it matches17// any configured Mailgun mailer.1819$mailers = PhabricatorMetaMTAMail::newMailers(20array(21'inbound' => true,22'types' => array(23PhabricatorMailMailgunAdapter::ADAPTERTYPE,24),25));26foreach ($mailers as $mailer) {27$api_key = $mailer->getOption('api-key');28$hash = hash_hmac('sha256', $timestamp.$token, $api_key);29if (phutil_hashes_are_identical($sig, $hash)) {30return true;31}32}3334return false;35}3637public function handleRequest(AphrontRequest $request) {3839// No CSRF for Mailgun.40$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();4142if (!$this->verifyMessage()) {43throw new Exception(44pht('Mail signature is not valid. Check your Mailgun API key.'));45}4647$raw_headers = $request->getStr('message-headers');48$raw_dict = array();49if (strlen($raw_headers)) {50$raw_headers = phutil_json_decode($raw_headers);51foreach ($raw_headers as $raw_header) {52list($name, $value) = $raw_header;53$raw_dict[$name] = $value;54}55}5657$headers = array(58'to' => $request->getStr('recipient'),59'from' => $request->getStr('from'),60'subject' => $request->getStr('subject'),61) + $raw_dict;6263$received = new PhabricatorMetaMTAReceivedMail();64$received->setHeaders($headers);65$received->setBodies(array(66'text' => $request->getStr('stripped-text'),67'html' => $request->getStr('stripped-html'),68));6970$file_phids = array();71foreach ($_FILES as $file_raw) {72try {73$file = PhabricatorFile::newFromPHPUpload(74$file_raw,75array(76'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,77));78$file_phids[] = $file->getPHID();79} catch (Exception $ex) {80phlog($ex);81}82}83$received->setAttachments($file_phids);8485try {86$received->save();87$received->processReceivedMail();88} catch (Exception $ex) {89// We can get exceptions here in two cases.9091// First, saving the message may throw if we have already received a92// message with the same Message ID. In this case, we're declining to93// process a duplicate message, so failing silently is correct.9495// Second, processing the message may throw (for example, if it contains96// an invalid !command). This will generate an email as a side effect,97// so we don't need to explicitly handle the exception here.9899// In these cases, we want to return HTTP 200. If we do not, MailGun will100// re-transmit the message later.101phlog($ex);102}103104$response = new AphrontWebpageResponse();105$response->setContent(pht("Got it! Thanks, Mailgun!\n"));106return $response;107}108109}110111112