[ 'enabled' => false, 'site_key' => '', 'action' => 'checker_validate', 'hide_badge' => false ], 'turnstile' => [ 'enabled' => false, 'site_key' => '', 'theme' => 'auto', 'size' => 'normal' ] ]; // Get reCAPTCHA settings if (isset($checker['security']['recaptcha']['enabled']) && $checker['security']['recaptcha']['enabled'] === 'yes') { $config['recaptcha'] = [ 'enabled' => true, 'site_key' => $checker['security']['recaptcha']['site_key'] ?? '', 'action' => $checker['security']['recaptcha']['action'] ?? 'checker_validate', 'hide_badge' => $checker['security']['recaptcha']['hide_badge'] === 'yes' ]; } // Get Turnstile settings if (isset($checker['security']['turnstile']['enabled']) && $checker['security']['turnstile']['enabled'] === 'yes') { $config['turnstile'] = [ 'enabled' => true, 'site_key' => $checker['security']['turnstile']['site_key'] ?? '', 'theme' => $checker['security']['turnstile']['theme'] ?? 'auto', 'size' => $checker['security']['turnstile']['size'] ?? 'normal' ]; } return $config; } /** * Get CAPTCHA field HTML for form * * @param int $checker_id Checker post ID * @return string HTML for CAPTCHA fields */ public static function get_captcha_fields($checker_id) { $config = self::get_captcha_config($checker_id); // Prefer Turnstile over reCAPTCHA when both are flagged (should not happen in UI) if ($config['turnstile']['enabled']) { $config['recaptcha']['enabled'] = false; } $html = ''; if ($config['recaptcha']['enabled'] || $config['turnstile']['enabled']) { // Add container for CAPTCHA $html .= '
'; if ($config['recaptcha']['enabled']) { // reCAPTCHA v3 doesn't need visible fields $html .= ''; } if ($config['turnstile']['enabled']) { // Turnstile container will be added dynamically $html .= '
'; $html .= ''; } $html .= '
'; } return $html; } /** * Check if CAPTCHA is configured and valid * * @param int $checker_id Checker post ID * @return array Validity check result */ public static function validate_captcha_config($checker_id) { $config = self::get_captcha_config($checker_id); $result = [ 'valid' => false, 'type' => null, 'issues' => [] ]; // Check reCAPTCHA if ($config['recaptcha']['enabled']) { if (empty($config['recaptcha']['site_key'])) { $result['issues'][] = 'reCAPTCHA site key is missing'; } elseif (!preg_match('/^6Lc[a-zA-Z0-9_-]{38}$/', $config['recaptcha']['site_key'])) { $result['issues'][] = 'reCAPTCHA site key appears to be invalid'; } if (count($result['issues']) === 0) { $result['valid'] = true; $result['type'] = 'recaptcha'; return $result; } } // Check Turnstile if ($config['turnstile']['enabled']) { if (empty($config['turnstile']['site_key'])) { $result['issues'][] = 'Turnstile site key is missing'; } elseif (!preg_match('/^0x4AAA[a-zA-Z0-9_-]{33}$/', $config['turnstile']['site_key'])) { $result['issues'][] = 'Turnstile site key appears to be invalid'; } if (count($result['issues']) === 0) { $result['valid'] = true; $result['type'] = 'turnstile'; return $result; } } // If both are enabled, it's an issue if ($config['recaptcha']['enabled'] && $config['turnstile']['enabled']) { $result['issues'][] = 'Both reCAPTCHA and Turnstile are enabled (only one should be used)'; } return $result; } }