Add LinkTokens service

[MAILPOET-2340]
This commit is contained in:
Amine Ben hammou
2019-09-19 16:24:06 +01:00
committed by Jack Kitterhing
parent b16cec570e
commit ab63bde9ed
4 changed files with 99 additions and 26 deletions

View File

@ -158,6 +158,7 @@ class ContainerConfigurator implements IContainerConfigurator {
$container->autowire(\MailPoet\Subscribers\RequiredCustomFieldValidator::class)->setPublic(true); $container->autowire(\MailPoet\Subscribers\RequiredCustomFieldValidator::class)->setPublic(true);
$container->autowire(\MailPoet\Subscribers\SubscriberActions::class)->setPublic(true); $container->autowire(\MailPoet\Subscribers\SubscriberActions::class)->setPublic(true);
$container->autowire(\MailPoet\Subscribers\InactiveSubscribersController::class); $container->autowire(\MailPoet\Subscribers\InactiveSubscribersController::class);
$container->autowire(\MailPoet\Subscribers\LinkTokens::class);
// Segments // Segments
$container->autowire(\MailPoet\Segments\SubscribersListings::class)->setPublic(true); $container->autowire(\MailPoet\Segments\SubscribersListings::class)->setPublic(true);
$container->autowire(\MailPoet\Segments\WooCommerce::class)->setPublic(true); $container->autowire(\MailPoet\Segments\WooCommerce::class)->setPublic(true);

View File

@ -0,0 +1,44 @@
<?php
namespace MailPoet\Subscribers;
use MailPoet\Models\Subscriber;
class LinkTokens {
const OBSOLETE_LINK_TOKEN_LENGTH = 6;
const LINK_TOKEN_LENGTH = 32;
function getToken(Subscriber $subscriber) {
if ($subscriber->link_token === null) {
$subscriber->link_token = $this->generateToken($subscriber->email);
// `$subscriber->save()` fails if the subscriber has subscriptions, segments or custom fields
\ORM::rawExecute(sprintf('UPDATE %s SET link_token = ? WHERE email = ?', Subscriber::$_table), [$subscriber->link_token, $subscriber->email]);
}
return $subscriber->link_token;
}
function verifyToken(Subscriber $subscriber, $token) {
$database_token = $subscriber->getLinkToken();
$request_token = substr($token, 0, strlen($database_token));
return call_user_func(
'hash_equals',
$database_token,
$request_token
);
}
/**
* Only for backward compatibility for old tokens
*/
private function generateToken($email = null, $length = self::OBSOLETE_LINK_TOKEN_LENGTH) {
if ($email !== null) {
$auth_key = '';
if (defined('AUTH_KEY')) {
$auth_key = AUTH_KEY;
}
return substr(md5($auth_key . $email), 0, $length);
}
return false;
}
}

View File

@ -672,32 +672,6 @@ class SubscriberTest extends \MailPoetTest {
expect($total)->equals(1); expect($total)->equals(1);
} }
function testItGeneratesSubscriberToken() {
$token = Subscriber::generateToken($this->test_data['email']);
expect(strlen($token))->equals(6);
}
function testItVerifiesSubscriberToken() {
$subscriber = Subscriber::createOrUpdate([
'email' => $this->test_data['email'],
]);
$token = $subscriber->getLinkToken();
expect($subscriber->verifyToken($token))->true();
expect($subscriber->verifyToken('faketoken'))->false();
}
function testItVerifiesOldVersionOfSubscriberToken() {
$subscriber = Subscriber::createOrUpdate([
'email' => $this->test_data['email'],
]);
$subscriber->link_token = 'abcdef';
$token = $subscriber->getLinkToken();
expect($subscriber->verifyToken($token))->true();
expect($subscriber->verifyToken('abcdefghijk'))->true();
expect($subscriber->verifyToken('faketoken'))->false();
expect($subscriber->verifyToken('fake'))->false();
}
function testItBulkDeletesSubscribers() { function testItBulkDeletesSubscribers() {
$segment = Segment::createOrUpdate( $segment = Segment::createOrUpdate(
[ [

View File

@ -0,0 +1,54 @@
<?php
namespace MailPoet\Subscribers;
use MailPoet\Models\Subscriber;
class LinkTokensTest extends \MailPoetTest {
/** @var LinkTokens */
private $link_tokens;
function _before() {
parent::_before();
$this->link_tokens = new LinkTokens;
}
function testItGeneratesSubscriberToken() {
$subscriber1 = $this->makeSubscriber(['email' => 'demo1@fake.loc']);
$subscriber2 = $this->makeSubscriber(['email' => 'demo2@fake.loc']);
$token1 = $this->link_tokens->getToken($subscriber1);
$token2 = $this->link_tokens->getToken($subscriber2);
expect(strlen($token1))->equals(6);
expect(strlen($token2))->equals(6);
expect($token1 != $token2)->equals(true);
}
function testItGetsSubscriberToken() {
$subscriber1 = $this->makeSubscriber(['email' => 'demo1@fake.loc', 'link_token' => 'already-existing-token']);
$subscriber2 = $this->makeSubscriber(['email' => 'demo2@fake.loc']);
expect($this->link_tokens->getToken($subscriber1))->equals('already-existing-token');
expect(strlen($this->link_tokens->getToken($subscriber2)))->equals(6);
}
function testItVerifiesSubscriberToken() {
$subscriber = $this->makeSubscriber([
'email' => 'demo@fake.loc',
]);
$token = $this->link_tokens->getToken($subscriber);
expect($this->link_tokens->verifyToken($subscriber, $token))->true();
expect($this->link_tokens->verifyToken($subscriber, 'faketoken'))->false();
}
function _after() {
\ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
}
private function makeSubscriber($data) {
$subscriber = Subscriber::create();
$subscriber->hydrate($data);
$subscriber->save();
return $subscriber;
}
}