PluginProbe
Patchstack – WordPress & Plugins Security / 2.3.1
Patchstack – WordPress & Plugins Security v2.3.1
2.3.7 trunk 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.17 2.1.18 2.1.19 2.1.2 2.1.20 2.1.21 2.1.22 2.1.23 2.1.24 2.1.25 2.1.3 2.1.4 2.1.5 2.1.6 All 49 releases
← All changes | includes/login.php +59 -31 trunk2.3.1 View file →
@@ -10,15 +10,8 @@
10 10 */
11 11 class P_Login extends P_Core {
12 12
13 13 /**
14 - * Validated request or not.
15 - *
16 - * @param boolean
17 - */
18 - private $validated = false;
19 -
20 - /**
21 14 * Add the actions required to interact with the login process.
22 15 *
23 16 * @param Patchstack $core
24 17 * @return void
@@ -31,8 +24,9 @@
31 24 }
32 25
33 26 add_action( 'login_init', [ $this, 'add_captcha' ] );
34 27 add_action( 'login_init', [ $this, 'check_ipban' ] );
28 + add_action( 'login_init', [ $this, 'check_logonhours' ] );
35 29 add_action( 'login_head', [ $this, 'add_captcha' ] );
36 30 add_action( 'login_enqueue_scripts', [ $this, 'login_enqueue_scripts' ], 1 );
37 31
38 32 // WooCommerce related functionality.
@@ -39,9 +33,11 @@
39 33 if ( class_exists( 'WooCommerce' ) ) {
40 34 add_action( 'woocommerce_login_form_start', [ $this, 'add_captcha' ] );
41 35 add_action( 'woocommerce_register_form_start', [ $this, 'add_captcha' ] );
42 36 add_action( 'wp_authenticate', [ $this, 'add_captcha' ] );
37 + add_filter( 'woocommerce_process_registration_errors', [$this, 'general_captcha_check' ], 10, 1 );
43 38 add_action( 'woocommerce_before_lost_password_form', [ $this, 'add_captcha' ] );
39 + add_action( 'lostpassword_post', [ $this, 'general_captcha_check' ], 1, 1 );
44 40 }
45 41
46 42 // 2FA related actions.
47 43 if ( $this->get_option( 'patchstack_login_2fa', 0 ) ) {
@@ -174,10 +170,9 @@
174 170
175 171 // Verify the code.
176 172 require_once dirname( __FILE__ ) . '/2fa/rfc6238.php';
177 173 $secret = $this->tfa_get_secret( $user );
178 - $code = isset( $_POST['patchstack_2fa_secretkey_verification'] ) ? trim( $_POST['patchstack_2fa_secretkey_verification'] ) : '';
179 - if ( ! TokenAuth6238::verify( $secret, $code ) ) {
174 + if ( ! TokenAuth6238::verify( $secret, trim( $_POST['patchstack_2fa_secretkey_verification'] ) ) ) {
180 175 wc_add_notice( __( 'The 2FA authentication code you entered is invalid.', 'patchstack' ), 'error' );
181 176 return;
182 177 }
183 178
@@ -285,8 +280,63 @@
285 280 }
286 281 }
287 282
288 283 /**
284 + * If logon hours are set, check the current time and allow or disallow the user
285 + * to login depending on the settings.
286 + *
287 + * @return void
288 + */
289 + public function check_logonhours() {
290 + if ( ! $this->get_option( 'patchstack_login_time_block', 0 ) || is_user_logged_in() || $this->get_option( 'patchstack_login_time_start', '00:00' ) == $this->get_option( 'patchstack_login_time_end', '23:59' ) ) {
291 + return;
292 + }
293 + $block = true;
294 +
295 + // Current time.
296 + $hour = current_time( 'G' );
297 + $min = current_time( 'i' );
298 + $stamp_current = current_time( 'U' );
299 +
300 + // Get time start.
301 + $start = explode( ':', str_replace( '00', '0', $this->get_option( 'patchstack_login_time_start', '00:00' ) ) );
302 + if ( count( $start ) != 2 ) {
303 + return;
304 + }
305 + $stamp_start = strtotime( current_time( 'Y-m-d' ) . ' ' . $this->get_option( 'patchstack_login_time_start', '00:00' ) . ':00' );
306 + $start[0] = (int) $start[0];
307 + $start[1] = (int) $start[1];
308 +
309 + // Get time end.
310 + $end = explode( ':', str_replace( '00', '0', $this->get_option( 'patchstack_login_time_end', '23:59' ) ) );
311 + if ( count( $end ) != 2 ) {
312 + return;
313 + }
314 + $stamp_end = strtotime( current_time( 'Y-m-d' ) . ' ' . $this->get_option( 'patchstack_login_time_end', '00:00' ) . ':00' );
315 + $end[0] = (int) $end[0];
316 + $end[1] = (int) $end[1];
317 +
318 + // If begin time is earlier than end time.
319 + if ( $start[0] <= $end[0] && $stamp_current >= $stamp_start && $stamp_current <= $stamp_end ) {
320 + $block = false;
321 + }
322 +
323 + // If begin time is later than end time.
324 + if ( $start[0] > $end[0] && ( $hour >= $start[0] || $hour <= $end[0] ) ) {
325 + $block = false;
326 +
327 + if ( ( $hour == $start[0] && $min < $start[1] ) || ( $hour == $end[0] && $min > $end[1] ) ) {
328 + $block = true;
329 + }
330 + }
331 +
332 + // Block the user?
333 + if ( $block ) {
334 + wp_die( esc_attr__( 'Access to the login page has been restricted due to set logon hours.', 'patchstack' ), esc_attr__( 'Login Disallowed', 'patchstack' ) );
335 + }
336 + }
337 +
338 + /**
289 339 * Determine if we should inject reCAPTCHA into certain pages.
290 340 *
291 341 * @return void
292 342 */
@@ -329,9 +379,8 @@
329 379 if ( $this->get_option( 'patchstack_captcha_registration_form' ) ) {
330 380 add_action( 'register_form', [ $this->plugin->hardening, 'captcha_display' ] );
331 381 add_action( 'woocommerce_register_form', [ $this->plugin->hardening, 'captcha_display' ] );
332 382 add_action( 'registration_errors', [ $this, 'general_captcha_check' ] );
333 - add_filter( 'woocommerce_process_registration_errors', [$this, 'general_captcha_check' ], 10, 1 );
334 383 }
335 384
336 385 // reCAPTCHA on the reset password form.
337 386 if ( $this->get_option( 'patchstack_captcha_reset_pwd_form' ) ) {
@@ -337,13 +386,8 @@
337 386 if ( $this->get_option( 'patchstack_captcha_reset_pwd_form' ) ) {
338 387 add_action( 'lostpassword_form', [ $this->plugin->hardening, 'captcha_display' ] );
339 388 add_action( 'woocommerce_lostpassword_form', [ $this->plugin->hardening, 'captcha_display' ] );
340 389 add_action( 'allow_password_reset', [ $this, 'general_captcha_check' ] );
341 -
342 - // WooCommerce only.
343 - if ( class_exists( 'WooCommerce' ) ) {
344 - add_action( 'lostpassword_post', [ $this, 'general_captcha_check' ], 1, 1 );
345 - }
346 390 }
347 391 }
348 392
349 393 /**
@@ -353,17 +397,12 @@
353 397 * @param string $password
354 398 * @return WP_User|WP_Error
355 399 */
356 400 public function login_captcha_check( $user, $password ) {
357 - if ( $this->validated ) {
358 - return $user;
359 - }
360 -
361 401 $result = $this->plugin->hardening->captcha_check();
362 402
363 403 if ( ! $result['response'] ) {
364 404 if ( $result['reason'] === 'ERROR_NO_KEYS' ) {
365 - $this->validated = true;
366 405 return $user;
367 406 }
368 407 $error_message = sprintf( '<strong>%s</strong>: %s', 'Error', esc_attr__( 'You have entered an incorrect reCAPTCHA value.', 'patchstack' ) );
369 408
@@ -375,9 +414,8 @@
375 414 if ( isset( $_REQUEST['log'], $_REQUEST['pwd'] ) ) {
376 415 return new WP_Error( 'patchstack_error', $error_message );
377 416 }
378 417 } else {
379 - $this->validated = true;
380 418 return $user;
381 419 }
382 420 }
383 421
@@ -388,16 +426,11 @@
388 426 * @param string $password
389 427 * @return WP_User|WP_Error
390 428 */
391 429 public function login_captcha_check_woocommerce( $error, $username, $password, $email ) {
392 - if ( $this->validated ) {
393 - return $error;
394 - }
395 -
396 430 $result = $this->plugin->hardening->captcha_check();
397 431
398 432 if ( $result['response'] || $result['reason'] == 'ERROR_NO_KEYS' ) {
399 - $this->validated = true;
400 433 return $error;
401 434 }
402 435
403 436 if ( ! is_wp_error( $error ) ) {
@@ -414,16 +447,11 @@
414 447 * @param mixed|WP_Error $error
415 448 * @return WP_Error
416 449 */
417 450 public function general_captcha_check( $error ) {
418 - if ( $this->validated ) {
419 - return $error;
420 - }
421 -
422 451 $result = $this->plugin->hardening->captcha_check();
423 452
424 453 if ( $result['response'] || $result['reason'] == 'ERROR_NO_KEYS' ) {
425 - $this->validated = true;
426 454 return $error;
427 455 }
428 456
429 457 if ( ! is_wp_error( $error ) ) {