Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion inc/class-registration.php
Original file line number Diff line number Diff line change
Expand Up @@ -547,11 +547,13 @@ function () {
array(
'reRecaptchaSitekey' => get_option( 'themeisle_google_captcha_api_site_key' ),
'reRecaptchaAPIURL' => apply_filters( 'otter_blocks_recaptcha_api_url', 'https://www.google.com/recaptcha/api.js' ),
'turnstileSitekey' => get_option( 'themeisle_cloudflare_turnstile_site_key' ),
'turnstileAPIURL' => apply_filters( 'otter_blocks_turnstile_api_url', 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit' ),
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'messages' => array(
'submission' => __( 'Form submission from', 'otter-blocks' ),
'captcha-not-loaded' => __( 'Captcha is not loaded. Please check your browser plugins to allow the Google reCaptcha.', 'otter-blocks' ),
'captcha-not-loaded' => __( 'Captcha is not loaded. Please check your browser plugins to allow it.', 'otter-blocks' ),
'check-captcha' => __( 'Please check the captcha.', 'otter-blocks' ),
'invalid-email' => __( 'The email address is invalid!', 'otter-blocks' ),
'already-registered' => __( 'The email was already registered!', 'otter-blocks' ),
Expand Down
2 changes: 1 addition & 1 deletion inc/integrations/api/form-response-data.php
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ public static function get_error_code_message( $error_code ) {
self::ERROR_MISSING_PROVIDER => __( 'Provider settings are missing.', 'otter-blocks' ),
self::ERROR_MISSING_API_KEY => __( 'API Key is missing from settings.', 'otter-blocks' ),
self::ERROR_MISSING_MAIL_LIST_ID => __( 'API Key is missing.', 'otter-blocks' ),
self::ERROR_INVALID_CAPTCHA_TOKEN => __( 'The reCaptcha token is invalid.', 'otter-blocks' ),
self::ERROR_INVALID_CAPTCHA_TOKEN => __( 'The captcha token is invalid.', 'otter-blocks' ),
self::ERROR_PROVIDER_INVALID_API_KEY_FORMAT => __( 'The API key format is invalid.', 'otter-blocks' ),
self::ERROR_PROVIDER_CLIENT_ALREADY_REGISTERED => __( 'The user with this email was already registered.', 'otter-blocks' ),
self::ERROR_PROVIDER_INVALID_EMAIL => __( 'The email address is invalid.', 'otter-blocks' ),
Expand Down
39 changes: 39 additions & 0 deletions inc/integrations/class-form-settings-data.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@
*/
private $has_captcha = false;

/**
* Captcha provider.
*
* @var string
*/
private $captcha_provider = 'recaptcha';

/**
* The metadata.
*
Expand Down Expand Up @@ -154,6 +161,10 @@
$this->set_captcha( $integration_data['hasCaptcha'] );
}

if ( isset( $integration_data['captchaProvider'] ) ) {
$this->set_captcha_provider( $integration_data['captchaProvider'] );
}

$this->set_meta( $integration_data );
}

Expand Down Expand Up @@ -225,6 +236,9 @@
if ( isset( $form['hasCaptcha'] ) ) {
$integration->set_captcha( $form['hasCaptcha'] );
}
if ( isset( $form['captchaProvider'] ) ) {
$integration->set_captcha_provider( $form['captchaProvider'] );
}
if ( isset( $form['redirectLink'] ) ) {
$integration->set_redirect_link( $form['redirectLink'] );
}
Expand Down Expand Up @@ -349,6 +363,21 @@
return $this;
}

/**
* Set captcha provider.
*
* @param string $provider Provider slug.
* @return Form_Settings_Data
* @since 3.1.12
*/
public function set_captcha_provider( $provider ) {
$provider = is_string( $provider ) ? sanitize_key( $provider ) : '';

Check failure on line 374 in inc/integrations/class-form-settings-data.php

View workflow job for this annotation

GitHub Actions / PHPStan

Call to function is_string() with string will always evaluate to true.
$allowed = array( 'recaptcha', 'turnstile' );

$this->captcha_provider = in_array( $provider, $allowed, true ) ? $provider : 'recaptcha';
return $this;
}

/**
* Check if it has the API Key and the list id set.
*
Expand Down Expand Up @@ -557,6 +586,16 @@
return $this->has_captcha;
}

/**
* Get captcha provider.
*
* @return string
* @since 3.1.12
*/
public function get_captcha_provider() {
return $this->captcha_provider;
}

/**
* Get the redirect link.
*
Expand Down
24 changes: 24 additions & 0 deletions inc/plugins/class-options-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,30 @@ public function register_settings() {
)
);

register_setting(
'themeisle_blocks_settings',
'themeisle_cloudflare_turnstile_site_key',
array(
'type' => 'string',
'description' => __( 'Cloudflare Turnstile Site key for the Form Block.', 'otter-blocks' ),
'sanitize_callback' => 'sanitize_text_field',
'show_in_rest' => true,
'default' => '',
)
);

register_setting(
'themeisle_blocks_settings',
'themeisle_cloudflare_turnstile_secret_key',
array(
'type' => 'string',
'description' => __( 'Cloudflare Turnstile Secret key for the Form Block.', 'otter-blocks' ),
'sanitize_callback' => 'sanitize_text_field',
'show_in_rest' => true,
'default' => '',
)
);

register_setting(
'themeisle_blocks_settings',
'themeisle_blocks_settings_default_block',
Expand Down
27 changes: 21 additions & 6 deletions inc/server/class-form-server.php
Original file line number Diff line number Diff line change
Expand Up @@ -966,21 +966,36 @@
$form_data->set_error( Form_Data_Response::ERROR_MISSING_CAPTCHA );
}

if ( $form_data->payload_has( 'token' ) ) {
$secret = get_option( 'themeisle_google_captcha_api_secret_key' );
$resp = wp_remote_post(
apply_filters( 'otter_blocks_recaptcha_verify_url', 'https://www.google.com/recaptcha/api/siteverify' ),
if ( $form_options->form_has_captcha() && $form_data->payload_has( 'token' ) ) {
$provider = $form_data->payload_has( 'captchaProvider' ) ? sanitize_key( $form_data->get_data_from_payload( 'captchaProvider' ) ) : null;
$provider = $provider ? $provider : ( method_exists( $form_options, 'get_captcha_provider' ) ? $form_options->get_captcha_provider() : 'recaptcha' );

if ( 'turnstile' === $provider ) {
$secret = get_option( 'themeisle_cloudflare_turnstile_secret_key' );
$verify_url = apply_filters( 'otter_blocks_turnstile_verify_url', 'https://challenges.cloudflare.com/turnstile/v0/siteverify' );
} else {
$secret = get_option( 'themeisle_google_captcha_api_secret_key' );
$verify_url = apply_filters( 'otter_blocks_recaptcha_verify_url', 'https://www.google.com/recaptcha/api/siteverify' );
}

$resp = wp_remote_post(
$verify_url,
array(
'body' => 'secret=' . $secret . '&response=' . $form_data->get_data_from_payload( 'token' ),
'body' => 'secret=' . rawurlencode( (string) $secret ) . '&response=' . rawurlencode( (string) $form_data->get_data_from_payload( 'token' ) ),
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
)
);

if ( is_wp_error( $resp ) || ! isset( $resp['body'] ) ) {

Check failure on line 991 in inc/server/class-form-server.php

View workflow job for this annotation

GitHub Actions / PHPStan

Offset 'body' on array{headers: WpOrg\Requests\Utility\CaseInsensitiveDictionary, body: string, response: array{code: int, message: string}, cookies: array<int, WP_Http_Cookie>, filename: string|null, http_response: WP_HTTP_Requests_Response} in isset() always exists and is not nullable.
$form_data->set_error( Form_Data_Response::ERROR_INVALID_CAPTCHA_TOKEN );
return $form_data;
}

$result = json_decode( $resp['body'], true );

if ( ! $result['success'] ) {
if ( ! is_array( $result ) || empty( $result['success'] ) ) {
$form_data->set_error( Form_Data_Response::ERROR_INVALID_CAPTCHA_TOKEN );
}
}
Expand Down
36 changes: 36 additions & 0 deletions packages/e2e-tests/mu-plugins/otter-e2e-bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
'themeisle_open_ai_api_key',
'otter_iphub_api_key',
'themeisle_blocks_settings_onboarding',
'themeisle_cloudflare_turnstile_site_key',
'themeisle_cloudflare_turnstile_secret_key',
);

/**
Expand Down Expand Up @@ -118,6 +120,40 @@ function stub_wp_mail_for_e2e( $short_circuit ) {

add_filter( 'pre_wp_mail', __NAMESPACE__ . '\\stub_wp_mail_for_e2e' );

/**
* Prevent external HTTP calls for captcha verification during E2E.
*
* @param mixed $preempt Whether to preempt an HTTP request.
* @param array $request HTTP request arguments.
* @param string $url The request URL.
* @return array|mixed
*/
function stub_captcha_http_verification_for_e2e( $preempt, $request, $url ) {
if ( null !== $preempt ) {
return $preempt;
}

if (
false !== strpos( $url, 'www.google.com/recaptcha/api/siteverify' ) ||
false !== strpos( $url, 'challenges.cloudflare.com/turnstile/v0/siteverify' )
) {
return array(
'response' => array(
'code' => 200,
),
'body' => wp_json_encode(
array(
'success' => true,
)
),
);
}

return $preempt;
}

add_filter( 'pre_http_request', __NAMESPACE__ . '\\stub_captcha_http_verification_for_e2e', 10, 3 );

add_action(
'rest_api_init',
function () {
Expand Down
4 changes: 4 additions & 0 deletions src/blocks/blocks/form/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
"hasCaptcha": {
"type": "boolean"
},
"captchaProvider": {
"type": "string",
"default": "recaptcha"
},
"provider": {
"type": "string",
"default": ""
Expand Down
Loading
Loading