PluginProbe
Loginizer / trunk
Loginizer vtrunk
2.1.1 2.1.0 2.0.9 2.0.8 1.9.8 1.9.9 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 trunk 1.0 1.0.1 1.0.2 1.1.0 1.1.1 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 All 75 releases
← All changes | init.php +104 -116 2.0.3 → trunk View file →
@@ -4,9 +4,9 @@
4 4 echo 'You are not allowed to access this page directly.';
5 5 exit;
6 6 }
7 7
8 -define('LOGINIZER_VERSION', '2.0.3');
8 +define('LOGINIZER_VERSION', '2.1.1');
9 9 define('LOGINIZER_DIR', dirname(LOGINIZER_FILE));
10 10 define('LOGINIZER_URL', plugins_url('', LOGINIZER_FILE));
11 11 define('LOGINIZER_PRO_URL', 'https://loginizer.com/features#compare');
12 12 define('LOGINIZER_PRICING_URL', 'https://loginizer.com/pricing');
@@ -225,9 +225,9 @@
225 225 }
226 226
227 227 }
228 228
229 -// Add the action to load the plugin
229 +// Add the action to load the plugin
230 230 add_action('plugins_loaded', 'loginizer_load_plugin');
231 231
232 232 // The function that will be called when the plugin is loaded
233 233 function loginizer_load_plugin(){
@@ -235,8 +235,18 @@
235 235 global $loginizer;
236 236
237 237 // Check if the installed version is outdated
238 238 loginizer_update_check();
239 +
240 + // There was an issue were for some users update was stuck, and free was able to get updated through auto updater option
241 + // removing these filters fixes that issue, and our Pro update blocker was improved in 2.1.1
242 + // This check can be removed 1 year from 28.09.2026
243 + if(defined('LOGINIZER_PRO_VERSION') && version_compare(LOGINIZER_PRO_VERSION, '2.1.1', '<')){
244 + foreach(['site_transient_update_plugins', 'pre_site_transient_update_plugins'] as $hook){
245 + remove_filter($hook, 'loginizer_pro_disable_manual_update_for_plugin'); // Older Pro used the default priority
246 + remove_filter($hook, 'loginizer_pro_disable_manual_update_for_plugin', 99);
247 + }
248 + }
239 249
240 250 // Set the array
241 251 if(empty($loginizer)){
242 252 $loginizer = array();
@@ -332,21 +342,22 @@
332 342 // Is called before displaying the error message so that we dont show that the username is wrong or the password
333 343 // Update Error message
334 344 add_action('wp_login_errors', 'loginizer_error_handler', 10001, 2);
335 345 add_action('woocommerce_login_failed', 'loginizer_woocommerce_error_handler', 10001);
336 - add_action('wp_login', 'loginizer_login_success', 10, 2);
346 + add_action('wp_login', 'loginizer_login_success', 11, 2);
347 + add_action('rsssl_two_factor_user_authenticated', 'loginizer_rsssl_2fa_success');
337 348
338 349 if(!empty($loginizer['ultimate-member-active'])){
339 350 add_action('wp_login_failed', 'loginizer_ultimatemember_error_handler', 10001);
340 351 }
341 352
342 - if(!empty($_COOKIE['lz_social_error']) && !empty($loginizer['social_settings']) && !loginizer_is_blacklisted()){
353 + if(!empty($_COOKIE['lz_social_error']) && !empty($loginizer['social_settings'])){
343 354 add_filter('wp_login_errors', 'loginizer_social_login_error_handler', 10000, 2);
344 355 }
345 356 }
346 357
347 358 // Social Login Form Actions
348 - if(!empty($loginizer['social_settings']) && !loginizer_is_blacklisted()){
359 + if(!empty($loginizer['social_settings'])){
349 360 if(!empty($loginizer['social_settings']['login']['login_form'])){
350 361 add_action('login_form', 'loginizer_social_btn_login');
351 362 }
352 363 }
@@ -494,26 +505,31 @@
494 505
495 506 if(empty($blacklist)){
496 507 return false;
497 508 }
498 -
509 +
510 + $current_ip_inet = inet_ptoi($loginizer['current_ip']);
511 +
499 512 foreach($blacklist as $k => $v){
500 -
513 +
514 + $start_inet = inet_ptoi($v['start']);
515 + $end_inet = inet_ptoi($v['end']);
516 +
501 517 // Is the IP in the blacklist ?
502 - if(inet_ptoi($v['start']) <= inet_ptoi($loginizer['current_ip']) && inet_ptoi($loginizer['current_ip']) <= inet_ptoi($v['end'])){
518 + if($start_inet <= $current_ip_inet && $current_ip_inet <= $end_inet){
503 519 $result = 1;
504 520 break;
505 521 }
506 -
522 +
507 523 // Is it in a wider range ?
508 - if(inet_ptoi($v['start']) >= 0 && inet_ptoi($v['end']) < 0){
524 + if($start_inet >= 0 && $end_inet < 0){
509 525
510 526 // Since the end of the RANGE (i.e. current IP range) is beyond the +ve value of inet_ptoi,
511 527 // if the current IP is <= than the start of the range, it is within the range
512 528 // OR
513 529 // if the current IP is <= than the end of the range, it is within the range
514 - if(inet_ptoi($v['start']) <= inet_ptoi($loginizer['current_ip'])
515 - || inet_ptoi($loginizer['current_ip']) <= inet_ptoi($v['end'])){
530 + if($start_inet <= $current_ip_inet
531 + || $current_ip_inet <= $end_inet){
516 532 $result = 1;
517 533 break;
518 534 }
519 535
@@ -519,9 +535,9 @@
519 535
520 536 }
521 537
522 538 }
523 -
539 +
524 540 // You are blacklisted
525 541 if(!empty($result)){
526 542 $lz_error['ip_blacklisted'] = $loginizer['msg']['ip_blacklisted'];
527 543 return true;
@@ -530,52 +546,8 @@
530 546 return false;
531 547
532 548 }
533 549
534 -function loginizer_is_whitelisted(){
535 -
536 - global $wpdb, $loginizer, $lz_error;
537 -
538 - $whitelist = $loginizer['whitelist'];
539 -
540 - if(empty($whitelist)){
541 - return false;
542 - }
543 -
544 - foreach($whitelist as $k => $v){
545 -
546 - // Is the IP in the blacklist ?
547 - if(inet_ptoi($v['start']) <= inet_ptoi($loginizer['current_ip']) && inet_ptoi($loginizer['current_ip']) <= inet_ptoi($v['end'])){
548 - $result = 1;
549 - break;
550 - }
551 -
552 - // Is it in a wider range ?
553 - if(inet_ptoi($v['start']) >= 0 && inet_ptoi($v['end']) < 0){
554 -
555 - // Since the end of the RANGE (i.e. current IP range) is beyond the +ve value of inet_ptoi,
556 - // if the current IP is <= than the start of the range, it is within the range
557 - // OR
558 - // if the current IP is <= than the end of the range, it is within the range
559 - if(inet_ptoi($v['start']) <= inet_ptoi($loginizer['current_ip'])
560 - || inet_ptoi($loginizer['current_ip']) <= inet_ptoi($v['end'])){
561 - $result = 1;
562 - break;
563 - }
564 -
565 - }
566 -
567 - }
568 -
569 - // You are whitelisted
570 - if(!empty($result)){
571 - return true;
572 - }
573 -
574 - return false;
575 -
576 -}
577 -
578 550 // When the login fails, then this is called
579 551 // We need to update the database
580 552 function loginizer_login_failed($username, $is_2fa = ''){
581 553
@@ -594,53 +566,78 @@
594 566
595 567 if(empty($lz_cannot_login) && empty($loginizer['ip_is_whitelisted']) && empty($loginizer['no_loginizer_logs'])){
596 568
597 569 // The params which comes when social login returns an error, have some characters, which WordPress could not save.
598 - $server_uri = $_SERVER['REQUEST_URI'];
599 - if(!empty($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], 'lz_social_provider') !== FALSE){
600 - $request_uri = explode('=', $_SERVER['REQUEST_URI']);
570 + // REQUEST_URI / HTTP_HOST are not always set (WP-CLI, some CGI and XML-RPC setups)
571 + $server_uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
572 + $http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
573 +
574 + if(!empty($server_uri) && strpos($server_uri, 'lz_social_provider') !== FALSE){
575 + $request_uri = explode('=', $server_uri);
601 576 $server_uri = $request_uri[0];
602 577 }
603 578
604 - $url = @addslashes((!empty($_SERVER['HTTPS']) ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].$server_uri);
605 - $url = esc_url($url);
579 + // No addslashes() here, $wpdb->prepare() below does the escaping
580 + $url = esc_url((!empty($_SERVER['HTTPS']) ? 'https://' : 'http://').$http_host.$server_uri);
606 581
582 + // Must never be 0, we divide by it below
583 + $max_retries = (int) $loginizer['max_retries'] < 1 ? 1 : (int) $loginizer['max_retries'];
584 +
585 + // This way is atomic now, the earlier one were causing race condition.
586 + // NOTE : In the UPDATE part `count` is already the new value, as MySQL / MariaDB
587 + // evaluate the assignments from left to right, so lockout must NOT add 1 again
588 + $upsert = $wpdb->prepare(
589 + "INSERT INTO `".$wpdb->prefix."loginizer_logs`
590 + (username, time, count, ip, lockout, url)
591 + VALUES
592 + (%s, %d, 1, %s, FLOOR(1 / %d), %s)
593 + ON DUPLICATE KEY UPDATE
594 + username = VALUES(username),
595 + time = VALUES(time),
596 + count = count + 1,
597 + lockout = FLOOR(count / %d),
598 + url = VALUES(url)",
599 + $username,
600 + time(),
601 + $loginizer['current_ip'],
602 + $max_retries,
603 + $url,
604 + $max_retries
605 + );
606 + $wpdb->query($upsert);
607 +
608 + // Re-read the persisted row so email/retries-left reflect the actual count
607 609 $sel_query = $wpdb->prepare("SELECT * FROM `".$wpdb->prefix."loginizer_logs` WHERE `ip` = %s", $loginizer['current_ip']);
608 610 $result = lz_selectquery($sel_query);
609 -
610 - if(!empty($result)){
611 - $lockout = floor((($result['count']+1) / $loginizer['max_retries']));
612 -
613 - $update_data = array('username' => $username,
614 - 'time' => time(),
615 - 'count' => $result['count']+1,
616 - 'lockout' => $lockout,
617 - 'url' => $url);
618 -
619 - $where_data = array('ip' => $loginizer['current_ip']);
620 -
621 - $format = array('%s','%d','%d','%d','%s');
622 - $where_format = array('%s');
623 -
624 - $wpdb->update($wpdb->prefix.'loginizer_logs', $update_data, $where_data, $format, $where_format);
625 -
626 - // Do we need to email admin ?
627 - if(!empty($loginizer['notify_email']) && $lockout >= $loginizer['notify_email']){
628 -
629 - $lockout_time = $loginizer['lockout_time'];
630 -
631 - if($lockout >= $loginizer['max_lockouts']){
632 - // extended lockout is in hours so we have to convert to minute
633 - $lockout_time = $loginizer['lockouts_extend'];
634 - }
635 -
636 - $sitename = lz_is_multisite() ? get_site_option('site_name') : get_option('blogname');
637 - $mail = array();
638 - $mail['to'] = $loginizer['notify_email_address'];
639 - $mail['subject'] = 'Failed '.$fail_type.' Attempts from IP '.$loginizer['current_ip'].' ('.$sitename.')';
640 - $mail['message'] = 'Hi,
641 611
642 -'.($result['count']+1).' failed '.strtolower($fail_type).' attempts and '.$lockout.' lockout(s) from IP '.$loginizer['current_ip'].' on your site :
612 + if(empty($result)){
613 + $result = array('count' => 0);
614 + }
615 +
616 + $count = (int) $result['count'];
617 + $lockout = !empty($result['lockout']) ? (int) $result['lockout'] : 0;
618 +
619 + // The lockout goes up only on every max_retries'th failure, which is the
620 + // attempt that actually locks the IP out. On the failures in between there
621 + // is nothing new to report, so we must not email on each one of them
622 + $is_new_lockout = !empty($count) && ($count % $max_retries) == 0;
623 +
624 + // Do we need to email admin ?
625 + if(!empty($loginizer['notify_email']) && !empty($is_new_lockout) && $lockout >= $loginizer['notify_email']){
626 +
627 + $lockout_time = $loginizer['lockout_time'];
628 +
629 + if($lockout >= $loginizer['max_lockouts']){
630 + $lockout_time = $loginizer['lockouts_extend'];
631 + }
632 +
633 + $sitename = lz_is_multisite() ? get_site_option('site_name') : get_option('blogname');
634 + $mail = array();
635 + $mail['to'] = $loginizer['notify_email_address'];
636 + $mail['subject'] = 'Failed '.$fail_type.' Attempts from IP '.$loginizer['current_ip'].' ('.$sitename.')';
637 + $mail['message'] = 'Hi,
638 +
639 +'.(int) $result['count'].' failed '.strtolower($fail_type).' attempts and '.$lockout.' lockout(s) from IP '.$loginizer['current_ip'].' on your site :
643 640 '.home_url().'
644 641
645 642 Last '.$fail_type.' Attempt : '.date('d/M/Y H:i:s P', time()).'
646 643 Last User Attempt : '.$username.'
@@ -648,35 +645,22 @@
648 645
649 646 Regards,
650 647 Loginizer';
651 648
652 - @wp_mail($mail['to'], $mail['subject'], $mail['message']);
653 - }
654 - }else{
655 - $result = array();
656 - $result['count'] = 0;
657 -
658 - $insert_data = array('username' => $username,
659 - 'time' => time(),
660 - 'count' => 1,
661 - 'ip' => $loginizer['current_ip'],
662 - 'lockout' => 0,
663 - 'url' => $url);
664 -
665 - $format = array('%s','%d','%d','%s','%d','%s');
666 -
667 - $wpdb->insert($wpdb->prefix.'loginizer_logs', $insert_data, $format);
649 + @wp_mail($mail['to'], $mail['subject'], $mail['message']);
668 650 }
669 -
670 - // We need to add one as this is a failed attempt as well
671 - $result['count'] = $result['count'] + 1;
651 +
672 652 loginizer_update_attempt_stats(0);
673 - $loginizer['retries_left'] = ($loginizer['max_retries'] - ($result['count'] % $loginizer['max_retries']));
674 - $loginizer['retries_left'] = $loginizer['retries_left'] == $loginizer['max_retries'] ? 0 : $loginizer['retries_left'];
653 + $loginizer['retries_left'] = $max_retries - ($count % $max_retries);
654 + $loginizer['retries_left'] = $loginizer['retries_left'] == $max_retries ? 0 : $loginizer['retries_left'];
675 655
676 656 }
677 657 }
678 658
659 +function loginizer_rsssl_2fa_success($user){
660 + loginizer_login_success('', $user);
661 +}
662 +
679 663 function loginizer_login_success($user_login, $user) {
680 664 global $wp_version, $loginizer;
681 665
682 666 loginizer_update_attempt_stats(1);
@@ -840,8 +824,12 @@
840 824
841 825 // Handles social login URL
842 826 function loginizer_social_login_error_handler($errors = '', $redirect_to = ''){
843 827 global $loginizer;
828 +
829 + if(loginizer_is_blacklisted()){
830 + return $errors;
831 + }
844 832
845 833 loginizer_get_social_error();
846 834
847 835 if(empty($loginizer['social_errors'])){