PluginProbe
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor / 4.0.3
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor v4.0.3
4.0.3 4.0.2 4.0.1 4.0.0 3.16.6 3.16.5 3.16.4 3.16.3 3.16.2 3.16.1 3.16.0 3.15.9 3.9.9 3.9.5 3.9.6 3.9.7 3.9.8 1.1.7 1.1.8 1.1.9 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 341 releases
← All changes | front-end/default-fields/turnstile/turnstile.php +133 -46 3.16.5 → 4.0.3 View file →
@@ -13,10 +13,13 @@
13 13 $response = wp_remote_post( $path, array(
14 14 'body' => $data
15 15 ) );
16 16
17 - if ( ! is_wp_error( $response ) )
18 - return $response["body"];
17 + if ( is_wp_error( $response ) ) {
18 + return '';
19 + }
20 +
21 + return isset( $response['body'] ) ? $response['body'] : '';
19 22 }
20 23
21 24 /**
22 25 * Gets the challenge HTML wrapper for Turnstile.
@@ -69,15 +72,16 @@
69 72 /* if we do not have a turnstile field do nothing */
70 73 if( empty( $field ) )
71 74 return;
72 75
73 - //do not add script if there is no shortcode
76 + global $wppb_turnstile_present;
74 77 global $wppb_shortcode_on_front;
75 - if( current_filter() == 'wp_footer' && ( !isset( $wppb_shortcode_on_front ) || $wppb_shortcode_on_front === false ) )
78 +
79 + //do not add script on regular frontend pages unless a PB shortcode or Turnstile HTML is present
80 + if( current_filter() == 'wp_footer' && ( !isset( $wppb_shortcode_on_front ) || $wppb_shortcode_on_front === false ) && ( !isset( $wppb_turnstile_present ) || $wppb_turnstile_present === false ) )
76 81 return;
77 82
78 83 //do not add script if the html for the field has not been added
79 - global $wppb_turnstile_present;
80 84 if( !isset( $wppb_turnstile_present ) || $wppb_turnstile_present === false )
81 85 return;
82 86
83 87 //we don't have jquery on the backend
@@ -183,15 +187,16 @@
183 187 'response' => $response
184 188 )
185 189 );
186 190
187 - $answers = json_decode($getResponse, true);
191 + $answers = json_decode( $getResponse, true );
188 192 $turnstileResponse = new wppb_TurnstileResponse();
189 193
190 - if (trim($answers ['success']) == true) {
194 + // Fail closed when the HTTP call fails or the body is not valid JSON.
195 + if ( ! is_array( $answers ) || empty( $answers['success'] ) ) {
196 + $turnstileResponse->is_valid = false;
197 + } else {
191 198 $turnstileResponse->is_valid = true;
192 - } else {
193 - $turnstileResponse->is_valid = false;
194 199 }
195 200
196 201 return $turnstileResponse;
197 202
@@ -235,15 +240,16 @@
235 240 }
236 241
237 242 }
238 243
239 - // Save valid results when they are being triggered from an ajax request
240 - if( wp_doing_ajax() && isset( $_POST['action'] ) && $_POST['action'] == 'pms_validate_checkout' ){
244 + // Save valid results when they are being triggered from an ajax request that only pre-validates the
245 + // credentials, so the same single use token is still accepted on the form submission that follows it
246 + if( wppb_is_captcha_prevalidation_request() ){
241 247
242 - $saved = get_option( 'wppb_turnstile_validations', array() );
248 + $saved = wppb_prune_captcha_prevalidations( get_option( 'wppb_turnstile_validations', array() ) );
243 249
244 250 if( $already_validated === true )
245 - $saved[ $turnstile_response_field ] = true;
251 + $saved[ $turnstile_response_field ] = time();
246 252
247 253 update_option( 'wppb_turnstile_validations', $saved, false );
248 254
249 255 }
@@ -476,34 +482,34 @@
476 482 if ( isset( $_POST['log'] ) && !is_wp_error($user) && !isset( $_POST['pms_login'] ) ) {
477 483
478 484 $field = wppb_get_turnstile_field();
479 485 if ( !empty($field) ){
480 - global $wppb_turnstile_response;
486 + /* Work out whether Turnstile is enabled for the form that was actually submitted before verifying
487 + anything. The Cloudflare token is single use, so verifying it on a form where our widget was never
488 + displayed spends a token that belongs to whatever else protects that form, and that plugin\'s own
489 + check then fails with timeout-or-duplicate. */
490 + if ( isset($_POST['wppb_login']) && ($_POST['wppb_login'] == true) ) {
491 + // it\'s a PB login form, check if we have Turnstile on it
492 + $turnstile_enabled = ( isset($field['turnstile-pb-forms']) && (strpos($field['turnstile-pb-forms'], 'pb_login') !== false) );
493 + }
494 + else {
495 + // default WP login form
496 + $turnstile_enabled = ( isset($field['turnstile-wp-forms']) && (strpos($field['turnstile-wp-forms'], 'default_wp_login') !== false) );
497 + }
481 498
482 - if (!isset($wppb_turnstile_response)) $wppb_turnstile_response = wppb_validate_turnstile_response( trim( $field['turnstile-site-key'] ), trim( $field['turnstile-secret-key'] ) );
499 + if ( $turnstile_enabled ) {
500 + global $wppb_turnstile_response;
483 501
484 - $turnstile_error_message = __('Cloudflare Turnstile could not be verified. Please try again.','profile-builder');
502 + if (!isset($wppb_turnstile_response)) $wppb_turnstile_response = wppb_validate_turnstile_response( trim( $field['turnstile-site-key'] ), trim( $field['turnstile-secret-key'] ) );
485 503
486 - //Turnstile error for displaying on the PB login form
487 - if ( isset($_POST['wppb_login']) && ($_POST['wppb_login'] == true) ) {
504 + $turnstile_error_message = __('Cloudflare Turnstile could not be verified. Please try again.','profile-builder');
488 505
489 - // it\'s a PB login form, check if we have Turnstile on it and display error if not valid
490 - if ((isset($field['turnstile-pb-forms'])) && (strpos($field['turnstile-pb-forms'], 'pb_login') !== false) && ($wppb_turnstile_response == false)) {
506 + if ( $wppb_turnstile_response == false ) {
491 507 $user = new WP_Error('wppb_turnstile_error', $turnstile_error_message);
492 508 remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
493 509 remove_filter( 'authenticate', 'wp_authenticate_email_password', 20, 3 );
494 510 }
495 -
496 511 }
497 - else {
498 - //Turnstile error for displaying on the default WP login form
499 - if (isset($field['turnstile-wp-forms']) && (strpos($field['turnstile-wp-forms'], 'default_wp_login') !== false) && ($wppb_turnstile_response == false)) {
500 - $user = new WP_Error('wppb_turnstile_error', $turnstile_error_message);
501 - remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
502 - remove_filter( 'authenticate', 'wp_authenticate_email_password', 20, 3 );
503 - }
504 -
505 - }
506 512 }
507 513 }
508 514 return $user;
509 515 }
@@ -558,18 +564,21 @@
558 564 return;
559 565
560 566 $field = wppb_get_turnstile_field();
561 567 if ( !empty($field) ){
562 - global $wppb_turnstile_response;
563 - if (!isset($wppb_turnstile_response)) $wppb_turnstile_response = wppb_validate_turnstile_response( trim( $field['turnstile-site-key'] ), trim( $field['turnstile-secret-key'] ) );
568 + /* Only verify where Turnstile is configured for the form being submitted. The Cloudflare token is
569 + single use, so verifying it on a form our widget was never displayed on spends a token that another
570 + plugin protecting that form still needs, and its own check then fails with timeout-or-duplicate. */
571 + if ( isset( $field['turnstile-wp-forms'] ) && ( strpos( $field['turnstile-wp-forms'], 'default_wp_recover_password' ) !== false ) ) {
572 + global $wppb_turnstile_response;
573 + if (!isset($wppb_turnstile_response)) $wppb_turnstile_response = wppb_validate_turnstile_response( trim( $field['turnstile-site-key'] ), trim( $field['turnstile-secret-key'] ) );
564 574
565 - $turnstile_error_message = esc_html__('Cloudflare Turnstile could not be verified. Please try again.','profile-builder');
575 + $turnstile_error_message = esc_html__('Cloudflare Turnstile could not be verified. Please try again.','profile-builder');
566 576
567 - // Fail closed, but only where Turnstile is configured for this form. Gate on turnstile-wp-forms (as the
568 - // login path does) instead of isset() of the token, so a missing token is treated as a failed verification
569 - // without blocking default WP password recovery on sites that only use Turnstile on PB forms.
570 - if ( isset( $field['turnstile-wp-forms'] ) && ( strpos( $field['turnstile-wp-forms'], 'default_wp_recover_password' ) !== false ) && ( $wppb_turnstile_response == false ) ) {
571 - wp_die( esc_html( $turnstile_error_message ) . '<br />' . esc_html__( "Click the BACK button on your browser, and try again.", 'profile-builder' ) ) ;
577 + // Fail closed: a missing token is treated as a failed verification.
578 + if ( $wppb_turnstile_response == false ) {
579 + wp_die( esc_html( $turnstile_error_message ) . '<br />' . esc_html__( "Click the BACK button on your browser, and try again.", 'profile-builder' ) ) ;
580 + }
572 581 }
573 582 }
574 583 }
575 584 add_action('lostpassword_post','wppb_verify_turnstile_default_wp_recover_password');
@@ -605,18 +614,21 @@
605 614 function wppb_verify_turnstile_default_wp_register( $errors ){
606 615
607 616 $field = wppb_get_turnstile_field();
608 617 if ( !empty($field) ){
609 - global $wppb_turnstile_response;
610 - if (!isset($wppb_turnstile_response)) $wppb_turnstile_response = wppb_validate_turnstile_response( trim( $field['turnstile-site-key'] ), trim( $field['turnstile-secret-key'] ) );
618 + /* Only verify where Turnstile is configured for the form being submitted. The Cloudflare token is
619 + single use, so verifying it on a form our widget was never displayed on spends a token that another
620 + plugin protecting that form still needs, and its own check then fails with timeout-or-duplicate. */
621 + if ( isset( $field['turnstile-wp-forms'] ) && ( strpos( $field['turnstile-wp-forms'], 'default_wp_register' ) !== false ) ) {
622 + global $wppb_turnstile_response;
623 + if (!isset($wppb_turnstile_response)) $wppb_turnstile_response = wppb_validate_turnstile_response( trim( $field['turnstile-site-key'] ), trim( $field['turnstile-secret-key'] ) );
611 624
612 - $turnstile_error_message = esc_html__('Cloudflare Turnstile could not be verified. Please try again.','profile-builder');
625 + $turnstile_error_message = esc_html__('Cloudflare Turnstile could not be verified. Please try again.','profile-builder');
613 626
614 - // Fail closed, but only where Turnstile is configured for this form. Gate on turnstile-wp-forms (as the
615 - // login path does) instead of isset() of the token, so a missing token is treated as a failed verification
616 - // without blocking default WP registration on sites that only use Turnstile on PB forms.
617 - if ( isset( $field['turnstile-wp-forms'] ) && ( strpos( $field['turnstile-wp-forms'], 'default_wp_register' ) !== false ) && ( $wppb_turnstile_response == false ) ) {
618 - $errors->add( 'wppb_turnstile_error', $turnstile_error_message );
627 + // Fail closed: a missing token is treated as a failed verification.
628 + if ( $wppb_turnstile_response == false ) {
629 + $errors->add( 'wppb_turnstile_error', $turnstile_error_message );
630 + }
619 631 }
620 632 }
621 633
622 634 return $errors;
@@ -621,8 +633,83 @@
621 633
622 634 return $errors;
623 635 }
624 636 add_filter('registration_errors','wppb_verify_turnstile_default_wp_register');
637 +
638 +/* Display Turnstile html on default WP Comments form */
639 +function wppb_display_turnstile_default_wp_comments(){
640 + $field = wppb_get_turnstile_field();
641 +
642 + if ( !empty( $field ) ) {
643 + if ( isset( $field['turnstile-wp-forms'] ) && ( strpos( $field['turnstile-wp-forms'], 'default_wp_comments' ) !== false ) ) {
644 + $publickey = trim( $field['turnstile-site-key'] );
645 + $item_title = apply_filters( 'wppb_comments_turnstile_custom_field_' . $field['id'] . '_item_title', wppb_icl_t( 'plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_title_translation', $field['field-title'], true ) );
646 + $item_description = wppb_icl_t( 'plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_description_translation', $field['description'], true );
647 +
648 + global $wppb_turnstile_present;
649 + $wppb_turnstile_present = true;
650 +
651 + $turnstile_output = '<label for="turnstile_response_field">' . $item_title . '</label>' . wppb_turnstile_get_html( $publickey, 'default_wp_comments' );
652 + if ( !empty( $item_description ) )
653 + $turnstile_output .= '<span class="wppb-description-delimiter">' . $item_description . '</span>';
654 +
655 + echo '<div class="wppb-form-field wppb-turnstile">' . $turnstile_output . '</div>'; /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */ /* properly escaped when constructing the var */
656 + }
657 + }
658 +}
659 +add_action( 'comment_form_after_fields', 'wppb_display_turnstile_default_wp_comments' );
660 +add_action( 'comment_form_logged_in_after', 'wppb_display_turnstile_default_wp_comments' );
661 +
662 +function wppb_get_turnstile_default_wp_comments_error_message(){
663 + return __( 'Cloudflare Turnstile could not be verified. Please try again.', 'profile-builder' );
664 +}
665 +
666 +function wppb_display_turnstile_default_wp_comments_error(){
667 + if ( !isset( $_GET['wppb_comment_turnstile_error'] ) )
668 + return;
669 +
670 + $field = wppb_get_turnstile_field();
671 +
672 + if ( empty( $field ) || !isset( $field['turnstile-wp-forms'] ) || ( strpos( $field['turnstile-wp-forms'], 'default_wp_comments' ) === false ) )
673 + return;
674 +
675 + echo '<p class="wppb-error wppb-comment-captcha-error" id="wppb_comment_turnstile_error">' . esc_html( wppb_get_turnstile_default_wp_comments_error_message() ) . '</p>';
676 +}
677 +add_action( 'comment_form_top', 'wppb_display_turnstile_default_wp_comments_error' );
678 +
679 +// Verify Turnstile for default WP Comments form
680 +function wppb_verify_turnstile_default_wp_comments( $approved, $commentdata ){
681 + if ( !isset( $_POST['comment_post_ID'] ) )
682 + return $approved;
683 +
684 + $field = wppb_get_turnstile_field();
685 +
686 + if ( !empty( $field ) ) {
687 + if ( isset( $field['turnstile-wp-forms'] ) && ( strpos( $field['turnstile-wp-forms'], 'default_wp_comments' ) !== false ) ) {
688 + global $wppb_turnstile_response;
689 + if ( !isset( $wppb_turnstile_response ) )
690 + $wppb_turnstile_response = wppb_validate_turnstile_response( trim( $field['turnstile-site-key'] ), trim( $field['turnstile-secret-key'] ) );
691 +
692 + if ( $wppb_turnstile_response == false ) {
693 + $redirect_to = wp_get_referer();
694 +
695 + if ( empty( $redirect_to ) && isset( $commentdata['comment_post_ID'] ) )
696 + $redirect_to = get_permalink( absint( $commentdata['comment_post_ID'] ) );
697 +
698 + if ( !empty( $redirect_to ) && !wp_doing_ajax() ) {
699 + $redirect_to = preg_replace( '/#.*$/', '', remove_query_arg( array( 'wppb_comment_recaptcha_error', 'wppb_comment_turnstile_error' ), $redirect_to ) );
700 + wp_safe_redirect( add_query_arg( 'wppb_comment_turnstile_error', '1', $redirect_to ) . '#respond' );
701 + exit;
702 + }
703 +
704 + return new WP_Error( 'wppb_turnstile_error', wppb_get_turnstile_default_wp_comments_error_message(), 200 );
705 + }
706 + }
707 + }
708 +
709 + return $approved;
710 +}
711 +add_filter( 'pre_comment_approved', 'wppb_verify_turnstile_default_wp_comments', 10, 2 );
625 712
626 713 // set default values in case there's already an existing Turnstile field in Manage fields (when upgrading)
627 714 function wppb_turnstile_set_default_values() {
628 715 $manage_fields = get_option('wppb_manage_fields', 'not_set');