From 860de39a7903d5e38a16e313be8e084e8209b800 Mon Sep 17 00:00:00 2001 From: Daniel Seifert Date: Tue, 4 Jun 2024 14:20:20 +0200 Subject: [PATCH] add DMARC check # Conflicts: # Application/Controller/Admin/SpfChecker.php # Application/views/admin/tpl/mailTester.tpl # Application/views/admin/tpl/mailconfigcheck.tpl # Application/views/admin/tpl/mailinfopage.tpl # Application/views/admin/tpl/smtpCheck.tpl # Application/views/admin/tpl/spfCheck.tpl --- Application/Controller/Admin/SpfChecker.php | 60 ++++++++++++++++++++- Application/Model/DmarcResult.php | 42 +++++++++++++++ Application/Model/SpfResult.php | 2 +- Application/views/admin/tpl/spfCheck.tpl | 59 +++++++++++++++++--- Application/views/de/translations.php | 14 ++++- Application/views/en/translations.php | 16 +++++- 6 files changed, 181 insertions(+), 12 deletions(-) create mode 100644 Application/Model/DmarcResult.php diff --git a/Application/Controller/Admin/SpfChecker.php b/Application/Controller/Admin/SpfChecker.php index 798ac38..a87534f 100644 --- a/Application/Controller/Admin/SpfChecker.php +++ b/Application/Controller/Admin/SpfChecker.php @@ -16,6 +16,10 @@ declare(strict_types=1); namespace D3\MailConfigChecker\Application\Controller\Admin; use Assert\InvalidArgumentException; +use D3\MailAuthenticationCheck\DMARCCheck; +use D3\MailAuthenticationCheck\Model\DMARCResult; +use D3\MailConfigChecker\Application\Model\Constants; +use D3\MailConfigChecker\Application\Model\DmarcResult as OxDmarcResult; use D3\MailConfigChecker\Application\Model\SpfResult; use Mika56\SPFCheck\DNS\DNSRecordGetter; use Mika56\SPFCheck\Model\Query; @@ -32,6 +36,7 @@ class SpfChecker extends AdminDetailsController public function render() { $this->checkSpf(); + $this->checkDmarc(); return parent::render(); } @@ -46,10 +51,24 @@ class SpfChecker extends AdminDetailsController } ); - $this->addTplParam('result', $result); + $this->addTplParam('spf_result', $result); } - protected function getMailDomains() + protected function checkDmarc() + { + $result = []; + $mailDomains = $this->getMailDomains(); + array_walk( + $mailDomains, + function ($domain) use (&$result) { + $this->checkDmarcByDomain($domain, $result); + } + ); + + $this->addTplParam('dmarc_result', $result); + } + + protected function getMailDomains(): array { /** @var Shop $shop */ $shop = Registry::getConfig()->getActiveShop(); @@ -119,4 +138,41 @@ class SpfChecker extends AdminDetailsController return 'danger'; } } + + public function checkDmarcByDomain($domain, &$summarize) + { + try { + $check = new DMARCCheck(new DNSRecordGetter()); + $query = new Query('', $domain); + $record = $check->getResult($query)->getRecord(); + + switch ( $record->getRejectPolicy()->getValue() ) { + case DMARCResult::REJECT_QUARANTINE: + case DMARCResult::REJECT_REJECT: + $status = OxDmarcResult::SET; + break; + case DMARCResult::REJECT_NONE: + $status = OxDmarcResult::MISSING; + break; + default: + $status = OxDmarcResult::ERROR; + } + + $summarize[$domain] = oxNew( OxDmarcResult::class, $status, $record->getRawRecord()); + } catch (\LogicException) { + $summarize[$domain] = oxNew( OxDmarcResult::class, OxDmarcResult::MISSING, ''); + } + } + + public function getDmarcStatusColor(OxDmarcResult $result) + { + switch ($result->getStatus()) { + case SpfResult::SET: + return 'success'; + case SpfResult::ERROR: + return 'warning'; + default: + return 'danger'; + } + } } diff --git a/Application/Model/DmarcResult.php b/Application/Model/DmarcResult.php new file mode 100644 index 0000000..5d6e0a4 --- /dev/null +++ b/Application/Model/DmarcResult.php @@ -0,0 +1,42 @@ + + * @link https://www.oxidmodule.com + */ + +declare(strict_types=1); + +namespace D3\MailConfigChecker\Application\Model; + +class DmarcResult +{ + public const SET = 'set'; + public const MISSING = 'missing'; + public const ERROR = 'error'; + + protected $status; + protected $record; + + public function __construct(string $status, ?string $record = null) + { + $this->status = $status; + $this->record = $record; + } + + public function getStatus() + { + return $this->status; + } + + public function getRecord() + { + return $this->record; + } +} diff --git a/Application/Model/SpfResult.php b/Application/Model/SpfResult.php index 6cd9b8d..e8e1cfe 100644 --- a/Application/Model/SpfResult.php +++ b/Application/Model/SpfResult.php @@ -17,7 +17,7 @@ namespace D3\MailConfigChecker\Application\Model; class SpfResult { - public const SET = 'set'; + public const SET = 'set'; public const MISSING = 'missing'; public const ERROR = 'error'; diff --git a/Application/views/admin/tpl/spfCheck.tpl b/Application/views/admin/tpl/spfCheck.tpl index 9301fd4..3cca203 100644 --- a/Application/views/admin/tpl/spfCheck.tpl +++ b/Application/views/admin/tpl/spfCheck.tpl @@ -10,15 +10,16 @@
-
+
+

