Added support for SPF
This commit is contained in:
+2
-1
@@ -21,7 +21,8 @@
|
|||||||
"php": "^8.4",
|
"php": "^8.4",
|
||||||
"filament/filament": "^5.0",
|
"filament/filament": "^5.0",
|
||||||
"cbowofrivia/dmarc-record-builder": "^4.0",
|
"cbowofrivia/dmarc-record-builder": "^4.0",
|
||||||
"mlocati/spf-lib": "^3.3"
|
"mlocati/spf-lib": "^3.3",
|
||||||
|
"mlocati/ip-lib": "^1.22"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|||||||
Generated
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "246c2f9c61981a9ca6650dcb4ce074be",
|
"content-hash": "b369fb991cc22ebbd6832aa81a937e0c",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "blade-ui-kit/blade-heroicons",
|
"name": "blade-ui-kit/blade-heroicons",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
{{ $this->form }}
|
{{ $this->form }}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<x-filament::modal id="dmarc-record-modal" width="2xl">
|
<x-filament::modal id="spf-record-modal" width="2xl">
|
||||||
<x-slot name="heading">
|
<x-slot name="heading">
|
||||||
Generated SPF Record
|
Generated SPF Record
|
||||||
</x-slot>
|
</x-slot>
|
||||||
|
|||||||
@@ -230,16 +230,17 @@ class GenerateDmarcPage extends Page
|
|||||||
'name' => '_dmarc',
|
'name' => '_dmarc',
|
||||||
'content' => $this->generatedRecord
|
'content' => $this->generatedRecord
|
||||||
]);
|
]);
|
||||||
|
|
||||||
event(new \App\Events\DmarcKeyGenerated(
|
if($data['update_dns']) {
|
||||||
zone: $domainName,
|
event(new \App\Events\DmarcKeyGenerated(
|
||||||
name: '_dmarc',
|
zone: $domainName,
|
||||||
type: 'TXT',
|
name: '_dmarc',
|
||||||
content: $this->generatedRecord,
|
type: 'TXT',
|
||||||
ttl: 3600,
|
content: $this->generatedRecord,
|
||||||
operation: 'create'
|
ttl: 3600,
|
||||||
));
|
operation: 'create'
|
||||||
|
));
|
||||||
|
};
|
||||||
$this->dispatch('open-modal', id: 'dmarc-record-modal');
|
$this->dispatch('open-modal', id: 'dmarc-record-modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ class GenerateSpfPage extends Page
|
|||||||
{
|
{
|
||||||
$data = $this->form->getState();
|
$data = $this->form->getState();
|
||||||
\Log::debug('SPF Form data:' . json_encode($data));
|
\Log::debug('SPF Form data:' . json_encode($data));
|
||||||
|
\Log::debug('Update dms state:' . $data['update_dns']);
|
||||||
|
|
||||||
// Generate the SPF record
|
// Generate the SPF record
|
||||||
$result = $spf->generate($this->domain, $data);
|
$result = $spf->generate($this->domain, $data);
|
||||||
@@ -313,19 +314,20 @@ class GenerateSpfPage extends Page
|
|||||||
// Log the generated record
|
// Log the generated record
|
||||||
\Log::debug('SPF Event data:', [
|
\Log::debug('SPF Event data:', [
|
||||||
'zone' => $this->dnsName,
|
'zone' => $this->dnsName,
|
||||||
'name' => '_dmarc',
|
'name' => '',
|
||||||
'content' => $this->generatedRecord
|
'content' => $this->generatedRecord
|
||||||
]);
|
]);
|
||||||
|
if($data['update_dns']) {
|
||||||
// Dispatch event
|
|
||||||
event(new \App\Events\SpfKeyGenerated(
|
event(new \App\Events\SpfRecordGenerated(
|
||||||
zone: $this->dnsName,
|
zone: $this->dnsName,
|
||||||
name: '_dmarc',
|
name: '',
|
||||||
type: 'TXT',
|
type: 'TXT',
|
||||||
content: $this->generatedRecord,
|
content: $this->generatedRecord,
|
||||||
ttl: (int) ($data['ttl'] ?? 3600),
|
ttl: (int) ($data['ttl'] ?? 3600),
|
||||||
operation: 'create'
|
operation: 'create'
|
||||||
));
|
));
|
||||||
|
};
|
||||||
|
|
||||||
// Show the modal with the generated record
|
// Show the modal with the generated record
|
||||||
$this->dispatch('open-modal', id: 'spf-record-modal');
|
$this->dispatch('open-modal', id: 'spf-record-modal');
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ use SPFLib\SemanticValidator;
|
|||||||
use SPFLib\Exception\InvalidTermException;
|
use SPFLib\Exception\InvalidTermException;
|
||||||
use VEximweb\Plugin\DnsTools\Models\SystemDomains as Domain;
|
use VEximweb\Plugin\DnsTools\Models\SystemDomains as Domain;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use IPLib\Factory;
|
||||||
|
use IPLib\Address\IPv4;
|
||||||
|
use IPLib\Address\IPv6;
|
||||||
|
|
||||||
class SpfRecordService
|
class SpfRecordService
|
||||||
{
|
{
|
||||||
@@ -25,9 +28,6 @@ class SpfRecordService
|
|||||||
// Initialize the SPF record with the domain
|
// Initialize the SPF record with the domain
|
||||||
$record = new Record($domain->domain);
|
$record = new Record($domain->domain);
|
||||||
|
|
||||||
// Add the version mechanism (v=spf1)
|
|
||||||
$record->addTerm(new Mechanism\VersionMechanism());
|
|
||||||
|
|
||||||
// 1. Add Include mechanisms (sending services)
|
// 1. Add Include mechanisms (sending services)
|
||||||
if (!empty($data['spf_includes'])) {
|
if (!empty($data['spf_includes'])) {
|
||||||
foreach ($data['spf_includes'] as $include) {
|
foreach ($data['spf_includes'] as $include) {
|
||||||
@@ -46,12 +46,17 @@ class SpfRecordService
|
|||||||
if (!empty($data['spf_ipv4'])) {
|
if (!empty($data['spf_ipv4'])) {
|
||||||
foreach ($data['spf_ipv4'] as $ipv4) {
|
foreach ($data['spf_ipv4'] as $ipv4) {
|
||||||
if (!empty($ipv4['ipv4'])) {
|
if (!empty($ipv4['ipv4'])) {
|
||||||
$record->addTerm(
|
$ip = $this->parseIpAddress($ipv4['ipv4']);
|
||||||
new Mechanism\Ip4Mechanism(
|
if ($ip instanceof IPv4) {
|
||||||
Mechanism::QUALIFIER_PASS,
|
$record->addTerm(
|
||||||
$ipv4['ipv4']
|
new Mechanism\Ip4Mechanism(
|
||||||
)
|
Mechanism::QUALIFIER_PASS,
|
||||||
);
|
$ip
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Log::warning('Invalid IPv4 address: ' . $ipv4['ipv4']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,12 +65,17 @@ class SpfRecordService
|
|||||||
if (!empty($data['spf_ipv6'])) {
|
if (!empty($data['spf_ipv6'])) {
|
||||||
foreach ($data['spf_ipv6'] as $ipv6) {
|
foreach ($data['spf_ipv6'] as $ipv6) {
|
||||||
if (!empty($ipv6['ipv6'])) {
|
if (!empty($ipv6['ipv6'])) {
|
||||||
$record->addTerm(
|
$ip = $this->parseIpAddress($ipv6['ipv6']);
|
||||||
new Mechanism\Ip6Mechanism(
|
if ($ip instanceof IPv6) {
|
||||||
Mechanism::QUALIFIER_PASS,
|
$record->addTerm(
|
||||||
$ipv6['ipv6']
|
new Mechanism\Ip6Mechanism(
|
||||||
)
|
Mechanism::QUALIFIER_PASS,
|
||||||
);
|
$ip
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Log::warning('Invalid IPv6 address: ' . $ipv6['ipv6']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +83,6 @@ class SpfRecordService
|
|||||||
// 4. Add MX mechanism
|
// 4. Add MX mechanism
|
||||||
if (!empty($data['spf_use_mx'])) {
|
if (!empty($data['spf_use_mx'])) {
|
||||||
if (!empty($data['spf_mx_domain'])) {
|
if (!empty($data['spf_mx_domain'])) {
|
||||||
// Custom MX domain
|
|
||||||
$record->addTerm(
|
$record->addTerm(
|
||||||
new Mechanism\MxMechanism(
|
new Mechanism\MxMechanism(
|
||||||
Mechanism::QUALIFIER_PASS,
|
Mechanism::QUALIFIER_PASS,
|
||||||
@@ -81,7 +90,6 @@ class SpfRecordService
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Use current domain's MX records
|
|
||||||
$record->addTerm(
|
$record->addTerm(
|
||||||
new Mechanism\MxMechanism(
|
new Mechanism\MxMechanism(
|
||||||
Mechanism::QUALIFIER_PASS
|
Mechanism::QUALIFIER_PASS
|
||||||
@@ -93,7 +101,6 @@ class SpfRecordService
|
|||||||
// 5. Add A mechanism
|
// 5. Add A mechanism
|
||||||
if (!empty($data['spf_use_a'])) {
|
if (!empty($data['spf_use_a'])) {
|
||||||
if (!empty($data['spf_a_domain'])) {
|
if (!empty($data['spf_a_domain'])) {
|
||||||
// Custom A domain
|
|
||||||
$record->addTerm(
|
$record->addTerm(
|
||||||
new Mechanism\AMechanism(
|
new Mechanism\AMechanism(
|
||||||
Mechanism::QUALIFIER_PASS,
|
Mechanism::QUALIFIER_PASS,
|
||||||
@@ -101,7 +108,6 @@ class SpfRecordService
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Use current domain's A record
|
|
||||||
$record->addTerm(
|
$record->addTerm(
|
||||||
new Mechanism\AMechanism(
|
new Mechanism\AMechanism(
|
||||||
Mechanism::QUALIFIER_PASS
|
Mechanism::QUALIFIER_PASS
|
||||||
@@ -111,7 +117,6 @@ class SpfRecordService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 6. Add Advanced mechanisms
|
// 6. Add Advanced mechanisms
|
||||||
// PTR (deprecated - use with caution)
|
|
||||||
if (!empty($data['spf_ptr']) && $data['spf_ptr'] === 'ptr') {
|
if (!empty($data['spf_ptr']) && $data['spf_ptr'] === 'ptr') {
|
||||||
$record->addTerm(
|
$record->addTerm(
|
||||||
new Mechanism\PtrMechanism(
|
new Mechanism\PtrMechanism(
|
||||||
@@ -120,7 +125,6 @@ class SpfRecordService
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists mechanism
|
|
||||||
if (!empty($data['spf_exists'])) {
|
if (!empty($data['spf_exists'])) {
|
||||||
$record->addTerm(
|
$record->addTerm(
|
||||||
new Mechanism\ExistsMechanism(
|
new Mechanism\ExistsMechanism(
|
||||||
@@ -130,7 +134,7 @@ class SpfRecordService
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. Add Redirect modifier (must be added before the ALL mechanism)
|
// 7. Add Redirect modifier
|
||||||
if (!empty($data['spf_redirect'])) {
|
if (!empty($data['spf_redirect'])) {
|
||||||
try {
|
try {
|
||||||
$record->addTerm(
|
$record->addTerm(
|
||||||
@@ -163,7 +167,6 @@ class SpfRecordService
|
|||||||
$issues = $this->validateRecord($record);
|
$issues = $this->validateRecord($record);
|
||||||
$lookupCount = $this->countLookups($record);
|
$lookupCount = $this->countLookups($record);
|
||||||
|
|
||||||
// Log any issues
|
|
||||||
if (!empty($issues)) {
|
if (!empty($issues)) {
|
||||||
Log::warning('SPF record validation issues:', [
|
Log::warning('SPF record validation issues:', [
|
||||||
'domain' => $domain->domain,
|
'domain' => $domain->domain,
|
||||||
@@ -185,7 +188,7 @@ class SpfRecordService
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'record' => 'v=spf1 -all', // Fallback to a safe default
|
'record' => 'v=spf1 -all',
|
||||||
'lookups' => 0,
|
'lookups' => 0,
|
||||||
'issues' => ['Error: ' . $e->getMessage()],
|
'issues' => ['Error: ' . $e->getMessage()],
|
||||||
'is_valid' => false,
|
'is_valid' => false,
|
||||||
@@ -193,14 +196,35 @@ class SpfRecordService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an IP address string with proper CIDR handling
|
||||||
|
*
|
||||||
|
* @param string $ipString
|
||||||
|
* @return IPv4|IPv6|null
|
||||||
|
*/
|
||||||
|
protected function parseIpAddress(string $ipString)
|
||||||
|
{
|
||||||
|
// Remove any whitespace
|
||||||
|
$ipString = trim($ipString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Factory::parseAddressString($ipString);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::warning('Failed to parse IP address: ' . $ipString, ['error' => $e->getMessage()]);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the qualifier for the ALL mechanism
|
* Get the qualifier for the ALL mechanism
|
||||||
|
* Must return an integer constant from Mechanism class
|
||||||
*
|
*
|
||||||
* @param string $policy
|
* @param string $policy
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
protected function getQualifier(string $policy): int
|
protected function getQualifier(string $policy): string
|
||||||
{
|
{
|
||||||
|
// Using match expression that returns integer constants
|
||||||
return match($policy) {
|
return match($policy) {
|
||||||
'-all' => Mechanism::QUALIFIER_FAIL,
|
'-all' => Mechanism::QUALIFIER_FAIL,
|
||||||
'~all' => Mechanism::QUALIFIER_SOFTFAIL,
|
'~all' => Mechanism::QUALIFIER_SOFTFAIL,
|
||||||
@@ -225,7 +249,7 @@ class SpfRecordService
|
|||||||
$formattedIssues = [];
|
$formattedIssues = [];
|
||||||
foreach ($issues as $issue) {
|
foreach ($issues as $issue) {
|
||||||
$formattedIssues[] = [
|
$formattedIssues[] = [
|
||||||
'level' => $issue->getLevel(), // 'info', 'warning', 'error'
|
'level' => $issue->getLevel(),
|
||||||
'message' => $issue->getMessage(),
|
'message' => $issue->getMessage(),
|
||||||
'term' => $issue->getTerm() ? (string) $issue->getTerm() : null,
|
'term' => $issue->getTerm() ? (string) $issue->getTerm() : null,
|
||||||
];
|
];
|
||||||
@@ -255,7 +279,6 @@ class SpfRecordService
|
|||||||
$terms = $record->getTerms();
|
$terms = $record->getTerms();
|
||||||
|
|
||||||
foreach ($terms as $term) {
|
foreach ($terms as $term) {
|
||||||
// Mechanisms that cause DNS lookups
|
|
||||||
if ($term instanceof Mechanism\IncludeMechanism ||
|
if ($term instanceof Mechanism\IncludeMechanism ||
|
||||||
$term instanceof Mechanism\MxMechanism ||
|
$term instanceof Mechanism\MxMechanism ||
|
||||||
$term instanceof Mechanism\AMechanism ||
|
$term instanceof Mechanism\AMechanism ||
|
||||||
@@ -264,7 +287,6 @@ class SpfRecordService
|
|||||||
$lookupCount++;
|
$lookupCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect modifier also causes a lookup
|
|
||||||
if ($term instanceof Modifier\RedirectModifier) {
|
if ($term instanceof Modifier\RedirectModifier) {
|
||||||
$lookupCount++;
|
$lookupCount++;
|
||||||
}
|
}
|
||||||
@@ -273,35 +295,6 @@ class SpfRecordService
|
|||||||
return $lookupCount;
|
return $lookupCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if an IP address is allowed by the SPF record
|
|
||||||
*
|
|
||||||
* @param string $ip
|
|
||||||
* @param string $domain
|
|
||||||
* @param array $data
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function testIp(string $ip, string $domain, array $data): bool
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
// Generate the record first
|
|
||||||
$result = $this->generate(new Domain(['domain' => $domain]), $data);
|
|
||||||
|
|
||||||
// Parse the record
|
|
||||||
$record = Record::fromString($result['record']);
|
|
||||||
|
|
||||||
// Check if the IP is allowed
|
|
||||||
// Note: This is a simplified check. In production, you'd use a proper SPF checker
|
|
||||||
// that performs actual DNS lookups. The mlocati/spf-lib doesn't have a built-in
|
|
||||||
// checker, so you might want to use a separate package for this.
|
|
||||||
|
|
||||||
return true; // Placeholder
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::error('Failed to test SPF record: ' . $e->getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a human-readable description of the SPF record
|
* Get a human-readable description of the SPF record
|
||||||
*
|
*
|
||||||
@@ -322,10 +315,6 @@ class SpfRecordService
|
|||||||
];
|
];
|
||||||
|
|
||||||
foreach ($terms as $term) {
|
foreach ($terms as $term) {
|
||||||
if ($term instanceof Mechanism\VersionMechanism) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$termString = (string) $term;
|
$termString = (string) $term;
|
||||||
|
|
||||||
if ($term instanceof Mechanism\AllMechanism) {
|
if ($term instanceof Mechanism\AllMechanism) {
|
||||||
@@ -342,18 +331,20 @@ class SpfRecordService
|
|||||||
'description' => 'Include SPF records from ' . $term->getDomain(),
|
'description' => 'Include SPF records from ' . $term->getDomain(),
|
||||||
];
|
];
|
||||||
} elseif ($term instanceof Mechanism\Ip4Mechanism) {
|
} elseif ($term instanceof Mechanism\Ip4Mechanism) {
|
||||||
|
$ip = $term->getIp();
|
||||||
$description['mechanisms'][] = [
|
$description['mechanisms'][] = [
|
||||||
'type' => 'ip4',
|
'type' => 'ip4',
|
||||||
'value' => $termString,
|
'value' => $termString,
|
||||||
'ip' => $term->getIp(),
|
'ip' => is_object($ip) ? (string) $ip : $ip,
|
||||||
'description' => 'Allow IP ' . $term->getIp(),
|
'description' => 'Allow IP ' . (is_object($ip) ? (string) $ip : $ip),
|
||||||
];
|
];
|
||||||
} elseif ($term instanceof Mechanism\Ip6Mechanism) {
|
} elseif ($term instanceof Mechanism\Ip6Mechanism) {
|
||||||
|
$ip = $term->getIp();
|
||||||
$description['mechanisms'][] = [
|
$description['mechanisms'][] = [
|
||||||
'type' => 'ip6',
|
'type' => 'ip6',
|
||||||
'value' => $termString,
|
'value' => $termString,
|
||||||
'ip' => $term->getIp(),
|
'ip' => is_object($ip) ? (string) $ip : $ip,
|
||||||
'description' => 'Allow IP ' . $term->getIp(),
|
'description' => 'Allow IP ' . (is_object($ip) ? (string) $ip : $ip),
|
||||||
];
|
];
|
||||||
} elseif ($term instanceof Mechanism\MxMechanism) {
|
} elseif ($term instanceof Mechanism\MxMechanism) {
|
||||||
$description['mechanisms'][] = [
|
$description['mechanisms'][] = [
|
||||||
@@ -369,6 +360,19 @@ class SpfRecordService
|
|||||||
'domain' => $term->getDomain() ?? 'current domain',
|
'domain' => $term->getDomain() ?? 'current domain',
|
||||||
'description' => 'Allow A record for ' . ($term->getDomain() ?? 'this domain'),
|
'description' => 'Allow A record for ' . ($term->getDomain() ?? 'this domain'),
|
||||||
];
|
];
|
||||||
|
} elseif ($term instanceof Mechanism\PtrMechanism) {
|
||||||
|
$description['mechanisms'][] = [
|
||||||
|
'type' => 'ptr',
|
||||||
|
'value' => $termString,
|
||||||
|
'description' => 'PTR mechanism (deprecated)',
|
||||||
|
];
|
||||||
|
} elseif ($term instanceof Mechanism\ExistsMechanism) {
|
||||||
|
$description['mechanisms'][] = [
|
||||||
|
'type' => 'exists',
|
||||||
|
'value' => $termString,
|
||||||
|
'domain' => $term->getDomain(),
|
||||||
|
'description' => 'Exists mechanism for ' . $term->getDomain(),
|
||||||
|
];
|
||||||
} elseif ($term instanceof Modifier\RedirectModifier) {
|
} elseif ($term instanceof Modifier\RedirectModifier) {
|
||||||
$description['modifiers'][] = [
|
$description['modifiers'][] = [
|
||||||
'type' => 'redirect',
|
'type' => 'redirect',
|
||||||
@@ -392,7 +396,6 @@ class SpfRecordService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a summary
|
|
||||||
$parts = [];
|
$parts = [];
|
||||||
foreach ($description['mechanisms'] as $mech) {
|
foreach ($description['mechanisms'] as $mech) {
|
||||||
if ($mech['type'] !== 'all') {
|
if ($mech['type'] !== 'all') {
|
||||||
@@ -413,27 +416,23 @@ class SpfRecordService
|
|||||||
/**
|
/**
|
||||||
* Get a description for a mechanism
|
* Get a description for a mechanism
|
||||||
*
|
*
|
||||||
* @param mixed $mechanism
|
* @param Mechanism\AllMechanism $mechanism
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function getMechanismDescription($mechanism): string
|
protected function getMechanismDescription(Mechanism\AllMechanism $mechanism): string
|
||||||
{
|
{
|
||||||
if ($mechanism instanceof Mechanism\AllMechanism) {
|
$qualifier = $mechanism->getQualifier();
|
||||||
$qualifier = $mechanism->getQualifier();
|
return match($qualifier) {
|
||||||
return match($qualifier) {
|
Mechanism::QUALIFIER_FAIL => 'Reject all other senders (Hard Fail)',
|
||||||
Mechanism::QUALIFIER_FAIL => 'Reject all other senders (Hard Fail)',
|
Mechanism::QUALIFIER_SOFTFAIL => 'Accept but mark as suspicious (Soft Fail)',
|
||||||
Mechanism::QUALIFIER_SOFTFAIL => 'Accept but mark as suspicious (Soft Fail)',
|
Mechanism::QUALIFIER_NEUTRAL => 'Do nothing (Neutral)',
|
||||||
Mechanism::QUALIFIER_NEUTRAL => 'Do nothing (Neutral)',
|
Mechanism::QUALIFIER_PASS => 'Allow all senders (DANGEROUS)',
|
||||||
Mechanism::QUALIFIER_PASS => 'Allow all senders (DANGEROUS)',
|
default => 'Unknown qualifier',
|
||||||
default => 'Unknown qualifier',
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
return 'SPF mechanism';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flatten a complex SPF record to its simplest form
|
* Flatten a complex SPF record to its simplest form
|
||||||
* (Useful for reducing lookups)
|
|
||||||
*
|
*
|
||||||
* @param string $recordString
|
* @param string $recordString
|
||||||
* @return array
|
* @return array
|
||||||
@@ -452,9 +451,11 @@ class SpfRecordService
|
|||||||
|
|
||||||
foreach ($terms as $term) {
|
foreach ($terms as $term) {
|
||||||
if ($term instanceof Mechanism\Ip4Mechanism) {
|
if ($term instanceof Mechanism\Ip4Mechanism) {
|
||||||
$ip4List[] = $term->getIp();
|
$ip = $term->getIp();
|
||||||
|
$ip4List[] = is_object($ip) ? (string) $ip : $ip;
|
||||||
} elseif ($term instanceof Mechanism\Ip6Mechanism) {
|
} elseif ($term instanceof Mechanism\Ip6Mechanism) {
|
||||||
$ip6List[] = $term->getIp();
|
$ip = $term->getIp();
|
||||||
|
$ip6List[] = is_object($ip) ? (string) $ip : $ip;
|
||||||
} elseif ($term instanceof Mechanism\IncludeMechanism) {
|
} elseif ($term instanceof Mechanism\IncludeMechanism) {
|
||||||
$includes[] = $term->getDomain();
|
$includes[] = $term->getDomain();
|
||||||
} elseif ($term instanceof Mechanism\AllMechanism) {
|
} elseif ($term instanceof Mechanism\AllMechanism) {
|
||||||
|
|||||||
Reference in New Issue
Block a user