Add captcha page [MAILPOET-2015]

This commit is contained in:
wxa
2019-07-03 13:49:55 +03:00
committed by M. Shull
parent f8ea514887
commit 08af443c1f
9 changed files with 148 additions and 6 deletions

View File

@ -44,6 +44,15 @@
margin: 0 7px;
}
.mailpoet_captcha_form {
.mailpoet_validate_success { color: #468847; }
.mailpoet_validate_error { color: #b94a48; }
}
.mailpoet_captcha_update {
cursor: pointer;
}
@keyframes mailpoet-bouncedelay {
0%,
80%,

View File

@ -175,6 +175,7 @@ class Populator {
'unsubscribe' => $mailpoet_page_id,
'manage' => $mailpoet_page_id,
'confirmation' => $mailpoet_page_id,
'captcha' => $mailpoet_page_id,
]);
}
}

View File

@ -111,6 +111,8 @@ abstract class Base {
protected static function getFieldName($block = []) {
if ((int)$block['id'] > 0) {
return 'cf_' . $block['id'];
} elseif (isset($block['params']['obfuscate']) && !$block['params']['obfuscate']) {
return $block['id'];
} else {
$obfuscator = new FieldNameObfuscator();
return $obfuscator->obfuscate($block['id']);//obfuscate field name for spambots

View File

@ -2,6 +2,7 @@
namespace MailPoet\Form;
use MailPoet\Settings\SettingsController;
use MailPoet\Subscription\Captcha;
use MailPoet\WP\Functions as WPFunctions;
@ -50,8 +51,8 @@ class Renderer {
'<label class="mailpoet_hp_email_label">' . WPFunctions::get()->__('Please leave this field empty', 'mailpoet') . '<input type="email" name="data[email]"></label>' :
'';
foreach ($blocks as $key => $block) {
if ($block['type'] == 'submit' && $settings->get('re_captcha.enabled')) {
$site_key = $settings->get('re_captcha.site_token');
if ($block['type'] == 'submit' && $settings->get('captcha.type') === Captcha::TYPE_RECAPTCHA) {
$site_key = $settings->get('captcha.recaptcha_site_token');
$html .= '<div class="mailpoet_recaptcha" data-sitekey="' . $site_key . '">
<div class="mailpoet_recaptcha_container"></div>
<noscript>

View File

@ -8,6 +8,7 @@ use MailPoet\Config\Renderer as ConfigRenderer;
use MailPoet\Form\Renderer as FormRenderer;
use MailPoet\Models\Form;
use MailPoet\Settings\SettingsController;
use MailPoet\Subscription\Captcha;
use MailPoet\Util\Security;
use MailPoet\WP\Functions as WPFunctions;
@ -117,8 +118,8 @@ class Widget extends \WP_Widget {
true
);
$captcha = $this->settings->get('re_captcha');
if (!empty($captcha['enabled'])) {
$captcha = $this->settings->get('captcha');
if (!empty($captcha['type']) && $captcha['type'] === Captcha::TYPE_RECAPTCHA) {
WPFunctions::get()->wpEnqueueScript(
'mailpoet_recaptcha',
self::RECAPTCHA_API_URL,

View File

@ -9,10 +9,14 @@ if (!defined('ABSPATH')) exit;
class Subscription {
const ENDPOINT = 'subscription';
const ACTION_CAPTCHA = 'captcha';
const ACTION_CAPTCHA_IMAGE = 'captchaImage';
const ACTION_CONFIRM = 'confirm';
const ACTION_MANAGE = 'manage';
const ACTION_UNSUBSCRIBE = 'unsubscribe';
public $allowed_actions = [
self::ACTION_CAPTCHA,
self::ACTION_CAPTCHA_IMAGE,
self::ACTION_CONFIRM,
self::ACTION_MANAGE,
self::ACTION_UNSUBSCRIBE,
@ -28,6 +32,17 @@ class Subscription {
$this->subscription_pages = $subscription_pages;
}
function captcha($data) {
$subscription = $this->initSubscriptionPage(UserSubscription\Pages::ACTION_CAPTCHA, $data);
}
function captchaImage($data) {
$captcha = new UserSubscription\Captcha;
$width = !empty($data['width']) ? (int)$data['width'] : null;
$height = !empty($data['height']) ? (int)$data['height'] : null;
return $captcha->renderImage($width, $height);
}
function confirm($data) {
$subscription = $this->initSubscriptionPage(UserSubscription\Pages::ACTION_CONFIRM, $data);
$subscription->confirm();

View File

@ -2,12 +2,42 @@
namespace MailPoet\Subscription;
use MailPoetVendor\Gregwar\Captcha\CaptchaBuilder;
class Captcha {
const TYPE_BUILTIN = 'built-in';
const TYPE_RECAPTCHA = 'recaptcha';
const TYPE_DISABLED = null;
const SESSION_KEY = 'mailpoet_captcha';
const SESSION_FORM_KEY = 'mailpoet_captcha_form';
function isSupported() {
return extension_loaded('gd') && function_exists('imagettftext');
}
function renderImage($width = null, $height = null) {
if (!$this->isSupported()) {
return false;
}
$font_numbers = array_merge(range(0, 3), [5]); // skip font #4
$font_number = $font_numbers[mt_rand(0, count($font_numbers) - 1)];
$reflector = new \ReflectionClass(CaptchaBuilder::class);
$captcha_directory = dirname($reflector->getFileName());
$font = $captcha_directory . '/Font/captcha' . $font_number . '.ttf';
$builder = CaptchaBuilder::create()
->setBackgroundColor(255, 255, 255)
->setTextColor(1, 1, 1)
->setMaxBehindLines(0)
->build($width ?: 220, $height ?: 60, $font);
$_SESSION[self::SESSION_KEY] = $builder->getPhrase();
header('Content-Type: image/jpeg');
$builder->output();
exit;
}
}

View File

@ -17,6 +17,7 @@ use MailPoet\WP\Functions as WPFunctions;
class Pages {
const DEMO_EMAIL = 'demo@mailpoet.com';
const ACTION_CAPTCHA = 'captcha';
const ACTION_CONFIRM = 'confirm';
const ACTION_MANAGE = 'manage';
const ACTION_UNSUBSCRIBE = 'unsubscribe';
@ -159,6 +160,9 @@ class Pages {
} else {
// when it's our own page, generate page title based on requested action
switch ($this->action) {
case self::ACTION_CAPTCHA:
return $this->getCaptchaTitle();
case self::ACTION_CONFIRM:
return $this->getConfirmTitle();
@ -183,6 +187,9 @@ class Pages {
$content = '';
switch ($this->action) {
case self::ACTION_CAPTCHA:
$content = $this->getCaptchaContent();
break;
case self::ACTION_CONFIRM:
$content = $this->getConfirmContent();
break;
@ -217,6 +224,10 @@ class Pages {
return $meta;
}
private function getCaptchaTitle() {
return WPFunctions::get()->__("Confirm youre not a robot", 'mailpoet');
}
private function getConfirmTitle() {
if ($this->isPreview()) {
$title = sprintf(
@ -252,6 +263,65 @@ class Pages {
}
}
private function getCaptchaContent() {
$fields = [
[
'id' => 'captcha',
'type' => 'text',
'params' => [
'label' => WPFunctions::get()->__('Type in the input the characters you see in the picture above:', 'mailpoet'),
'value' => '',
'obfuscate' => false,
],
],
];
$form = array_merge(
$fields,
[
[
'id' => 'submit',
'type' => 'submit',
'params' => [
'label' => WPFunctions::get()->__('Subscribe', 'mailpoet'),
],
],
]
);
$form_id = isset($_SESSION[Captcha::SESSION_FORM_KEY]['form_id']) ? (int)$_SESSION[Captcha::SESSION_FORM_KEY]['form_id'] : 0;
$form_html = '<form method="POST" ' .
'action="' . admin_url('admin-post.php?action=mailpoet_subscription_form') . '" ' .
'class="mailpoet_form mailpoet_captcha_form" ' .
'novalidate>';
$form_html .= '<input type="hidden" name="data[form_id]" value="' . $form_id . '" />';
$form_html .= '<input type="hidden" name="api_version" value="v1" />';
$form_html .= '<input type="hidden" name="endpoint" value="subscribers" />';
$form_html .= '<input type="hidden" name="mailpoet_method" value="subscribe" />';
$form_html .= '<input type="hidden" name="mailpoet_redirect" ' .
'value="' . htmlspecialchars($this->url_helper->getCurrentUrl(), ENT_QUOTES) . '" />';
$width = 220;
$height = 60;
$captcha_url = Url::getCaptchaImageUrl($width, $height);
$form_html .= '<div class="mailpoet_form_hide_on_success">';
$form_html .= '<p class="mailpoet_paragraph">';
$form_html .= '<img class="mailpoet_captcha mailpoet_captcha_update" src="' . $captcha_url . '" width="' . $width . '" height="' . $height . '" title="' . WPFunctions::get()->__('Click to refresh the captcha', 'mailpoet') . '" />';
$form_html .= '</p>';
// subscription form
$form_html .= FormRenderer::renderBlocks($form, $honeypot = false);
$form_html .= '</div>';
$form_html .= '<div class="mailpoet_message">';
$form_html .= '<p class="mailpoet_validate_success" style="display:none;">Check your inbox or spam folder to confirm your subscription.</p>';
$form_html .= '<p class="mailpoet_validate_error" style="display:none;"></p>';
$form_html .= '</div>';
$form_html .= '</form>';
return $form_html;
}
private function getConfirmContent() {
if ($this->isPreview() || $this->subscriber !== false) {
return $this->wp->__("Yup, we've added you to our email list. You'll hear from us shortly.", 'mailpoet');

View File

@ -8,6 +8,16 @@ use MailPoet\Settings\SettingsController;
use MailPoet\WP\Functions as WPFunctions;
class Url {
static function getCaptchaUrl(Subscriber $subscriber = null) {
$post = WPFunctions::get()->getPost(self::getSetting('subscription.pages.captcha'));
return self::getSubscriptionUrl($post, 'captcha', $subscriber);
}
static function getCaptchaImageUrl($width, $height) {
$post = WPFunctions::get()->getPost(self::getSetting('subscription.pages.captcha'));
return self::getSubscriptionUrl($post, 'captchaImage', null, ['width' => $width, 'height' => $height]);
}
static function getConfirmationUrl(Subscriber $subscriber = null) {
$post = WPFunctions::get()->getPost(self::getSetting('subscription.pages.confirmation'));
return self::getSubscriptionUrl($post, 'confirm', $subscriber);
@ -24,7 +34,10 @@ class Url {
}
static function getSubscriptionUrl(
$post = null, $action = null, Subscriber $subscriber = null
$post = null,
$action = null,
Subscriber $subscriber = null,
$data = null
) {
if ($post === null || $action === null) return;
@ -35,7 +48,7 @@ class Url {
'token' => Subscriber::generateToken($subscriber->email),
'email' => $subscriber->email,
];
} else {
} elseif (is_null($data)) {
$data = [
'preview' => 1,
];