Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php
12256 views
1
<?php
2
3
final class PhabricatorMetaMTAMailgunReceiveController
4
extends PhabricatorMetaMTAController {
5
6
public function shouldRequireLogin() {
7
return false;
8
}
9
10
private function verifyMessage() {
11
$request = $this->getRequest();
12
$timestamp = $request->getStr('timestamp');
13
$token = $request->getStr('token');
14
$sig = $request->getStr('signature');
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
array(
22
'inbound' => true,
23
'types' => array(
24
PhabricatorMailMailgunAdapter::ADAPTERTYPE,
25
),
26
));
27
foreach ($mailers as $mailer) {
28
$api_key = $mailer->getOption('api-key');
29
$hash = hash_hmac('sha256', $timestamp.$token, $api_key);
30
if (phutil_hashes_are_identical($sig, $hash)) {
31
return true;
32
}
33
}
34
35
return false;
36
}
37
38
public function handleRequest(AphrontRequest $request) {
39
40
// No CSRF for Mailgun.
41
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
42
43
if (!$this->verifyMessage()) {
44
throw new Exception(
45
pht('Mail signature is not valid. Check your Mailgun API key.'));
46
}
47
48
$raw_headers = $request->getStr('message-headers');
49
$raw_dict = array();
50
if (strlen($raw_headers)) {
51
$raw_headers = phutil_json_decode($raw_headers);
52
foreach ($raw_headers as $raw_header) {
53
list($name, $value) = $raw_header;
54
$raw_dict[$name] = $value;
55
}
56
}
57
58
$headers = array(
59
'to' => $request->getStr('recipient'),
60
'from' => $request->getStr('from'),
61
'subject' => $request->getStr('subject'),
62
) + $raw_dict;
63
64
$received = new PhabricatorMetaMTAReceivedMail();
65
$received->setHeaders($headers);
66
$received->setBodies(array(
67
'text' => $request->getStr('stripped-text'),
68
'html' => $request->getStr('stripped-html'),
69
));
70
71
$file_phids = array();
72
foreach ($_FILES as $file_raw) {
73
try {
74
$file = PhabricatorFile::newFromPHPUpload(
75
$file_raw,
76
array(
77
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
78
));
79
$file_phids[] = $file->getPHID();
80
} catch (Exception $ex) {
81
phlog($ex);
82
}
83
}
84
$received->setAttachments($file_phids);
85
86
try {
87
$received->save();
88
$received->processReceivedMail();
89
} catch (Exception $ex) {
90
// We can get exceptions here in two cases.
91
92
// First, saving the message may throw if we have already received a
93
// message with the same Message ID. In this case, we're declining to
94
// process a duplicate message, so failing silently is correct.
95
96
// Second, processing the message may throw (for example, if it contains
97
// an invalid !command). This will generate an email as a side effect,
98
// so we don't need to explicitly handle the exception here.
99
100
// In these cases, we want to return HTTP 200. If we do not, MailGun will
101
// re-transmit the message later.
102
phlog($ex);
103
}
104
105
$response = new AphrontWebpageResponse();
106
$response->setContent(pht("Got it! Thanks, Mailgun!\n"));
107
return $response;
108
}
109
110
}
111
112