This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace LeKoala\Mailgun; |
||
4 | |||
5 | use \Exception; |
||
6 | use SilverStripe\Forms\Tab; |
||
7 | use SilverStripe\Forms\Form; |
||
8 | use SilverStripe\Forms\TabSet; |
||
9 | use SilverStripe\ORM\ArrayLib; |
||
10 | use SilverStripe\ORM\ArrayList; |
||
11 | use SilverStripe\View\ArrayData; |
||
12 | use SilverStripe\Control\Session; |
||
13 | use SilverStripe\Forms\DateField; |
||
14 | use SilverStripe\Forms\FieldList; |
||
15 | use SilverStripe\Forms\FormField; |
||
16 | use SilverStripe\Forms\TextField; |
||
17 | use LeKoala\Mailgun\MailgunHelper; |
||
18 | use SilverStripe\Control\Director; |
||
19 | use SilverStripe\Core\Environment; |
||
20 | use SilverStripe\Forms\FormAction; |
||
21 | use SilverStripe\Admin\LeftAndMain; |
||
22 | use SilverStripe\Forms\HiddenField; |
||
23 | use SilverStripe\Security\Security; |
||
24 | use SilverStripe\View\ViewableData; |
||
25 | use SilverStripe\Forms\LiteralField; |
||
26 | use SilverStripe\Control\Email\Email; |
||
27 | use SilverStripe\Forms\DropdownField; |
||
28 | use SilverStripe\Security\Permission; |
||
29 | use Mailgun\Model\Event\EventResponse; |
||
30 | use SilverStripe\Forms\CompositeField; |
||
31 | use SilverStripe\SiteConfig\SiteConfig; |
||
32 | use Mailgun\Model\Webhook\IndexResponse as WebhookIndexResponse; |
||
33 | use SilverStripe\Core\Injector\Injector; |
||
34 | use LeKoala\Mailgun\MailgunSwiftTransport; |
||
35 | use SilverStripe\Control\Email\SwiftMailer; |
||
36 | use SilverStripe\Forms\GridField\GridField; |
||
37 | use SilverStripe\Security\PermissionProvider; |
||
38 | use SilverStripe\Forms\GridField\GridFieldConfig; |
||
39 | use SilverStripe\Forms\GridField\GridFieldFooter; |
||
40 | use SilverStripe\Forms\GridField\GridFieldDetailForm; |
||
41 | use SilverStripe\Forms\GridField\GridFieldDataColumns; |
||
42 | use Symbiote\GridFieldExtensions\GridFieldTitleHeader; |
||
43 | use SilverStripe\Forms\GridField\GridFieldToolbarHeader; |
||
44 | use SilverStripe\Forms\GridField\GridFieldSortableHeader; |
||
45 | use Mailgun\Model\Domain\IndexResponse as DomainIndexResponse; |
||
46 | |||
47 | /** |
||
48 | * Allow you to see messages sent through the api key used to send messages |
||
49 | * |
||
50 | * @author LeKoala <[email protected]> |
||
51 | */ |
||
52 | class MailgunAdmin extends LeftAndMain implements PermissionProvider |
||
53 | { |
||
54 | |||
55 | const MESSAGE_CACHE_MINUTES = 5; |
||
56 | const WEBHOOK_CACHE_MINUTES = 1440; // 1 day |
||
57 | const SENDINGDOMAIN_CACHE_MINUTES = 1440; // 1 day |
||
58 | |||
59 | private static $menu_title = "Mailgun"; |
||
60 | private static $url_segment = "mailgun"; |
||
61 | private static $menu_icon = "mailgun/images/mailgun-icon.png"; |
||
62 | private static $url_rule = '/$Action/$ID/$OtherID'; |
||
63 | private static $allowed_actions = [ |
||
64 | 'settings', |
||
65 | 'SearchForm', |
||
66 | 'doSearch', |
||
67 | "doInstallHook", |
||
68 | "doUninstallHook", |
||
69 | "doInstallDomain", |
||
70 | "doUninstallDomain", |
||
71 | ]; |
||
72 | |||
73 | /** |
||
74 | * @var boolean |
||
75 | */ |
||
76 | private static $cache_enabled = true; |
||
77 | |||
78 | /** |
||
79 | * @var Exception |
||
80 | */ |
||
81 | protected $lastException; |
||
82 | |||
83 | /** |
||
84 | * @var ViewableData |
||
85 | */ |
||
86 | protected $currentMessage; |
||
87 | |||
88 | /** |
||
89 | * Inject public dependencies into the controller |
||
90 | * |
||
91 | * @var array |
||
92 | */ |
||
93 | private static $dependencies = [ |
||
94 | 'logger' => '%$Psr\Log\LoggerInterface', |
||
95 | 'cache' => '%$Psr\SimpleCache\CacheInterface.mailgun', // see _config/cache.yml |
||
96 | ]; |
||
97 | |||
98 | /** |
||
99 | * @var Psr\Log\LoggerInterface |
||
100 | */ |
||
101 | public $logger; |
||
102 | |||
103 | /** |
||
104 | * @var Psr\SimpleCache\CacheInterface |
||
105 | */ |
||
106 | public $cache; |
||
107 | |||
108 | public function init() |
||
109 | { |
||
110 | parent::init(); |
||
111 | |||
112 | if (isset($_GET['refresh'])) { |
||
113 | $this->getCache()->clear(); |
||
114 | } |
||
115 | } |
||
116 | |||
117 | public function index($request) |
||
118 | { |
||
119 | return parent::index($request); |
||
120 | } |
||
121 | |||
122 | public function settings($request) |
||
123 | { |
||
124 | return parent::index($request); |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * @return Session |
||
129 | */ |
||
130 | public function getSession() |
||
131 | { |
||
132 | return $this->getRequest()->getSession(); |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Returns a GridField of messages |
||
137 | * @return CMSForm |
||
138 | */ |
||
139 | public function getEditForm($id = null, $fields = null) |
||
140 | { |
||
141 | if (!$id) { |
||
142 | $id = $this->currentPageID(); |
||
143 | } |
||
144 | |||
145 | $form = parent::getEditForm($id); |
||
0 ignored issues
–
show
|
|||
146 | |||
147 | $record = $this->getRecord($id); |
||
148 | |||
149 | // Check if this record is viewable |
||
150 | if ($record && !$record->canView()) { |
||
151 | $response = Security::permissionFailure($this); |
||
152 | $this->setResponse($response); |
||
153 | return null; |
||
154 | } |
||
155 | |||
156 | // Build gridfield |
||
157 | $messageListConfig = GridFieldConfig::create()->addComponents( |
||
158 | new GridFieldSortableHeader(), |
||
159 | new GridFieldDataColumns(), |
||
160 | new GridFieldFooter() |
||
161 | ); |
||
162 | |||
163 | $messages = $this->Messages(); |
||
164 | if (is_string($messages)) { |
||
165 | // The api returned an error |
||
166 | $messagesList = new LiteralField("MessageAlert", $this->MessageHelper($messages, 'bad')); |
||
167 | } else { |
||
168 | $messagesList = GridField::create( |
||
169 | 'Messages', |
||
170 | false, |
||
171 | $messages, |
||
172 | $messageListConfig |
||
173 | )->addExtraClass("messages_grid"); |
||
174 | |||
175 | $columns = $messageListConfig->getComponentByType(GridFieldDataColumns::class); |
||
176 | $columns->setDisplayFields([ |
||
177 | 'event_id' => _t('MailgunAdmin.EventTransmissionId', 'Id'), |
||
178 | 'timestamp' => _t('MailgunAdmin.EventDate', 'Date'), |
||
179 | 'type' => _t('MailgunAdmin.EventType', 'Type'), |
||
180 | 'recipient' => _t('MailgunAdmin.EventRecipient', 'Recipient'), |
||
181 | 'subject' => _t('MailgunAdmin.EventSubject', 'Subject'), |
||
182 | 'sender' => _t('MailgunAdmin.EventSender', 'Sender'), |
||
183 | ]); |
||
184 | |||
185 | $columns->setFieldFormatting([ |
||
186 | 'timestamp' => function ($value, &$item) { |
||
0 ignored issues
–
show
|
|||
187 | return date('Y-m-d H:i:s', $value); |
||
188 | }, |
||
189 | ]); |
||
190 | |||
191 | // Validator setup |
||
192 | $validator = null; |
||
193 | if ($record && method_exists($record, 'getValidator')) { |
||
194 | $validator = $record->getValidator(); |
||
195 | } |
||
196 | |||
197 | if ($validator) { |
||
198 | $messageListConfig |
||
199 | ->getComponentByType(GridFieldDetailForm::class) |
||
200 | ->setValidator($validator); |
||
201 | } |
||
202 | } |
||
203 | |||
204 | // Create tabs |
||
205 | $messagesTab = new Tab( |
||
206 | 'Messages', |
||
207 | _t('MailgunAdmin.Messages', 'Messages'), |
||
208 | $this->SearchFields(), |
||
209 | $messagesList, |
||
210 | // necessary for tree node selection in LeftAndMain.EditForm.js |
||
211 | new HiddenField('ID', false, 0) |
||
212 | ); |
||
213 | |||
214 | $fields = new FieldList([ |
||
215 | $root = new TabSet('Root', $messagesTab) |
||
216 | ]); |
||
217 | |||
218 | if ($this->CanConfigureApi()) { |
||
219 | $settingsTab = new Tab('Settings', _t('MailgunAdmin.Settings', 'Settings')); |
||
220 | |||
221 | $domainTabData = $this->DomainTab(); |
||
222 | $settingsTab->push($domainTabData); |
||
223 | |||
224 | $webhookTabData = $this->WebhookTab(); |
||
225 | $settingsTab->push($webhookTabData); |
||
226 | |||
227 | // Add a refresh button |
||
228 | $refreshButton = new LiteralField('RefreshButton', $this->ButtonHelper( |
||
229 | $this->Link() . '?refresh=true', |
||
230 | _t('MailgunAdmin.REFRESH', 'Force data refresh from the API') |
||
231 | )); |
||
232 | $settingsTab->push($refreshButton); |
||
233 | |||
234 | $fields->addFieldToTab('Root', $settingsTab); |
||
235 | } |
||
236 | |||
237 | // Tab nav in CMS is rendered through separate template |
||
238 | $root->setTemplate('SilverStripe\\Forms\\CMSTabSet'); |
||
239 | |||
240 | // Manage tabs state |
||
241 | $actionParam = $this->getRequest()->param('Action'); |
||
242 | if ($actionParam == 'setting') { |
||
243 | $settingsTab->addExtraClass('ui-state-active'); |
||
244 | } elseif ($actionParam == 'messages') { |
||
245 | $messagesTab->addExtraClass('ui-state-active'); |
||
246 | } |
||
247 | |||
248 | $actions = new FieldList(); |
||
0 ignored issues
–
show
$actions is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
249 | |||
250 | |||
251 | // Build replacement form |
||
252 | $form = Form::create( |
||
253 | $this, |
||
254 | 'EditForm', |
||
255 | $fields, |
||
256 | new FieldList() |
||
257 | )->setHTMLID('Form_EditForm'); |
||
258 | $form->addExtraClass('cms-edit-form fill-height'); |
||
259 | $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); |
||
260 | $form->addExtraClass('ss-tabset cms-tabset ' . $this->BaseCSSClasses()); |
||
261 | $form->setAttribute('data-pjax-fragment', 'CurrentForm'); |
||
262 | |||
263 | $this->extend('updateEditForm', $form); |
||
264 | |||
265 | return $form; |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Get logger |
||
270 | * |
||
271 | * @return Psr\Log\LoggerInterface |
||
272 | */ |
||
273 | public function getLogger() |
||
274 | { |
||
275 | return $this->logger; |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * Get the cache |
||
280 | * |
||
281 | * @return Psr\SimpleCache\CacheInterface |
||
282 | */ |
||
283 | public function getCache() |
||
284 | { |
||
285 | return $this->cache; |
||
286 | } |
||
287 | |||
288 | /** |
||
289 | * @return boolean |
||
290 | */ |
||
291 | public function getCacheEnabled() |
||
292 | { |
||
293 | $v = $this->config()->cache_enabled; |
||
294 | if ($v === null) { |
||
295 | $v = self::$cache_enabled; |
||
296 | } |
||
297 | return $v; |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * A simple cache helper |
||
302 | * |
||
303 | * @param string $method Using dot notation like events.get |
||
304 | * @param array $params |
||
305 | * @param int $expireInSeconds |
||
306 | * @return array |
||
307 | */ |
||
308 | protected function getCachedData($method, $params, $expireInSeconds = 60) |
||
309 | { |
||
310 | $enabled = $this->getCacheEnabled(); |
||
311 | if ($enabled) { |
||
312 | $cache = $this->getCache(); |
||
313 | $key = md5($method . '-' . serialize($params)); |
||
314 | $cacheResult = $cache->get($key); |
||
315 | } |
||
316 | if ($enabled && $cacheResult) { |
||
317 | $data = unserialize($cacheResult); |
||
318 | } else { |
||
319 | try { |
||
320 | $client = MailgunHelper::getClient(); |
||
321 | |||
322 | if (!strpos($method, '.') !== false) { |
||
323 | throw new Exception("$method should use dot notation"); |
||
324 | } |
||
325 | |||
326 | // Split dot notation |
||
327 | $methodParts = explode('.', $method); |
||
328 | $service = $methodParts[0]; |
||
329 | $realMethod = $methodParts[1]; |
||
330 | |||
331 | if ($service == 'domains') { |
||
332 | if (!empty($params)) { |
||
333 | $data = $client->$service()->$realMethod($params[0]); |
||
334 | } else { |
||
335 | $data = $client->$service()->$realMethod(); |
||
336 | } |
||
337 | } else { |
||
338 | $data = $client->$service()->$realMethod(MailgunHelper::getDomain(), $params); |
||
339 | } |
||
340 | } catch (Exception $ex) { |
||
341 | $this->lastException = $ex; |
||
342 | $this->getLogger()->debug($ex); |
||
343 | $data = false; |
||
344 | } |
||
345 | |||
346 | //5 minutes cache |
||
347 | if ($enabled) { |
||
348 | $cache->set($key, serialize($data), $expireInSeconds); |
||
349 | } |
||
350 | } |
||
351 | |||
352 | return $data; |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * Values are mixed with default values and formatted for api usage |
||
357 | * |
||
358 | * @link https://documentation.mailgun.com/en/latest/api-events.html#query-options |
||
359 | * @return array |
||
360 | */ |
||
361 | public function getParams() |
||
362 | { |
||
363 | $params = $this->config()->default_search_params; |
||
364 | if (!$params) { |
||
365 | $params = []; |
||
366 | } |
||
367 | $data = $this->getSession()->get(__class__ . '.Search'); |
||
368 | if (!$data) { |
||
369 | $data = []; |
||
370 | } |
||
371 | |||
372 | $params = array_merge($params, $data); |
||
373 | |||
374 | // Respect api formats |
||
375 | if (!empty($params['begin'])) { |
||
376 | View Code Duplication | if (!is_int($params['begin'])) { |
|
377 | $params['begin'] = strtotime(str_replace('/', '-', $params['begin'])); |
||
378 | } |
||
379 | // Need an end date, default to now |
||
380 | if (empty($params['end'])) { |
||
381 | $params['end'] = time(); |
||
382 | } |
||
383 | } |
||
384 | View Code Duplication | if (!empty($params['end'])) { |
|
385 | if (!is_int($params['end'])) { |
||
386 | $params['end'] = strtotime(str_replace('/', '-', $params['end'])); |
||
387 | } |
||
388 | } |
||
389 | |||
390 | |||
391 | $params = array_filter($params); |
||
392 | |||
393 | return $params; |
||
394 | } |
||
395 | |||
396 | /** |
||
397 | * Get a raw value for a single param |
||
398 | * Useful for retrieving values as set by user |
||
399 | * |
||
400 | * @param string $name |
||
401 | * @param mixed $default |
||
402 | * @return mixed |
||
403 | */ |
||
404 | public function getParam($name, $default = null) |
||
405 | { |
||
406 | $data = $this->getSession()->get(__class__ . '.Search'); |
||
407 | if (!$data) { |
||
408 | return $default; |
||
409 | } |
||
410 | return (isset($data[$name]) && strlen($data[$name])) ? $data[$name] : $default; |
||
411 | } |
||
412 | |||
413 | public function SearchFields() |
||
414 | { |
||
415 | $disabled_filters = $this->config()->disabled_search_filters; |
||
416 | if (!$disabled_filters) { |
||
417 | $disabled_filters = []; |
||
418 | } |
||
419 | |||
420 | $fields = new CompositeField(); |
||
421 | $fields->push($from = new DateField('params[begin]', _t('MailgunAdmin.DATEFROM', 'From'), $this->getParam('begin'))); |
||
422 | // $from->setConfig('min', date('Y-m-d', strtotime('-10 days'))); |
||
423 | |||
424 | $fields->push(new DateField('params[end]', _t('MailgunAdmin.DATETO', 'To'), $to = $this->getParam('end'))); |
||
425 | |||
426 | View Code Duplication | if (!in_array('from', $disabled_filters)) { |
|
427 | $fields->push($friendly_froms = new TextField('params[from]', _t('MailgunAdmin.FRIENDLYFROM', 'Sender'), $this->getParam('from'))); |
||
428 | $friendly_froms->setAttribute('placeholder', '[email protected],[email protected]'); |
||
429 | } |
||
430 | |||
431 | View Code Duplication | if (!in_array('to', $disabled_filters)) { |
|
432 | $fields->push($recipients = new TextField('params[to]', _t('MailgunAdmin.RECIPIENTS', 'Recipients'), $this->getParam('to'))); |
||
433 | $recipients->setAttribute('placeholder', '[email protected],[email protected]'); |
||
434 | } |
||
435 | |||
436 | $fields->push(new DropdownField('params[limit]', _t('MailgunAdmin.PERPAGE', 'Number of results'), array( |
||
437 | 100 => 100, |
||
438 | 200 => 200, |
||
439 | 300 => 300, |
||
440 | ), $this->getParam('limit', 100))); |
||
441 | |||
442 | foreach ($fields->FieldList() as $field) { |
||
443 | $field->addExtraClass('no-change-track'); |
||
444 | } |
||
445 | |||
446 | // This is a ugly hack to allow embedding a form into another form |
||
447 | $doSearch = new FormAction('doSearch', _t('MailgunAdmin.DOSEARCH', 'Search')); |
||
448 | $doSearch->addExtraClass('btn-primary'); |
||
449 | $fields->push($doSearch); |
||
450 | $doSearch->setAttribute('onclick', "jQuery('#Form_SearchForm').append(jQuery('#Form_EditForm input,#Form_EditForm select').clone()).submit();"); |
||
451 | |||
452 | return $fields; |
||
453 | } |
||
454 | |||
455 | public function SearchForm() |
||
456 | { |
||
457 | $doSearch = new FormAction('doSearch'); |
||
458 | $SearchForm = new Form($this, 'SearchForm', new FieldList(), new FieldList( |
||
459 | [$doSearch] |
||
460 | )); |
||
461 | $SearchForm->setAttribute('style', 'display:none'); |
||
462 | return $SearchForm; |
||
463 | } |
||
464 | |||
465 | public function doSearch($data, Form $form) |
||
466 | { |
||
467 | $post = $this->getRequest()->postVar('params'); |
||
468 | if (!$post) { |
||
469 | return $this->redirectBack(); |
||
470 | } |
||
471 | $params = []; |
||
472 | |||
473 | $validFields = []; |
||
474 | foreach ($this->SearchFields()->FieldList()->dataFields() as $field) { |
||
475 | $validFields[] = str_replace(['params[', ']'], '', $field->getName()); |
||
476 | } |
||
477 | |||
478 | foreach ($post as $k => $v) { |
||
479 | if (in_array($k, $validFields)) { |
||
480 | $params[$k] = $v; |
||
481 | } |
||
482 | } |
||
483 | |||
484 | $this->getSession()->set(__class__ . '.Search', $params); |
||
485 | $this->getSession()->save($this->getRequest()); |
||
486 | |||
487 | return $this->redirectBack(); |
||
488 | } |
||
489 | |||
490 | /** |
||
491 | * List of messages events |
||
492 | * |
||
493 | * Messages are cached to avoid hammering the api |
||
494 | * |
||
495 | * @return ArrayList|string |
||
496 | */ |
||
497 | public function Messages() |
||
498 | { |
||
499 | $params = $this->getParams(); |
||
500 | |||
501 | /* @var $response EventResponse */ |
||
502 | $response = $this->getCachedData('events.get', $params, 60 * self::MESSAGE_CACHE_MINUTES); |
||
503 | |||
504 | $messages = []; |
||
505 | if ($response) { |
||
506 | $messages = $response->getItems(); |
||
507 | } |
||
508 | |||
509 | if (empty($messages)) { |
||
510 | if ($this->lastException) { |
||
511 | return $this->lastException->getMessage(); |
||
512 | } |
||
513 | return _t('MailgunAdmin.NO_MESSAGES', 'No messages'); |
||
514 | } |
||
515 | |||
516 | $list = new ArrayList(); |
||
517 | if ($messages) { |
||
518 | $mergedMessages = []; |
||
0 ignored issues
–
show
$mergedMessages is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
519 | $allHeaders = []; |
||
520 | |||
521 | // events may not contain full headers |
||
522 | foreach ($messages as $message) { |
||
523 | $realMessage = $message->getMessage(); |
||
524 | // "message-id" => "20191118104902.1.F9F052E7ED79D36A@sandbox7d650fc2614d4234be80987482afde91.mailgun.org" |
||
525 | View Code Duplication | if (!empty($realMessage['headers']['to'])) { |
|
526 | $allHeaders[$realMessage['headers']['message-id']] = $realMessage['headers']; |
||
527 | } |
||
528 | } |
||
529 | |||
530 | foreach ($messages as $message) { |
||
531 | /* |
||
532 | "headers" => array:4 [â–¼ |
||
533 | "to" => ""Some Name" <[email protected]>" |
||
534 | "message-id" => "somekindofsandbox.mailgun.org" |
||
535 | "from" => "[email protected]" |
||
536 | "subject" => "Email subject here" |
||
537 | ] |
||
538 | "attachments" => [] |
||
539 | "size" => 110 |
||
540 | */ |
||
541 | $realMessage = $message->getMessage(); |
||
542 | View Code Duplication | if (empty($realMessage['headers']['to'])) { |
|
543 | $headers = $allHeaders[$realMessage['headers']['message-id']]; |
||
544 | } else { |
||
545 | $headers = $realMessage['headers']; |
||
546 | } |
||
547 | |||
548 | $shortid = substr($realMessage['headers']['message-id'], 0, strpos($realMessage['headers']['message-id'], '@')); |
||
549 | $m = new ArrayData([ |
||
550 | 'event_id' => $shortid, |
||
551 | 'timestamp' => $message->getTimestamp(), |
||
552 | 'type' => $message->getEvent(), |
||
553 | 'recipient' => $headers['to'] ?? '', |
||
554 | 'subject' => $headers['subject'] ?? '', |
||
555 | 'sender' => $headers['from'] ?? '', |
||
556 | ]); |
||
557 | $list->push($m); |
||
558 | } |
||
559 | } |
||
560 | |||
561 | return $list; |
||
562 | } |
||
563 | |||
564 | /** |
||
565 | * Provides custom permissions to the Security section |
||
566 | * |
||
567 | * @return array |
||
568 | */ |
||
569 | public function providePermissions() |
||
570 | { |
||
571 | $title = _t("MailgunAdmin.MENUTITLE", LeftAndMain::menu_title_for_class('Mailgun')); |
||
572 | return [ |
||
573 | "CMS_ACCESS_MAILGUN" => [ |
||
574 | 'name' => _t('MailgunAdmin.ACCESS', "Access to '{title}' section", ['title' => $title]), |
||
575 | 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access'), |
||
576 | 'help' => _t( |
||
577 | 'MailgunAdmin.ACCESS_HELP', |
||
578 | 'Allow use of Mailgun admin section' |
||
579 | ) |
||
580 | ], |
||
581 | ]; |
||
582 | } |
||
583 | |||
584 | /** |
||
585 | * Message helper |
||
586 | * |
||
587 | * @param string $message |
||
588 | * @param string $status |
||
589 | * @return string |
||
590 | */ |
||
591 | protected function MessageHelper($message, $status = 'info') |
||
592 | { |
||
593 | return '<div class="message ' . $status . '">' . $message . '</div>'; |
||
594 | } |
||
595 | |||
596 | /** |
||
597 | * Button helper |
||
598 | * |
||
599 | * @param string $link |
||
600 | * @param string $text |
||
601 | * @param boolean $confirm |
||
602 | * @return string |
||
603 | */ |
||
604 | protected function ButtonHelper($link, $text, $confirm = false) |
||
605 | { |
||
606 | $link = '<a class="btn btn-primary" href="' . $link . '"'; |
||
607 | if ($confirm) { |
||
608 | $link .= ' onclick="return confirm(\'' . _t('MailgunAdmin.CONFIRM_MSG', 'Are you sure?') . '\')"'; |
||
609 | } |
||
610 | $link .= '>' . $text . '</a>'; |
||
611 | return $link; |
||
612 | } |
||
613 | |||
614 | /** |
||
615 | * A template accessor to check the ADMIN permission |
||
616 | * |
||
617 | * @return bool |
||
618 | */ |
||
619 | public function IsAdmin() |
||
620 | { |
||
621 | return Permission::check("ADMIN"); |
||
622 | } |
||
623 | |||
624 | /** |
||
625 | * Check the permission for current user |
||
626 | * |
||
627 | * @return bool |
||
628 | */ |
||
629 | public function canView($member = null) |
||
630 | { |
||
631 | $mailer = MailgunHelper::getMailer(); |
||
632 | // Another custom mailer has been set |
||
633 | if (!$mailer instanceof SwiftMailer) { |
||
634 | return false; |
||
635 | } |
||
636 | // Doesn't use the proper transport |
||
637 | if (!$mailer->getSwiftMailer()->getTransport() instanceof MailgunSwiftTransport) { |
||
638 | return false; |
||
639 | } |
||
640 | return Permission::check("CMS_ACCESS_MAILGUN", 'any', $member); |
||
641 | } |
||
642 | |||
643 | /** |
||
644 | * |
||
645 | * @return bool |
||
646 | */ |
||
647 | public function CanConfigureApi() |
||
648 | { |
||
649 | return Permission::check('ADMIN') || Director::isDev(); |
||
650 | } |
||
651 | |||
652 | /** |
||
653 | * Check if webhook is installed |
||
654 | * |
||
655 | * @return array |
||
656 | */ |
||
657 | public function WebhookInstalled() |
||
658 | { |
||
659 | /* @var $response WebhookIndexResponse */ |
||
660 | $response = $this->getCachedData('webhooks.index', null, 60 * self::WEBHOOK_CACHE_MINUTES); |
||
661 | if (!$response) { |
||
662 | return false; |
||
663 | } |
||
664 | $url = $this->WebhookUrl(); |
||
0 ignored issues
–
show
$url is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
665 | $dom = $this->getDomain(); |
||
666 | if (strpos($response->getBounceUrl(), $dom)) { |
||
667 | return true; |
||
668 | } |
||
669 | if (strpos($response->getDeliverUrl(), $dom)) { |
||
670 | return true; |
||
671 | } |
||
672 | if (strpos($response->getDropUrl(), $dom)) { |
||
673 | return true; |
||
674 | } |
||
675 | if (strpos($response->getSpamUrl(), $dom)) { |
||
676 | return true; |
||
677 | } |
||
678 | if (strpos($response->getUnsubscribeUrl(), $dom)) { |
||
679 | return true; |
||
680 | } |
||
681 | if (strpos($response->getClickUrl(), $dom)) { |
||
682 | return true; |
||
683 | } |
||
684 | if (strpos($response->getOpenUrl(), $dom)) { |
||
685 | return true; |
||
686 | } |
||
687 | return false; |
||
688 | } |
||
689 | |||
690 | /** |
||
691 | * Hook details for template |
||
692 | * @return \ArrayData |
||
693 | */ |
||
694 | public function WebhookDetails() |
||
695 | { |
||
696 | $el = $this->WebhookInstalled(); |
||
697 | if ($el) { |
||
698 | return new ArrayData($el); |
||
699 | } |
||
700 | } |
||
701 | |||
702 | /** |
||
703 | * Get content of the tab |
||
704 | * |
||
705 | * @return FormField |
||
706 | */ |
||
707 | public function WebhookTab() |
||
708 | { |
||
709 | if ($this->WebhookInstalled()) { |
||
710 | return $this->UninstallHookForm(); |
||
711 | } |
||
712 | return $this->InstallHookForm(); |
||
713 | } |
||
714 | |||
715 | /** |
||
716 | * @return string |
||
717 | */ |
||
718 | public function WebhookUrl() |
||
719 | { |
||
720 | if (self::config()->webhook_base_url) { |
||
721 | return rtrim(self::config()->webhook_base_url, '/') . '/__mailgun/incoming'; |
||
722 | } |
||
723 | if (Director::isLive()) { |
||
724 | return Director::absoluteURL('/__mailgun/incoming'); |
||
725 | } |
||
726 | $protocol = Director::protocol(); |
||
727 | return $protocol . $this->getDomain() . '/__mailgun/incoming'; |
||
728 | } |
||
729 | |||
730 | /** |
||
731 | * Install hook form |
||
732 | * |
||
733 | * @return FormField |
||
734 | */ |
||
735 | View Code Duplication | public function InstallHookForm() |
|
736 | { |
||
737 | $fields = new CompositeField(); |
||
738 | $fields->push(new LiteralField('Info', $this->MessageHelper( |
||
739 | _t('MailgunAdmin.WebhookNotInstalled', 'Webhook is not installed. It should be configured using the following url {url}. This url must be publicly visible to be used as a hook.', ['url' => $this->WebhookUrl()]), |
||
740 | 'bad' |
||
741 | ))); |
||
742 | $fields->push(new LiteralField('doInstallHook', $this->ButtonHelper( |
||
743 | $this->Link('doInstallHook'), |
||
744 | _t('MailgunAdmin.DOINSTALL_WEBHOOK', 'Install webhook') |
||
745 | ))); |
||
746 | return $fields; |
||
747 | } |
||
748 | |||
749 | public function doInstallHook() |
||
750 | { |
||
751 | if (!$this->CanConfigureApi()) { |
||
752 | return $this->redirectBack(); |
||
753 | } |
||
754 | |||
755 | $client = MailgunHelper::getClient(); |
||
756 | |||
757 | $url = $this->WebhookUrl(); |
||
758 | $description = SiteConfig::current_site_config()->Title; |
||
0 ignored issues
–
show
$description is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
759 | |||
760 | try { |
||
761 | $types = self::config()->webhook_events; |
||
762 | if (!empty($types)) { |
||
763 | foreach ($types as $type) { |
||
764 | $client->webhooks()->create(MailgunHelper::getDomain(), $type, $url . '?type=' . $type); |
||
765 | } |
||
766 | } |
||
767 | $this->getCache()->clear(); |
||
768 | } catch (Exception $ex) { |
||
769 | $this->getLogger()->debug($ex); |
||
770 | } |
||
771 | |||
772 | return $this->redirectBack(); |
||
773 | } |
||
774 | |||
775 | /** |
||
776 | * Uninstall hook form |
||
777 | * |
||
778 | * @return FormField |
||
779 | */ |
||
780 | View Code Duplication | public function UninstallHookForm() |
|
781 | { |
||
782 | $fields = new CompositeField(); |
||
783 | $fields->push(new LiteralField('Info', $this->MessageHelper( |
||
784 | _t('MailgunAdmin.WebhookInstalled', 'Webhook is installed and accessible at the following url {url}.', ['url' => $this->WebhookUrl()]), |
||
785 | 'good' |
||
786 | ))); |
||
787 | $fields->push(new LiteralField('doUninstallHook', $this->ButtonHelper( |
||
788 | $this->Link('doUninstallHook'), |
||
789 | _t('MailgunAdmin.DOUNINSTALL_WEBHOOK', 'Uninstall webhook'), |
||
790 | true |
||
791 | ))); |
||
792 | return $fields; |
||
793 | } |
||
794 | |||
795 | public function doUninstallHook($data, Form $form) |
||
796 | { |
||
797 | if (!$this->CanConfigureApi()) { |
||
798 | return $this->redirectBack(); |
||
799 | } |
||
800 | |||
801 | $client = MailgunHelper::getClient(); |
||
802 | |||
803 | try { |
||
804 | $response = $client->webhooks()->index(MailgunHelper::getDomain()); |
||
805 | if ($response) { |
||
806 | if ($response->getBounceUrl()) { |
||
807 | $client->webhooks()->delete(MailgunHelper::getDomain(), 'bounce'); |
||
808 | } |
||
809 | if ($response->getDeliverUrl()) { |
||
810 | $client->webhooks()->delete(MailgunHelper::getDomain(), 'deliver'); |
||
811 | } |
||
812 | if ($response->getDropUrl()) { |
||
813 | $client->webhooks()->delete(MailgunHelper::getDomain(), 'drop'); |
||
814 | } |
||
815 | if ($response->getSpamUrl()) { |
||
816 | $client->webhooks()->delete(MailgunHelper::getDomain(), 'spam'); |
||
817 | } |
||
818 | if ($response->getUnsubscribeUrl()) { |
||
819 | $client->webhooks()->delete(MailgunHelper::getDomain(), 'unsubscribe'); |
||
820 | } |
||
821 | if ($response->getClickUrl()) { |
||
822 | $client->webhooks()->delete(MailgunHelper::getDomain(), 'clicked'); |
||
823 | } |
||
824 | if ($response->getOpenUrl()) { |
||
825 | $client->webhooks()->delete(MailgunHelper::getDomain(), 'open'); |
||
826 | } |
||
827 | } |
||
828 | $this->getCache()->clear(); |
||
829 | } catch (Exception $ex) { |
||
830 | $this->getLogger()->debug($ex); |
||
831 | } |
||
832 | |||
833 | return $this->redirectBack(); |
||
834 | } |
||
835 | |||
836 | /** |
||
837 | * Check if sending domain is installed |
||
838 | * |
||
839 | * @return array |
||
840 | */ |
||
841 | public function SendingDomainInstalled() |
||
842 | { |
||
843 | $client = MailgunHelper::getClient(); |
||
0 ignored issues
–
show
$client is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
844 | |||
845 | /* @var $response DomainIndexResponse */ |
||
846 | $response = $this->getCachedData('domains.index', $this->getDomain(), 60 * self::SENDINGDOMAIN_CACHE_MINUTES); |
||
847 | |||
848 | $domains = $response->getDomains(); |
||
849 | $defaultDomain = $this->getDomain(); |
||
850 | |||
851 | foreach ($domains as $domain) { |
||
852 | if ($domain->getName() == $defaultDomain) { |
||
853 | return true; |
||
854 | } |
||
855 | } |
||
856 | return false; |
||
857 | } |
||
858 | |||
859 | /** |
||
860 | * Trigger request to check if sending domain is verified |
||
861 | * |
||
862 | * @return array |
||
863 | */ |
||
864 | public function VerifySendingDomain() |
||
865 | { |
||
866 | $client = MailgunHelper::getClient(); |
||
867 | |||
868 | $host = $this->getDomain(); |
||
869 | |||
870 | $verification = $client->verifySendingDomain($host); |
||
871 | |||
872 | if (empty($verification)) { |
||
873 | return false; |
||
874 | } |
||
875 | return $verification; |
||
876 | } |
||
877 | |||
878 | /** |
||
879 | * Get content of the tab |
||
880 | * |
||
881 | * @return FormField |
||
882 | */ |
||
883 | public function DomainTab() |
||
884 | { |
||
885 | $defaultDomain = $this->getDomain(); |
||
886 | $defaultDomainInfos = null; |
||
887 | |||
888 | /* @var $response DomainIndexResponse */ |
||
889 | $response = $this->getCachedData('domains.index', null, 60 * self::SENDINGDOMAIN_CACHE_MINUTES); |
||
890 | $domains = []; |
||
891 | if ($response) { |
||
892 | $domains = $response->getDomains(); |
||
893 | } |
||
894 | |||
895 | /* |
||
896 | 0 => Domain {#2919 â–¼ |
||
897 | -createdAt: DateTimeImmutable @1573661800 {#2921 â–¶} |
||
898 | -smtpLogin: "[email protected]" |
||
899 | -name: "sandbox.mailgun.org" |
||
900 | -smtpPassword: "some-pass-word" |
||
901 | -wildcard: false |
||
902 | -spamAction: "disabled" |
||
903 | -state: "active" |
||
904 | } |
||
905 | */ |
||
906 | |||
907 | $fields = new CompositeField(); |
||
908 | |||
909 | $list = new ArrayList(); |
||
910 | if ($domains) { |
||
911 | foreach ($domains as $domain) { |
||
912 | $showResponse = $this->getCachedData('domains.show', [$domain->getName()], 60 * self::SENDINGDOMAIN_CACHE_MINUTES); |
||
913 | |||
914 | /* |
||
915 | "sending_dns_records": [ |
||
916 | { |
||
917 | "record_type": "TXT", |
||
918 | "valid": "valid", |
||
919 | "name": "domain.com", |
||
920 | "value": "v=spf1 include:mailgun.org ~all" |
||
921 | }, |
||
922 | { |
||
923 | "record_type": "TXT", |
||
924 | "valid": "valid", |
||
925 | "name": "domain.com", |
||
926 | "value": "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUA...." |
||
927 | }, |
||
928 | { |
||
929 | "record_type": "CNAME", |
||
930 | "valid": "valid", |
||
931 | "name": "email.domain.com", |
||
932 | "value": "mailgun.org" |
||
933 | } |
||
934 | ] |
||
935 | */ |
||
936 | |||
937 | $dnsRecords = $showResponse->getOutboundDNSRecords(); |
||
938 | |||
939 | $spfOk = false; |
||
940 | $dkimOk = false; |
||
941 | |||
942 | foreach ($dnsRecords as $dnsRecord) { |
||
943 | $value = $dnsRecord->getValue(); |
||
944 | if (strpos($value, 'v=spf1') !== false) { |
||
945 | $spfOk = $dnsRecord->isValid(); |
||
946 | } |
||
947 | if (strpos($value, 'k=rsa') !== false) { |
||
948 | $dkimOk = $dnsRecord->isValid(); |
||
949 | } |
||
950 | } |
||
951 | |||
952 | $list->push(new ArrayData([ |
||
953 | 'Domain' => $domain->getName(), |
||
954 | 'SPF' => $spfOk, |
||
955 | 'DKIM' => $dkimOk, |
||
956 | 'Verified' => ($domain->getState() == 'active') ? true : false, |
||
957 | ])); |
||
958 | |||
959 | if ($domain->getName() == $defaultDomain) { |
||
960 | $defaultDomainInfos = $domain; |
||
961 | } |
||
962 | } |
||
963 | } |
||
964 | |||
965 | $config = GridFieldConfig::create(); |
||
966 | $config->addComponent(new GridFieldToolbarHeader()); |
||
967 | $config->addComponent(new GridFieldTitleHeader()); |
||
968 | $config->addComponent($columns = new GridFieldDataColumns()); |
||
969 | $columns->setDisplayFields(ArrayLib::valuekey(['Domain', 'SPF', 'DKIM', 'Verified'])); |
||
970 | $domainsList = new GridField('SendingDomains', _t('MailgunAdmin.ALL_SENDING_DOMAINS', 'Configured sending domains'), $list, $config); |
||
971 | $domainsList->addExtraClass('mb-2'); |
||
972 | $fields->push($domainsList); |
||
973 | |||
974 | if (!$defaultDomainInfos) { |
||
975 | $this->InstallDomainForm($fields); |
||
976 | } else { |
||
977 | $this->UninstallDomainForm($fields); |
||
978 | } |
||
979 | |||
980 | return $fields; |
||
981 | } |
||
982 | |||
983 | /** |
||
984 | * @return string |
||
985 | */ |
||
986 | public function InboundUrl() |
||
987 | { |
||
988 | $subdomain = self::config()->inbound_subdomain; |
||
989 | $domain = $this->getDomain(); |
||
990 | if ($domain) { |
||
991 | return $subdomain . '.' . $domain; |
||
992 | } |
||
993 | return false; |
||
994 | } |
||
995 | |||
996 | /** |
||
997 | * Get domain name from current host |
||
998 | * |
||
999 | * @return boolean|string |
||
1000 | */ |
||
1001 | public function getDomainFromHost() |
||
1002 | { |
||
1003 | $base = Environment::getEnv('SS_BASE_URL'); |
||
1004 | if (!$base) { |
||
1005 | $base = Director::protocolAndHost(); |
||
1006 | } |
||
1007 | $host = parse_url($base, PHP_URL_HOST); |
||
1008 | $hostParts = explode('.', $host); |
||
1009 | $parts = count($hostParts); |
||
1010 | if ($parts < 2) { |
||
1011 | return false; |
||
1012 | } |
||
1013 | $domain = $hostParts[$parts - 2] . "." . $hostParts[$parts - 1]; |
||
1014 | return $domain; |
||
1015 | } |
||
1016 | |||
1017 | /** |
||
1018 | * Get domain from admin email |
||
1019 | * |
||
1020 | * @return boolean|string |
||
1021 | */ |
||
1022 | public function getDomainFromEmail() |
||
1023 | { |
||
1024 | $email = MailgunHelper::resolveDefaultFromEmail(null, false); |
||
1025 | if ($email) { |
||
1026 | $domain = substr(strrchr($email, "@"), 1); |
||
1027 | return $domain; |
||
1028 | } |
||
1029 | return false; |
||
1030 | } |
||
1031 | |||
1032 | /** |
||
1033 | * Get domain |
||
1034 | * |
||
1035 | * @return boolean|string |
||
1036 | */ |
||
1037 | public function getDomain() |
||
1038 | { |
||
1039 | $domain = $this->getDomainFromEmail(); |
||
1040 | if (!$domain) { |
||
1041 | return $this->getDomainFromHost(); |
||
1042 | } |
||
1043 | return $domain; |
||
1044 | } |
||
1045 | |||
1046 | /** |
||
1047 | * Install domain form |
||
1048 | * |
||
1049 | * @param CompositeField $fieldsd |
||
1050 | * @return FormField |
||
1051 | */ |
||
1052 | View Code Duplication | public function InstallDomainForm(CompositeField $fields) |
|
1053 | { |
||
1054 | $host = $this->getDomain(); |
||
1055 | |||
1056 | $fields->push(new LiteralField('Info', $this->MessageHelper( |
||
1057 | _t('MailgunAdmin.DomainNotInstalled', 'Default sending domain {domain} is not installed.', ['domain' => $host]), |
||
1058 | "bad" |
||
1059 | ))); |
||
1060 | $fields->push(new LiteralField('doInstallDomain', $this->ButtonHelper( |
||
1061 | $this->Link('doInstallDomain'), |
||
1062 | _t('MailgunAdmin.DOINSTALLDOMAIN', 'Install domain') |
||
1063 | ))); |
||
1064 | } |
||
1065 | |||
1066 | View Code Duplication | public function doInstallDomain() |
|
1067 | { |
||
1068 | if (!$this->CanConfigureApi()) { |
||
1069 | return $this->redirectBack(); |
||
1070 | } |
||
1071 | |||
1072 | $client = MailgunHelper::getClient(); |
||
1073 | |||
1074 | $domain = $this->getDomain(); |
||
1075 | |||
1076 | if (!$domain) { |
||
1077 | return $this->redirectBack(); |
||
1078 | } |
||
1079 | |||
1080 | try { |
||
1081 | $client->domains()->create($domain); |
||
1082 | $this->getCache()->clear(); |
||
1083 | } catch (Exception $ex) { |
||
1084 | $this->getLogger()->debug($ex); |
||
1085 | } |
||
1086 | |||
1087 | return $this->redirectBack(); |
||
1088 | } |
||
1089 | |||
1090 | /** |
||
1091 | * Uninstall domain form |
||
1092 | * |
||
1093 | * @param CompositeField $fieldsd |
||
1094 | * @return FormField |
||
1095 | */ |
||
1096 | public function UninstallDomainForm(CompositeField $fields) |
||
1097 | { |
||
1098 | $domainInfos = $this->SendingDomainInstalled(); |
||
1099 | |||
1100 | $domain = $this->getDomain(); |
||
1101 | |||
1102 | if ($domainInfos && $domainInfos->getState() == 'active') { |
||
1103 | $fields->push(new LiteralField('Info', $this->MessageHelper( |
||
1104 | _t('MailgunAdmin.DomainInstalled', 'Default domain {domain} is installed.', ['domain' => $domain]), |
||
1105 | 'good' |
||
1106 | ))); |
||
1107 | } else { |
||
1108 | $fields->push(new LiteralField('Info', $this->MessageHelper( |
||
1109 | _t('MailgunAdmin.DomainInstalledBut', 'Default domain {domain} is installed, but is not properly configured.'), |
||
1110 | 'warning' |
||
1111 | ))); |
||
1112 | } |
||
1113 | $fields->push(new LiteralField('doUninstallHook', $this->ButtonHelper( |
||
1114 | $this->Link('doUninstallHook'), |
||
1115 | _t('MailgunAdmin.DOUNINSTALLDOMAIN', 'Uninstall domain'), |
||
1116 | true |
||
1117 | ))); |
||
1118 | } |
||
1119 | |||
1120 | View Code Duplication | public function doUninstallDomain($data, Form $form) |
|
1121 | { |
||
1122 | if (!$this->CanConfigureApi()) { |
||
1123 | return $this->redirectBack(); |
||
1124 | } |
||
1125 | |||
1126 | $client = MailgunHelper::getClient(); |
||
1127 | |||
1128 | $domain = $this->getDomain(); |
||
1129 | |||
1130 | if (!$domain) { |
||
1131 | return $this->redirectBack(); |
||
1132 | } |
||
1133 | |||
1134 | try { |
||
1135 | $el = $this->SendingDomainInstalled(); |
||
1136 | if ($el) { |
||
1137 | $client->domains()->delete($domain); |
||
1138 | } |
||
1139 | $this->getCache()->clear(); |
||
1140 | } catch (Exception $ex) { |
||
1141 | $this->getLogger()->debug($ex); |
||
1142 | } |
||
1143 | |||
1144 | return $this->redirectBack(); |
||
1145 | } |
||
1146 | } |
||
1147 |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.