plugin = $plugin_instance; } /** * Verifies a Captcha response if submitted. */ public function verify_submission() { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- CAPTCHA submission occurs prior to authenticated sessions/nonces. if (!isset($_POST['_advaipbl_challenge_type'])) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Missing if (!isset($_POST['cf-turnstile-response']) && !isset($_POST['h-captcha-response'])) { return; } if (!empty($this->plugin->request_is_asn_whitelisted) || $this->plugin->is_whitelisted($this->plugin->get_client_ip()) || !empty($this->plugin->is_advanced_rule_allowed)) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Missing $challenge_type = sanitize_key($_POST['_advaipbl_challenge_type'] ?? 'signature'); // phpcs:ignore WordPress.Security.NonceVerification.Missing $engine = isset($_POST['cf-turnstile-response']) ? 'turnstile' : 'hcaptcha'; // phpcs:ignore WordPress.Security.NonceVerification.Missing $token = sanitize_text_field(wp_unslash($_POST['cf-turnstile-response'] ?? $_POST['h-captcha-response'])); $ip = $this->plugin->get_client_ip(); $is_valid = false; if ($engine === 'turnstile') { $secret_key = $this->plugin->options['turnstile_secret_key'] ?? ''; // phpcs:ignore PluginCheck.CodeAnalysis.Offloading.OffloadedContent $response = wp_remote_post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [ 'body' => [ 'secret' => $secret_key, 'response' => $token, 'remoteip' => $ip, ], ]); if (!is_wp_error($response)) { $body = json_decode(wp_remote_retrieve_body($response), true); if (!empty($body['success'])) { $is_valid = true; } } } elseif ($engine === 'hcaptcha') { $secret_key = $this->plugin->options['hcaptcha_secret_key'] ?? ''; $response = wp_remote_post('https://api.hcaptcha.com/siteverify', [ 'body' => [ 'secret' => $secret_key, 'response' => $token, 'remoteip' => $ip, ], ]); if (!is_wp_error($response)) { $body = json_decode(wp_remote_retrieve_body($response), true); if (!empty($body['success'])) { $is_valid = true; } } } $global_duration_hours = (int)($this->plugin->options['global_challenge_cookie_duration'] ?? 4); $cookie_duration = ($global_duration_hours > 0) ? $global_duration_hours * HOUR_IN_SECONDS : 0; if ($challenge_type === 'geo_challenge') { $duration_hours = (int)($this->plugin->options['geo_challenge_cookie_duration'] ?? 24); $cookie_duration = ($duration_hours > 0) ? $duration_hours * HOUR_IN_SECONDS : 0; } if ($is_valid) { if (isset($this->plugin->challenge_metrics)) { $this->plugin->challenge_metrics->increment('passed'); } set_transient('advaipbl_grace_pass_' . md5($ip), true, 15); $this->plugin->js_challenge_manager->set_vip_pass_cookie($cookie_duration, $ip); // phpcs:ignore WordPress.Security.NonceVerification.Missing $redirect_to = !empty($_POST['_advaipbl_redirect_to']) ? esc_url_raw(wp_unslash($_POST['_advaipbl_redirect_to'])) : ''; if (empty($redirect_to)) { $protocol = is_ssl() ? 'https://' : 'http://'; $host = sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'] ?? '')); $uri = esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'] ?? '/')); $redirect_to = $protocol . $host . $uri; } wp_safe_redirect($redirect_to); exit; } else { if (isset($this->plugin->challenge_metrics)) { $this->plugin->challenge_metrics->increment('failed'); } $this->plugin->log_event("{$engine} verification failed.", 'warning', ['ip' => $ip, 'token' => substr($token, 0, 10) . '...']); wp_die( esc_html__('Verification failed. Please try again.', 'advanced-ip-blocker'), esc_html__('Verification Failed', 'advanced-ip-blocker'), ['response' => 403] ); } } /** * Serves the Captcha challenge (Turnstile or hCaptcha). */ public function serve_challenge($challenge_type, $engine, $challenge_mode = 'managed') { if (isset($this->plugin->challenge_metrics)) { $this->plugin->challenge_metrics->increment('served'); } if (!defined('DONOTCACHEPAGE')) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound -- Required constant name for caching plugins define('DONOTCACHEPAGE', true); } if (headers_sent()) { return; } header('Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0'); header('Pragma: no-cache'); header('Expires: Thu, 01 Jan 1970 00:00:01 GMT'); header('X-LiteSpeed-Cache-Control: no-cache'); header('Cloudflare-CDN-Cache-Control: no-store'); header('CDN-Cache-Control: no-store'); header('Surrogate-Control: no-store'); header('X-Accel-Expires: 0'); header('X-Cache-Enabled: False'); header('X-Frame-Options: DENY'); header('X-Content-Type-Options: nosniff'); if ($engine === 'turnstile') { // phpcs:ignore PluginCheck.CodeAnalysis.Offloading.OffloadedContent header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://challenges.cloudflare.com https://static.cloudflareinsights.com; frame-src https://challenges.cloudflare.com; style-src 'self' 'unsafe-inline';"); } else { header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://hcaptcha.com https://*.hcaptcha.com https://static.cloudflareinsights.com; frame-src https://hcaptcha.com https://*.hcaptcha.com; style-src 'self' 'unsafe-inline' https://hcaptcha.com https://*.hcaptcha.com; connect-src 'self' https://hcaptcha.com https://*.hcaptcha.com;"); } status_header(503); header('Content-Type: text/html; charset=utf-8'); header('Retry-After: 10'); $protocol = is_ssl() ? 'https://' : 'http://'; $host = sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'] ?? '')); $uri = esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'] ?? '/')); $action_url = esc_url($protocol . $host . $uri); $site_title = get_bloginfo('name', 'display'); $site_host = wp_parse_url(home_url(), PHP_URL_HOST); $page_title = esc_html__('Verifying your connection...', 'advanced-ip-blocker'); $main_heading = esc_html__('Security Check Required', 'advanced-ip-blocker'); $site_msg = esc_html__('needs to review the security of your connection before proceeding.', 'advanced-ip-blocker'); $site_key = ''; if ($engine === 'turnstile') { $site_key = $this->plugin->options['turnstile_site_key'] ?? ''; } elseif ($engine === 'hcaptcha') { $site_key = $this->plugin->options['hcaptcha_site_key'] ?? ''; } ?>