<?php
|
namespace JVBase\managers;
|
|
use WP_User;
|
use WP_Error;
|
|
if (!defined('ABSPATH')) {
|
exit; // Exit if accessed directly
|
}
|
/**
|
* Cloudflare Turnstile Integration for WordPress
|
*
|
* Adds Turnstile protection to login and registration forms
|
*/
|
|
class CloudflareTurnstile
|
{
|
|
private string $site_key;
|
private string $secret_key;
|
|
/**
|
* Constructor
|
*/
|
public function __construct()
|
{
|
return;
|
// Set your Cloudflare Turnstile keys here
|
|
// $this->site_key = JVB_CLOUDFLARE_SITE_KEY;
|
// $this->secret_key = JVB_CLOUDFLARE_SECRET_KEY;
|
|
// Add hooks for login and registration forms
|
add_action('login_enqueue_scripts', [$this, 'enqueueTurnstileScripts']);
|
add_action('login_form', [$this, 'addTurnstileToLogin']);
|
add_action('register_form', [$this, 'addTurnstileToRegister']);
|
|
// Add verification hooks
|
add_filter('authenticate', [$this, 'verifyLoginTurnstile'], 99, 3);
|
add_filter('registration_errors', [$this, 'verifyRegisterTurnstile'], 10, 3);
|
|
// Add hook for lost password form
|
add_action('lostpassword_form', [$this, 'addTurnstileToLogin']);
|
add_action('lostpassword_post', [$this, 'verifyLostpasswordTurnstile']);
|
}
|
|
/**
|
* Enqueue Turnstile script
|
* @return void
|
*/
|
public function enqueueTurnstileScripts():void
|
{
|
wp_enqueue_script(
|
'cloudflare-turnstile',
|
'https://challenges.cloudflare.com/turnstile/v0/api.js',
|
[],
|
null,
|
true
|
);
|
// Add this line to set the async and defer attributes
|
wp_script_add_data('cloudflare-turnstile', 'async', true);
|
wp_script_add_data('cloudflare-turnstile', 'defer', true);
|
}
|
|
/**
|
* Add Turnstile to login form
|
* @return void
|
*/
|
public function addTurnstileToLogin():void
|
{
|
echo '<div class="cf-turnstile-wrapper" style="margin: 1em 0;">';
|
echo '<div class="cf-turnstile" data-sitekey="' . esc_attr($this->site_key) . '" data-theme="light"></div>';
|
echo '</div>';
|
}
|
|
/**
|
* Add Turnstile to registration form
|
* @return void
|
*/
|
public function addTurnstileToRegister():void
|
{
|
echo '<div class="cf-turnstile-wrapper" style="margin: 1em 0;">';
|
echo '<div class="cf-turnstile" data-sitekey="' . esc_attr($this->site_key) . '" data-theme="light"></div>';
|
echo '<style>.register .cf-turnstile-wrapper { clear: both; }</style>';
|
echo '</div>';
|
}
|
|
/**
|
* Verify Turnstile token
|
* @param $token
|
*
|
* @return bool
|
*/
|
public function verifyTurnstile($token = null):bool
|
{
|
// If no token is provided, try to get it from the request
|
if (!$token && isset($_POST['cf-turnstile-response'])) {
|
$token = $_POST['cf-turnstile-response'];
|
}
|
|
// If still no token, verification fails
|
if (!$token) {
|
return false;
|
}
|
|
$data = [
|
'secret' => $this->secret_key,
|
'response' => $token,
|
'remoteip' => $_SERVER['REMOTE_ADDR']
|
];
|
|
$url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
|
$response = wp_remote_post($url, [
|
'body' => $data,
|
'timeout' => 30
|
]);
|
|
|
|
if (is_wp_error($response)) {
|
return false;
|
}
|
|
$body = wp_remote_retrieve_body($response);
|
$result = json_decode($body, true);
|
|
return isset($result['success']) && $result['success'] === true;
|
}
|
|
/**
|
* Verify login form
|
* @param null|WP_User|WP_Error $user
|
* @param string $username
|
* @param string $password
|
*
|
* @return WP_Error|WP_User
|
*/
|
public function verifyLoginTurnstile(null|WP_User|WP_Error $user, string $username, string $password):WP_Error|WP_User
|
{
|
global $_POST;
|
// Skip verification if already logged in or if no username/password
|
if (is_user_logged_in() || empty($username) || empty($password)) {
|
return $user;
|
}
|
|
// Skip on AJAX requests (for better compatibility with other plugins)
|
if (wp_doing_ajax()) {
|
return $user;
|
}
|
|
// If already have an error, just return it
|
if (is_wp_error($user)) {
|
return $user;
|
}
|
|
// Check Turnstile
|
if (!$this->verifyTurnstile()) {
|
return new WP_Error('turnstile_verification_failed', '<strong>ERROR</strong>: Please complete the security check.');
|
}
|
|
return $user;
|
}
|
|
/**
|
* Verify registration form
|
* @param WP_Error $errors
|
* @param string $sanitized_user_login
|
* @param string $user_email
|
*
|
* @return WP_Error
|
*/
|
public function verifyRegisterTurnstile(WP_Error $errors, string $sanitized_user_login, string $user_email):WP_Error
|
{
|
// Skip on AJAX requests (for better compatibility with other plugins)
|
if (wp_doing_ajax()) {
|
return $errors;
|
}
|
|
// Check Turnstile
|
if (!$this->verifyTurnstile()) {
|
$errors->add('turnstile_verification_failed', '<strong>ERROR</strong>: Please complete the security check.');
|
}
|
|
return $errors;
|
}
|
|
/**
|
* Verify lost password form
|
* @param WP_Error $errors
|
*
|
* @return WP_Error
|
*/
|
public function verifyLostpasswordTurnstile(WP_Error $errors):WP_Error
|
{
|
// Skip on AJAX requests (for better compatibility with other plugins)
|
if (wp_doing_ajax()) {
|
return $errors;
|
}
|
|
// Check if the form was submitted
|
if (!isset($_POST['user_login']) || empty($_POST['user_login'])) {
|
return $errors ;
|
}
|
|
// Check Turnstile
|
if (!$this->verifyTurnstile()) {
|
$redirect_to = isset($_POST['redirect_to']) ? $_POST['redirect_to'] : '';
|
$errors = new WP_Error('turnstile_verification_failed', '<strong>ERROR</strong>: Please complete the security check.');
|
|
// WP's lost password form handling
|
wp_die($errors->get_error_message(), __('Security Check Failed', 'edmonton-ink'), [
|
'response' => 403,
|
'back_link' => wp_lostpassword_url($redirect_to)
|
]);
|
}
|
return $errors;
|
}
|
}
|