Limit Login Attempts Reloaded - Version 2.21.0

Version Description

  • GDPR compliance: IPs obfuscation replaced with a customizable consent message on the login page.
  • Cloud API: fixed removing of blocked IPs from the access lists under certain conditions.
  • Cloud API: domain for Setup Code is taken from the WordPress settings now.
Download this release

Release Info

Developer wpchefgadget
Plugin Icon 128x128 Limit Login Attempts Reloaded
Version 2.21.0
Comparing to
See all releases

Code changes from version 2.20.6 to 2.21.0

assets/css/login-page-styles.css ADDED
@@ -0,0 +1 @@
 
1
+ #llar-login-page-gdpr{position:fixed;padding:15px;background-color:rgba(0,0,0,0.9);width:100%;bottom:0;left:0;right:0;color:#fff;display:block;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box}#llar-login-page-gdpr .llar-login-page-gdpr__message{font-size:14px;color:#fff}
assets/sass/login-page-styles.scss ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #llar-login-page-gdpr {
2
+ position: fixed;
3
+ padding: 15px;
4
+ background-color: rgba(#000,0.9);
5
+ width: 100%;
6
+ bottom: 0;
7
+ left: 0;
8
+ right: 0;
9
+ color: #fff;
10
+ display: block;
11
+ text-align: center;
12
+ box-sizing: border-box;
13
+
14
+ .llar-login-page-gdpr__message {
15
+ font-size: 14px;
16
+ color: #fff;
17
+ }
18
+ }
core/App.php CHANGED
@@ -92,7 +92,9 @@ class LLAR_App {
92
  }
93
 
94
  $link = 'https://' . $link;
95
- $link = add_query_arg( 'domain', $_SERVER['SERVER_NAME'], $link );
 
 
96
 
97
  $plugin_data = get_plugin_data( LLA_PLUGIN_DIR . '/limit-login-attempts-reloaded.php' );
98
  $link = add_query_arg( 'version', $plugin_data['Version'], $link );
92
  }
93
 
94
  $link = 'https://' . $link;
95
+
96
+ $domain = parse_url( home_url( '/' ) );
97
+ $link = add_query_arg( 'domain', $domain['host'], $link );
98
 
99
  $plugin_data = get_plugin_data( LLA_PLUGIN_DIR . '/limit-login-attempts-reloaded.php' );
100
  $link = add_query_arg( 'version', $plugin_data['Version'], $link );
