| @@ -479,8 +479,9 @@ | ||
| 479 | 479 | |
| 480 | 480 | if ( ( 'wppb-epf-cpt' == $post_type ) || ( 'wppb-rf-cpt' == $post_type ) || ( 'wppb-ul-cpt' == $post_type ) ){ |
| 481 | 481 | wp_enqueue_style( 'wppb-back-end-style', WPPB_PLUGIN_URL . 'assets/css/style-back-end.css', false, PROFILE_BUILDER_VERSION ); |
| 482 | 482 | wp_enqueue_script( 'wppb-epf-rf', WPPB_PLUGIN_URL . 'assets/js/jquery-epf-rf.js', array(), PROFILE_BUILDER_VERSION, true ); |
| 483 | + wp_localize_script( 'wppb-epf-rf', 'wppbEpfRf', array( 'nonce' => wp_create_nonce( 'wppb-epf-rf-id-change' ) ) ); | |
| 483 | 484 | } |
| 484 | 485 | else if( 'wppb-roles-editor' == $post_type ){ |
| 485 | 486 | wp_enqueue_style( 'wppb-back-end-style', WPPB_PLUGIN_URL . 'assets/css/style-back-end.css', array(), PROFILE_BUILDER_VERSION ); |
| 486 | 487 | } |
| @@ -839,8 +840,22 @@ | ||
| 839 | 840 | return apply_filters( 'wppb_user_meta_exists_meta_name', $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $id, $meta_name ) ), $id, $meta_name ); |
| 840 | 841 | } |
| 841 | 842 | |
| 842 | 843 | |
| 844 | +/** | |
| 845 | + * Sanitize a URL from request input. Non-string values (e.g. arrays from bracket notation) return ''. | |
| 846 | + * | |
| 847 | + * @param mixed $url Candidate URL. | |
| 848 | + * @return string | |
| 849 | + */ | |
| 850 | +function wppb_sanitize_request_url( $url ) { | |
| 851 | + if ( ! is_string( $url ) || $url === '' ) { | |
| 852 | + return ''; | |
| 853 | + } | |
| 854 | + | |
| 855 | + return esc_url_raw( wp_unslash( $url ) ); | |
| 856 | +} | |
| 857 | + | |
| 843 | 858 | // function to check if there is a need to add the http:// prefix |
| 844 | 859 | function wppb_check_missing_http( $redirectLink ) { |
| 845 | 860 | return preg_match( '#^(?:[a-z\d]+(?:-+[a-z\d]+)*\.)+[a-z]+(?::\d+)?(?:/|$)#i', $redirectLink ); |
| 846 | 861 | } |
| @@ -1119,8 +1134,52 @@ | ||
| 1119 | 1134 | |
| 1120 | 1135 | return ''; |
| 1121 | 1136 | } |
| 1122 | 1137 | |
| 1138 | + | |
| 1139 | +/** | |
| 1140 | + * Returns the AJAX actions that check the login/checkout credentials before the real form submission is sent. | |
| 1141 | + * | |
| 1142 | + * Those requests run the whole authentication stack, so our CAPTCHA check runs too and the token gets spent | |
| 1143 | + * with the CAPTCHA provider, but they never log the user in - the browser still submits the form afterwards | |
| 1144 | + * with the very same token. CAPTCHA tokens are single use, so verifying one a second time comes back as a | |
| 1145 | + * duplicate and the login fails. For these actions we remember the successful verification and reuse it once, | |
| 1146 | + * when the actual form submission arrives. | |
| 1147 | + */ | |
| 1148 | +function wppb_get_captcha_prevalidation_actions() { | |
| 1149 | + return apply_filters( 'wppb_captcha_prevalidation_actions', array( | |
| 1150 | + 'pms_validate_checkout', // Paid Member Subscriptions checkout validation | |
| 1151 | + 'wordfence_ls_authenticate', // Wordfence Login Security login pre-flight, used to decide if it needs to ask for a 2FA code | |
| 1152 | + ) ); | |
| 1153 | +} | |
| 1154 | + | |
| 1155 | +/* Whether the current request is one of the CAPTCHA pre-validation AJAX calls above */ | |
| 1156 | +function wppb_is_captcha_prevalidation_request() { | |
| 1157 | + if ( ! wp_doing_ajax() || empty( $_POST['action'] ) || ! is_string( $_POST['action'] ) ) /* phpcs:ignore WordPress.Security.NonceVerification.Missing */ | |
| 1158 | + return false; | |
| 1159 | + | |
| 1160 | + return in_array( sanitize_text_field( $_POST['action'] ), wppb_get_captcha_prevalidation_actions(), true ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing */ | |
| 1161 | +} | |
| 1162 | + | |
| 1163 | +/** | |
| 1164 | + * Drops pre-validated CAPTCHA tokens that were never claimed by a form submission. | |
| 1165 | + * | |
| 1166 | + * A pre-validation that is not followed by a submission (wrong password, abandoned login, bots) leaves its | |
| 1167 | + * entry behind, so without this the option would keep growing on sites where every login is pre-validated. | |
| 1168 | + */ | |
| 1169 | +function wppb_prune_captcha_prevalidations( $saved ) { | |
| 1170 | + if ( ! is_array( $saved ) ) | |
| 1171 | + return array(); | |
| 1172 | + | |
| 1173 | + $lifetime = apply_filters( 'wppb_captcha_prevalidation_lifetime', 15 * MINUTE_IN_SECONDS ); | |
| 1174 | + | |
| 1175 | + foreach ( $saved as $token => $validated_at ) { | |
| 1176 | + if ( ! is_int( $validated_at ) || ( time() - $validated_at ) > $lifetime ) | |
| 1177 | + unset( $saved[ $token ] ); | |
| 1178 | + } | |
| 1179 | + | |
| 1180 | + return $saved; | |
| 1181 | +} | |
| 1123 | 1182 | |
| 1124 | 1183 | /* Function for displaying reCAPTCHA error on Login and Recover Password forms */ |
| 1125 | 1184 | function wppb_recaptcha_field_error($field_title='') { |
| 1126 | 1185 | |