Skip to content
This repository has been archived by the owner on Mar 3, 2022. It is now read-only.

pull email disposablity checking out of the signatures_queue #105

Open
wants to merge 2 commits into
base: 7.x-3.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions modules/custom/disposable_email/disposable_email.info
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name = Disposable Email
description = Provides functionality for checking the disposability of a given email address against a list of known domains.
core = 7.x

dependencies[] = libraries
30 changes: 30 additions & 0 deletions modules/custom/disposable_email/disposable_email.install
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/**
* Implements hook_requirements().
*
* Verify the disposable_email_checker library is available.
*/

function disposable_email_requirements($phase) {
$requirements = array();
// Ensure translations do not break at install time
$t = get_t();

$requirements['disposable_email_checker'] = array(
'title' => $t('Disposable Email Checker'),
);

$libraries = libraries_get_libraries();
if (isset($libraries['disposable_email_checker'])) {
$requirements['disposable_email_checker']['value'] = $t('Installed');
$requirements['disposable_email_checker']['severity'] = REQUIREMENT_OK;
}
else {
$requirements['disposable_email_checker']['value'] = $t('Not Installed');
$requirements['disposable_email_checker']['severity'] = REQUIREMENT_ERROR;
$requirements['disposable_email_checker']['description'] = $t('Please install the disposable_email_checker library %url.', array('%url' => 'https://github.com/vboctor/disposable_email_checker.git'));
}

return $requirements;
}
91 changes: 91 additions & 0 deletions modules/custom/disposable_email/disposable_email.module
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php
/**
* Determines whether a given email address is disposable or not.
*
* @param string $address
* An email address to test.
*
* @return bool
* TRUE if the email address is disposable, or FALSE if not.
*/
function disposable_email_is_disposable_email($address) {
libraries_load('disposable_email_checker');
return DisposableEmailChecker::is_disposable_email($address);
}

/**
* Determines disposability of a given email address.
*
* @param string $address
* An email address to test.
*
* @return object
* Object containing boolean values of various disposable classifications.
*/
function disposable_email_get_email_disposability($address) {
libraries_load('disposable_email_checker');
$disposability = new stdClass();
$disposability->is_disposable = DisposableEmailChecker::is_disposable_email($address);
$disposability->is_free_email = DisposableEmailChecker::is_free_email($address);
$disposability->is_open_email = DisposableEmailChecker::is_open_email($address);
$disposability->is_forwarding_email = DisposableEmailChecker::is_forwarding_email($address);
$disposability->is_trash_email = DisposableEmailChecker::is_trash_email($address);
$disposability->is_time_bound_email = DisposableEmailChecker::is_time_bound_email($address);
$disposability->is_shredder_email = DisposableEmailChecker::is_shredder_email($address);
return $disposability;
}

/**
* Determines whether a given email address is subaddressed or not.
*
* Subaddressed email addresses, also known as plus addresses or tagged
* addresses, have the form [email protected].
*
* @param string $address
* An email address to test.
*
* @return bool
* TRUE if the email address is subaddressed, or FALSE if not.
*
* @see https://en.wikipedia.org/wiki/Email_address#Address_tags
*/
function disposable_email_is_subaddressed_email($address) {
// A subaddressed email address must contain a username and a plus sign. Match
// any string that begins with one or more characters other than an at sign
// (@), followed by a plus sign (+).
return (preg_match('/^[^@]+\+/', $address) == 1);
}

