__( 'None', 'frontglut' ), 'recaptcha' => 'Google reCAPTCHA v2', 'recaptcha3' => 'Google reCAPTCHA v3', 'hcaptcha' => 'hCaptcha', 'turnstile' => 'Cloudflare Turnstile', ); } public static function enabled() { $p = Settings::get( 'captcha.provider' ); return $p && Settings::get( 'captcha.site_key' ) && Settings::get( 'captcha.secret_key' ); } /** Should captcha show for this context (login/register/post/...)? */ public static function active_for( $ctx ) { if ( ! self::enabled() ) { return false; } $where = (array) Settings::get( 'captcha.where', array() ); return in_array( $ctx, $where, true ); } public static function render() { if ( ! self::enabled() ) { return ''; } $p = Settings::get( 'captcha.provider' ); $key = esc_attr( Settings::get( 'captcha.site_key' ) ); $urls = array( 'recaptcha' => 'https://www.google.com/recaptcha/api.js', 'recaptcha3' => 'https://www.google.com/recaptcha/api.js?render=' . rawurlencode( Settings::get( 'captcha.site_key' ) ), 'hcaptcha' => 'https://js.hcaptcha.com/1/api.js', 'turnstile' => 'https://challenges.cloudflare.com/turnstile/v0/api.js', ); if ( empty( $urls[ $p ] ) ) { return ''; } static $loaded = false; if ( ! $loaded ) { $loaded = true; wp_enqueue_script( 'frontglut-captcha', $urls[ $p ], array(), null, true ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters } switch ( $p ) { case 'recaptcha': return '
'; case 'recaptcha3': return '
'; case 'hcaptcha': return '
'; case 'turnstile': return '
'; } return ''; } /** @return true|\WP_Error */ public static function verify( array $req ) { if ( ! self::enabled() ) { return true; } $p = Settings::get( 'captcha.provider' ); $secret = Settings::get( 'captcha.secret_key' ); $map = array( 'recaptcha' => array( 'https://www.google.com/recaptcha/api/siteverify', 'g-recaptcha-response' ), 'recaptcha3' => array( 'https://www.google.com/recaptcha/api/siteverify', 'frontglut_captcha_token' ), 'hcaptcha' => array( 'https://hcaptcha.com/siteverify', 'h-captcha-response' ), 'turnstile' => array( 'https://challenges.cloudflare.com/turnstile/v0/siteverify', 'cf-turnstile-response' ), ); if ( empty( $map[ $p ] ) ) { return true; } $token = isset( $req[ $map[ $p ][1] ] ) ? sanitize_text_field( $req[ $map[ $p ][1] ] ) : ''; if ( '' === $token ) { return new \WP_Error( 'captcha', __( 'Please complete the captcha.', 'frontglut' ) ); } $res = wp_remote_post( $map[ $p ][0], array( 'timeout' => 10, 'body' => array( 'secret' => $secret, 'response' => $token ) ) ); if ( is_wp_error( $res ) ) { return new \WP_Error( 'captcha', __( 'Captcha could not be verified. Try again.', 'frontglut' ) ); } $body = json_decode( wp_remote_retrieve_body( $res ), true ); if ( empty( $body['success'] ) ) { return new \WP_Error( 'captcha', __( 'Captcha verification failed.', 'frontglut' ) ); } if ( 'recaptcha3' === $p && isset( $body['score'] ) && $body['score'] < (float) Settings::get( 'captcha.min_score', 0.5 ) ) { return new \WP_Error( 'captcha', __( 'Captcha score too low.', 'frontglut' ) ); } return true; } }