core/LimitLoginAttempts.php CHANGED
@@ -7,6 +7,7 @@ class Limit_Login_Attempts {
7
 
8
  public $default_options = array(
9
  'gdpr' => 0,
 
10
 
11
  /* Are we behind a proxy? */
12
  'client_type' => LLA_DIRECT_ADDR,
@@ -85,6 +86,9 @@ class Limit_Login_Attempts {
85
  public $app = null;
86
 
87
  public function __construct() {
 
 
 
88
  $this->hooks_init();
89
  $this->app_init();
90
  }
@@ -95,6 +99,7 @@ class Limit_Login_Attempts {
95
  public function hooks_init() {
96
  add_action( 'plugins_loaded', array( $this, 'setup' ), 9999 );
97
  add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) );
 
98
  add_filter( 'limit_login_whitelist_ip', array( $this, 'check_whitelist_ips' ), 10, 2 );
99
  add_filter( 'limit_login_whitelist_usernames', array( $this, 'check_whitelist_usernames' ), 10, 2 );
100
  add_filter( 'limit_login_blacklist_ip', array( $this, 'check_blacklist_ips' ), 10, 2 );
@@ -124,6 +129,8 @@ class Limit_Login_Attempts {
124
  add_action( 'admin_init', array( $this, 'welcome_page_redirect' ), 9999 );
125
  add_action( 'admin_head', array( $this, 'welcome_page_hide_menu' ) );
126
 
 
 
127
  register_activation_hook( LLA_PLUGIN_FILE, array( $this, 'activation' ) );
128
  }
129
 
@@ -235,6 +242,17 @@ class Limit_Login_Attempts {
235
  add_filter( 'plugin_action_links_' . LLA_PLUGIN_BASENAME, array( $this, 'add_action_links' ) );
236
  }
237
 
 
 
 
 
 
 
 
 
 
 
 
238
  public function add_action_links( $actions ) {
239
 
240
  $actions = array_merge( array(
@@ -541,6 +559,13 @@ class Limit_Login_Attempts {
541
 
542
  }
543
 
 
 
 
 
 
 
 
544
  /**
545
  * Add admin options page
546
  */
@@ -702,12 +727,7 @@ class Limit_Login_Attempts {
702
  /* lockout active? */
703
  $lockouts = $this->get_option( 'lockouts' );
704
 
705
- $a = $this->checkKey($lockouts, $ip);
706
- $b = $this->checkKey($lockouts, $this->getHash($ip));
707
- return (
708
- ! is_array( $lockouts ) ||
709
- (! isset( $lockouts[ $ip ] ) && ! isset( $lockouts[ $this->getHash($ip) ] )) ||
710
- (time() >= $a && time() >= $b ));
711
  }
712
 
713
  /**
@@ -755,7 +775,6 @@ class Limit_Login_Attempts {
755
  } else {
756
 
757
  $ip = $this->get_address();
758
- $ipHash = $this->getHash($this->get_address());
759
 
760
  /* if currently locked-out, do not add to retries */
761
  $lockouts = $this->get_option( 'lockouts' );
@@ -764,7 +783,7 @@ class Limit_Login_Attempts {
764
  $lockouts = array();
765
  }
766
 
767
- if ( (isset( $lockouts[ $ip ] ) && time() < $lockouts[ $ip ]) || (isset( $lockouts[ $ipHash ] ) && time() < $lockouts[ $ipHash ] )) {
768
  return;
769
  }
770
 
@@ -798,8 +817,6 @@ class Limit_Login_Attempts {
798
  }
799
  $this->update_option( 'retries_stats', $retries_stats );
800
 
801
- $gdpr = $this->get_option('gdpr');
802
- $ip = ($gdpr ? $ipHash : $ip);
803
  /* Check validity and add one to retries */
804
  if ( isset( $retries[ $ip ] ) && isset( $valid[ $ip ] ) && time() < $valid[ $ip ]) {
805
  $retries[ $ip ] ++;
@@ -835,18 +852,16 @@ class Limit_Login_Attempts {
835
  } else {
836
  global $limit_login_just_lockedout;
837
  $limit_login_just_lockedout = true;
838
- $gdpr = $this->get_option('gdpr');
839
- $index = ($gdpr ? $ipHash : $ip);
840
 
841
  /* setup lockout, reset retries as needed */
842
- if ( (isset($retries[ $ip ]) ? $retries[ $ip ] : 0) >= $retries_long || (isset($retries[ $ipHash ]) ? $retries[ $ipHash ] : 0) >= $retries_long ) {
843
  /* long lockout */
844
- $lockouts[ $index ] = time() + $this->get_option( 'long_duration' );
845
- unset( $retries[ $index ] );
846
- unset( $valid[ $index ] );
847
  } else {
848
  /* normal lockout */
849
- $lockouts[ $index ] = time() + $this->get_option( 'lockout_duration' );
850
  }
851
  }
852
 
@@ -906,15 +921,15 @@ class Limit_Login_Attempts {
906
  }
907
 
908
  /* check if we are at the right nr to do notification */
909
- if (
910
- (isset( $retries[ $ip ] ) || isset( $retries[ $this->getHash($ip) ] ))
911
  &&
912
- ( ( intval($retries[ $ip ] + $retries[ $this->getHash($ip) ]) / $this->get_option( 'allowed_retries' ) ) % $this->get_option( 'notify_email_after' ) ) != 0 ) {
 
913
  return;
914
  }
915
 
916
  /* Format message. First current lockout duration */
917
- if ( !isset( $retries[ $ip ] ) && !isset( $retries[ $this->getHash($ip) ] ) ) {
918
  /* longer lockout */
919
  $count = $this->get_option( 'allowed_retries' )
920
  * $this->get_option( 'allowed_lockouts' );
@@ -923,7 +938,7 @@ class Limit_Login_Attempts {
923
  $when = sprintf( _n( '%d hour', '%d hours', $time, 'limit-login-attempts-reloaded' ), $time );
924
  } else {
925
  /* normal lockout */
926
- $count = $retries[ $ip ] + $retries[ $this->getHash($ip) ];
927
  $lockouts = floor( ($count) / $this->get_option( 'allowed_retries' ) );
928
  $time = round( $this->get_option( 'lockout_duration' ) / 60 );
929
  $when = sprintf( _n( '%d minute', '%d minutes', $time, 'limit-login-attempts-reloaded' ), $time );
@@ -1010,23 +1025,22 @@ class Limit_Login_Attempts {
1010
  }
1011
  $ip = $this->get_address();
1012
 
1013
- $index = ($this->get_option('gdpr') ? $this->getHash($ip) : $ip );
1014
  /* can be written much simpler, if you do not mind php warnings */
1015
- if ( !isset( $log[ $index ] ) )
1016
- $log[ $index ] = array();
1017
 
1018
- if ( !isset( $log[ $index ][ $user_login ] ) )
1019
- $log[ $index ][ $user_login ] = array( 'counter' => 0 );
1020
 
1021
- elseif ( !is_array( $log[ $index ][ $user_login ] ) )
1022
- $log[ $index ][ $user_login ] = array(
1023
- 'counter' => $log[ $index ][ $user_login ],
1024
  );
1025
 
1026
- $log[ $index ][ $user_login ]['counter']++;
1027
- $log[ $index ][ $user_login ]['date'] = time();
1028
 
1029
- $log[ $index ][ $user_login ]['gateway'] = $this->detect_gateway();
1030
 
1031
  if ( $option === false ) {
1032
  $this->add_option( 'logged', $log );
@@ -1604,6 +1618,7 @@ class Limit_Login_Attempts {
1604
  $this->update_option('long_duration', (int)$_POST['long_duration'] * 3600 );
1605
  $this->update_option('notify_email_after', (int)$_POST['email_after'] );
1606
  $this->update_option('active_app', sanitize_text_field( $_POST['active_app'] ) );
 
1607
 
1608
  $this->update_option('admin_notify_email', sanitize_email( $_POST['admin_notify_email'] ) );
1609
 
@@ -2357,7 +2372,7 @@ class Limit_Login_Attempts {
2357
  <tr class="llar-app-rule-<?php echo esc_attr( $item['rule'] ); ?>">
2358
  <td class="rule-pattern" scope="col"><?php echo esc_html( $item['pattern'] ); ?></td>
2359
  <td scope="col"><?php echo esc_html( $item['rule'] ); ?></td>
2360
- <td class="llar-app-acl-action-col" scope="col"><button class="button llar-app-acl-remove" data-type="login" data-pattern="<?php echo esc_attr( $item['pattern'] ); ?>"><span class="dashicons dashicons-no"></span></button></td>
2361
  </tr>
2362
  <?php endforeach; ?>
2363
  <?php else : ?>
7
 
8
  public $default_options = array(
9
  'gdpr' => 0,
10
+ 'gdpr_message' => '',
11
 
12
  /* Are we behind a proxy? */
13
  'client_type' => LLA_DIRECT_ADDR,
86
  public $app = null;
87
 
88
  public function __construct() {
89
+
90
+ $this->default_options['gdpr_message'] = __( 'By proceeding you understand and give your consent that your IP address and browser information might be processed by the security plugins installed on this site.', 'limit-login-attempts-reloaded' );
91
+
92
  $this->hooks_init();
93
  $this->app_init();
94
  }
99
  public function hooks_init() {
100
  add_action( 'plugins_loaded', array( $this, 'setup' ), 9999 );
101
  add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) );
102
+ add_action( 'login_enqueue_scripts', array( $this, 'login_page_enqueue' ) );
103
  add_filter( 'limit_login_whitelist_ip', array( $this, 'check_whitelist_ips' ), 10, 2 );
104
  add_filter( 'limit_login_whitelist_usernames', array( $this, 'check_whitelist_usernames' ), 10, 2 );
105
  add_filter( 'limit_login_blacklist_ip', array( $this, 'check_blacklist_ips' ), 10, 2 );
129
  add_action( 'admin_init', array( $this, 'welcome_page_redirect' ), 9999 );
130
  add_action( 'admin_head', array( $this, 'welcome_page_hide_menu' ) );
131
 
132
+ add_action( 'login_footer', array( $this, 'login_page_gdpr_message' ) );
133
+
134
  register_activation_hook( LLA_PLUGIN_FILE, array( $this, 'activation' ) );
135
  }
136
 
242
  add_filter( 'plugin_action_links_' . LLA_PLUGIN_BASENAME, array( $this, 'add_action_links' ) );
243
  }
244
 
245
+ public function login_page_gdpr_message() {
246
+
247
+ if( ! $this->get_option( 'gdpr' )) return;
248
+
249
+ ?>
250
+ <div id="llar-login-page-gdpr">
251
+ <div class="llar-login-page-gdpr__message"><?php echo esc_html( $this->get_option( 'gdpr_message' ) ); ?></div>
252
+ </div>
253
+ <?php
254
+ }
255
+
256
  public function add_action_links( $actions ) {
257
 
258
  $actions = array_merge( array(
559
 
560
  }
561
 
562
+ public function login_page_enqueue() {
563
+
564
+ $plugin_data = get_plugin_data( LLA_PLUGIN_DIR . '/limit-login-attempts-reloaded.php' );
565
+
566
+ wp_enqueue_style( 'llar-login-page-styles', LLA_PLUGIN_URL . 'assets/css/login-page-styles.css', array(), $plugin_data['Version'] );
567
+ }
568
+
569
  /**
570
  * Add admin options page
571
  */
727
  /* lockout active? */
728
  $lockouts = $this->get_option( 'lockouts' );
729
 
730
+ return ( !is_array( $lockouts ) || !isset( $lockouts[ $ip ] ) || time() >= $lockouts[$ip] );
 
 
 
 
 
731
  }
732
 
733
  /**
775
  } else {
776
 
777
  $ip = $this->get_address();
 
778
 
779
  /* if currently locked-out, do not add to retries */
780
  $lockouts = $this->get_option( 'lockouts' );
783
  $lockouts = array();
784
  }
785
 
786
+ if ( isset( $lockouts[ $ip ] ) && time() < $lockouts[ $ip ] ) {
787
  return;
788
  }
789
 
817
  }
818
  $this->update_option( 'retries_stats', $retries_stats );
819
 
 
 
820
  /* Check validity and add one to retries */
821
  if ( isset( $retries[ $ip ] ) && isset( $valid[ $ip ] ) && time() < $valid[ $ip ]) {
822
  $retries[ $ip ] ++;
852
  } else {
853
  global $limit_login_just_lockedout;
854
  $limit_login_just_lockedout = true;
 
 
855
 
856
  /* setup lockout, reset retries as needed */
857
+ if ( (isset($retries[ $ip ]) ? $retries[ $ip ] : 0) >= $retries_long ) {
858
  /* long lockout */
859
+ $lockouts[ $ip ] = time() + $this->get_option( 'long_duration' );
860
+ unset( $retries[ $ip ] );
861
+ unset( $valid[ $ip ] );
862
  } else {
863
  /* normal lockout */
864
+ $lockouts[ $ip ] = time() + $this->get_option( 'lockout_duration' );
865
  }
866
  }
867
 
921
  }
922
 
923
  /* check if we are at the right nr to do notification */
924
+ if ( isset( $retries[ $ip ] )
 
925
  &&
926
+ ( ( intval($retries[$ip]) / $this->get_option( 'allowed_retries' ) ) % $this->get_option( 'notify_email_after' ) ) != 0 ) {
927
+
928
  return;
929
  }
930
 
931
  /* Format message. First current lockout duration */
932
+ if ( !isset( $retries[ $ip ] ) ) {
933
  /* longer lockout */
934
  $count = $this->get_option( 'allowed_retries' )
935
  * $this->get_option( 'allowed_lockouts' );
938
  $when = sprintf( _n( '%d hour', '%d hours', $time, 'limit-login-attempts-reloaded' ), $time );
939
  } else {
940
  /* normal lockout */
941
+ $count = $retries[ $ip ];
942
  $lockouts = floor( ($count) / $this->get_option( 'allowed_retries' ) );
943
  $time = round( $this->get_option( 'lockout_duration' ) / 60 );
944
  $when = sprintf( _n( '%d minute', '%d minutes', $time, 'limit-login-attempts-reloaded' ), $time );
1025
  }
1026
  $ip = $this->get_address();
1027
 
 
1028
  /* can be written much simpler, if you do not mind php warnings */
1029
+ if ( !isset( $log[ $ip ] ) )
1030
+ $log[ $ip ] = array();
1031
 
1032
+ if ( !isset( $log[ $ip ][ $user_login ] ) )
1033
+ $log[ $ip ][ $user_login ] = array( 'counter' => 0 );
1034
 
1035
+ elseif ( !is_array( $log[ $ip ][ $user_login ] ) )
1036
+ $log[ $ip ][ $user_login ] = array(
1037
+ 'counter' => $log[ $ip ][ $user_login ],
1038
  );
1039
 
1040
+ $log[ $ip ][ $user_login ]['counter']++;
1041
+ $log[ $ip ][ $user_login ]['date'] = time();
1042
 
1043
+ $log[ $ip ][ $user_login ]['gateway'] = $this->detect_gateway();
1044
 
1045
  if ( $option === false ) {
1046
  $this->add_option( 'logged', $log );
1618
  $this->update_option('long_duration', (int)$_POST['long_duration'] * 3600 );
1619
  $this->update_option('notify_email_after', (int)$_POST['email_after'] );
1620
  $this->update_option('active_app', sanitize_text_field( $_POST['active_app'] ) );
1621
+ $this->update_option('gdpr_message', sanitize_textarea_field( $_POST['gdpr_message'] ) );
1622
 
1623
  $this->update_option('admin_notify_email', sanitize_email( $_POST['admin_notify_email'] ) );
1624
 
2372
  <tr class="llar-app-rule-<?php echo esc_attr( $item['rule'] ); ?>">
2373
  <td class="rule-pattern" scope="col"><?php echo esc_html( $item['pattern'] ); ?></td>
2374
  <td scope="col"><?php echo esc_html( $item['rule'] ); ?></td>
2375
+ <td class="llar-app-acl-action-col" scope="col"><button class="button llar-app-acl-remove" data-type="<?php echo esc_attr( $type ); ?>" data-pattern="<?php echo esc_attr( $item['pattern'] ); ?>"><span class="dashicons dashicons-no"></span></button></td>
2376
  </tr>
2377
  <?php endforeach; ?>
2378
  <?php else : ?>
limit-login-attempts-reloaded.php CHANGED
@@ -5,7 +5,7 @@ Description: Limit the rate of login attempts for each IP address.
5
  Author: Limit Login Attempts Reloaded
6
  Author URI: https://www.limitloginattempts.com/
7
  Text Domain: limit-login-attempts-reloaded
8
- Version: 2.20.6
9
 
10
  Copyright 2008 - 2012 Johan Eenfeldt, 2016 - 2021 Limit Login Attempts Reloaded
11
  */
5
  Author: Limit Login Attempts Reloaded
6
  Author URI: https://www.limitloginattempts.com/
7
  Text Domain: limit-login-attempts-reloaded
8
+ Version: 2.21.0
9
 
10
  Copyright 2008 - 2012 Johan Eenfeldt, 2016 - 2021 Limit Login Attempts Reloaded
11
  */
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.paypal.com/donate?hosted_button_id=FKD4MYFCMNVQQ
4
  Tags: brute force, login, security, firewall, protection
5
  Requires at least: 3.0
6
  Tested up to: 5.7
7
- Stable tag: 2.20.6
8
 
9
  Reloaded version of the original Limit Login Attempts plugin for Login Protection by a team of WordPress developers. GDPR compliant.
10
 
@@ -98,6 +98,11 @@ Please follow this link: <a href="https://www.limitloginattempts.com/resources/"
98
 
99
  == Changelog ==
100
 
 
 
 
 
 
101
  = 2.20.6 =
102
  * Multisite tab links fixed.
103
 
4
  Tags: brute force, login, security, firewall, protection
5
  Requires at least: 3.0
6
  Tested up to: 5.7
7
+ Stable tag: 2.21.0
8
 
9
  Reloaded version of the original Limit Login Attempts plugin for Login Protection by a team of WordPress developers. GDPR compliant.
10
 
98
 
99
  == Changelog ==
100
 
101
+ = 2.21.0 =
102
+ * GDPR compliance: IPs obfuscation replaced with a customizable consent message on the login page.
103
+ * Cloud API: fixed removing of blocked IPs from the access lists under certain conditions.
104
+ * Cloud API: domain for Setup Code is taken from the WordPress settings now.
105
+
106
  = 2.20.6 =
107
  * Multisite tab links fixed.
108
 
views/tab-settings.php CHANGED
@@ -7,6 +7,7 @@ if( !defined( 'ABSPATH' ) ) exit();
7
  */
8
 
9
  $gdpr = $this->get_option( 'gdpr' );
 
10
 
11
  $v = explode( ',', $this->get_option( 'lockout_notify' ) );
12
  $email_checked = in_array( 'email', $v ) ? ' checked ' : '';
@@ -60,7 +61,6 @@ $active_app_config = $this->get_custom_app_config();
60
  <?php endif ?>
61
 
62
  <table class="form-table">
63
- <?php if( $active_app === 'local' ) : ?>
64
  <tr>
65
  <th scope="row"
66
  valign="top"><?php echo __( 'GDPR compliance', 'limit-login-attempts-reloaded' ); ?></th>
@@ -69,7 +69,13 @@ $active_app_config = $this->get_custom_app_config();
69
  <?php echo __( 'this makes the plugin <a href="https://gdpr-info.eu/" target="_blank" >GDPR</a> compliant', 'limit-login-attempts-reloaded' ); ?> <br/>
70
  </td>
71
  </tr>
72
- <?php endif; ?>
 
 
 
 
 
 
73
 
74
  <tr>
75
  <th scope="row"
7
  */
8
 
9
  $gdpr = $this->get_option( 'gdpr' );
10
+ $gdpr_message = $this->get_option( 'gdpr_message' );
11
 
12
  $v = explode( ',', $this->get_option( 'lockout_notify' ) );
13
  $email_checked = in_array( 'email', $v ) ? ' checked ' : '';
61
  <?php endif ?>
62
 
63
  <table class="form-table">
 
64
  <tr>
65
  <th scope="row"
66
  valign="top"><?php echo __( 'GDPR compliance', 'limit-login-attempts-reloaded' ); ?></th>
69
  <?php echo __( 'this makes the plugin <a href="https://gdpr-info.eu/" target="_blank" >GDPR</a> compliant', 'limit-login-attempts-reloaded' ); ?> <br/>
70
  </td>
71
  </tr>
72
+ <tr>
73
+ <th scope="row"
74
+ valign="top"><?php echo __( 'GDPR message', 'limit-login-attempts-reloaded' ); ?></th>
75
+ <td>
76
+ <textarea name="gdpr_message" cols="60"><?php echo esc_textarea( $gdpr_message ); ?></textarea>
77
+ </td>
78
+ </tr>
79
 
80
  <tr>
81
  <th scope="row"