Limit Login Attempts Reloaded - Version 2.17.0

Version Description

  • Refactoring.
  • Email text and notification updated.
  • New links in the list of plugins.
Download this release

Release Info

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

Code changes from version 2.16.0 to 2.17.0

assets/css/limit-login-attempts.css CHANGED
@@ -1 +1 @@
1
- .limit-login-page-settings .field-col{display:inline-block;margin-right:20px}.limit-login-page-settings .limit-login-log table{background-color:#fff}.limit-login-page-settings .limit-login-log table th,.limit-login-page-settings .limit-login-log table td{padding:10px}.limit-login-page-settings .limit-login-log table tr:nth-child(even){background-color:rgba(0,0,0,0.09)}.limit-login-page-settings #limit-login-app-setup-link{width:85%}.limit-login-page-settings .nav-tab-wrapper{position:relative}.limit-login-page-settings .nav-tab-wrapper .llar-failover-link{font-size:14px;float:right;line-height:2}.limit-login-page-settings .limit-login-app-dashboard .llar-table-scroll-wrap{max-height:400px;overflow-y:auto}.limit-login-page-settings .limit-login-app-dashboard .form-table{background-color:#fff;border:1px solid #f4f4f4;border-top:3px solid #3c8dbc;position:relative}.limit-login-page-settings .limit-login-app-dashboard .form-table.llar-preloader:before{content:"";display:block;width:100%;height:100%;background-color:rgba(255,255,255,0.7);z-index:999;position:absolute;top:0;left:0}.limit-login-page-settings .limit-login-app-dashboard .form-table th{font-weight:bold;border-bottom:1px solid #dbdbdb !important}.limit-login-page-settings .limit-login-app-dashboard .form-table th,.limit-login-page-settings .limit-login-app-dashboard .form-table td{padding:10px;border:1px solid #b9b9b9}.limit-login-page-settings .limit-login-app-dashboard .form-table th.llar-col-nowrap,.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-col-nowrap{white-space:nowrap}.limit-login-page-settings .limit-login-app-dashboard .form-table td button{line-height:1;margin-right:5px}.limit-login-page-settings .limit-login-app-dashboard .form-table td button:last-child{margin-right:0}.limit-login-page-settings .limit-login-app-dashboard .form-table td button .dashicons{vertical-align:middle}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions{text-align:center}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn{display:inline-block;line-height:20px;cursor:pointer}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn i{vertical-align:middle}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn:hover i{color:#3c8dbc}.limit-login-page-settings .limit-login-app-dashboard .form-table tr:nth-child(even){background-color:#f9f9f9}.limit-login-page-settings .limit-login-app-dashboard .llar-app-log-pagination>a{font-size:16px;line-height:1.625}.limit-login-page-settings .limit-login-app-dashboard .llar-app-log-pagination .spinner{float:none}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col{-webkit-box-flex:0;-ms-flex:0 0 49%;flex:0 0 49%}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table select{width:100%}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-acl-action-col{text-align:center}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-pass{background-color:#cffbe8}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-allow{background-color:#abdfff}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-deny{background-color:#fd2c2c3d}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-acl-remove{color:crimson;border-color:crimson}.limit-login-page-settings .llar-app-notice{background-color:#fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);padding:15px;border-radius:3px;margin-top:20px;margin-bottom:20px;font-size:14px;border-left:5px solid #ffba00}.limit-login-page-settings .llar-app-notice.success{border-color:#46b450}.limit-login-page-settings .llar-app-notice p{font-size:inherit;margin:0 0 20px}.limit-login-page-settings .llar-app-notice p:last-child{margin-bottom:0}.limit-login-page-settings input[name="admin_notify_email"]{min-width:243px}.limit-login-page-settings .llar-protect-notice{font-size:15px;color:#848484;margin-left:10px}.limit-login-page-settings .llar-protect-notice a{color:#222222;text-decoration:none;border-bottom:1px dashed}.limit-login-page-settings .llar-show-app-fields{position:absolute;right:15px;top:15px;color:#bdbdbd}.limit-login-page-settings .llar-show-app-fields:hover{color:#222}.limit-login-page-settings .llar-app-field{display:none}.limit-login-page-settings .llar-app-field.active{display:table-row}.llar-notice-review{display:-webkit-box;display:-ms-flexbox;display:flex;padding:15px 20px 0 !important;border-left:4px solid #333 !important}.llar-notice-review .llar-review-image img{margin-top:10px}.llar-notice-review .llar-review-info{-webkit-box-flex:1;-ms-flex:1;flex:1;margin-left:30px}.llar-notice-review .llar-review-info .llar-buttons{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.llar-notice-review .llar-review-info .llar-buttons li{margin-right:10px}.llar-notice-review .llar-review-info .llar-buttons li .dashicons{margin-right:5px}.llar-accordion .ui-accordion-header{font-weight:bold;background-color:#778899;color:#fff}.llar-accordion .ui-accordion-header.ui-accordion-header-active{background-color:#87CEFA}.custom-app-tab{position:relative}.custom-app-tab .spinner{float:none}.custom-app-tab .llar-app-ajax-msg{font-size:13px;margin-top:5px;display:block}.custom-app-tab .llar-app-ajax-msg.error{color:red}.custom-app-tab .llar-app-ajax-msg.success{color:green}.custom-app-tab .llar-delete-app{color:#dc3232;position:absolute;bottom:15px;right:15px}.custom-app-tab .llar-delete-app:hover{opacity:0.8}.custom-app-tab .llar-why-use-premium-text{margin-top:20px}.custom-app-tab .llar-why-use-premium-text .title{font-weight:bold;font-size:16px;color:#4d4d4d}.custom-app-tab .llar-why-use-premium-text ul li .dashicons{color:#3ab54a;font-size:25px;width:25px;top:-2px;position:relative}#llar-progress-bar{position:fixed;top:0;height:6px;left:0;width:100%;z-index:999999;background-color:#eee}#llar-progress-bar span{height:100%;position:absolute;display:block;width:0;background-color:#00b357;-webkit-transition:width 0.4s;transition:width 0.4s}
1
+ .limit-login-page-settings .field-col{display:inline-block;margin-right:20px}.limit-login-page-settings .limit-login-log table{background-color:#fff}.limit-login-page-settings .limit-login-log table th,.limit-login-page-settings .limit-login-log table td{padding:10px}.limit-login-page-settings .limit-login-log table tr:nth-child(even){background-color:rgba(0,0,0,0.09)}.limit-login-page-settings #limit-login-app-setup-link{width:85%}.limit-login-page-settings .nav-tab-wrapper{position:relative}.limit-login-page-settings .nav-tab-wrapper .llar-failover-link{font-size:14px;float:right;line-height:2}.limit-login-page-settings .limit-login-app-dashboard .llar-table-scroll-wrap{max-height:400px;overflow-y:auto}.limit-login-page-settings .limit-login-app-dashboard .form-table{background-color:#fff;border:1px solid #f4f4f4;border-top:3px solid #3c8dbc;position:relative}.limit-login-page-settings .limit-login-app-dashboard .form-table.llar-preloader:before{content:"";display:block;width:100%;height:100%;background-color:rgba(255,255,255,0.7);z-index:999;position:absolute;top:0;left:0}.limit-login-page-settings .limit-login-app-dashboard .form-table th{font-weight:bold;border-bottom:1px solid #dbdbdb !important}.limit-login-page-settings .limit-login-app-dashboard .form-table th,.limit-login-page-settings .limit-login-app-dashboard .form-table td{padding:10px;border:1px solid #b9b9b9}.limit-login-page-settings .limit-login-app-dashboard .form-table th.llar-col-nowrap,.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-col-nowrap{white-space:nowrap}.limit-login-page-settings .limit-login-app-dashboard .form-table td button{line-height:1;margin-right:5px}.limit-login-page-settings .limit-login-app-dashboard .form-table td button:last-child{margin-right:0}.limit-login-page-settings .limit-login-app-dashboard .form-table td button .dashicons{vertical-align:middle}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions{text-align:center}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn{display:inline-block;line-height:20px;cursor:pointer}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn i{vertical-align:middle}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn:hover i{color:#3c8dbc}.limit-login-page-settings .limit-login-app-dashboard .form-table tr:nth-child(even){background-color:#f9f9f9}.limit-login-page-settings .limit-login-app-dashboard .llar-app-log-pagination>a{font-size:16px;line-height:1.625}.limit-login-page-settings .limit-login-app-dashboard .llar-app-log-pagination .spinner{float:none}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col{-webkit-box-flex:0;-ms-flex:0 0 49%;flex:0 0 49%}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table select{width:100%}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-acl-action-col{text-align:center}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-pass{background-color:#cffbe8}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-allow{background-color:#abdfff}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-deny{background-color:#fd2c2c3d}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-acl-remove{color:crimson;border-color:crimson}.limit-login-page-settings .llar-app-notice{background-color:#fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);padding:15px;border-radius:3px;margin-top:20px;margin-bottom:20px;font-size:14px;border-left:5px solid #ffba00}.limit-login-page-settings .llar-app-notice.success{border-color:#46b450}.limit-login-page-settings .llar-app-notice p{font-size:inherit;margin:0 0 20px}.limit-login-page-settings .llar-app-notice p:last-child{margin-bottom:0}.limit-login-page-settings input[name="admin_notify_email"]{min-width:243px}.limit-login-page-settings .llar-protect-notice{font-size:15px;color:#848484;margin-left:10px}.limit-login-page-settings .llar-protect-notice a{color:#222222;text-decoration:none;border-bottom:1px dashed}.limit-login-page-settings .llar-show-app-fields{position:absolute;right:15px;top:15px;color:#bdbdbd}.limit-login-page-settings .llar-show-app-fields:hover{color:#222}.limit-login-page-settings .llar-app-field{display:none}.limit-login-page-settings .llar-app-field.active{display:table-row}.llar-notice-review,.llar-notice-notify{display:-webkit-box;display:-ms-flexbox;display:flex;padding:15px 20px 0 !important;border-left:4px solid #333 !important}.llar-notice-review .llar-review-image img,.llar-notice-notify .llar-review-image img{margin-top:10px;margin-bottom:20px}.llar-notice-review .llar-review-image span,.llar-notice-notify .llar-review-image span{font-size:80px;color:orange;width:80px;height:auto;margin-bottom:20px}.llar-notice-review .llar-review-info,.llar-notice-notify .llar-review-info{-webkit-box-flex:1;-ms-flex:1;flex:1;margin-left:30px}.llar-notice-review .llar-review-info .llar-buttons,.llar-notice-notify .llar-review-info .llar-buttons{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.llar-notice-review .llar-review-info .llar-buttons li,.llar-notice-notify .llar-review-info .llar-buttons li{margin-right:10px}.llar-notice-review .llar-review-info .llar-buttons li .dashicons,.llar-notice-notify .llar-review-info .llar-buttons li .dashicons{margin-right:5px}.llar-accordion .ui-accordion-header{font-weight:bold;background-color:#778899;color:#fff}.llar-accordion .ui-accordion-header.ui-accordion-header-active{background-color:#87CEFA}.custom-app-tab{position:relative}.custom-app-tab .spinner{float:none}.custom-app-tab .llar-app-ajax-msg{font-size:13px;margin-top:5px;display:block}.custom-app-tab .llar-app-ajax-msg.error{color:red}.custom-app-tab .llar-app-ajax-msg.success{color:green}.custom-app-tab .llar-delete-app{color:#dc3232;position:absolute;bottom:15px;right:15px}.custom-app-tab .llar-delete-app:hover{opacity:0.8}.custom-app-tab .llar-why-use-premium-text{margin-top:20px}.custom-app-tab .llar-why-use-premium-text .title{font-weight:bold;font-size:16px;color:#4d4d4d}.custom-app-tab .llar-why-use-premium-text ul li .dashicons{color:#3ab54a;font-size:25px;width:25px;top:-2px;position:relative}#llar-progress-bar{position:fixed;top:0;height:6px;left:0;width:100%;z-index:999999;background-color:#eee}#llar-progress-bar span{height:100%;position:absolute;display:block;width:0;background-color:#00b357;-webkit-transition:width 0.4s;transition:width 0.4s}
assets/sass/limit-login-attempts.scss CHANGED
@@ -213,7 +213,8 @@
213
  }
214
  }
