__( '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;
}
}