Add SPF check API method to backend [MAILPOET-2295]
This commit is contained in:
@ -8,12 +8,17 @@ use MailPoet\API\JSON\Error as APIError;
|
|||||||
use MailPoet\Config\AccessControl;
|
use MailPoet\Config\AccessControl;
|
||||||
use MailPoet\Config\Installer;
|
use MailPoet\Config\Installer;
|
||||||
use MailPoet\Services\Bridge;
|
use MailPoet\Services\Bridge;
|
||||||
|
use MailPoet\Services\SPFCheck;
|
||||||
|
use MailPoet\Settings\SettingsController;
|
||||||
use MailPoet\WP\DateTime;
|
use MailPoet\WP\DateTime;
|
||||||
use MailPoet\WP\Functions as WPFunctions;
|
use MailPoet\WP\Functions as WPFunctions;
|
||||||
|
|
||||||
class Services extends APIEndpoint {
|
class Services extends APIEndpoint {
|
||||||
public $bridge;
|
public $bridge;
|
||||||
public $date_time;
|
public $date_time;
|
||||||
|
public $settings;
|
||||||
|
public $spf_check;
|
||||||
|
|
||||||
public $permissions = [
|
public $permissions = [
|
||||||
'global' => AccessControl::PERMISSION_MANAGE_SETTINGS,
|
'global' => AccessControl::PERMISSION_MANAGE_SETTINGS,
|
||||||
];
|
];
|
||||||
@ -21,6 +26,24 @@ class Services extends APIEndpoint {
|
|||||||
function __construct() {
|
function __construct() {
|
||||||
$this->bridge = new Bridge();
|
$this->bridge = new Bridge();
|
||||||
$this->date_time = new DateTime();
|
$this->date_time = new DateTime();
|
||||||
|
$this->settings = new SettingsController();
|
||||||
|
$this->spf_check = new SPFCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkSPFRecord($data = []) {
|
||||||
|
$sender_address = $this->settings->get('sender.address');
|
||||||
|
$domain_name = mb_substr($sender_address, mb_strpos($sender_address, '@') + 1);
|
||||||
|
|
||||||
|
$result = $this->spf_check->checkSPFRecord($domain_name);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
return $this->errorResponse(
|
||||||
|
[APIError::BAD_REQUEST => WPFunctions::get()->__('SPF check has failed.', 'mailpoet')],
|
||||||
|
['sender_address' => $sender_address, 'domain_name' => $domain_name]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkMSSKey($data = []) {
|
function checkMSSKey($data = []) {
|
||||||
|
31
lib/Services/SPFCheck.php
Normal file
31
lib/Services/SPFCheck.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Services;
|
||||||
|
|
||||||
|
class SPFCheck {
|
||||||
|
function checkSPFRecord($domain) {
|
||||||
|
$record = $this->getSPFRecord($domain);
|
||||||
|
if (empty($record)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return strpos($record, 'include:spf.sendingservice.net') !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSPFRecord($domain) {
|
||||||
|
$records = $this->dnsGetRecord($domain, DNS_TXT);
|
||||||
|
if (empty($records[0])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach ($records as $record) {
|
||||||
|
if (empty($record['txt']) || !preg_match('/^v=spf1/', trim($record['txt']))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return $record['txt'];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function dnsGetRecord($domain, $type) {
|
||||||
|
return dns_get_record($domain, $type);
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ use MailPoet\API\JSON\v1\Services;
|
|||||||
use MailPoet\API\JSON\Response as APIResponse;
|
use MailPoet\API\JSON\Response as APIResponse;
|
||||||
use MailPoet\Config\Installer;
|
use MailPoet\Config\Installer;
|
||||||
use MailPoet\Services\Bridge;
|
use MailPoet\Services\Bridge;
|
||||||
|
use MailPoet\Services\SPFCheck;
|
||||||
use MailPoet\Settings\SettingsController;
|
use MailPoet\Settings\SettingsController;
|
||||||
|
|
||||||
class ServicesTest extends \MailPoetTest {
|
class ServicesTest extends \MailPoetTest {
|
||||||
@ -20,6 +21,30 @@ class ServicesTest extends \MailPoetTest {
|
|||||||
$this->settings = new SettingsController();
|
$this->settings = new SettingsController();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testItRespondsWithErrorIfSPFCheckFails() {
|
||||||
|
$email = 'spf_test@example.com';
|
||||||
|
$this->settings->set('sender.address', $email);
|
||||||
|
$this->services_endpoint->spf_check = Stub::make(
|
||||||
|
SPFCheck::class,
|
||||||
|
['checkSPFRecord' => false],
|
||||||
|
$this
|
||||||
|
);
|
||||||
|
$response = $this->services_endpoint->checkSPFRecord([]);
|
||||||
|
expect($response->status)->equals(APIResponse::STATUS_NOT_FOUND);
|
||||||
|
expect($response->meta['sender_address'])->equals($email);
|
||||||
|
expect($response->meta['domain_name'])->equals('example.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItRespondsWithSuccessIfSPFCheckPasses() {
|
||||||
|
$this->services_endpoint->spf_check = Stub::make(
|
||||||
|
SPFCheck::class,
|
||||||
|
['checkSPFRecord' => true],
|
||||||
|
$this
|
||||||
|
);
|
||||||
|
$response = $this->services_endpoint->checkSPFRecord([]);
|
||||||
|
expect($response->status)->equals(APIResponse::STATUS_OK);
|
||||||
|
}
|
||||||
|
|
||||||
function testItRespondsWithErrorIfNoMSSKeyIsGiven() {
|
function testItRespondsWithErrorIfNoMSSKeyIsGiven() {
|
||||||
$response = $this->services_endpoint->checkMSSKey(['key' => '']);
|
$response = $this->services_endpoint->checkMSSKey(['key' => '']);
|
||||||
expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST);
|
expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST);
|
||||||
|
24
tests/unit/Services/SPFCheckTest.php
Normal file
24
tests/unit/Services/SPFCheckTest.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Services;
|
||||||
|
|
||||||
|
class SPFCheckTest extends \MailPoetUnitTest {
|
||||||
|
function testItChecksSPFRecord() {
|
||||||
|
$domain = 'example.com';
|
||||||
|
// Failed to get DNS records
|
||||||
|
$response = false;
|
||||||
|
$check = $this->make(SPFCheck::class, ['dnsGetRecord' => $response]);
|
||||||
|
expect($check->checkSPFRecord($domain))->equals(true);
|
||||||
|
// No SPF record
|
||||||
|
$response = [['txt' => '123'], ['txt' => 'abc']];
|
||||||
|
$check = $this->make(SPFCheck::class, ['dnsGetRecord' => $response]);
|
||||||
|
expect($check->checkSPFRecord($domain))->equals(true);
|
||||||
|
// Good SPF record
|
||||||
|
$response = [['txt' => 'v=spf1 include:spf.protection.outlook.com include:sendgrid.net include:spf.sendingservice.net -all']];
|
||||||
|
$check = $this->make(SPFCheck::class, ['dnsGetRecord' => $response]);
|
||||||
|
expect($check->checkSPFRecord($domain))->equals(true);
|
||||||
|
// Bad SPF record
|
||||||
|
$response = [['txt' => 'v=spf1 include:spf.protection.outlook.com include:sendgrid.net -all']];
|
||||||
|
$check = $this->make(SPFCheck::class, ['dnsGetRecord' => $response]);
|
||||||
|
expect($check->checkSPFRecord($domain))->equals(false);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user