forked from LiveCarta/LiveCartaWP
Changed source root directory
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
$opts = $opts ?? [];
|
||||
$opts = true === is_array($opts) ?
|
||||
$opts :
|
||||
[];
|
||||
|
||||
$site_key = $opts['site_key'] ?? '';
|
||||
$secret_key = $opts['secret_key'] ?? '';
|
||||
$enabled = $opts['enabled'] ?? '0';
|
||||
$display_for_authorized = $opts['display_for_authorized'] ?? '0';
|
||||
$theme = $opts['theme'] ?? '';
|
||||
$type = $opts['type'] ?? '';
|
||||
|
||||
$theme_options = [
|
||||
'light' => esc_html__('Light', 'mailchimp-for-wp'),
|
||||
'dark' => esc_html__('Dark', 'mailchimp-for-wp'),
|
||||
];
|
||||
$type_options = [
|
||||
'frictionless' => esc_html__('Frictionless', 'mailchimp-for-wp'),
|
||||
'pow' => esc_html__('Proof of Work', 'mailchimp-for-wp'),
|
||||
'image' => esc_html__('Image Captcha', 'mailchimp-for-wp'),
|
||||
];
|
||||
|
||||
?>
|
||||
|
||||
<?php
|
||||
if ('1' === $enabled) {
|
||||
?>
|
||||
<p>
|
||||
<?php echo esc_html__('Preview: if the credentials are valid, you should be able to complete the captcha below:', 'mailchimp-for-wp'); ?>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
$procaptcha_api = MC4WP_Procaptcha::get_instance();
|
||||
echo $procaptcha_api->print_captcha_element(true, true);
|
||||
?>
|
||||
|
||||
<input class="prosopo-procaptcha__enabled-setting" type="hidden" name="mc4wp_integrations[prosopo-procaptcha][enabled]" value="<?php echo esc_attr($enabled); ?>">
|
||||
|
||||
<table class="form-table">
|
||||
<tbody>
|
||||
<tr valign="top">
|
||||
<th scope="row"><?php echo esc_html__('Site Key', 'mailchimp-for-wp'); ?></th>
|
||||
<td class="nowrap integration-toggles-wrap">
|
||||
<label>
|
||||
<input class="widefat prosopo-procaptcha__site-key" type="text" name="mc4wp_integrations[prosopo-procaptcha][site_key]"
|
||||
placeholder="<?php echo esc_attr__('Enter your site key', 'mailchimp-for-wp'); ?>"
|
||||
value="<?php echo esc_attr($site_key); ?>">
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php
|
||||
echo
|
||||
sprintf(
|
||||
// translators: %1$s: opening anchor tag, %2$s: closing anchor tag
|
||||
esc_html__('The API key for connecting with your Procaptcha account. %1$s Get your Site key here %2$s', 'mailchimp-for-wp'),
|
||||
'<a href="https://portal.prosopo.io/" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<th scope="row"><?php echo esc_html__('Secret Key', 'mailchimp-for-wp'); ?></th>
|
||||
<td class="nowrap integration-toggles-wrap">
|
||||
<label>
|
||||
<input class="widefat prosopo-procaptcha__secret-key" type="password" name="mc4wp_integrations[prosopo-procaptcha][secret_key]"
|
||||
placeholder="<?php echo esc_attr__('Enter your secret key', 'mailchimp-for-wp'); ?>"
|
||||
value="<?php echo esc_attr($secret_key); ?>">
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<th scope="row"><?php echo esc_html__('Theme', 'mailchimp-for-wp'); ?></th>
|
||||
<td class="nowrap integration-toggles-wrap">
|
||||
<label>
|
||||
<select name="mc4wp_integrations[prosopo-procaptcha][theme]" style="width:250px;">
|
||||
<?php
|
||||
foreach ($theme_options as $value => $label) {
|
||||
$selected = $theme === $value ? ' selected' : '';
|
||||
printf('<option value="%s"%s>%s</option>', esc_attr($value), esc_attr($selected), esc_html($label));
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<th scope="row"><?php echo esc_html__('Type', 'mailchimp-for-wp'); ?></th>
|
||||
<td class="nowrap integration-toggles-wrap">
|
||||
<label>
|
||||
<select name="mc4wp_integrations[prosopo-procaptcha][type]" style="width:250px;">
|
||||
<?php
|
||||
foreach ($type_options as $value => $label) {
|
||||
$selected = $type === $value ? ' selected' : '';
|
||||
printf('<option value="%s"%s>%s</option>', esc_attr($value), esc_attr($selected), esc_html($label));
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<th scope="row"><?php echo esc_html__('Display for authorized users', 'mailchimp-for-wp'); ?></th>
|
||||
<td class="nowrap integration-toggles-wrap">
|
||||
<label>
|
||||
<input type="radio" name="mc4wp_integrations[prosopo-procaptcha][display_for_authorized]" value="1" <?php checked($display_for_authorized, '1'); ?> />‏
|
||||
<?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?>
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="mc4wp_integrations[prosopo-procaptcha][display_for_authorized]" value="0" <?php checked($display_for_authorized, '0'); ?> />‏
|
||||
<?php echo esc_html__('No', 'mailchimp-for-wp'); ?>
|
||||
</label>
|
||||
<p class="description"><?php echo esc_html__('Select "yes" to require the captcha even from authorized users.', 'mailchimp-for-wp'); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<prosopo-procaptcha-settings></prosopo-procaptcha-settings>
|
||||
|
||||
<script type="module">
|
||||
class ProsopoProcaptchaSettings extends HTMLElement {
|
||||
connectedCallback(){
|
||||
"loading" === document.readyState ?
|
||||
document.addEventListener("DOMContentLoaded", this.setup.bind(this)) :
|
||||
this.setup()
|
||||
}
|
||||
|
||||
updateEnabledSetting(event){
|
||||
let form = event.target;
|
||||
let enabledInput = form.querySelector('.prosopo-procaptcha__enabled-setting');
|
||||
let siteKey= form.querySelector('.prosopo-procaptcha__site-key').value.trim();
|
||||
let secretKey = form.querySelector('.prosopo-procaptcha__secret-key').value.trim();
|
||||
|
||||
enabledInput.value = '' !== siteKey &&
|
||||
'' !== secretKey?
|
||||
1:
|
||||
0;
|
||||
}
|
||||
|
||||
setup(){
|
||||
this.closest('form').addEventListener('submit', this.updateEnabledSetting.bind(this))
|
||||
}
|
||||
}
|
||||
customElements.define('prosopo-procaptcha-settings', ProsopoProcaptchaSettings);
|
||||
</script>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
// translators: %1$s is opening anchor tag, %2$s is closing anchor tag
|
||||
echo sprintf(
|
||||
esc_html__(
|
||||
'%1$s Procaptcha (by Prosopo) %2$s is offering seamless bot protection without compromising user data. You can customize settings and algorithms, ensuring optimal defense against all types of malicious bots.',
|
||||
'mailchimp-for-wp'
|
||||
),
|
||||
'<a href="https://prosopo.io/" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
mc4wp_register_integration('prosopo-procaptcha', 'MC4WP_Procaptcha_Integration');
|
||||
|
||||
MC4WP_Procaptcha::get_instance()->set_hooks();
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
defined('ABSPATH') or exit;
|
||||
|
||||
/**
|
||||
* Class MC4WP_Ninja_Forms_Integration
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
class MC4WP_Procaptcha_Integration extends MC4WP_Integration
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name = 'Procaptcha (by Prosopo)';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $description = 'Privacy-friendly and GDPR-compliant anti-bot protection.';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function add_hooks()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_installed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_ui_elements()
|
||||
{
|
||||
return [
|
||||
'procaptcha_site_key',
|
||||
'procaptcha_secret_key',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function get_default_options()
|
||||
{
|
||||
return [
|
||||
'enabled' => '0',
|
||||
'css' => '0',
|
||||
'site_key' => '',
|
||||
'secret_key' => '',
|
||||
'theme' => 'light',
|
||||
'type' => 'frictionless',
|
||||
'display_for_authorized' => '0',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,382 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class MC4WP_Procaptcha
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
class MC4WP_Procaptcha
|
||||
{
|
||||
private const SCRIPT_URL = 'https://js.prosopo.io/js/procaptcha.bundle.js';
|
||||
private const FORM_FIELD_NAME = 'procaptcha-response';
|
||||
private const API_URL = 'https://api.prosopo.io/siteverify';
|
||||
|
||||
/**
|
||||
* @var MC4WP_Procaptcha
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $is_in_use;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $is_enabled;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $is_displayed_for_authorized;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $site_key;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $secret_key;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $theme;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $type;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->is_in_use = false;
|
||||
$this->is_enabled = false;
|
||||
$this->is_displayed_for_authorized = false;
|
||||
$this->site_key = '';
|
||||
$this->secret_key = '';
|
||||
$this->theme = '';
|
||||
$this->type = '';
|
||||
|
||||
$this->read_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function read_settings()
|
||||
{
|
||||
$integrations = get_option('mc4wp_integrations', []);
|
||||
if (
|
||||
false === is_array($integrations) ||
|
||||
false === key_exists('prosopo-procaptcha', $integrations) ||
|
||||
false === is_array($integrations['prosopo-procaptcha'])
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = $integrations['prosopo-procaptcha'];
|
||||
|
||||
$this->is_enabled = true === key_exists('enabled', $settings) &&
|
||||
'1' === $settings['enabled'];
|
||||
$this->is_displayed_for_authorized = true === key_exists('display_for_authorized', $settings) &&
|
||||
'1' === $settings['display_for_authorized'];
|
||||
$this->site_key = true === key_exists('site_key', $settings) &&
|
||||
true === is_string($settings['site_key']) ?
|
||||
$settings['site_key'] :
|
||||
'';
|
||||
$this->secret_key = true === key_exists('secret_key', $settings) &&
|
||||
true === is_string($settings['secret_key']) ?
|
||||
$settings['secret_key'] :
|
||||
'';
|
||||
$this->theme = true === key_exists('theme', $settings) &&
|
||||
true === is_string($settings['theme']) ?
|
||||
$settings['theme'] :
|
||||
'';
|
||||
$this->type = true === key_exists('type', $settings) &&
|
||||
true === is_string($settings['type']) ?
|
||||
$settings['type'] :
|
||||
'';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MC4WP_Procaptcha
|
||||
*/
|
||||
public static function get_instance()
|
||||
{
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function print_captcha_js()
|
||||
{
|
||||
$attributes = [
|
||||
'siteKey' => $this->site_key,
|
||||
'theme' => $this->theme,
|
||||
'captchaType' => $this->type,
|
||||
];
|
||||
?>
|
||||
<script data-name="prosopo-procaptcha-element" type="module">
|
||||
let attributes = <?php echo json_encode($attributes); ?>;
|
||||
|
||||
class MC4WPProcaptcha extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.isValid = false;
|
||||
this.validationErrorElement = null;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
// wait window.load to make sure 'window.procaptcha' is available.
|
||||
"complete" !== document.readyState ?
|
||||
window.addEventListener("load", this.setup.bind(this)) :
|
||||
this.setup();
|
||||
}
|
||||
|
||||
|
||||
validatedCallback(output) {
|
||||
this.isValid = true;
|
||||
|
||||
// the element is optional.
|
||||
if (null !== this.validationErrorElement) {
|
||||
this.validationErrorElement.style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
|
||||
maybePreventSubmission(event) {
|
||||
if (true === this.isValid ||
|
||||
// the element is optional.
|
||||
null === this.validationErrorElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
this.validationErrorElement.style.visibility = 'visible';
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.validationErrorElement = this.querySelector('.mc4wp-procaptcha__validation-error')
|
||||
attributes.callback = this.validatedCallback.bind(this);
|
||||
|
||||
window.procaptcha.render(this.querySelector('.mc4wp-procaptcha__captcha'), attributes);
|
||||
this.closest('form').addEventListener('submit', this.maybePreventSubmission.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("mc4wp-procaptcha", MC4WPProcaptcha);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_human_made_request()
|
||||
{
|
||||
$token = $_POST[self::FORM_FIELD_NAME] ?? '';
|
||||
$token = true === is_string($token) ?
|
||||
$token :
|
||||
'';
|
||||
|
||||
// bail early if the token is empty.
|
||||
if ('' === $token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = wp_remote_post(
|
||||
self::API_URL,
|
||||
[
|
||||
'method' => 'POST',
|
||||
// limit waiting time to 20 seconds.
|
||||
'timeout' => 20,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'body' => (string) wp_json_encode(
|
||||
[
|
||||
'secret' => $this->secret_key,
|
||||
'token' => $token,
|
||||
]
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
// Check if request failed, either locally or remotely
|
||||
if (true === is_wp_error($response) || wp_remote_retrieve_response_code($response) >= 400) {
|
||||
/** @var MC4WP_Debug_Log */
|
||||
$logger = mc4wp('log');
|
||||
$logger->error(sprintf('ProCaptcha request error: %d %s - %s', wp_remote_retrieve_response_code($response), wp_remote_retrieve_response_message($response), wp_remote_retrieve_body($response)));
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$body = json_decode($body, true);
|
||||
$is_verified = is_array($body) && isset($body['verified']) && $body['verified'];
|
||||
|
||||
return true === $is_verified;
|
||||
}
|
||||
|
||||
public function maybe_add_type_module_attribute(string $tag, string $handle, string $src): string
|
||||
{
|
||||
if (
|
||||
'prosopo-procaptcha' !== $handle ||
|
||||
// make sure we don't make it twice if other Procaptcha integrations are present.
|
||||
false !== strpos('type="module"', $tag)
|
||||
) {
|
||||
return $tag;
|
||||
}
|
||||
|
||||
// for old WP versions.
|
||||
$tag = str_replace(' type="text/javascript"', '', $tag);
|
||||
|
||||
return str_replace(' src=', ' type="module" src=', $tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_enabled()
|
||||
{
|
||||
return $this->is_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $is_without_validation_element
|
||||
* @param bool $is_forced_render E.g. if it's a preview.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function print_captcha_element($is_without_validation_element = false, $is_forced_render = false)
|
||||
{
|
||||
if (
|
||||
false === $this->is_displayed_for_authorized &&
|
||||
true === is_user_logged_in() &&
|
||||
false === $is_forced_render
|
||||
) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$this->is_in_use = true;
|
||||
|
||||
$html = '<mc4wp-procaptcha class="mc4wp-procaptcha" style="display: block;">';
|
||||
$html .= '<div class="mc4wp-procaptcha__captcha"></div>';
|
||||
|
||||
// The element is optional, e.g. should be missing on the settings page.
|
||||
if (false === $is_without_validation_element) {
|
||||
$html .= '<p class="mc4wp-procaptcha__validation-error" style="visibility: hidden;color:red;line-height:1;font-size: 12px;padding: 7px 0 10px 10px;margin:0;">';
|
||||
$html .= esc_html__('Please verify that you are human.', 'mailchimp-for-wp');
|
||||
$html .= '</p>';
|
||||
}
|
||||
|
||||
$html .= '</mc4wp-procaptcha>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_enqueue_captcha_js()
|
||||
{
|
||||
if (false === $this->is_in_use) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do not use wp_enqueue_module() because it doesn't work on the login screens.
|
||||
wp_enqueue_script(
|
||||
'prosopo-procaptcha',
|
||||
self::SCRIPT_URL,
|
||||
[],
|
||||
null,
|
||||
[
|
||||
'in_footer' => true,
|
||||
'strategy' => 'defer',
|
||||
]
|
||||
);
|
||||
|
||||
$this->print_captcha_js();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string> $messages
|
||||
* @return array<string,string>
|
||||
*/
|
||||
public function register_error_message(array $messages)
|
||||
{
|
||||
$messages['procaptcha_required'] = 'Please verify that you are human.';
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $error_keys
|
||||
* @param MC4WP_Form $form
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function validate_form($error_keys, $form)
|
||||
{
|
||||
if (
|
||||
false === strpos($form->content, $this->get_field_stub()) ||
|
||||
(false === $this->is_displayed_for_authorized && true === is_user_logged_in()) ||
|
||||
true === $this->is_human_made_request()
|
||||
) {
|
||||
return $error_keys;
|
||||
}
|
||||
|
||||
$error_keys[] = 'procaptcha_required';
|
||||
|
||||
return $error_keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $html
|
||||
* @return string
|
||||
*/
|
||||
public function inject_captcha_element($html)
|
||||
{
|
||||
$stub = $this->get_field_stub();
|
||||
|
||||
if (false === strpos($html, $stub)) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$captcha_element = $this->print_captcha_element();
|
||||
|
||||
return str_replace($stub, $captcha_element, $html);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_field_stub()
|
||||
{
|
||||
return '<input type="hidden" name="procaptcha">';
|
||||
}
|
||||
|
||||
public function set_hooks(): void
|
||||
{
|
||||
if (false === $this->is_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter('mc4wp_form_messages', [$this, 'register_error_message']);
|
||||
add_action('mc4wp_form_content', [$this, 'inject_captcha_element']);
|
||||
add_filter('mc4wp_form_errors', [$this, 'validate_form'], 10, 2);
|
||||
|
||||
add_filter('script_loader_tag', [$this, 'maybe_add_type_module_attribute'], 10, 3);
|
||||
|
||||
$hook = true === is_admin() ?
|
||||
'admin_print_footer_scripts' :
|
||||
'wp_print_footer_scripts';
|
||||
|
||||
// priority must be less than 10, to make sure the wp_enqueue_script still has effect.
|
||||
add_action($hook, [$this, 'maybe_enqueue_captcha_js'], 9);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user