PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.13.3
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.13.3
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
← All changes | includes/core/classes/class-wpfnl-ajax-handler.php +83 -26 3.12.4 → 3.13.3 View file →
@@ -23,8 +23,15 @@
23 23 */
24 24 class Ajax_Handler {
25 25
26 26 /**
27 + * Upper bound on notification recipients for a single opt-in submission.
28 + *
29 + * @since 3.12.14
30 + */
31 + const MAX_NOTIFICATION_RECIPIENTS = 10;
32 +
33 + /**
27 34 * Initializes AJAX actions and filters for handling different types of form submissions.
28 35 * Sets up AJAX hooks for various form submission scenarios, including shortcode and Gutenberg submissions.
29 36 * Also hooks into the 'mailmint_after_form_submit_response' filter for processing form submissions.
30 37 */
@@ -47,9 +54,9 @@
47 54 * @return void
48 55 * @since 2.5.7
49 56 */
50 57 public function optin_form_submission() {
51 - // check_ajax_referer( 'optin_form_nonce', 'security' );
58 + check_ajax_referer( 'optin_form_nonce', 'security' );
52 59
53 60 $step_id = isset( $_POST[ 'step_id' ] ) ? $_POST[ 'step_id' ] : '';
54 61 $postData = isset( $_POST[ 'postData' ] ) ? $_POST[ 'postData' ] : '';
55 62
@@ -146,9 +153,9 @@
146 153
147 154 /**
148 155 * User registration
149 156 */
150 - if ( !empty( $user_info[ 'optin_allow_registration' ] ) && $user_info[ 'optin_allow_registration' ] == 'yes' ) {
157 + if ( !empty( $form[ 'settings' ][ 'allow_registration' ] ) && 'yes' == $form[ 'settings' ][ 'allow_registration' ] ) {
151 158
152 159 $this->create_user_optin_allow_registration( $name, $user_info );
153 160 }
154 161
@@ -155,13 +162,12 @@
155 162
156 163 /**
157 164 * Recaptcha Check
158 165 */
159 - $is_recaptcha = isset( $post_data[ 'wpf-is-recapcha' ] ) ? $post_data[ 'wpf-is-recapcha' ] : 'no';
160 - $recaptcha_site_key = isset( $post_data[ 'wpf-optin-g-token' ] ) ? $post_data[ 'wpf-optin-g-token' ] : '';
161 - $recaptcha_site_secrect = isset( $post_data[ 'wpf-optin-g-secret-key' ] ) ? $post_data[ 'wpf-optin-g-secret-key' ] : '';
166 + $recaptcha = $this->get_trusted_recaptcha_settings();
167 + $recaptcha_response = isset( $post_data[ 'wpf-optin-g-token' ] ) ? $post_data[ 'wpf-optin-g-token' ] : '';
162 168
163 - $response = $this->send_mail_after_checking_google_recaptcha_response( $is_recaptcha, $recaptcha_site_key, $recaptcha_site_secrect, $admin_email, $admin_email_subject, $user_info, $response );
169 + $response = $this->send_mail_after_checking_google_recaptcha_response( $recaptcha[ 'enabled' ], $recaptcha_response, $recaptcha[ 'secret' ], $admin_email, $admin_email_subject, $user_info, $response );
164 170
165 171 if( \WPFunnels\Integrations\Helper::maybe_enabled() && !empty($form[ 'settings' ]['enable_mm_contact']) && 'yes' === $form[ 'settings' ]['enable_mm_contact'] ){
166 172 $lists = [];
167 173 $tags = [];
@@ -256,12 +262,12 @@
256 262 * @since @since 2.5.7
257 263 */
258 264 public function wpfnl_shortcode_optin_submission( $response = [] ) {
259 265 $post = filter_input_array( INPUT_POST );
260 - // if ( !wp_verify_nonce( htmlspecialchars( $post[ 'security' ] ?? '' ), 'optin_form_nonce' )
261 - // && !wp_verify_nonce( htmlspecialchars( $post[ 'wp_nonce' ] ?? '' ), 'wp_rest' ) ) {
262 - // die( '-1' );
263 - // }
266 + if ( !wp_verify_nonce( htmlspecialchars( $post[ 'security' ] ?? '' ), 'optin_form_nonce' )
267 + && !wp_verify_nonce( htmlspecialchars( $post[ 'wp_nonce' ] ?? '' ), 'wp_rest' ) ) {
268 + wp_send_json_error( array( 'message' => __( 'Unauthorized request', 'wpfnl' ) ), 403 );
269 + }
264 270
265 271 $return = true;
266 272 if ( empty( $response ) ) {
267 273 $response = [];
@@ -498,18 +504,49 @@
498 504 * @return array The updated response after processing reCAPTCHA and sending the email.
499 505 * @since 2.8.2
500 506 */
501 507 private function process_recaptcha( $post_data, $response, $user_info ) {
502 - $admin_email = $post_data[ 'admin_email' ] ?? false;
503 - $admin_email_subject = $post_data[ 'admin_email_subject' ] ?? 'Opt-in form Submission';
504 - $is_recaptcha = $post_data[ 'wpf-is-recapcha' ] ?? 'false';
505 - $recaptcha_site_key = $post_data[ 'wpf-optin-g-token' ] ?? '';
506 - $recaptcha_site_secrect = $post_data[ 'wpf-optin-g-secret-key' ] ?? '';
508 + $admin_email = $post_data[ 'admin_email' ] ?? false;
509 + $admin_email_subject = $post_data[ 'admin_email_subject' ] ?? 'Opt-in form Submission';
510 + $allow_registration = $post_data[ 'optin_allow_registration' ] ?? '';
511 + $token = $post_data[ 'wpfnl_optin_settings_token' ] ?? '';
507 512
508 - return $this->send_mail_after_checking_google_recaptcha_response( $is_recaptcha, $recaptcha_site_key, $recaptcha_site_secrect, $admin_email, $admin_email_subject, $user_info, $response );
513 + // The recipient and subject are hidden inputs, so they come back as request
514 + // data. Honour them only when they are still the ones this form was
515 + // rendered with; otherwise there is no notification to send.
516 + if ( ! Wpfnl_functions::is_valid_optin_settings_token( $token, (string) $admin_email, (string) $admin_email_subject, (string) $allow_registration ) ) {
517 + $admin_email = false;
518 + $admin_email_subject = false;
519 + }
520 +
521 + $recaptcha = $this->get_trusted_recaptcha_settings();
522 + $recaptcha_response = $post_data[ 'wpf-optin-g-token' ] ?? '';
523 +
524 + return $this->send_mail_after_checking_google_recaptcha_response( $recaptcha[ 'enabled' ], $recaptcha_response, $recaptcha[ 'secret' ], $admin_email, $admin_email_subject, $user_info, $response );
509 525 }
510 526
511 527 /**
528 + * reCAPTCHA configuration as stored for the site.
529 + *
530 + * Never read the switch or the secret from a submission: both are rendered
531 + * into the form, so a caller can omit the switch or substitute keys for a
532 + * challenge they control.
533 + *
534 + * @return array
535 + * @since 3.12.14
536 + */
537 + private function get_trusted_recaptcha_settings() {
538 + $settings = Wpfnl_functions::get_recaptcha_settings();
539 + $enabled = isset( $settings[ 'enable_recaptcha' ] ) ? $settings[ 'enable_recaptcha' ] : 'no';
540 + $secret = isset( $settings[ 'recaptcha_site_secret' ] ) ? $settings[ 'recaptcha_site_secret' ] : '';
541 +
542 + return array(
543 + 'enabled' => ( 'on' === $enabled && $secret ) ? 'on' : 'off',
544 + 'secret' => $secret,
545 + );
546 + }
547 +
548 + /**
512 549 * Gutenberg opt-in form handling
513 550 *
514 551 * @return void
515 552 * @since 2.5.9
@@ -613,9 +650,9 @@
613 650 }
614 651 /**
615 652 * User registration
616 653 */
617 - if ( !empty( $post_data[ 'optin_allow_registration' ] ) && $post_data[ 'optin_allow_registration' ] == 'yes' ) {
654 + if ( !empty( $block_attr[ 'registration_checkbox' ] ) ) {
618 655
619 656 $this->create_user_optin_allow_registration( $name, $post_data );
620 657 }
621 658 /**
@@ -620,13 +657,12 @@
620 657 }
621 658 /**
622 659 * Check google Recaptcha V3
623 660 */
624 - $is_recaptcha = isset( $post_data[ 'wpf-is-recapcha' ] ) ? $post_data[ 'wpf-is-recapcha' ] : 'false';
625 - $recaptcha_site_key = isset( $post_data[ 'wpf-optin-g-token' ] ) ? $post_data[ 'wpf-optin-g-token' ] : '';
626 - $recaptcha_site_secrect = isset( $post_data[ 'wpf-optin-g-secret-key' ] ) ? $post_data[ 'wpf-optin-g-secret-key' ] : '';
661 + $recaptcha = $this->get_trusted_recaptcha_settings();
662 + $recaptcha_response = isset( $post_data[ 'wpf-optin-g-token' ] ) ? $post_data[ 'wpf-optin-g-token' ] : '';
627 663
628 - $response = $this->send_mail_after_checking_google_recaptcha_response( $is_recaptcha, $recaptcha_site_key, $recaptcha_site_secrect, $admin_email, $admin_email_subject, $post_data, $response );
664 + $response = $this->send_mail_after_checking_google_recaptcha_response( $recaptcha[ 'enabled' ], $recaptcha_response, $recaptcha[ 'secret' ], $admin_email, $admin_email_subject, $post_data, $response );
629 665
630 666
631 667 $user_data = [
632 668 'first_name' => $post_data['first_name'] ?? '',
@@ -734,12 +770,17 @@
734 770 * @since 2.5.9
735 771 */
736 772 private function send_email_to_admin( $emails = '', $subject = '', $user_info = [] ) {
737 773 $email_array = explode( ",", $emails );
774 +
775 + // Bound the fan-out and drop anything that is not an address, so a single
776 + // submission cannot be turned into a mail relay.
777 + $email_array = array_slice( array_filter( array_map( 'trim', $email_array ) ), 0, self::MAX_NOTIFICATION_RECIPIENTS );
778 +
738 779 if ( is_array( $email_array ) ) {
739 780 foreach( $email_array as $email ) {
740 781
741 - if ( $email ) {
782 + if ( $email && is_email( $email ) ) {
742 783 $email = trim( $email );
743 784 $current_date = date( "d M Y" );
744 785 $time = new \DateTimeImmutable( 'now', wp_timezone() );
745 786 $current_time = $time->format( "h:i A" );
@@ -745,18 +786,22 @@
745 786 $current_time = $time->format( "h:i A" );
746 787 $poweredBy = __( 'WPFunnels', 'wpfnl' );
747 788 $info = '';
748 789 if ( isset( $user_info[ 'first_name' ] ) && $user_info[ 'first_name' ] ) {
749 - $info .= "First Name : {$user_info['first_name']}<br>";
790 + $esc_first_name = esc_html( $user_info[ 'first_name' ] );
791 + $info .= "First Name : {$esc_first_name}<br>";
750 792 }
751 793 if ( isset( $user_info[ 'last_name' ] ) && $user_info[ 'last_name' ] ) {
752 - $info .= "Last Name : {$user_info['last_name']}<br>";
794 + $esc_last_name = esc_html( $user_info[ 'last_name' ] );
795 + $info .= "Last Name : {$esc_last_name}<br>";
753 796 }
754 797 if ( isset( $user_info[ 'email' ] ) && $user_info[ 'email' ] ) {
755 - $info .= "Email : {$user_info['email']}<br><br>";
798 + $esc_email = esc_html( $user_info[ 'email' ] );
799 + $info .= "Email : {$esc_email}<br><br>";
756 800 }
757 801 if ( isset( $user_info[ 'phone' ] ) && $user_info[ 'phone' ] ) {
758 - $info .= "Phone : {$user_info['phone']}<br><br>";
802 + $esc_phone = esc_html( $user_info[ 'phone' ] );
803 + $info .= "Phone : {$esc_phone}<br><br>";
759 804 }
760 805 if ( isset( $user_info[ 'web-url' ] ) && $user_info[ 'web-url' ] ) {
761 806 $esc_url = esc_url( $user_info[ 'web-url' ] );
762 807 $info .= "Website URL : {$esc_url}<br><br>";
@@ -782,8 +827,16 @@
782 827 /**
783 828 * Create User as a subscriber
784 829 * When allow the subscriber option for registration from builder
785 830 *
831 + * Registration is refused unless the site itself allows it. Every caller
832 + * routes through here - the Elementor and Gutenberg submission handlers as
833 + * well as the after_optin_submit callback - so the site-wide switch is
834 + * enforced at this one choke point rather than at each call site, and any
835 + * future caller inherits it. On multisite, core filters
836 + * option_users_can_register from the network registration setting, so this
837 + * is the correct check there too.
838 + *
786 839 * @param $name
787 840 * @param $post_data
788 841 *
789 842 * @since 2.5.9
@@ -788,8 +841,12 @@
788 841 *
789 842 * @since 2.5.9
790 843 */
791 844 public static function create_user_optin_allow_registration( $name, $post_data ) {
845 + if ( ! get_option( 'users_can_register' ) ) {
846 + return;
847 + }
848 +
792 849 $exist_user_by_username = get_user_by( 'login', $name );
793 850 $exist_user_by_email = get_user_by( 'email', $post_data[ 'email' ] );
794 851
795 852 if ( empty( $exist_user_by_email ) || empty( $exist_user_by_username ) ) {