/**
* Parses an email address to remove subaddressing and dots in mailbox.
*
* Subaddressed email addresses, also known as plus addresses or tagged
* addresses, have the form [email protected].
*
* @param string $address
* An email address to test.
*
* @return string
* Email address without subaddressing or dots in mailbox.
*
* @see https://en.wikipedia.org/wiki/Email_address#Address_tags
*/
function disposable_email_unsubaddress_email($address) {
$address = strtolower($address);
$domain_pos = strpos($address, '@');

// If no @ sign, assume domain was passed in and return as is.
if ($domain_pos !== FALSE) {
$domain = substr($address, $domain_pos + 1);
$mailbox = substr($address, 0, $domain_pos);
$mailbox = str_replace('.', '', $mailbox);

// Filter out subaddressing.
if (disposable_email_is_subaddressed_email($address)) {
$tag_pos = strpos($mailbox, '+');
$mailbox = substr($mailbox, 0, $tag_pos);
}
$address = $mailbox . '@' . $domain;
}
return $address;
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,14 @@ function _signatures_queue_process_signatures($job_id, $server_name, $worker_nam
// Increment signature count.
PetitionsController::incrementSignatureCount($item['petition_id']);

$disposability = signatures_queue_get_email_disposability($item['email']);
$disposability = disposable_email_get_email_disposability($item['email']);
$disposability->is_free_email ? PetitionsController::incrementPetitionMetricCount($item['petition_id'], PetitionItem::PETITION_SIGNATURE_COUNT_FREE_EMAILS) : NULL;
$disposability->is_open_email ? PetitionsController::incrementPetitionMetricCount($item['petition_id'], PetitionItem::PETITION_SIGNATURE_COUNT_OPEN_EMAILS) : NULL;
$disposability->is_forwarding_email ? PetitionsController::incrementPetitionMetricCount($item['petition_id'], PetitionItem::PETITION_SIGNATURE_COUNT_FORWARDED_EMAILS) : NULL;
$disposability->is_trash_email ? PetitionsController::incrementPetitionMetricCount($item['petition_id'], PetitionItem::PETITION_SIGNATURE_COUNT_TRASH_EMAILS) : NULL;
$disposability->is_time_bound_email ? PetitionsController::incrementPetitionMetricCount($item['petition_id'], PetitionItem::PETITION_SIGNATURE_COUNT_TIMEBOUND_EMAILS) : NULL;
$disposability->is_shredder_email ? PetitionsController::incrementPetitionMetricCount($item['petition_id'], PetitionItem::PETITION_SIGNATURE_COUNT_SHRED_EMAILS) : NULL;
signatures_queue_is_subaddressed_email($item['email']) ? PetitionsController::incrementPetitionMetricCount($item['petition_id'], PetitionItem::PETITION_SIGNATURE_COUNT_SUBADDRESSED_EMAILS) : NULL;
disposable_email_is_subaddressed_email($item['email']) ? PetitionsController::incrementPetitionMetricCount($item['petition_id'], PetitionItem::PETITION_SIGNATURE_COUNT_SUBADDRESSED_EMAILS) : NULL;
// PT-1721 performs unique email / ip count updates inside of _signatures_queue_process_signatures_save_signature().
_signatures_queue_process_signatures_compare_thresholds($item['petition_id']);

Expand Down Expand Up @@ -587,7 +587,7 @@ function _signatures_queue_process_signatures_save_signature(array $item, $user,
$signature = SignaturesController::save($signature);

// Store metrics for fraud reporting.
$email = signatures_queue_unsubaddress_email($item['email']);
$email = disposable_email_unsubaddress_email($item['email']);
petition_add_signature_email($item['petition_id'], $email);
petition_add_signature_ip($item['petition_id'], $item['client_ip']);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ function _signatures_queue_enqueue_item(array $item) {
* _signatures_queue_build_new_queue_item().
*/
function _signatures_queue_log_signatory_details($api_key, $petition_id, array $signature) {
$is_disposable = signatures_queue_is_disposable_email($signature['email']) ? 'true' : 'false';
$is_subaddressed = signatures_queue_is_subaddressed_email($signature['email']) ? 'true' : 'false';
$is_disposable = disposable_email_is_disposable_email($signature['email']) ? 'true' : 'false';
$is_subaddressed = disposable_email_is_subaddressed_email($signature['email']) ? 'true' : 'false';

// Log in aggregate, per API key, and per petition ID metrics.
$metric_prefixes = array(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -454,96 +454,6 @@ function signatures_queue_invoke_workflow($workflow, array $options = array()) {
return $status;
}

/**
* Determines whether a given email address is disposable or not.
*
* @param string $address
* An email address to test.
*
* @return bool
* TRUE if the email address is disposable, or FALSE if not.
*/
function signatures_queue_is_disposable_email($address) {
libraries_load('disposable_email_checker');
return DisposableEmailChecker::is_disposable_email($address);
}

/**
* Determines disposability of a given email address.
*
* @param string $address
* An email address to test.
*
* @return object
* Object containing boolean values of various disposable classifications.
*/
function signatures_queue_get_email_disposability($address) {
libraries_load('disposable_email_checker');
$disposability = new stdClass();
$disposability->is_disposable = DisposableEmailChecker::is_disposable_email($address);
$disposability->is_free_email = DisposableEmailChecker::is_free_email($address);
$disposability->is_open_email = DisposableEmailChecker::is_open_email($address);
$disposability->is_forwarding_email = DisposableEmailChecker::is_forwarding_email($address);
$disposability->is_trash_email = DisposableEmailChecker::is_trash_email($address);
$disposability->is_time_bound_email = DisposableEmailChecker::is_time_bound_email($address);
$disposability->is_shredder_email = DisposableEmailChecker::is_shredder_email($address);
return $disposability;
}

/**
* Determines whether a given email address is subaddressed or not.
*
* Subaddressed email addresses, also known as plus addresses or tagged
* addresses, have the form [email protected].
*
* @param string $address
* An email address to test.
*
* @return bool
* TRUE if the email address is subaddressed, or FALSE if not.
*
* @see https://en.wikipedia.org/wiki/Email_address#Address_tags
*/
function signatures_queue_is_subaddressed_email($address) {
// A subaddressed email address must contain a username and a plus sign. Match
// any string that begins with one or more characters other than an at sign
// (@), followed by a plus sign (+).
return (preg_match('/^[^@]+\+/', $address) == 1);
}

/**
* Parses an email address to remove subaddressing and dots in mailbox.
*
* Subaddressed email addresses, also known as plus addresses or tagged
* addresses, have the form [email protected].
*
* @param string $address
* An email address to test.
*
* @return string
* Email address without subaddressing or dots in mailbox.
*
* @see https://en.wikipedia.org/wiki/Email_address#Address_tags
*/
function signatures_queue_unsubaddress_email($address) {
$address = strtolower($address);
$domain_pos = strpos($address, '@');

// If no @ sign, assume domain was passed in and return as is.
if ($domain_pos !== FALSE) {
$domain = substr($address, $domain_pos + 1);
$mailbox = substr($address, 0, $domain_pos);
$mailbox = str_replace('.', '', $mailbox);
// Filter out subaddressing.
if (signatures_queue_is_subaddressed_email($address)) {
$tag_pos = strpos($mailbox, '+');
$mailbox = substr($mailbox, 0, $tag_pos);
}
$address = $mailbox . '@' . $domain;
}
return $address;
}

/**
* Gets a status string usable for logging from a workflow status return value.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function providerSignaturesQueueGetDomainFromEmail() {
*/
public function testSignaturesQueueIsSubaddressedEmail($expected, $address) {
$message = ($expected) ? 'Failed to identify a subaddressed email' : 'Falsely identified a non-subaddressed email.';
$this->assertEquals($expected, signatures_queue_is_subaddressed_email($address), $message);
$this->assertEquals($expected, disposable_email_is_subaddressed_email($address), $message);
}

/**
Expand Down Expand Up @@ -86,7 +86,7 @@ public function providerSignaturesQueueIsSubaddressedEmail() {
* @dataProvider providerSignaturesQueueUnsubaddressEmail
*/
public function testSignaturesQueueUnsubaddressEmail($address, $expected) {
$this->assertEquals($expected, signatures_queue_unsubaddress_email($address));
$this->assertEquals($expected, disposable_email_unsubaddress_email($address));
}
/**
* Data provider for testSignaturesQueueUnsubaddressEmail().
Expand Down
6 changes: 3 additions & 3 deletions modules/custom/signature_mail/signature_mail.module
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ function signature_mail_entity_delete($entity, $type) {
->execute()
->fetchField();

$disposability = signatures_queue_get_email_disposability($signature_email);
$disposability = disposable_email_get_email_disposability($signature_email);
$disposability->is_free_email ? PetitionsController::incrementPetitionMetricCount($petition_id, PetitionItem::PETITION_SIGNATURE_COUNT_FREE_EMAILS, TRUE) : NULL;
$disposability->is_open_email ? PetitionsController::incrementPetitionMetricCount($petition_id, PetitionItem::PETITION_SIGNATURE_COUNT_OPEN_EMAILS, TRUE) : NULL;
$disposability->is_forwarding_email ? PetitionsController::incrementPetitionMetricCount($petition_id, PetitionItem::PETITION_SIGNATURE_COUNT_FORWARDED_EMAILS, TRUE) : NULL;
$disposability->is_trash_email ? PetitionsController::incrementPetitionMetricCount($petition_id, PetitionItem::PETITION_SIGNATURE_COUNT_TRASH_EMAILS, TRUE) : NULL;
$disposability->is_time_bound_email ? PetitionsController::incrementPetitionMetricCount($petition_id, PetitionItem::PETITION_SIGNATURE_COUNT_TIMEBOUND_EMAILS, TRUE) : NULL;
$disposability->is_shredder_email ? PetitionsController::incrementPetitionMetricCount($petition_id, PetitionItem::PETITION_SIGNATURE_COUNT_SHRED_EMAILS, TRUE) : NULL;
signatures_queue_is_subaddressed_email($signature_email) ? PetitionsController::incrementPetitionMetricCount($petition_id, PetitionItem::PETITION_SIGNATURE_COUNT_SUBADDRESSED_EMAILS, TRUE) : NULL;
disposable_email_is_subaddressed_email($signature_email) ? PetitionsController::incrementPetitionMetricCount($petition_id, PetitionItem::PETITION_SIGNATURE_COUNT_SUBADDRESSED_EMAILS, TRUE) : NULL;

$email = signatures_queue_unsubaddress_email($signature_email);
$email = disposable_email_unsubaddress_email($signature_email);
petition_remove_signature_email($petition_id, $email);
petition_remove_signature_ip($petition_id, $entity->ip_address);
petition_update_total_unique_ips_and_emails($petition_id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ function signature_mail_fraud_data_form_views_exposed_form_alter(&$form, &$form_
* IP Address (v4 or v6 format)
*/
function signature_mail_fraud_data_update_data($signature_mail_id, $petition_id, $email, $ip_address) {
$disposability = signatures_queue_get_email_disposability($email);
$unsub_email = signatures_queue_unsubaddress_email($email);
$disposability = disposable_email_get_email_disposability($email);
$unsub_email = disposable_email_unsubaddress_email($email);
$ip_address_binary = 0;
if (!empty($ip_address) && strlen($ip_address) > 7) {
$ip_address_binary = inet_pton($ip_address);
Expand Down