initial
This commit is contained in:
commit
e8e4a5706b
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2024 D3 Data Development (Inh. Thomas Dartsch)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
38
composer.json
Normal file
38
composer.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "d3/mailauthenticationcheck",
|
||||
"description": "Checks for configured mail athentication methods like SPF, DKIM and DMARC",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"SPF",
|
||||
"DKIM",
|
||||
"DMARC",
|
||||
"e-mail",
|
||||
"dns",
|
||||
"record",
|
||||
"authentication"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "D3 Data Development (Inh. Thomas Dartsch)",
|
||||
"email": "info@shopmodule.com",
|
||||
"homepage": "https://www.d3data.de",
|
||||
"role": "Owner"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"email": "support@shopmodule.com"
|
||||
},
|
||||
"homepage": "https://www.oxidmodule.com/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4",
|
||||
"mika56/spfcheck": "^2.1.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"D3\\MailAuthenticationCheck\\": "src"
|
||||
}
|
||||
}
|
||||
}
|
111
src/DMARCCheck.php
Normal file
111
src/DMARCCheck.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck;
|
||||
|
||||
use D3\MailAuthenticationCheck\Mechanism\DMARC\RejectPolicy;
|
||||
use D3\MailAuthenticationCheck\Model\DMARCRecord as Record;
|
||||
use D3\MailAuthenticationCheck\Model\DMARCResult as Result;
|
||||
use Mika56\SPFCheck\DNS\DNSRecordGetterInterface;
|
||||
use Mika56\SPFCheck\Exception\DNSLookupException;
|
||||
use Mika56\SPFCheck\Model\Query;
|
||||
|
||||
class DMARCCheck
|
||||
{
|
||||
protected DNSRecordGetterInterface $DNSRecordGetter;
|
||||
|
||||
public function __construct(DNSRecordGetterInterface $DNSRecordGetter)
|
||||
{
|
||||
$this->DNSRecordGetter = $DNSRecordGetter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $domainName
|
||||
* @return Record[]
|
||||
* @throws DNSLookupException
|
||||
*/
|
||||
public function getDomainDMARCRecords(string $domainName): array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
if (!str_starts_with($domainName, '_dmarc.')) {
|
||||
$domainName = '_dmarc.'.$domainName;
|
||||
}
|
||||
|
||||
$records = $this->DNSRecordGetter->resolveTXT($domainName);
|
||||
|
||||
foreach ($records as $record) {
|
||||
$txt = strtolower($record);
|
||||
// An DMARC record can be empty (default policy)
|
||||
if ($txt == 'v=dmarc1;' || str_starts_with($txt, 'v=dmarc1; ')) {
|
||||
$result[] = new Record($record);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getResult(Query $query): Result
|
||||
{
|
||||
return $this->doGetResult($query);
|
||||
}
|
||||
|
||||
private function doGetResult(Query $query): Result
|
||||
{
|
||||
$domainName = $query->getDomainName();
|
||||
|
||||
$result??= new Result();
|
||||
|
||||
if(empty($domainName)) {
|
||||
$result->setResult(Result::NONE);
|
||||
return $result;
|
||||
}
|
||||
|
||||
try {
|
||||
$records = $this->getDomainDMARCRecords( $domainName);
|
||||
} catch (DNSLookupException $e) {
|
||||
$result->setResult(Result::TEMPERROR);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (count($records) == 0) {
|
||||
$result->setResult(Result::NONE);
|
||||
|
||||
return $result;
|
||||
}
|
||||
if (count($records) > 1) {
|
||||
$result->setResult(Result::PERMERROR);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
$record = $records[0];
|
||||
$result->setRecord($record);
|
||||
if (!$record->isValid()) {
|
||||
$result->setResult(Result::PERMERROR);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach ($record->getTerms() as $term) {
|
||||
if ( $term instanceof RejectPolicy) {
|
||||
$result->setResult($term->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
30
src/Enum/DMARCMechanism.php
Normal file
30
src/Enum/DMARCMechanism.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Enum;
|
||||
|
||||
abstract class DMARCMechanism
|
||||
{
|
||||
public const REJECT_POLICY = 'p';
|
||||
public const SUB_REJECT_POLICY = 'sp';
|
||||
public const REPORT_URI_AGGREGATE = 'rua';
|
||||
public const REPORT_URI_FORENSIC = 'ruf';
|
||||
public const SPF_ALIGNMENT = 'aspf';
|
||||
public const DKIM_ALIGNMENT = 'adkim';
|
||||
public const REPORTING_INTERVAL = 'ri';
|
||||
public const REPORTING_FORMAT = 'rf';
|
||||
public const FORENSIC_REPORT_OPTIONS = 'fo';
|
||||
public const PERCENTAGE = 'pct';
|
||||
}
|
49
src/Mechanism/AbstractMechanism.php
Normal file
49
src/Mechanism/AbstractMechanism.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Mechanism;
|
||||
|
||||
use Mika56\SPFCheck\Mechanism\AbstractMechanism as SpfAbstractMechanism;
|
||||
|
||||
abstract class AbstractMechanism extends SpfAbstractMechanism
|
||||
{
|
||||
private string $qualifier;
|
||||
private string $content;
|
||||
|
||||
/**
|
||||
* @param string $rawTerm
|
||||
* @param string $qualifier
|
||||
* @param string $termContent
|
||||
*/
|
||||
public function __construct(string $rawTerm, string $qualifier, string $termContent)
|
||||
{
|
||||
parent::__construct($rawTerm, $qualifier);
|
||||
$this->qualifier = $qualifier;
|
||||
$this->content = $termContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getQualifier(): string
|
||||
{
|
||||
return $this->qualifier;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
}
|
33
src/Mechanism/DMARC/DkimAlignment.php
Normal file
33
src/Mechanism/DMARC/DkimAlignment.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Mechanism\DMARC;
|
||||
|
||||
use D3\MailAuthenticationCheck\Mechanism\AbstractMechanism;
|
||||
|
||||
class DkimAlignment extends AbstractMechanism
|
||||
{
|
||||
public const DEFAULT = 'r';
|
||||
|
||||
public function isStrict(): bool
|
||||
{
|
||||
return strtolower((string) $this) === 's';
|
||||
}
|
||||
|
||||
public function isRelaxed(): bool
|
||||
{
|
||||
return !$this->isStrict();
|
||||
}
|
||||
}
|
48
src/Mechanism/DMARC/ForensicReportOptions.php
Normal file
48
src/Mechanism/DMARC/ForensicReportOptions.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Mechanism\DMARC;
|
||||
|
||||
use D3\MailAuthenticationCheck\Mechanism\AbstractMechanism;
|
||||
|
||||
class ForensicReportOptions extends AbstractMechanism
|
||||
{
|
||||
public const DEFAULT = '0';
|
||||
|
||||
public function getList(): array
|
||||
{
|
||||
return explode(':', trim(strtolower((string) $this)));
|
||||
}
|
||||
|
||||
public function SpfAndDkimAlignmentFailed(): bool
|
||||
{
|
||||
return in_array('0', $this->getList());
|
||||
}
|
||||
|
||||
public function SpfOrDkimAlignmentFailed(): bool
|
||||
{
|
||||
return in_array('1', $this->getList());
|
||||
}
|
||||
|
||||
public function DkimFailed(): bool
|
||||
{
|
||||
return in_array('d', $this->getList());
|
||||
}
|
||||
|
||||
public function SpfFailed(): bool
|
||||
{
|
||||
return in_array('s', $this->getList());
|
||||
}
|
||||
}
|
23
src/Mechanism/DMARC/Percentage.php
Normal file
23
src/Mechanism/DMARC/Percentage.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Mechanism\DMARC;
|
||||
|
||||
use D3\MailAuthenticationCheck\Mechanism\AbstractMechanism;
|
||||
|
||||
class Percentage extends AbstractMechanism
|
||||
{
|
||||
public const DEFAULT = 100;
|
||||
}
|
35
src/Mechanism/DMARC/RejectPolicy.php
Normal file
35
src/Mechanism/DMARC/RejectPolicy.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Mechanism\DMARC;
|
||||
|
||||
use D3\MailAuthenticationCheck\Mechanism\AbstractMechanism;
|
||||
use D3\MailAuthenticationCheck\Model\DMARCResult;
|
||||
|
||||
class RejectPolicy extends AbstractMechanism
|
||||
{
|
||||
public function getValue(): string
|
||||
{
|
||||
switch (strtolower((string) $this)) {
|
||||
case 'quarantine':
|
||||
return DMARCResult::REJECT_QUARANTINE;
|
||||
case 'reject':
|
||||
return DMARCResult::REJECT_REJECT;
|
||||
case 'none':
|
||||
default:
|
||||
return DMARCResult::REJECT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
31
src/Mechanism/DMARC/ReportUriAggregateData.php
Normal file
31
src/Mechanism/DMARC/ReportUriAggregateData.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Mechanism\DMARC;
|
||||
|
||||
use D3\MailAuthenticationCheck\Mechanism\AbstractMechanism;
|
||||
|
||||
class ReportUriAggregateData extends AbstractMechanism
|
||||
{
|
||||
public function getList(): array
|
||||
{
|
||||
return array_map(
|
||||
function($item) {
|
||||
return preg_replace('@^mailto:@', '', $item);
|
||||
},
|
||||
explode(',', strtolower((string) $this))
|
||||
);
|
||||
}
|
||||
}
|
31
src/Mechanism/DMARC/ReportUriForensicData.php
Normal file
31
src/Mechanism/DMARC/ReportUriForensicData.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Mechanism\DMARC;
|
||||
|
||||
use D3\MailAuthenticationCheck\Mechanism\AbstractMechanism;
|
||||
|
||||
class ReportUriForensicData extends AbstractMechanism
|
||||
{
|
||||
public function getList(): array
|
||||
{
|
||||
return array_map(
|
||||
function($item) {
|
||||
return preg_replace('@^mailto:@', '', $item);
|
||||
},
|
||||
explode(',', strtolower((string) $this))
|
||||
);
|
||||
}
|
||||
}
|
23
src/Mechanism/DMARC/ReportingFormat.php
Normal file
23
src/Mechanism/DMARC/ReportingFormat.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Mechanism\DMARC;
|
||||
|
||||
use D3\MailAuthenticationCheck\Mechanism\AbstractMechanism;
|
||||
|
||||
class ReportingFormat extends AbstractMechanism
|
||||
{
|
||||
public const DEFAULT = 'afrf';
|
||||
}
|
23
src/Mechanism/DMARC/ReportingInterval.php
Normal file
23
src/Mechanism/DMARC/ReportingInterval.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Mechanism\DMARC;
|
||||
|
||||
use D3\MailAuthenticationCheck\Mechanism\AbstractMechanism;
|
||||
|
||||
class ReportingInterval extends AbstractMechanism
|
||||
{
|
||||
public const DEFAULT = 86400;
|
||||
}
|
33
src/Mechanism/DMARC/SpfAlignment.php
Normal file
33
src/Mechanism/DMARC/SpfAlignment.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Mechanism\DMARC;
|
||||
|
||||
use D3\MailAuthenticationCheck\Mechanism\AbstractMechanism;
|
||||
|
||||
class SpfAlignment extends AbstractMechanism
|
||||
{
|
||||
public const DEFAULT = 'r';
|
||||
|
||||
public function isStrict(): bool
|
||||
{
|
||||
return strtolower((string) $this) === 's';
|
||||
}
|
||||
|
||||
public function isRelaxed(): bool
|
||||
{
|
||||
return !$this->isStrict();
|
||||
}
|
||||
}
|
35
src/Mechanism/DMARC/SubRejectPolicy.php
Normal file
35
src/Mechanism/DMARC/SubRejectPolicy.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Mechanism\DMARC;
|
||||
|
||||
use D3\MailAuthenticationCheck\Mechanism\AbstractMechanism;
|
||||
use D3\MailAuthenticationCheck\Model\DMARCResult;
|
||||
|
||||
class SubRejectPolicy extends AbstractMechanism
|
||||
{
|
||||
public function getValue(): string
|
||||
{
|
||||
switch (strtolower((string) $this)) {
|
||||
case 'quarantine':
|
||||
return DMARCResult::REJECT_QUARANTINE;
|
||||
case 'reject':
|
||||
return DMARCResult::REJECT_REJECT;
|
||||
case 'none':
|
||||
default:
|
||||
return DMARCResult::REJECT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
156
src/Model/DMARCRecord.php
Normal file
156
src/Model/DMARCRecord.php
Normal file
@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Model;
|
||||
|
||||
use D3\MailAuthenticationCheck\Enum\DMARCMechanism as Mechanism;
|
||||
use D3\MailAuthenticationCheck\Mechanism\AbstractMechanism;
|
||||
use D3\MailAuthenticationCheck\Mechanism\DMARC\DkimAlignment;
|
||||
use D3\MailAuthenticationCheck\Mechanism\DMARC\Percentage;
|
||||
use D3\MailAuthenticationCheck\Mechanism\DMARC\ReportingFormat;
|
||||
use D3\MailAuthenticationCheck\Mechanism\DMARC\ReportingInterval;
|
||||
use D3\MailAuthenticationCheck\Mechanism\DMARC\SpfAlignment;
|
||||
use D3\MailAuthenticationCheck\Mechanism\DMARC\ForensicReportOptions;
|
||||
use D3\MailAuthenticationCheck\Mechanism\DMARC\RejectPolicy;
|
||||
use D3\MailAuthenticationCheck\Mechanism\DMARC\ReportUriAggregateData;
|
||||
use D3\MailAuthenticationCheck\Mechanism\DMARC\ReportUriForensicData;
|
||||
use D3\MailAuthenticationCheck\Mechanism\DMARC\SubRejectPolicy;
|
||||
use LogicException;
|
||||
|
||||
class DMARCRecord
|
||||
{
|
||||
private string $rawRecord;
|
||||
|
||||
public function __construct(string $rawRecord = '')
|
||||
{
|
||||
$this->rawRecord = $rawRecord;
|
||||
}
|
||||
|
||||
public function getRawRecord(): string
|
||||
{
|
||||
return $this->rawRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AbstractMechanism[]
|
||||
*/
|
||||
public function getTerms(): iterable
|
||||
{
|
||||
$terms = explode(' ', $this->rawRecord);
|
||||
|
||||
array_shift($terms); // Remove first part (v=DMARC1)
|
||||
|
||||
foreach ($terms as $term) {
|
||||
if(empty($term)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
preg_match('`^(?<qualifier>(p|rua|ruf|sp|aspf|adkim|fo|ri|rf|pct))=(?<term>[^;]*);*$`U', $term, $matches);
|
||||
|
||||
switch(strtolower($matches['qualifier'])) {
|
||||
case Mechanism::REJECT_POLICY:
|
||||
yield new RejectPolicy($term, $matches['qualifier'], $matches['term']);
|
||||
break;
|
||||
case Mechanism::SUB_REJECT_POLICY:
|
||||
yield new SubRejectPolicy($term, $matches['qualifier'], $matches['term']);
|
||||
break;
|
||||
case Mechanism::REPORT_URI_AGGREGATE:
|
||||
yield new ReportUriAggregateData($term, $matches['qualifier'], $matches['term']);
|
||||
break;
|
||||
case Mechanism::REPORT_URI_FORENSIC:
|
||||
yield new ReportUriForensicData($term, $matches['qualifier'], $matches['term']);
|
||||
break;
|
||||
case Mechanism::SPF_ALIGNMENT:
|
||||
yield new SpfAlignment($term, $matches['qualifier'], $matches['term']);
|
||||
break;
|
||||
case Mechanism::DKIM_ALIGNMENT:
|
||||
yield new DkimAlignment($term, $matches['qualifier'], $matches['term']);
|
||||
break;
|
||||
case Mechanism::REPORTING_INTERVAL:
|
||||
yield new ReportingInterval($term, $matches['qualifier'], $matches['term']);
|
||||
break;
|
||||
case Mechanism::REPORTING_FORMAT:
|
||||
yield new ReportingFormat($term, $matches['qualifier'], $matches['term']);
|
||||
break;
|
||||
case Mechanism::FORENSIC_REPORT_OPTIONS:
|
||||
yield new ForensicReportOptions($term, $matches['qualifier'], $matches['term']);
|
||||
break;
|
||||
case Mechanism::PERCENTAGE:
|
||||
yield new Percentage($term, $matches['qualifier'], $matches['term']);
|
||||
break;
|
||||
default:
|
||||
throw new LogicException('Unknown mechanism '.$matches['qualifier']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function isValid(): bool
|
||||
{
|
||||
return (bool) preg_match(
|
||||
'/(^v=DMARC1;)?( +(p=(none|quarantine|reject);|rua=mailto:([^;]*);|ruf=mailto:([^;]*);|sp=(none|quarantine|reject);|aspf=s;|adkim=s;|fo=((?!:)(:?\w+)+);))/i',
|
||||
$this->rawRecord
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RejectPolicy
|
||||
* @throws LogicException
|
||||
*/
|
||||
public function getRejectPolicy(): RejectPolicy
|
||||
{
|
||||
/** @var RejectPolicy $mechanism */
|
||||
$mechanism = $this->getTerm(RejectPolicy::class);
|
||||
return $mechanism;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ReportUriAggregateData
|
||||
* @throws LogicException
|
||||
*/
|
||||
public function getReportUriAggregate(): ReportUriAggregateData
|
||||
{
|
||||
/** @var ReportUriAggregateData $mechanism */
|
||||
$mechanism = $this->getTerm(ReportUriAggregateData::class);
|
||||
return $mechanism;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ReportUriForensicData
|
||||
* @throws LogicException
|
||||
*/
|
||||
public function getReportUriForensic(): ReportUriForensicData
|
||||
{
|
||||
/** @var ReportUriForensicData $mechanism */
|
||||
$mechanism = $this->getTerm(ReportUriForensicData::class);
|
||||
return $mechanism;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
*
|
||||
* @return AbstractMechanism
|
||||
* @throws LogicException
|
||||
*/
|
||||
public function getTerm(string $className): AbstractMechanism
|
||||
{
|
||||
foreach ($this->getTerms() as $term) {
|
||||
if ( $term instanceof $className ) {
|
||||
return $term;
|
||||
}
|
||||
}
|
||||
|
||||
throw new LogicException('undefined term '.$className);
|
||||
}
|
||||
}
|
67
src/Model/DMARCResult.php
Normal file
67
src/Model/DMARCResult.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* https://www.d3data.de
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
||||
* @link https://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\MailAuthenticationCheck\Model;
|
||||
|
||||
use D3\MailAuthenticationCheck\Model\DMARCRecord as Record;
|
||||
|
||||
class DMARCResult
|
||||
{
|
||||
public const REJECT_NONE = 'none';
|
||||
public const REJECT_QUARANTINE = 'quarantine';
|
||||
public const REJECT_REJECT = 'reject';
|
||||
|
||||
public const NONE = 'None';
|
||||
public const TEMPERROR = 'TempError';
|
||||
public const PERMERROR = 'PermError';
|
||||
|
||||
private string $result;
|
||||
|
||||
protected Record $record;
|
||||
|
||||
public function hasResult(): bool
|
||||
{
|
||||
return isset($this->result);
|
||||
}
|
||||
|
||||
public function getResult(): string
|
||||
{
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function setRecord(Record $record): self
|
||||
{
|
||||
$this->record = $record;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRecord(): Record
|
||||
{
|
||||
return $this->record ?? new Record('');
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function setResult(string $result): self
|
||||
{
|
||||
$this->result = $result;
|
||||
return $this;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user