Moves newsletter hash generating logic into Security helper class

Updates Links class to use Security helper's hash generating method
This commit is contained in:
Vlad
2017-05-14 17:54:53 -04:00
parent a3e8d47199
commit 6e700b0cfa
6 changed files with 32 additions and 17 deletions

View File

@@ -19,7 +19,6 @@ class Newsletter extends Model {
const STATUS_SENT = 'sent'; const STATUS_SENT = 'sent';
// automatic newsletters status // automatic newsletters status
const STATUS_ACTIVE = 'active'; const STATUS_ACTIVE = 'active';
const NEWSLETTER_HASH_LENGTH = 6;
function __construct() { function __construct() {
parent::__construct(); parent::__construct();
@@ -80,7 +79,7 @@ class Newsletter extends Model {
$this->set('hash', $this->set('hash',
($this->hash) ($this->hash)
? $this->hash ? $this->hash
: self::generateHash() : Security::generateHash()
); );
return parent::save(); return parent::save();
} }
@@ -787,12 +786,4 @@ class Newsletter extends Model {
return parent::where('hash', $hash) return parent::where('hash', $hash)
->findOne(); ->findOne();
} }
static function generateHash() {
return substr(
md5(AUTH_KEY . Security::generateRandomString(15)),
0,
self::NEWSLETTER_HASH_LENGTH
);
}
} }

View File

@@ -12,7 +12,6 @@ use MailPoet\Util\Security;
class Links { class Links {
const DATA_TAG_CLICK = '[mailpoet_click_data]'; const DATA_TAG_CLICK = '[mailpoet_click_data]';
const DATA_TAG_OPEN = '[mailpoet_open_data]'; const DATA_TAG_OPEN = '[mailpoet_open_data]';
const HASH_LENGTH = 5;
const LINK_TYPE_SHORTCODE = 'shortcode'; const LINK_TYPE_SHORTCODE = 'shortcode';
const LINK_TYPE_LINK = 'link'; const LINK_TYPE_LINK = 'link';
@@ -72,7 +71,7 @@ class Links {
static function hash($extracted_links) { static function hash($extracted_links) {
$processed_links = array(); $processed_links = array();
foreach($extracted_links as $extracted_link) { foreach($extracted_links as $extracted_link) {
$hash = Security::generateRandomString(self::HASH_LENGTH); $hash = Security::generateRandomString();
// Use URL as a key to map between extracted and processed links // Use URL as a key to map between extracted and processed links
// regardless of their sequential position (useful for link skips etc.) // regardless of their sequential position (useful for link skips etc.)
$key = $extracted_link['link']; $key = $extracted_link['link'];
@@ -216,4 +215,4 @@ class Links {
$transformed_data['preview'] = (!empty($data[4])) ? $data[4] : false; $transformed_data['preview'] = (!empty($data[4])) ? $data[4] : false;
return $transformed_data; return $transformed_data;
} }
} }

View File

@@ -49,7 +49,9 @@ class Track {
Newsletter::findOne($data->queue->newsletter_id) : Newsletter::findOne($data->queue->newsletter_id) :
false; false;
if(!empty($data->link_hash)) { if(!empty($data->link_hash)) {
$data->link = NewsletterLink::getByHash($data->link_hash); $data->link = NewsletterLink::where('queue_id', $data->queue_id)
->where('hash', $data->link_hash)
->findOne();
} }
return $this->_validateTrackData($data); return $this->_validateTrackData($data);
} }

View File

@@ -5,6 +5,8 @@ if(!defined('ABSPATH')) exit;
require_once(ABSPATH . 'wp-includes/pluggable.php'); require_once(ABSPATH . 'wp-includes/pluggable.php');
class Security { class Security {
const HASH_LENGTH = 6;
static function generateToken($action = 'mailpoet_token') { static function generateToken($action = 'mailpoet_token') {
return wp_create_nonce($action); return wp_create_nonce($action);
} }
@@ -17,4 +19,13 @@ class Security {
min(max(5, (int)$length), 32) min(max(5, (int)$length), 32)
); );
} }
static function generateHash($length = false) {
$length = ($length) ? $length : self::HASH_LENGTH;
return substr(
md5(AUTH_KEY . self::generateRandomString(15)),
0,
$length
);
}
} }

View File

@@ -10,6 +10,7 @@ use MailPoet\Models\NewsletterOption;
use MailPoet\Models\StatisticsOpens; use MailPoet\Models\StatisticsOpens;
use MailPoet\Models\StatisticsClicks; use MailPoet\Models\StatisticsClicks;
use MailPoet\Models\StatisticsUnsubscribes; use MailPoet\Models\StatisticsUnsubscribes;
use MailPoet\Util\Security;
class NewsletterTest extends MailPoetTest { class NewsletterTest extends MailPoetTest {
function _before() { function _before() {
@@ -358,21 +359,21 @@ class NewsletterTest extends MailPoetTest {
function testItGeneratesHashOnNewsletterSave() { function testItGeneratesHashOnNewsletterSave() {
expect(strlen($this->newsletter->hash)) expect(strlen($this->newsletter->hash))
->equals(Newsletter::NEWSLETTER_HASH_LENGTH); ->equals(Security::HASH_LENGTH);
} }
function testItRegeneratesHashOnNewsletterDuplication() { function testItRegeneratesHashOnNewsletterDuplication() {
$duplicate_newsletter = $this->newsletter->duplicate(); $duplicate_newsletter = $this->newsletter->duplicate();
expect($duplicate_newsletter->hash)->notEquals($this->newsletter->hash); expect($duplicate_newsletter->hash)->notEquals($this->newsletter->hash);
expect(strlen($duplicate_newsletter->hash)) expect(strlen($duplicate_newsletter->hash))
->equals(Newsletter::NEWSLETTER_HASH_LENGTH); ->equals(Security::HASH_LENGTH);
} }
function testItRegeneratesHashOnNotificationHistoryCreation() { function testItRegeneratesHashOnNotificationHistoryCreation() {
$notification_history = $this->newsletter->createNotificationHistory(); $notification_history = $this->newsletter->createNotificationHistory();
expect($notification_history->hash)->notEquals($this->newsletter->hash); expect($notification_history->hash)->notEquals($this->newsletter->hash);
expect(strlen($notification_history->hash)) expect(strlen($notification_history->hash))
->equals(Newsletter::NEWSLETTER_HASH_LENGTH); ->equals(Security::HASH_LENGTH);
} }
function testItGetsQueueFromNewsletter() { function testItGetsQueueFromNewsletter() {

View File

@@ -29,4 +29,15 @@ class SecurityTest extends MailPoetTest {
expect(ctype_alnum($short_hash))->true(); expect(ctype_alnum($short_hash))->true();
expect(ctype_alnum($long_hash))->true(); expect(ctype_alnum($long_hash))->true();
} }
function testItGeneratesRandomHash() {
$hash_1 = Security::generateHash();
$hash_2 = Security::generateHash();
expect($hash_1)->notEquals($hash_2);
expect(strlen($hash_1))->equals(Security::HASH_LENGTH);
}
function testItGeneratesRandomHashWithCustomLength() {
expect(strlen(Security::generateHash(10)))->equals(10);
}
} }