[{oxmultilang ident="D3_MAILCHECKER_SPFRESULT_HL"}]

[{oxmultilang ident="D3_MAILCHECKER_SPFRESULT_DESC"}]
-
+
- [{foreach from=$result key="domain" item="spf"}] -
+ [{foreach from=$spf_result key="domain" item="spf"}] +
[{$domain}] @@ -27,8 +28,8 @@

[{oxmultilang ident="D3_MAILCHECKER_SPFRESULT_"|cat:$spf->getStatus()|upper}]

[{if $spf->getRecord()}]

- - + +

[{/if}] @@ -45,7 +46,6 @@ [{oxmultilang ident="D3_MAILCHECKER_SPFRESULT_LINK_GENERATOR"}] - [{/if}]
  • @@ -62,6 +62,51 @@
  • +
    +
    +

    [{oxmultilang ident="D3_MAILCHECKER_DMARCRESULT_HL"}]

    + [{oxmultilang ident="D3_MAILCHECKER_DMARCRESULT_DESC"}] +
    +
    +
    +
    +
    + [{foreach from=$dmarc_result key="domain" item="dmarc"}] +
    +
    +
    + [{$domain}] +
    +
    +

    [{oxmultilang ident="D3_MAILCHECKER_DMARCRESULT_"|cat:$dmarc->getStatus()|upper}]

    + [{if $dmarc->getRecord()}] +

    + + +

    + [{/if}] + +
    [{oxmultilang ident="D3_MAILCHECKER_DMARCRESULT_LINKS"}]
    + +
    +
    +
    + [{/foreach}] +
    +
    +
    + [{include file="bottomnaviitem.tpl"}] [{include file="bottomitem.tpl"}] diff --git a/Application/views/de/translations.php b/Application/views/de/translations.php index 68b220c..b4e115d 100644 --- a/Application/views/de/translations.php +++ b/Application/views/de/translations.php @@ -6,7 +6,7 @@ return [ 'D3_TAB_MAILCHECKER_MODULEDESCRIPTION' => 'Beschreibung', 'D3_TAB_MAILCHECKER_CONFIGCHECK' => 'Konfigurationsprüfung', 'D3_TAB_MAILCHECKER_SMTPCHECK' => 'SMTP Check', - 'D3_TAB_MAILCHECKER_SPFCHECK' => 'SPF Check', + 'D3_TAB_MAILCHECKER_SPFCHECK' => 'Authentisierung Check', 'D3_TAB_MAILCHECKER_TESTMAIL' => 'Testmail', 'D3_MAILCHECKER_INFO_1' => 'Dieses Modul kann Ihnen helfen, um Schwierigkeiten beim Versand von Mails oder bei nicht zugestellten Mails zu identifizieren. Gehen Sie bitte die folgenden Tabs durch. Nötige Nacharbeiten werden Ihnen dort angezeigt.', @@ -41,6 +41,9 @@ return [ 'D3_MAILCHECKER_SMTPCHECK_NOTRANSMIT' => 'Datenübertragung nicht erfolgreich', 'D3_MAILCHECKER_SMTPCHECK_SUCCESS' => 'Die SMTP-Kommunikation wurde erfolgreich abgeschlossen.', + 'D3_MAILCHECKER_RECORD' => 'Eintrag', + + 'D3_MAILCHECKER_SPFRESULT_HL' => 'SPF (Herkunftsprüfung)', 'D3_MAILCHECKER_SPFRESULT_DESC' => 'Mit dem Sender Policy Framework (SPF) definiert der Domaininhaber, welcher Server E-Mails mit dem Domainabsender versenden darf. Diese Angabe wird vom Empfangsserver geprüft. Fehlt der SPF-Eintrag, werden E-Mails üblicherweise als Spam klassifiziert.', 'D3_MAILCHECKER_SPFRESULT_SET' => 'Es ist ein SPF-Eintrag gesetzt', 'D3_MAILCHECKER_SPFRESULT_MISSING' => 'Es ist kein SPF-Eintrag gesetzt, dieser sollte dringend nachgetragen werden', @@ -50,6 +53,15 @@ return [ 'D3_MAILCHECKER_SPFRESULT_LINK_GENERATOR' => 'SPF Generator', 'D3_MAILCHECKER_SPFRESULT_LINK_BLACKLISTCHECK' => 'Blacklist Check', + 'D3_MAILCHECKER_DMARCRESULT_HL' => 'DMARC (Ablehnungsrichtlinien und Berichterstattung)', + 'D3_MAILCHECKER_DMARCRESULT_DESC' => 'Der DMARC-Eintrag definiert, wie mit Mails umgegangen wird, bei denen die Authentisierungsprüfungen fehlgeschlagen sind. Dort können auch Mailadressen für Reporte angegeben werden.', + 'D3_MAILCHECKER_DMARCRESULT_SET' => 'Es ist ein DMARC-Eintrag gesetzt, das Verhalten ist nicht auf "ignorieren" gestellt.', + 'D3_MAILCHECKER_DMARCRESULT_MISSING' => 'Es ist kein DMARC-Eintrag gesetzt oder mit "ignorieren" konfiguriert. Dies sollte dringend geändert werden.', + 'D3_MAILCHECKER_DMARCRESULT_ERROR' => 'Der DMARC-Eintrag kann nicht geprüft werden', + 'D3_MAILCHECKER_DMARCRESULT_LINKS' => 'weiterführende Links', + 'D3_MAILCHECKER_DMARCRESULT_LINK_ANALYSIS' => 'DMARC Analyse', + 'D3_MAILCHECKER_DMARCRESULT_LINK_GENERATOR' => 'DMARC Generator', + 'D3_MAILCHECKER_TESTMAIL_DESC' => 'Die Testmail wird auf identischem Weg geschickt, den auch alle regulären Mails aus dem Shop nehmen (z.B. Bestellbestätigungen, ...) und kann z.B. zur Headeranalyse dienen.', 'D3_MAILCHECKER_TESTMAIL_HEADERANALYSIS' => 'Email Header Analyzer', 'D3_MAILCHECKER_TESTMAIL_SUBJECT' => 'Betreff', diff --git a/Application/views/en/translations.php b/Application/views/en/translations.php index d5ec530..88cb8c6 100644 --- a/Application/views/en/translations.php +++ b/Application/views/en/translations.php @@ -6,7 +6,7 @@ return [ "D3_TAB_MAILCHECKER_MODULEDESCRIPTION" => "Description", "D3_TAB_MAILCHECKER_CONFIGCHECK" => "Configuration check", "D3_TAB_MAILCHECKER_SMTPCHECK" => "SMTP check", - "D3_TAB_MAILCHECKER_SPFCHECK" => "SPF check", + "D3_TAB_MAILCHECKER_SPFCHECK" => "Authentication check", "D3_TAB_MAILCHECKER_TESTMAIL" => "Test email", "D3_MAILCHECKER_ASSERTIONS_FAILED" => "The following %d checks failed:", "D3_MAILCHECKER_ASSERTIONS_NOTSET" => "is not (correctly) set", @@ -34,6 +34,10 @@ return [ "D3_MAILCHECKER_SMTPCHECK_TRANSMIT" => "Data transfer", "D3_MAILCHECKER_SMTPCHECK_NOTRANSMIT" => "Data transfer not successful", "D3_MAILCHECKER_SMTPCHECK_SUCCESS" => "SMTP communication was completed successfully.", + + 'D3_MAILCHECKER_RECORD' => 'Record', + + 'D3_MAILCHECKER_SPFRESULT_HL' => 'SPF (Origin verification)', "D3_MAILCHECKER_SPFRESULT_DESC" => "With the Sender Policy Framework (SPF), the domain owner defines which server is allowed to send emails with the domain sender. This information is checked by the receiving server. If the SPF entry is missing, emails are usually sent as ", "D3_MAILCHECKER_SPFRESULT_SET" => "An SPF entry is set", "D3_MAILCHECKER_SPFRESULT_MISSING" => "There is no SPF entry set, this should be added urgently", @@ -42,6 +46,16 @@ return [ "D3_MAILCHECKER_SPFRESULT_LINK_ANALYSIS" => "SPF analysis", "D3_MAILCHECKER_SPFRESULT_LINK_GENERATOR" => "SPF generator", "D3_MAILCHECKER_SPFRESULT_LINK_BLACKLISTCHECK" => "Blacklist check", + + 'D3_MAILCHECKER_DMARCRESULT_HL' => 'DMARC (Reject policy and reporting)', + 'D3_MAILCHECKER_DMARCRESULT_DESC' => 'The DMARC entry defines how to deal with mails for which the authentication checks have failed. Mail addresses for reports can also be specified there.', + 'D3_MAILCHECKER_DMARCRESULT_SET' => 'A DMARC entry is set, the behaviour is not set to ‘ignore’.', + 'D3_MAILCHECKER_DMARCRESULT_MISSING' => 'No DMARC entry is set or configured with ‘ignore’. This should be changed urgently.', + 'D3_MAILCHECKER_DMARCRESULT_ERROR' => 'The DMARC record cannot be checked', + 'D3_MAILCHECKER_DMARCRESULT_LINKS' => 'Related Links', + 'D3_MAILCHECKER_DMARCRESULT_LINK_ANALYSIS' => 'DMARC analysis', + 'D3_MAILCHECKER_DMARCRESULT_LINK_GENERATOR' => 'DMARC generator', + "D3_MAILCHECKER_TESTMAIL_DESC" => "The test email is sent in the same way as all regular emails from the shop (e.g..B. order confirmations, ...) and can ", "D3_MAILCHECKER_TESTMAIL_HEADERANALYSIS" => "Email Header Analyzer", "D3_MAILCHECKER_TESTMAIL_SUBJECT" => "Regarding",