diff --git a/includes/class-captcha.php b/includes/class-captcha.php new file mode 100644 index 0000000..b6566b4 --- /dev/null +++ b/includes/class-captcha.php @@ -0,0 +1,334 @@ +get_provider(); + return 'none' !== $provider && ! empty( $provider ); + } + + /** + * Get current captcha provider + * + * @return string none|recaptcha_v2|recaptcha_v3|hcaptcha + */ + public function get_provider() { + return get_option( 'umzugsliste_captcha_provider', 'none' ); + } + + /** + * Get site key + * + * @return string + */ + private function get_site_key() { + return get_option( 'umzugsliste_captcha_site_key', '' ); + } + + /** + * Get secret key + * + * @return string + */ + private function get_secret_key() { + return get_option( 'umzugsliste_captcha_secret_key', '' ); + } + + /** + * Enqueue captcha provider scripts + */ + public function enqueue_scripts() { + if ( ! $this->is_enabled() ) { + return; + } + + $provider = $this->get_provider(); + $site_key = $this->get_site_key(); + + if ( empty( $site_key ) ) { + return; + } + + switch ( $provider ) { + case 'recaptcha_v2': + wp_enqueue_script( + 'recaptcha-v2', + 'https://www.google.com/recaptcha/api.js', + array(), + null, + true + ); + break; + + case 'recaptcha_v3': + wp_enqueue_script( + 'recaptcha-v3', + 'https://www.google.com/recaptcha/api.js?render=' . $site_key, + array(), + null, + true + ); + break; + + case 'hcaptcha': + wp_enqueue_script( + 'hcaptcha', + 'https://js.hcaptcha.com/1/api.js', + array(), + null, + true + ); + break; + } + } + + /** + * Render captcha widget in form + * + * @return string HTML for captcha widget + */ + public function render_widget() { + if ( ! $this->is_enabled() ) { + return ''; + } + + $provider = $this->get_provider(); + $site_key = $this->get_site_key(); + + if ( empty( $site_key ) ) { + return ''; + } + + ob_start(); + + switch ( $provider ) { + case 'recaptcha_v2': + ?> +
+ + + + + + is_enabled() ) { + return true; + } + + $provider = $this->get_provider(); + + switch ( $provider ) { + case 'recaptcha_v2': + return $this->verify_recaptcha_v2( $post_data ); + + case 'recaptcha_v3': + return $this->verify_recaptcha_v3( $post_data ); + + case 'hcaptcha': + return $this->verify_hcaptcha( $post_data ); + + default: + return true; + } + } + + /** + * Verify reCAPTCHA v2 response + * + * @param array $post_data POST data + * @return bool + */ + private function verify_recaptcha_v2( $post_data ) { + $response = isset( $post_data['g-recaptcha-response'] ) ? $post_data['g-recaptcha-response'] : ''; + + if ( empty( $response ) ) { + return false; + } + + $secret_key = $this->get_secret_key(); + if ( empty( $secret_key ) ) { + return false; + } + + $verify_url = 'https://www.google.com/recaptcha/api/siteverify'; + + $response = wp_remote_post( + $verify_url, + array( + 'body' => array( + 'secret' => $secret_key, + 'response' => $response, + 'remoteip' => $_SERVER['REMOTE_ADDR'], + ), + ) + ); + + if ( is_wp_error( $response ) ) { + return false; + } + + $body = json_decode( wp_remote_retrieve_body( $response ), true ); + + return isset( $body['success'] ) && $body['success']; + } + + /** + * Verify reCAPTCHA v3 response + * + * @param array $post_data POST data + * @return bool + */ + private function verify_recaptcha_v3( $post_data ) { + $response = isset( $post_data['g-recaptcha-response'] ) ? $post_data['g-recaptcha-response'] : ''; + + if ( empty( $response ) ) { + return false; + } + + $secret_key = $this->get_secret_key(); + if ( empty( $secret_key ) ) { + return false; + } + + $verify_url = 'https://www.google.com/recaptcha/api/siteverify'; + + $response = wp_remote_post( + $verify_url, + array( + 'body' => array( + 'secret' => $secret_key, + 'response' => $response, + 'remoteip' => $_SERVER['REMOTE_ADDR'], + ), + ) + ); + + if ( is_wp_error( $response ) ) { + return false; + } + + $body = json_decode( wp_remote_retrieve_body( $response ), true ); + + // Check success and score (must be >= 0.5) + return isset( $body['success'] ) && $body['success'] && isset( $body['score'] ) && $body['score'] >= 0.5; + } + + /** + * Verify hCaptcha response + * + * @param array $post_data POST data + * @return bool + */ + private function verify_hcaptcha( $post_data ) { + $response = isset( $post_data['h-captcha-response'] ) ? $post_data['h-captcha-response'] : ''; + + if ( empty( $response ) ) { + return false; + } + + $secret_key = $this->get_secret_key(); + if ( empty( $secret_key ) ) { + return false; + } + + $verify_url = 'https://hcaptcha.com/siteverify'; + + $response = wp_remote_post( + $verify_url, + array( + 'body' => array( + 'secret' => $secret_key, + 'response' => $response, + 'remoteip' => $_SERVER['REMOTE_ADDR'], + ), + ) + ); + + if ( is_wp_error( $response ) ) { + return false; + } + + $body = json_decode( wp_remote_retrieve_body( $response ), true ); + + return isset( $body['success'] ) && $body['success']; + } +}