215
 
216
- .llar-notice-review {
 
217
  display: flex;
218
  padding: 15px 20px 0 !important;
219
  border-left: 4px solid #333 !important;
@@ -221,6 +222,14 @@
221
  .llar-review-image {
222
  img {
223
  margin-top: 10px;
 
 
 
 
 
 
 
 
224
  }
225
  }
226
  .llar-review-info {
213
  }
214
  }
215
 
216
+ .llar-notice-review,
217
+ .llar-notice-notify {
218
  display: flex;
219
  padding: 15px 20px 0 !important;
220
  border-left: 4px solid #333 !important;
222
  .llar-review-image {
223
  img {
224
  margin-top: 10px;
225
+ margin-bottom: 20px;
226
+ }
227
+ span {
228
+ font-size: 80px;
229
+ color: orange;
230
+ width: 80px;
231
+ height: auto;
232
+ margin-bottom: 20px;
233
  }
234
  }
235
  .llar-review-info {
core/LimitLoginAttempts.php CHANGED
@@ -30,12 +30,13 @@ class Limit_Login_Attempts {
30
  'cookies' => true,
31
 
32
  /* Notify on lockout. Values: '', 'log', 'email', 'log,email' */
33
- 'lockout_notify' => 'log',
34
 
35
  /* If notify by email, do so after this number of lockouts */
36
- 'notify_email_after' => 4,
37
 
38
  'review_notice_shown' => false,
 
39
 
40
  'whitelist' => array(),
41
  'whitelist_usernames' => array(),
@@ -94,8 +95,11 @@ class Limit_Login_Attempts {
94
  add_filter( 'limit_login_blacklist_usernames', array( $this, 'check_blacklist_usernames' ), 10, 2 );
95
 
96
  add_filter( 'illegal_user_logins', array( $this, 'register_user_blacklist' ), 999 );
 
97
  add_action( 'admin_notices', array( $this, 'show_leave_review_notice' ) );
98
- add_action( 'wp_ajax_dismiss_review_notice', array( $this, 'dismiss_review_notice_callback' ));
 
 
99
  add_action( 'wp_ajax_app_config_save', array( $this, 'app_config_save_callback' ));
100
  add_action( 'wp_ajax_app_setup', array( $this, 'app_setup_callback' ));
101
  add_action( 'wp_ajax_app_log_action', array( $this, 'app_log_action_callback' ));
@@ -113,6 +117,18 @@ class Limit_Login_Attempts {
113
  */
114
  public function setup() {
115
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  // Load languages files
117
  load_plugin_textdomain( 'limit-login-attempts-reloaded', false, plugin_basename( dirname( __FILE__ ) ) . '/../languages' );
118
 
@@ -171,11 +187,19 @@ class Limit_Login_Attempts {
171
  */
172
  add_action( 'authenticate', array( $this, 'bp_authenticate_filter' ), 35, 3 );
173
 
174
- if ( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST )
175
- add_action( 'init', array( $this, 'check_xmlrpc_lock' ) );
176
-
177
  add_action('wp_ajax_limit-login-unlock', array( $this, 'ajax_unlock' ) );
178
 
 
 
 
 
 
 
 
 
 
 
 
179
  }
180
 
181
  public function app_init() {
@@ -192,18 +216,6 @@ class Limit_Login_Attempts {
192
  wp_enqueue_style('llar-jquery-ui', LLA_PLUGIN_URL.'assets/css/jquery-ui.css');
193
  }
194
 
195
- public function check_xmlrpc_lock()
196
- {
197
- if ( is_user_logged_in() || $this->is_ip_whitelisted() )
198
- return;
199
-
200
- if ( $this->is_ip_blacklisted() || !$this->is_limit_login_ok() )
201
- {
202
- header('HTTP/1.0 403 Forbidden');
203
- exit;
204
- }
205
- }
206
-
207
  public function check_whitelist_ips( $allow, $ip ) {
208
  return $this->ip_in_range( $ip, (array) $this->get_option( 'whitelist' ) );
209
  }
@@ -277,39 +289,12 @@ class Limit_Login_Attempts {
277
  return $error;
278
  }
279
 
280
- if ( ! $this->is_limit_login_ok() ) {
281
- return new IXR_Error( 403, $this->error_msg() );
282
- }
283
-
284
- $ip = $this->get_address();
285
- $retries = $this->get_option( 'retries' );
286
- $valid = $this->get_option( 'retries_valid' );
287
 
288
- /* Should we show retries remaining? */
289
-
290
- if ( ! is_array( $retries ) || ! is_array( $valid ) ) {
291
- /* no retries at all */
292
- return $error;
293
- }
294
- if (
295
- (! isset( $retries[ $ip ] ) && ! isset( $retries[ $this->getHash($ip) ] )) ||
296
- (! isset( $valid[ $ip ] ) && ! isset( $valid[ $this->getHash($ip) ] )) ||
297
- (time() > $valid[ $ip ] && time() > $valid[ $this->getHash($ip) ])
298
-
299
- ) {
300
- /* no: no valid retries */
301
- return $error;
302
- }
303
- if (
304
- ( ((isset($retries[ $ip ]) ? $retries[ $ip ] : 0) + (isset($retries[ $this->getHash($ip) ]) ? $retries[ $this->getHash($ip) ] : 0)) % $this->get_option( 'allowed_retries' ) ) == 0
305
- ) {
306
- //* no: already been locked out for these retries */
307
- return $error;
308
- }
309
-
310
- $remaining = max( ( $this->get_option( 'allowed_retries' ) - ( ((isset($retries[ $ip ]) ? $retries[ $ip ] : 0) + (isset($retries[ $this->getHash($ip) ]) ? $retries[ $this->getHash($ip) ] : 0)) % $this->get_option( 'allowed_retries' ) ) ), 0 );
311
 
312
- return new IXR_Error( 403, sprintf( _n( "<strong>%d</strong> attempt remaining.", "<strong>%d</strong> attempts remaining.", $remaining, 'limit-login-attempts-reloaded' ), $remaining ) );
313
  }
314
 
315
  /**
@@ -379,6 +364,12 @@ class Limit_Login_Attempts {
379
 
380
  $user = new WP_Error();
381
  $user->add( 'username_blacklisted', $err );
 
 
 
 
 
 
382
  }
383
  else if( $response['result'] === 'pass' ) {
384
 
@@ -407,6 +398,12 @@ class Limit_Login_Attempts {
407
  $user = new WP_Error();
408
  $user->add( 'username_blacklisted', "<strong>ERROR:</strong> Too many failed login attempts." );
409
 
 
 
 
 
 
 
410
  } elseif ( $this->is_username_whitelisted( $username ) || $this->is_ip_whitelisted( $ip ) ) {
411
 
412
  remove_filter( 'wp_login_failed', array( $this, 'limit_login_failed' ) );
@@ -846,41 +843,56 @@ class Limit_Login_Attempts {
846
  $when = sprintf( _n( '%d minute', '%d minutes', $time, 'limit-login-attempts-reloaded' ), $time );
847
  }
848
 
849
- $blogname = $this->use_local_options ? get_option( 'blogname' ) : get_site_option( 'site_name' );
850
- $blogname = htmlspecialchars_decode( $blogname, ENT_QUOTES );
851
 
852
- if ( $whitelisted ) {
853
- $subject = sprintf( __( "[%s] Failed login attempts from whitelisted IP"
854
- , 'limit-login-attempts-reloaded' )
855
- , $blogname );
856
  } else {
857
- $subject = sprintf( __( "[%s] Too many failed login attempts"
858
- , 'limit-login-attempts-reloaded' )
859
- , $blogname );
860
- }
861
 
862
- $message = sprintf( __( "%d failed login attempts (%d lockout(s)) from IP: %s"
863
- , 'limit-login-attempts-reloaded' ) . "\r\n\r\n"
864
- , $count, $lockouts, $ip );
865
- if ( $user != '' ) {
866
- $message .= sprintf( __( "Last user attempted: %s", 'limit-login-attempts-reloaded' )
867
- . "\r\n\r\n", $user );
868
- }
869
- if ( $whitelisted ) {
870
- $message .= __( "IP was NOT blocked because of external whitelist.", 'limit-login-attempts-reloaded' );
871
- } else {
872
- $message .= sprintf( __( "IP was blocked for %s", 'limit-login-attempts-reloaded' ), $when );
873
  }
874
 
875
- if( $custom_admin_email = $this->get_option( 'admin_notify_email' ) ) {
876
 
877
- $admin_email = $custom_admin_email;
878
- } else {
879
 
880
- $admin_email = $this->use_local_options ? get_option( 'admin_email' ) : get_site_option( 'admin_email' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
881
  }
882
 
883
- @wp_mail( $admin_email, $subject, $message );
 
 
 
 
 
 
 
 
884
  }
885
 
886
  /**
@@ -1610,36 +1622,6 @@ class Limit_Login_Attempts {
1610
  if ( !current_user_can('manage_options') || $this->get_option('review_notice_shown') || $screen->parent_base === 'edit' ) return;
1611
 
1612
  $activation_timestamp = $this->get_option('activation_timestamp');
1613
- $file_changed_timestamp = filemtime(LLA_PLUGIN_DIR . 'core/Helpers.php');
1614
-
1615
- if($file_changed_timestamp < strtotime("-1 week") && !$activation_timestamp) {
1616
-
1617
- $activation_timestamp = $file_changed_timestamp;
1618
-
1619
- $this->update_option( 'activation_timestamp', $activation_timestamp );
1620
-
1621
- } else {
1622
-
1623
- if(!$activation_timestamp || $activation_timestamp < time()) {
1624
-
1625
- $logs = $this->get_option('logged');
1626
-
1627
- preg_match_all('/\"date\";\i\:([0-9]+)\;/', serialize($logs), $matches);
1628
-
1629
- if(!empty($matches[1]) && $min_time = min($matches[1])) {
1630
-
1631
- $activation_timestamp = $min_time;
1632
-
1633
- $this->update_option( 'activation_timestamp', $activation_timestamp );
1634
- }
1635
- }
1636
-
1637
- if(!$activation_timestamp) {
1638
-
1639
- // Write time when the plugin is activated
1640
- $this->update_option( 'activation_timestamp', time());
1641
- }
1642
- }
1643
 
1644
  if ( $activation_timestamp && $activation_timestamp < strtotime("-1 month") ) { ?>
1645
 
@@ -1701,6 +1683,110 @@ class Limit_Login_Attempts {
1701
  }
1702
  }
1703
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1704
  public function dismiss_review_notice_callback() {
1705
 
1706
  if ( !current_user_can('activate_plugins') ) {
@@ -1710,7 +1796,7 @@ class Limit_Login_Attempts {
1710
 
1711
  check_ajax_referer('llar-action', 'sec');
1712
 
1713
- $type = isset( $_POST['type'] ) ? $_POST['type'] : false;
1714
 
1715
  if ($type === 'dismiss'){
1716
 
@@ -1719,12 +1805,58 @@ class Limit_Login_Attempts {
1719
 
1720
  if ($type === 'later') {
1721
 
1722
- $this->update_option( 'activation_timestamp', strtotime("+1 month") );
1723
  }
1724
 
1725
  wp_send_json_success(array());
1726
  }
1727
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1728
  public function app_setup_callback() {
1729
 
1730
  if ( !current_user_can('activate_plugins') ) {
30
  'cookies' => true,
31
 
32
  /* Notify on lockout. Values: '', 'log', 'email', 'log,email' */
33
+ 'lockout_notify' => 'log,email',
34
 
35
  /* If notify by email, do so after this number of lockouts */
36
+ 'notify_email_after' => 3,
37
 
38
  'review_notice_shown' => false,
39
+ 'enable_notify_notice_shown' => false,
40
 
41
  'whitelist' => array(),
42
  'whitelist_usernames' => array(),
95
  add_filter( 'limit_login_blacklist_usernames', array( $this, 'check_blacklist_usernames' ), 10, 2 );
96
 
97
  add_filter( 'illegal_user_logins', array( $this, 'register_user_blacklist' ), 999 );
98
+ add_action( 'admin_notices', array( $this, 'show_enable_notify_notice' ) );
99
  add_action( 'admin_notices', array( $this, 'show_leave_review_notice' ) );
100
+ add_action( 'wp_ajax_dismiss_review_notice', array( $this, 'dismiss_review_notice_callback' ) );
101
+ add_action( 'wp_ajax_dismiss_notify_notice', array( $this, 'dismiss_notify_notice_callback' ) );
102
+ add_action( 'wp_ajax_enable_notify', array( $this, 'enable_notify_callback' ) );
103
  add_action( 'wp_ajax_app_config_save', array( $this, 'app_config_save_callback' ));
104
  add_action( 'wp_ajax_app_setup', array( $this, 'app_setup_callback' ));
105
  add_action( 'wp_ajax_app_log_action', array( $this, 'app_log_action_callback' ));
117
  */
118
  public function setup() {
119
 
120
+ if( ! ( $activation_timestamp = $this->get_option( 'activation_timestamp' ) ) ) {
121
+
122
+ // Write time when the plugin is activated
123
+ $this->update_option( 'activation_timestamp', time() );
124
+ }
125
+
126
+ if( ! ( $activation_timestamp = $this->get_option( 'notice_enable_notify_timestamp' ) ) ) {
127
+
128
+ // Write time when the plugin is activated
129
+ $this->update_option( 'notice_enable_notify_timestamp', strtotime( '-32 day' ) );
130
+ }
131
+
132
  // Load languages files
133
  load_plugin_textdomain( 'limit-login-attempts-reloaded', false, plugin_basename( dirname( __FILE__ ) ) . '/../languages' );
134
 
187
  */
188
  add_action( 'authenticate', array( $this, 'bp_authenticate_filter' ), 35, 3 );
189
 
 
 
 
190
  add_action('wp_ajax_limit-login-unlock', array( $this, 'ajax_unlock' ) );
191
 
192
+ add_filter( 'plugin_action_links_' . LLA_PLUGIN_BASENAME, array( $this, 'add_action_links' ) );
193
+ }
194
+
195
+ public function add_action_links( $actions ) {
196
+
197
+ $actions = array_merge( array(
198
+ '<a href="' . $this->get_options_page_uri( 'settings' ) . '">' . __( 'Settings', 'limit-login-attempts-reloaded' ) . '</a>',
199
+ '<a href="https://www.limitloginattempts.com/community/?from=plugin-plugins" target="_blank" style="font-weight: bold;">' . __( 'Premium Support', 'limit-login-attempts-reloaded' ) . '</a>',
200
+ ), $actions );
201
+
202
+ return $actions;
203
  }
204
 
205
  public function app_init() {
216
  wp_enqueue_style('llar-jquery-ui', LLA_PLUGIN_URL.'assets/css/jquery-ui.css');
217
  }
218
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  public function check_whitelist_ips( $allow, $ip ) {
220
  return $this->ip_in_range( $ip, (array) $this->get_option( 'whitelist' ) );
221
  }
289
  return $error;
290
  }
291
 
292
+ if( $login_error = $this->get_message() ) {
 
 
 
 
 
 
293
 
294
+ return new IXR_Error( 403, strip_tags( $login_error ) );
295
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
 
297
+ return $error;
298
  }
299
 
300
  /**
364
 
365
  $user = new WP_Error();
366
  $user->add( 'username_blacklisted', $err );
367
+
368
+ if ( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST ) {
369
+
370
+ header('HTTP/1.0 403 Forbidden');
371
+ exit;
372
+ }
373
  }
374
  else if( $response['result'] === 'pass' ) {
375
 
398
  $user = new WP_Error();
399
  $user->add( 'username_blacklisted', "<strong>ERROR:</strong> Too many failed login attempts." );
400
 
401
+ if ( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST ) {
402
+
403
+ header('HTTP/1.0 403 Forbidden');
404
+ exit;
405
+ }
406
+
407
  } elseif ( $this->is_username_whitelisted( $username ) || $this->is_ip_whitelisted( $ip ) ) {
408
 
409
  remove_filter( 'wp_login_failed', array( $this, 'limit_login_failed' ) );
843
  $when = sprintf( _n( '%d minute', '%d minutes', $time, 'limit-login-attempts-reloaded' ), $time );
844
  }
845
 
846
+ if( $custom_admin_email = $this->get_option( 'admin_notify_email' ) ) {
 
847
 
848
+ $admin_email = $custom_admin_email;
 
 
 
849
  } else {
 
 
 
 
850
 
851
+ $admin_email = $this->use_local_options ? get_option( 'admin_email' ) : get_site_option( 'admin_email' );
 
 
 
 
 
 
 
 
 
 
852
  }
853
 
854
+ $admin_name = '';
855
 
856
+ global $wpdb;
 
857
 
858
+ $res = $wpdb->get_col( $wpdb->prepare( "
859
+ SELECT u.display_name
860
+ FROM $wpdb->users AS u
861
+ LEFT JOIN $wpdb->usermeta AS m ON u.ID = m.user_id
862
+ WHERE u.user_email = %s
863
+ AND m.meta_key LIKE 'wp_capabilities'
864
+ AND m.meta_value LIKE '%administrator%'",
865
+ $admin_email
866
+ )
867
+ );
868
+
869
+ if( $res ) {
870
+ $admin_name = ' ' . $res[0];
871
+ }
872
+
873
+ $blogname = $this->use_local_options ? get_option( 'blogname' ) : get_site_option( 'site_name' );
874
+ $blogname = htmlspecialchars_decode( $blogname, ENT_QUOTES );
875
+
876
+ $subject = sprintf( __( "[%s] Too many failed login attempts", 'limit-login-attempts-reloaded' ) , $blogname );
877
+
878
+ $message = sprintf( __( "<p>Hello%s,</p>", 'limit-login-attempts-reloaded' ), $admin_name );
879
+
880
+ $message .= sprintf( __( "<p>%d failed login attempts (%d lockout(s)) from IP: %s<br>"
881
+ , 'limit-login-attempts-reloaded' ), $count, $lockouts, $ip );
882
+
883
+ if ( $user != '' ) {
884
+ $message .= sprintf( __( "Last user attempted: %s<br>", 'limit-login-attempts-reloaded' ), $user );
885
  }
886
 
887
+ $message .= sprintf( __( "IP was blocked for %s</p>", 'limit-login-attempts-reloaded' ), $when );
888
+ $message .= __( "<p>This notification was sent automatically via <b>Limit Login Attempts Reloaded Plugin</b>.</p>", 'limit-login-attempts-reloaded' ) . "\r\n\r\n";
889
+ $message .= sprintf( __( '<p>Under Attack? Try our <a href="%s" target="_blank">advanced protection</a>. ' .
890
+ 'Have questions? Visit our <a href="%s" target="_blank">help section</a>.</p>', 'limit-login-attempts-reloaded' ),
891
+ 'https://www.limitloginattempts.com/features/?from=plugin-lockout-email',
892
+ 'https://www.limitloginattempts.com/resources/?from=plugin-lockout-email'
893
+ );
894
+
895
+ @wp_mail( $admin_email, $subject, $message, array( 'content-type: text/html' ) );
896
  }
897
 
898
  /**
1622
  if ( !current_user_can('manage_options') || $this->get_option('review_notice_shown') || $screen->parent_base === 'edit' ) return;
1623
 
1624
  $activation_timestamp = $this->get_option('activation_timestamp');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1625
 
1626
  if ( $activation_timestamp && $activation_timestamp < strtotime("-1 month") ) { ?>
1627
 
1683
  }
1684
  }
1685
 
1686
+ public function show_enable_notify_notice() {
1687
+
1688
+ $screen = get_current_screen();
1689
+
1690
+ if(isset($_COOKIE['llar_enable_notify_notice_shown'])) {
1691
+
1692
+ $this->update_option('enable_notify_notice_shown', true);
1693
+ @setcookie('llar_enable_notify_notice_shown', '', time() - 3600, '/');
1694
+ }
1695
+
1696
+ $active_app = $this->get_option( 'active_app' );
1697
+ $notify_methods = explode( ',', $this->get_option( 'lockout_notify' ) );
1698
+
1699
+ if ( $active_app !== 'local' ||
1700
+ in_array( 'email', $notify_methods ) ||
1701
+ !current_user_can('manage_options') ||
1702
+ $this->get_option('enable_notify_notice_shown') ||
1703
+ $screen->parent_base === 'edit' ) return;
1704
+
1705
+ $activation_timestamp = $this->get_option('notice_enable_notify_timestamp');
1706
+
1707
+ if ( $activation_timestamp && $activation_timestamp < strtotime("-1 month") ) {
1708
+
1709
+ $review_activation_timestamp = $this->get_option('activation_timestamp');
1710
+ if ( $review_activation_timestamp && $review_activation_timestamp < strtotime("-1 month") ) {
1711
+ $this->update_option( 'activation_timestamp', time() );
1712
+ }
1713
+
1714
+ ?>
1715
+
1716
+ <div id="message" class="updated fade notice is-dismissible llar-notice-notify">
1717
+ <div class="llar-review-image">
1718
+ <span class="dashicons dashicons-warning"></span>
1719
+ </div>
1720
+ <div class="llar-review-info">
1721
+ <p><?php _e('You have been upgraded to the latest version of <strong>Limit Login Attempts Reloaded</strong>.<br> ' .
1722
+ 'Due to increased security threats around the holidays, we recommend turning on email ' .
1723
+ 'notifications when you receive a failed login attempt.', 'limit-login-attempts-reloaded'); ?></p>
1724
+
1725
+ <ul class="llar-buttons">
1726
+ <li><a class="button button-primary llar-ajax-enable-notify" target="_blank" href="#"><?php _e('Yes, turn on email notifications', 'limit-login-attempts-reloaded'); ?></a></li>
1727
+ <li><a href="#" class="llar-notify-notice-dismiss button" data-type="later"><?php _e('Remind me a month from now', 'limit-login-attempts-reloaded'); ?></a></li>
1728
+ <li><a href="#" class="llar-notify-notice-dismiss" data-type="dismiss"><?php _e('Don\'t show this message again', 'limit-login-attempts-reloaded'); ?></a></li>
1729
+ </ul>
1730
+ </div>
1731
+ </div>
1732
+ <script type="text/javascript">
1733
+ (function($){
1734
+
1735
+ $(document).ready(function(){
1736
+ $('.llar-notify-notice-dismiss').on('click', function(e) {
1737
+ e.preventDefault();
1738
+
1739
+ var type = $(this).data('type');
1740
+
1741
+ $.post(ajaxurl, {
1742
+ action: 'dismiss_notify_notice',
1743
+ type: type,
1744
+ sec: '<?php echo wp_create_nonce( "llar-action" ); ?>'
1745
+ });
1746
+
1747
+ $(this).closest('.llar-notice-notify').remove();
1748
+ });
1749
+
1750
+ $(".llar-notice-notify").on("click", ".notice-dismiss", function (e) {
1751
+ createCookie('llar_enable_notify_notice_shown', '1', 30);
1752
+ });
1753
+
1754
+ $(".llar-ajax-enable-notify").on("click", function (e) {
1755
+ e.preventDefault();
1756
+
1757
+ $.post(ajaxurl, {
1758
+ action: 'enable_notify',
1759
+ sec: '<?php echo wp_create_nonce( "llar-action" ); ?>'
1760
+ }, function(response){
1761
+
1762
+ if(response.success) {
1763
+ $(".llar-notice-notify .llar-review-info p").text('You are all set!');
1764
+ $(".llar-notice-notify .llar-buttons").remove();
1765
+ }
1766
+
1767
+ });
1768
+ });
1769
+
1770
+ function createCookie(name, value, days) {
1771
+ var expires;
1772
+
1773
+ if (days) {
1774
+ var date = new Date();
1775
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
1776
+ expires = "; expires=" + date.toGMTString();
1777
+ } else {
1778
+ expires = "";
1779
+ }
1780
+ document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/";
1781
+ }
1782
+ });
1783
+
1784
+ })(jQuery);
1785
+ </script>
1786
+ <?php
1787
+ }
1788
+ }
1789
+
1790
  public function dismiss_review_notice_callback() {
1791
 
1792
  if ( !current_user_can('activate_plugins') ) {
1796
 
1797
  check_ajax_referer('llar-action', 'sec');
1798
 
1799
+ $type = isset( $_POST['type'] ) ? sanitize_text_field( $_POST['type'] ) : false;
1800
 
1801
  if ($type === 'dismiss'){
1802
 
1805
 
1806
  if ($type === 'later') {
1807
 
1808
+ $this->update_option( 'activation_timestamp', time() );
1809
  }
1810
 
1811
  wp_send_json_success(array());
1812
  }
1813
 
1814
+ public function dismiss_notify_notice_callback() {
1815
+
1816
+ if ( !current_user_can('activate_plugins') ) {
1817
+
1818
+ wp_send_json_error(array());
1819
+ }
1820
+
1821
+ check_ajax_referer('llar-action', 'sec');
1822
+
1823
+ $type = isset( $_POST['type'] ) ? sanitize_text_field( $_POST['type'] ) : false;
1824
+
1825
+ if ($type === 'dismiss'){
1826
+
1827
+ $this->update_option( 'enable_notify_notice_shown', true );
1828
+ }
1829
+
1830
+ if ($type === 'later') {
1831
+
1832
+ $this->update_option( 'notice_enable_notify_timestamp', time() );
1833
+ }
1834
+
1835
+ wp_send_json_success(array());
1836
+ }
1837
+
1838
+ public function enable_notify_callback() {
1839
+
1840
+ if ( !current_user_can('activate_plugins') ) {
1841
+
1842
+ wp_send_json_error(array());
1843
+ }
1844
+
1845
+ check_ajax_referer('llar-action', 'sec');
1846
+
1847
+ $notify_methods = explode( ',', $this->get_option( 'lockout_notify' ) );
1848
+
1849
+ if( !in_array( 'email', $notify_methods ) ) {
1850
+
1851
+ $notify_methods[] = 'email';
1852
+ }
1853
+
1854
+ $this->update_option( 'lockout_notify', implode( ',', $notify_methods ) );
1855
+ $this->update_option( 'enable_notify_notice_shown', true );
1856
+
1857
+ wp_send_json_success(array());
1858
+ }
1859
+
1860
  public function app_setup_callback() {
1861
 
1862
  if ( !current_user_can('activate_plugins') ) {
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://limitloginattempts.com/
7
  Text Domain: limit-login-attempts-reloaded
8
- Version: 2.16.0
9
 
10
  Copyright 2008 - 2012 Johan Eenfeldt, 2016 - 2020 Limit Login Attempts Reloaded
11
  */
@@ -15,6 +15,7 @@ Copyright 2008 - 2012 Johan Eenfeldt, 2016 - 2020 Limit Login Attempts Reloaded
15
  **************************************************************************************/
16
  define( 'LLA_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
17
  define( 'LLA_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
 
18
 
19
  /***************************************************************************************
20
  * Different ways to get remote address: direct & behind proxy
5
  Author: Limit Login Attempts Reloaded
6
  Author URI: https://limitloginattempts.com/
7
  Text Domain: limit-login-attempts-reloaded
8
+ Version: 2.17.0
9
 
10
  Copyright 2008 - 2012 Johan Eenfeldt, 2016 - 2020 Limit Login Attempts Reloaded
11
  */
15
  **************************************************************************************/
16
  define( 'LLA_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
17
  define( 'LLA_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
18
+ define( 'LLA_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
19
 
20
  /***************************************************************************************
21
  * Different ways to get remote address: direct & behind proxy
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.paypal.com/donate?hosted_button_id=FKD4MYFCMNVQQ
4
  Tags: brute force, login, security, GDPR, protection
5
  Requires at least: 3.0
6
  Tested up to: 5.5
7
- Stable tag: 2.16.0
8
 
9
  Reloaded version of the original Limit Login Attempts plugin for Login Protection by a team of WordPress developers. GDPR compliant.
10
 
@@ -90,6 +90,11 @@ Please follow this link: <a href="https://www.limitloginattempts.com/resources/"
90
 
91
  == Changelog ==
92
 
 
 
 
 
 
93
  = 2.16.0 =
94
  * Custom Apps functionality implemented. More details: https://limitloginattempts.com/app/
95
 
4
  Tags: brute force, login, security, GDPR, protection
5
  Requires at least: 3.0
6
  Tested up to: 5.5
7
+ Stable tag: 2.17.0
8
 
9
  Reloaded version of the original Limit Login Attempts plugin for Login Protection by a team of WordPress developers. GDPR compliant.
10
 
90
 
91
  == Changelog ==
92
 
93
+ = 2.17.0 =
94
+ * Refactoring.
95
+ * Email text and notification updated.
96
+ * New links in the list of plugins.
97
+
98
  = 2.16.0 =
99
  * Custom Apps functionality implemented. More details: https://limitloginattempts.com/app/
100
 
views/tab-settings.php CHANGED
@@ -168,7 +168,7 @@ $active_app_config = $this->get_custom_app_config();
168
  <span class="llar-app-ajax-msg"></span>
169
 
170
  <?php if( $active_app === 'local' ) : ?>
171
- <p class="description"><?php echo sprintf( __( 'Use the <a href="%s" target="_blank">premium app</a> that we offer or follow the instructions on <a href="%s" target="_blank">how to</a> create your own one.', 'limit-login-attempts-reloaded' ), 'https://app.limitloginattempts.com/network/create', 'https://www.limitloginattempts.com/app/' ); ?></p>
172
  <div class="llar-why-use-premium-text">
173
  <div class="title"><?php _e( 'Why Use Our Premium Cloud App?', 'limit-login-attempts-reloaded' ); ?></div>
174
  <ul>
168
  <span class="llar-app-ajax-msg"></span>
169
 
170
  <?php if( $active_app === 'local' ) : ?>
171
+ <p class="description"><?php echo sprintf( __( 'Use the <a href="%s" target="_blank">premium app</a> that we offer or follow the instructions on <a href="%s" target="_blank">how to</a> create your own one.', 'limit-login-attempts-reloaded' ), 'https://app.limitloginattempts.com/network/create?from=plugin-settings', 'https://www.limitloginattempts.com/app/?from=plugin-settings' ); ?></p>
172
  <div class="llar-why-use-premium-text">
173
  <div class="title"><?php _e( 'Why Use Our Premium Cloud App?', 'limit-login-attempts-reloaded' ); ?></div>
174
  <ul>