From b9e0014d471df2dd2f83b91f2ca45316b5f1c615 Mon Sep 17 00:00:00 2001 From: Sapayth Hossain Date: Tue, 29 Oct 2024 13:14:50 +0600 Subject: [PATCH 1/4] toggle button styling and data save in settings --- Lib/WeDevs_Settings_API.php | 30 ++++++++++++ assets/css/admin.css | 44 ++++++++++++++++++ assets/css/admin/wpuf-module.css | 59 ------------------------ assets/less/admin.less | 53 +++++++++++++++++++++ includes/Admin/Plugin_Upgrade_Notice.php | 2 +- includes/functions/settings-options.php | 6 +++ 6 files changed, 134 insertions(+), 60 deletions(-) diff --git a/Lib/WeDevs_Settings_API.php b/Lib/WeDevs_Settings_API.php index 7a5cd9ad5..5a29b0c5f 100644 --- a/Lib/WeDevs_Settings_API.php +++ b/Lib/WeDevs_Settings_API.php @@ -460,6 +460,36 @@ function callback_color( $args ) { echo $html; } + /** + * Displays a toggle field for a settings field + * + * @param array $args settings field args + */ + public function callback_toggle( $args ) { + $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); + $disabled = ! empty( $args['is_pro_preview'] ) && $args['is_pro_preview'] ? 'disabled' : ''; + $name = $args['section'] . '[' . $args['id'] . ']'; + ?> +
+ +
+ =' ) ) { + if ( version_compare( WPUF_VERSION, $min_version, '>=' ) ) { return; } diff --git a/includes/functions/settings-options.php b/includes/functions/settings-options.php index 16d75bb82..753748a83 100644 --- a/includes/functions/settings-options.php +++ b/includes/functions/settings-options.php @@ -159,6 +159,12 @@ function wpuf_settings_fields() { 'desc' => __( 'Register here to get reCaptcha Site and Secret keys.', 'wp-user-frontend' ), ], + [ + 'name' => 'enable_turnstile', + 'label' => __( 'Enable Turnstile', 'wp-user-frontend' ), + 'type' => 'toggle', + 'default' => 'off', + ], [ 'name' => 'custom_css', 'label' => __( 'Custom CSS codes', 'wp-user-frontend' ), From 6b01a8c2c1c7ce0f35ee49c037eeff9dba24f143 Mon Sep 17 00:00:00 2001 From: Sapayth Hossain Date: Tue, 29 Oct 2024 16:09:33 +0600 Subject: [PATCH 2/4] show/hide dependent field conditionally --- Lib/WeDevs_Settings_API.php | 47 +++++++++++++++++++++++-- includes/functions/settings-options.php | 17 +++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/Lib/WeDevs_Settings_API.php b/Lib/WeDevs_Settings_API.php index 5a29b0c5f..90b8638f7 100644 --- a/Lib/WeDevs_Settings_API.php +++ b/Lib/WeDevs_Settings_API.php @@ -140,6 +140,7 @@ function admin_init() { 'max' => isset( $option['max'] ) ? $option['max'] : '', 'step' => isset( $option['step'] ) ? $option['step'] : '', 'is_pro_preview' => ! empty( $option['is_pro_preview'] ) ? $option['is_pro_preview'] : false, + 'depends_on' => ! empty( $option['depends_on'] ) ? $option['depends_on'] : '', ); add_settings_field( $section . '[' . $option['name'] . ']', $option['label'], (isset($option['callback']) ? $option['callback'] : array($this, 'callback_' . $type )), $section, $section, $args ); @@ -173,14 +174,17 @@ public function get_field_description( $args ) { * @param array $args settings field args */ function callback_text( $args ) { - $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); $size = isset( $args['size'] ) && !is_null( $args['size'] ) ? $args['size'] : 'regular'; $type = isset( $args['type'] ) ? $args['type'] : 'text'; $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"'; $disabled = ! empty( $args['is_pro_preview'] ) && $args['is_pro_preview'] ? 'disabled' : ''; + $depends_on = ! empty( $args['depends_on'] ) ? $args['depends_on'] : ''; - $html = sprintf( '', $type, $size, $args['section'], $args['id'], $value, $placeholder, $disabled ); + $html = sprintf( + '', + $type, $size, $args['section'], $args['id'], $value, $placeholder, $disabled, $depends_on + ); $html .= $this->get_field_description( $args ); if ( ! empty( $args['is_pro_preview'] ) && $args['is_pro_preview'] ) { @@ -703,6 +707,45 @@ function(){ // disable the pro preview checkboxes $('span.pro-icon-title').siblings('input[type="checkbox"]').prop('disabled', true); + + + var fields = $('table.form-table input, table.form-table select, table.form-table textarea'); + + // iterate over each field and check if it depends on another field + fields.each(function() { + var $this = $(this); + var data_depends_on = $this.data('depends-on'); + + if (!data_depends_on) { + return; + } + + var $depends_on = $("input[id*='"+ data_depends_on +"']"); + var $depends_on_type = $depends_on.attr('type'); + + if ($depends_on_type === 'checkbox') { + if ($depends_on.is(':checked')) { + $this.closest('tr').show(); + } else { + $this.closest('tr').hide(); + } + $depends_on.on('change', function() { + if ($(this).is(':checked')) { + $this.closest('tr').show(); + } else { + $this.closest('tr').hide(); + } + }); + } else { + $depends_on.on('keyup change', function() { + if ($(this).val() === $this.data('depends-on-value')) { + $this.closest('tr').show(); + } else { + $this.closest('tr').hide(); + } + }); + } + }); }); diff --git a/includes/functions/settings-options.php b/includes/functions/settings-options.php index 753748a83..b2915141e 100644 --- a/includes/functions/settings-options.php +++ b/includes/functions/settings-options.php @@ -165,6 +165,23 @@ function wpuf_settings_fields() { 'type' => 'toggle', 'default' => 'off', ], + [ + 'name' => 'turnstile_site_key', + 'label' => __( 'Turnstile Site Key', 'wp-user-frontend' ), + 'depends_on' => 'enable_turnstile', + ], + [ + 'name' => 'turnstile_secret_key', + 'label' => __( 'Turnstile Site Key', 'wp-user-frontend' ), + 'depends_on' => 'enable_turnstile', + 'desc' => sprintf( + // translators: %s is a link + __( + 'Register here to get Turnstile Site and Secret keys.', + 'wp-user-frontend' + ), esc_url( 'https://developers.cloudflare.com/turnstile/' ) + ), + ], [ 'name' => 'custom_css', 'label' => __( 'Custom CSS codes', 'wp-user-frontend' ), From 0dbd738ae68d0ab025b8168b4a88496ae3c21474 Mon Sep 17 00:00:00 2001 From: Sapayth Hossain Date: Wed, 30 Oct 2024 10:29:52 +0600 Subject: [PATCH 3/4] client side rendering and validation --- Lib/WeDevs_Settings_API.php | 32 +++++++++++++------------ includes/Assets.php | 5 +++- includes/Free/Simple_Login.php | 7 +++++- includes/functions/settings-options.php | 13 +++++++++- templates/login-form.php | 25 +++++++++++++++++-- 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/Lib/WeDevs_Settings_API.php b/Lib/WeDevs_Settings_API.php index 90b8638f7..eac841279 100644 --- a/Lib/WeDevs_Settings_API.php +++ b/Lib/WeDevs_Settings_API.php @@ -475,22 +475,24 @@ public function callback_toggle( $args ) { $name = $args['section'] . '[' . $args['id'] . ']'; ?>
- +
+ + '1.6.0', 'in_footer' => true, ], - 'admin-shortcode' => [ + 'admin-shortcode' => [ 'src' => WPUF_ASSET_URI . '/js/admin-shortcode.js', 'deps' => [ 'jquery' ], ], @@ -374,6 +374,9 @@ public function get_scripts() { 'headway' => [ 'src' => '//cdn.headwayapp.co/widget.js', ], + 'turnstile' => [ + 'src' => 'https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback', + ], ]; if ( ! empty( $api_key ) ) { diff --git a/includes/Free/Simple_Login.php b/includes/Free/Simple_Login.php index 200e7f638..d44f64ce0 100644 --- a/includes/Free/Simple_Login.php +++ b/includes/Free/Simple_Login.php @@ -339,7 +339,7 @@ public function login_form() { $reset = isset( $getdata['reset'] ) ? sanitize_text_field( $getdata['reset'] ) : ''; if ( false === $login_page ) { - return; + return ''; } ob_start(); @@ -394,6 +394,11 @@ public function login_form() { default: $loggedout = isset( $getdata['loggedout'] ) ? sanitize_text_field( $getdata['loggedout'] ) : ''; + $enable_turnstile = wpuf_get_option( 'enable_turnstile', 'wpuf_general', 'off' ); + + if ( 'on' === $enable_turnstile ) { + wp_enqueue_script( 'wpuf-turnstile' ); + } if ( $loggedout === 'true' ) { $this->messages[] = __( 'You are now logged out.', 'wp-user-frontend' ); diff --git a/includes/functions/settings-options.php b/includes/functions/settings-options.php index b2915141e..315862b35 100644 --- a/includes/functions/settings-options.php +++ b/includes/functions/settings-options.php @@ -172,7 +172,7 @@ function wpuf_settings_fields() { ], [ 'name' => 'turnstile_secret_key', - 'label' => __( 'Turnstile Site Key', 'wp-user-frontend' ), + 'label' => __( 'Turnstile Secret Key', 'wp-user-frontend' ), 'depends_on' => 'enable_turnstile', 'desc' => sprintf( // translators: %s is a link @@ -454,6 +454,17 @@ function wpuf_settings_fields() { 'type' => 'checkbox', 'default' => 'off', ], + [ + 'name' => 'login_form_turnstile', + 'label' => __( 'Turnstile in Login Form', 'wp-user-frontend' ), + 'desc' => __( + 'If enabled, users have to verify Cloudflare Turnstile in login page. Also, make sure that Turnstile is configured properly from General Options', + 'wp-user-frontend' + ), + 'type' => 'toggle', + 'default' => 'off', + 'depends_on' => 'enable_turnstile', + ], ] ), 'wpuf_payment' => apply_filters( 'wpuf_options_payment', [ [ diff --git a/templates/login-form.php b/templates/login-form.php index c23aaacb1..2b12921ea 100644 --- a/templates/login-form.php +++ b/templates/login-form.php @@ -30,8 +30,13 @@

- - + +

+ +
+ + +

From 89e7c2469dc2db1b0a3646449bfef04bdee8282d Mon Sep 17 00:00:00 2001 From: Sapayth Hossain Date: Wed, 30 Oct 2024 12:14:46 +0600 Subject: [PATCH 4/4] server side verification done --- assets/css/frontend-forms.css | 2 +- assets/less/frontend-forms.less | 2 +- includes/Free/Simple_Login.php | 71 ++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/assets/css/frontend-forms.css b/assets/css/frontend-forms.css index 0ff853676..39fb30fe9 100644 --- a/assets/css/frontend-forms.css +++ b/assets/css/frontend-forms.css @@ -84,7 +84,7 @@ body .wpuf-error { background-color: #f2dede; color: #a94442; border: 1px solid #ebccd1; - margin: 10px 10px 20px; + margin: 10px 0 20px 0; padding: 10px; -webkit-border-radius: 3px; -moz-border-radius: 3px; diff --git a/assets/less/frontend-forms.less b/assets/less/frontend-forms.less index 6954c3b8a..902907249 100644 --- a/assets/less/frontend-forms.less +++ b/assets/less/frontend-forms.less @@ -116,7 +116,7 @@ body { background-color: #f2dede; color: #a94442; border: 1px solid #ebccd1; - margin: 10px 10px 20px; + margin: 10px 0 20px 0; padding: 10px; .border-radius(3px); font-size: 13px; diff --git a/includes/Free/Simple_Login.php b/includes/Free/Simple_Login.php index d44f64ce0..2afac5da4 100644 --- a/includes/Free/Simple_Login.php +++ b/includes/Free/Simple_Login.php @@ -19,6 +19,13 @@ class Simple_Login { private $messages = []; + /** + * Cloudflare Turnstile messages + * + * @var array + */ + private $cf_messages = []; + private static $_instance; public function __construct() { @@ -415,6 +422,52 @@ public function login_form() { return ob_get_clean(); } + /** + * Verify if cloudflare turnstile request is successful + * + * @since WPUF_SINCE + * + * @return bool + */ + private function verify_cloudflare_turnstile_on_login() { + $nonce = isset( $_POST['wpuf-login-nonce'] ) ? sanitize_key( wp_unslash( $_POST['wpuf-login-nonce'] ) ) : ''; + + if ( isset( $nonce ) && ! wp_verify_nonce( $nonce, 'wpuf_login_action' ) ) { + return false; + } + + $secret = wpuf_get_option( 'turnstile_secret_key', 'wpuf_general', '' ); + + if ( empty( $secret ) ) { + return false; + } + + $remote_addr = ! empty( $_SERVER['REMOTE_ADDR'] ) ? sanitize_url( + wp_unslash( $_SERVER['REMOTE_ADDR'] ) + ) : ''; + + $cf_url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'; + $token = ! empty( $_POST['cf-turnstile-response'] ) ? sanitize_text_field( wp_unslash( $_POST['cf-turnstile-response'] ) ) : ''; + + // Request data + $data = [ + 'secret' => $secret, + 'response' => $token, + 'remoteip' => $remote_addr, + ]; + + $response = wp_remote_post( $cf_url, [ 'body' => $data ] ); + $body = json_decode( wp_remote_retrieve_body( $response ), true ); + + if ( ! empty( $body['success'] ) ) { + return true; + } else { + $this->cf_messages[] = ! empty( $body['error-codes'] ) ? $body['error-codes'] : ''; + + return false; + } + } + /** * Remove selected cookie to have consistency with the login nonce. * fixes WooCommerce Stripe Gateway plugin conflict @@ -452,10 +505,24 @@ public function process_login() { return; } - $log = isset( $_POST['log'] ) ? esc_attr( wp_unslash( $_POST['log'] ) ) : ''; - $pwd = isset( $_POST['pwd'] ) ? trim( $_POST['pwd'] ) : ''; + $log = isset( $_POST['log'] ) ? sanitize_text_field( wp_unslash( $_POST['log'] ) ) : ''; + $pwd = isset( $_POST['pwd'] ) ? sanitize_text_field( ( wp_unslash( $_POST['pwd'] ) ) ) : ''; // $g_recaptcha_response = isset( $_POST['g-recaptcha-response'] ) ? sanitize_text_field( wp_unslash( $_POST['g-recaptcha-response'] ) ) : ''; + if ( ! $this->verify_cloudflare_turnstile_on_login() ) { + $errors = ! empty( $this->cf_messages[0] ) ? $this->cf_messages[0] : ''; + $errors = implode( ', ', $errors ); + $this->login_errors[] = + sprintf( + // translators: %1$s and %2$s are strong tags, %3$s is the error message + __( '%1$sError%2$s: Cloudflare Turnstile verification failed. Reasons: [%3$s]', 'wp-user-frontend' ), + '', + '', + $errors + ); + '' . __( 'Error', 'wp-user-frontend' ) . ': ' . __( 'Cloudflare Turnstile verification failed. Reasons: [', 'wp-user-frontend' ); + } + $validation_error = new WP_Error(); $validation_error = apply_filters( 'wpuf_process_login_errors', $validation_error, $log, $pwd );