Limit Login Attempts Reloaded - Version 2.10.0

Version Description

  • Debug information has been added for better support.
Download this release

Release Info

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

Code changes from version 2.9.0 to 2.10.0

limit-login-attempts-reloaded.php CHANGED
@@ -5,7 +5,7 @@ Description: Limit the rate of login attempts, including by way of cookies and f
5
  Author: WPChef
6
  Author URI: https://wpchef.org
7
  Text Domain: limit-login-attempts-reloaded
8
- Version: 2.9.0
9
 
10
  Copyright 2008 - 2012 Johan Eenfeldt, 2016 - 2019 WPChef
11
  */
5
  Author: WPChef
6
  Author URI: https://wpchef.org
7
  Text Domain: limit-login-attempts-reloaded
8
+ Version: 2.10.0
9
 
10
  Copyright 2008 - 2012 Johan Eenfeldt, 2016 - 2019 WPChef
11
  */
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: wpchefgadget
3
  Tags: brute force, login, security, GDPR, protection
4
  Requires at least: 3.0
5
- Tested up to: 5.2.1
6
- Stable tag: 2.9.0
7
 
8
  Reloaded version of the original Limit Login Attempts plugin for Login Protection by a team of WordPress developers. GDPR compliant.
9
 
@@ -51,6 +51,9 @@ Based on the original code from Limit Login Attemps plugin by Johan Eenfeldt.
51
 
52
  == Changelog ==
53
 
 
 
 
54
  = 2.9.0 =
55
  * Trusted IP origins option has been added.
56
 
2
  Contributors: wpchefgadget
3
  Tags: brute force, login, security, GDPR, protection
4
  Requires at least: 3.0
5
+ Tested up to: 5.3
6
+ Stable tag: 2.10.0
7
 
8
  Reloaded version of the original Limit Login Attempts plugin for Login Protection by a team of WordPress developers. GDPR compliant.
9
 
51
 
52
  == Changelog ==
53
 
54
+ = 2.10.0 =
55
+ * Debug information has been added for better support.
56
+
57
  = 2.9.0 =
58
  * Trusted IP origins option has been added.
59
 
views/options-page.php CHANGED
@@ -1,269 +1,24 @@
1
  <?php
2
 
3
- if( !defined( 'ABSPATH' ) )
4
- exit();
5
 
6
- /**
7
- * @var $this Limit_Login_Attempts
8
- */
9
-
10
- $gdpr = $this->get_option( 'gdpr', 0 );
11
-
12
- $lockouts_total = $this->get_option( 'lockouts_total', 0 );
13
- $lockouts = $this->get_option( 'login_lockouts' );
14
- $lockouts_now = is_array( $lockouts ) ? count( $lockouts ) : 0;
15
-
16
- $v = explode( ',', $this->get_option( 'lockout_notify' ) );
17
- $log_checked = in_array( 'log', $v ) ? ' checked ' : '';
18
- $email_checked = in_array( 'email', $v ) ? ' checked ' : '';
19
-
20
- $white_list_ips = $this->get_option( 'whitelist' );
21
- $white_list_ips = ( is_array( $white_list_ips ) && !empty( $white_list_ips ) ) ? implode( "\n", $white_list_ips ) : '';
22
-
23
- $white_list_usernames = $this->get_option( 'whitelist_usernames' );
24
- $white_list_usernames = ( is_array( $white_list_usernames ) && !empty( $white_list_usernames ) ) ? implode( "\n", $white_list_usernames ) : '';
25
-
26
- $black_list_ips = $this->get_option( 'blacklist' );
27
- $black_list_ips = ( is_array( $black_list_ips ) && !empty( $black_list_ips ) ) ? implode( "\n", $black_list_ips ) : '';
28
-
29
- $black_list_usernames = $this->get_option( 'blacklist_usernames' );
30
- $black_list_usernames = ( is_array( $black_list_usernames ) && !empty( $black_list_usernames ) ) ? implode( "\n", $black_list_usernames ) : '';
31
-
32
- $admin_notify_email = $this->get_option( 'admin_notify_email' );
33
- $admin_email_placeholder = (!is_multisite()) ? get_option( 'admin_email' ) : get_site_option( 'admin_email' );
34
-
35
- $trusted_ip_origins = $this->get_option( 'trusted_ip_origins' );
36
- $trusted_ip_origins = ( is_array( $trusted_ip_origins ) && !empty( $trusted_ip_origins ) ) ? implode( ", ", $trusted_ip_origins ) : 'REMOTE_ADDR';
37
 
 
 
 
 
38
  ?>
 
39
  <div class="wrap limit-login-page-settings">
40
  <h2><?php echo __( 'Limit Login Attempts Settings', 'limit-login-attempts-reloaded' ); ?></h2>
41
- <h3><?php echo __( 'Statistics', 'limit-login-attempts-reloaded' ); ?></h3>
42
- <form action="<?php echo $this->get_options_page_uri(); ?>" method="post">
43
- <?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
44
- <table class="form-table">
45
- <tr>
46
- <th scope="row" valign="top"><?php echo __( 'Total lockouts', 'limit-login-attempts-reloaded' ); ?></th>
47
- <td>
48
- <?php if( $lockouts_total > 0 ) { ?>
49
- <input class="button" name="reset_total"
50
- value="<?php echo __( 'Reset Counter', 'limit-login-attempts-reloaded' ); ?>"
51
- type="submit"/>
52
- <?php echo sprintf( _n( '%d lockout since last reset', '%d lockouts since last reset', $lockouts_total, 'limit-login-attempts-reloaded' ), $lockouts_total ); ?>
53
- <?php } else {
54
- echo __( 'No lockouts yet', 'limit-login-attempts-reloaded' );
55
- } ?>
56
- </td>
57
- </tr>
58
- <?php if( $lockouts_now > 0 ) { ?>
59
- <tr>
60
- <th scope="row"
61
- valign="top"><?php echo __( 'Active lockouts', 'limit-login-attempts-reloaded' ); ?></th>
62
- <td>
63
- <input class="button" name="reset_current"
64
- value="<?php echo __( 'Restore Lockouts', 'limit-login-attempts-reloaded' ); ?>"
65
- type="submit"/>
66
- <?php echo sprintf( __( '%d IP is currently blocked from trying to log in', 'limit-login-attempts-reloaded' ), $lockouts_now ); ?>
67
- </td>
68
- </tr>
69
- <?php } ?>
70
- </table>
71
- </form>
72
- <h3><?php echo __( 'Options', 'limit-login-attempts-reloaded' ); ?></h3>
73
- <form action="<?php echo $this->get_options_page_uri(); ?>" method="post">
74
- <?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
75
- <?php if ( is_network_admin() ): ?>
76
- <input type="checkbox" name="allow_local_options" <?php echo $this->get_option( 'allow_local_options' ) ? 'checked' : '' ?> value="1"/> <?php esc_html_e( 'Let network sites use their own settings', 'limit-login-attempts-reloaded' ); ?>
77
- <p class="description"><?php esc_html_e('If disabled, the global settings will be forcibly applied to the entire network.') ?></p>
78
- <?php elseif ( $this->network_mode ): ?>
79
- <input type="checkbox" name="use_global_options" <?php echo $this->get_option('use_local_options' ) ? '' : 'checked' ?> value="1" class="use_global_options"/> <?php echo __( 'Use global settings', 'limit-login-attempts-reloaded' ); ?><br/>
80
- <script>
81
- jQuery(function($){
82
- var first = true;
83
- $('.use_global_options').change( function(){
84
- var form = $(this).siblings('table');
85
- form.stop();
86
-
87
- if ( this.checked )
88
- first ? form.hide() : form.fadeOut();
89
- else
90
- first ? form.show() : form.fadeIn();
91
-
92
- first = false;
93
- }).change();
94
- });
95
- </script>
96
- <?php endif ?>
97
- <table class="form-table">
98
- <tr>
99
- <th scope="row"
100
- valign="top"><?php echo __( 'GDPR compliance', 'limit-login-attempts-reloaded' ); ?></th>
101
- <td>
102
- <input type="checkbox" name="gdpr" value="1" <?php if($gdpr): ?> checked <?php endif; ?>/>
103
- <?php echo __( 'this makes the plugin <a href="https://gdpr-info.eu/" target="_blank" >GDPR</a> compliant', 'limit-login-attempts-reloaded' ); ?> <br/>
104
- </td>
105
- </tr>
106
- <tr>
107
- <th scope="row" valign="top"><?php echo __( 'Lockout', 'limit-login-attempts-reloaded' ); ?></th>
108
- <td>
109
-
110
- <input type="text" size="3" maxlength="4"
111
- value="<?php echo( $this->get_option( 'allowed_retries' ) ); ?>"
112
- name="allowed_retries"/> <?php echo __( 'allowed retries', 'limit-login-attempts-reloaded' ); ?>
113
- <br/>
114
- <input type="text" size="3" maxlength="4"
115
- value="<?php echo( $this->get_option( 'lockout_duration' ) / 60 ); ?>"
116
- name="lockout_duration"/> <?php echo __( 'minutes lockout', 'limit-login-attempts-reloaded' ); ?>
117
- <br/>
118
- <input type="text" size="3" maxlength="4"
119
- value="<?php echo( $this->get_option( 'allowed_lockouts' ) ); ?>"
120
- name="allowed_lockouts"/> <?php echo __( 'lockouts increase lockout time to', 'limit-login-attempts-reloaded' ); ?>
121
- <input type="text" size="3" maxlength="4"
122
- value="<?php echo( $this->get_option( 'long_duration' ) / 3600 ); ?>"
123
- name="long_duration"/> <?php echo __( 'hours', 'limit-login-attempts-reloaded' ); ?> <br/>
124
- <input type="text" size="3" maxlength="4"
125
- value="<?php echo( $this->get_option( 'valid_duration' ) / 3600 ); ?>"
126
- name="valid_duration"/> <?php echo __( 'hours until retries are reset', 'limit-login-attempts-reloaded' ); ?>
127
- </td>
128
- </tr>
129
- <tr>
130
- <th scope="row"
131
- valign="top"><?php echo __( 'Notify on lockout', 'limit-login-attempts-reloaded' ); ?></th>
132
- <td>
133
- <input type="checkbox" name="lockout_notify_log" <?php echo $log_checked; ?>
134
- value="log"/> <?php echo __( 'Lockout log', 'limit-login-attempts-reloaded' ); ?><br/>
135
- <input type="checkbox" name="lockout_notify_email" <?php echo $email_checked; ?>
136
- value="email"/> <?php echo __( 'Email to', 'limit-login-attempts-reloaded' ); ?>
137
- <input type="email" name="admin_notify_email"
138
- value="<?php echo esc_attr( $admin_notify_email ) ?>"
139
- placeholder="<?php echo esc_attr( $admin_email_placeholder ); ?>"/> <?php echo __( 'after', 'limit-login-attempts-reloaded' ); ?>
140
- <input type="text" size="3" maxlength="4"
141
- value="<?php echo( $this->get_option( 'notify_email_after' ) ); ?>"
142
- name="email_after"/> <?php echo __( 'lockouts', 'limit-login-attempts-reloaded' ); ?>
143
- </td>
144
- </tr>
145
- <tr>
146
- <th scope="row"
147
- valign="top"><?php echo __( 'Whitelist', 'limit-login-attempts-reloaded' ); ?></th>
148
- <td>
149
- <div class="field-col">
150
- <p class="description"><?php _e( 'One IP or IP range (1.2.3.4-5.6.7.8) per line', 'limit-login-attempts-reloaded' ); ?></p>
151
- <textarea name="lla_whitelist_ips" rows="10" cols="50"><?php echo esc_textarea( $white_list_ips ); ?></textarea>
152
- </div>
153
- <div class="field-col">
154
- <p class="description"><?php _e( 'One Username per line', 'limit-login-attempts-reloaded' ); ?></p>
155
- <textarea name="lla_whitelist_usernames" rows="10" cols="50"><?php echo esc_textarea( $white_list_usernames ); ?></textarea>
156
- </div>
157
- </td>
158
- </tr>
159
- <tr>
160
- <th scope="row"
161
- valign="top"><?php echo __( 'Blacklist', 'limit-login-attempts-reloaded' ); ?></th>
162
- <td>
163
- <div class="field-col">
164
- <p class="description"><?php _e( 'One IP or IP range (1.2.3.4-5.6.7.8) per line', 'limit-login-attempts-reloaded' ); ?></p>
165
- <textarea name="lla_blacklist_ips" rows="10" cols="50"><?php echo esc_textarea( $black_list_ips ); ?></textarea>
166
- </div>
167
- <div class="field-col">
168
- <p class="description"><?php _e( 'One Username per line', 'limit-login-attempts-reloaded' ); ?></p>
169
- <textarea name="lla_blacklist_usernames" rows="10" cols="50"><?php echo esc_textarea( $black_list_usernames ); ?></textarea>
170
- </div>
171
- </td>
172
- </tr>
173
- <tr>
174
- <th scope="row"
175
- valign="top"><?php echo __( 'Trusted IP Origins', 'limit-login-attempts-reloaded' ); ?></th>
176
- <td>
177
- <div class="field-col">
178
- <input type="text" class="regular-text" style="width: 100%;max-width: 431px;" name="lla_trusted_ip_origins" value="<?php echo esc_attr( $trusted_ip_origins ); ?>">
179
- <p class="description"><?php _e( 'Specify the origins you trust in order of priority, separated by commas. We strongly recommend that you <b>do not</b> use anything other than REMOTE_ADDR since other origins can be easily faked. Examples: HTTP_X_FORWARDED_FOR, HTTP_CF_CONNECTING_IP, HTTP_X_SUCURI_CLIENTIP', 'limit-login-attempts-reloaded' ); ?></p>
180
- </div>
181
- </td>
182
- </tr>
183
- </table>
184
- <p class="submit">
185
- <input class="button button-primary" name="update_options" value="<?php echo __( 'Save Options', 'limit-login-attempts-reloaded' ); ?>"
186
- type="submit"/>
187
- </p>
188
- </form>
189
- <?php
190
- $log = $this->get_option( 'logged' );
191
- $log = LLA_Helpers::sorted_log_by_date( $log );
192
-
193
- $lockouts = (array)$this->get_option('lockouts');
194
-
195
- if( is_array( $log ) && ! empty( $log ) ) { ?>
196
- <h3><?php echo __( 'Lockout log', 'limit-login-attempts-reloaded' ); ?></h3>
197
- <form action="<?php echo $this->get_options_page_uri(); ?>" method="post">
198
- <?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
199
- <input type="hidden" value="true" name="clear_log"/>
200
- <p class="submit">
201
- <input class="button" name="submit" value="<?php echo __( 'Clear Log', 'limit-login-attempts-reloaded' ); ?>"
202
- type="submit"/>
203
- </p>
204
- </form>
205
-
206
- <div class="limit-login-log">
207
- <table class="form-table">
208
- <tr>
209
- <th scope="col"><?php _e( "Date", 'limit-login-attempts-reloaded' ); ?></th>
210
- <th scope="col"><?php echo _x( "IP", "Internet address", 'limit-login-attempts-reloaded' ); ?></th>
211
- <th scope="col"><?php _e( 'Tried to log in as', 'limit-login-attempts-reloaded' ); ?></th>
212
- <th scope="col"><?php _e( 'Gateway', 'limit-login-attempts-reloaded' ); ?></th>
213
- <th>
214
- </tr>
215
-
216
- <?php foreach ( $log as $date => $user_info ) : ?>
217
- <tr>
218
- <td class="limit-login-date"><?php echo date_i18n( 'F d, Y H:i', $date ); ?></td>
219
- <td class="limit-login-ip">
220
- <?php echo esc_html( $user_info['ip'] ); ?>
221
- </td>
222
- <td class="limit-login-max"><?php echo esc_html( $user_info['username'] ) . ' (' . esc_html( $user_info['counter'] ) .' lockouts)'; ?></td>
223
- <td class="limit-login-gateway"><?php echo esc_html( $user_info['gateway'] ); ?></td>
224
- <td>
225
- <?php if ( !empty( $lockouts[ $user_info['ip'] ] ) && $lockouts[ $user_info['ip'] ] > time() ) : ?>
226
- <a href="#" class="button limit-login-unlock" data-ip="<?=esc_attr($user_info['ip'])?>" data-username="<?=esc_attr($user_info['username'])?>">Unlock</a>
227
- <?php elseif ( $user_info['unlocked'] ): ?>
228
- Unlocked
229
- <?php endif ?>
230
- </tr>
231
- <?php endforeach; ?>
232
-
233
- </table>
234
- </div>
235
- <script>jQuery( function($) {
236
- $('.limit-login-log .limit-login-unlock').click( function()
237
- {
238
- var btn = $(this);
239
-
240
- if ( btn.hasClass('disabled') )
241
- return false;
242
- btn.addClass( 'disabled' );
243
-
244
- $.post( ajaxurl, {
245
- action: 'limit-login-unlock',
246
- sec: '<?=wp_create_nonce('limit-login-unlock') ?>',
247
- ip: btn.data('ip'),
248
- username: btn.data('username')
249
- } )
250
- .done( function(data) {
251
- if ( data === true )
252
- btn.fadeOut( function(){ $(this).parent().text('Unlocked') });
253
- else
254
- fail();
255
- }).fail( fail );
256
 
257
- function fail() {
258
- alert('Connection error');
259
- btn.removeClass('disabled');
260
- }
261
 
262
- return false;
263
- } );
264
- } )</script>
265
- <?php
266
- } /* if showing $log */
267
- ?>
268
 
269
- </div>
1
  <?php
2
 
3
+ if( !defined( 'ABSPATH' ) ) exit();
 
4
 
5
+ $active_tab = "settings";
6
+ if(isset($_GET["tab"])) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
+ if($_GET["tab"] === "debug") {
9
+ $active_tab = "debug";
10
+ }
11
+ }
12
  ?>
13
+
14
  <div class="wrap limit-login-page-settings">
15
  <h2><?php echo __( 'Limit Login Attempts Settings', 'limit-login-attempts-reloaded' ); ?></h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
+ <h2 class="nav-tab-wrapper">
18
+ <a href="<?php echo $this->get_options_page_uri(); ?>&tab=settings" class="nav-tab <?php if($active_tab == 'settings'){echo 'nav-tab-active';} ?> "><?php _e('Settings', 'limit-login-attempts-reloaded'); ?></a>
19
+ <a href="<?php echo $this->get_options_page_uri(); ?>&tab=debug" class="nav-tab <?php if($active_tab == 'debug'){echo 'nav-tab-active';} ?>"><?php _e('Debug', 'limit-login-attempts-reloaded'); ?></a>
20
+ </h2>
21
 
22
+ <?php include_once(LLA_PLUGIN_DIR.'views/tab-'.$active_tab.'.php'); ?>
23
+ </div>
 
 
 
 
24
 
 
views/tab-debug.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if( !defined( 'ABSPATH' ) ) exit();
4
+
5
+ $debug_info = '';
6
+
7
+ $ips = $server = [];
8
+ foreach ($_SERVER as $key => $value) {
9
+
10
+ if(in_array($key, ['SERVER_ADDR'])) continue;
11
+
12
+ if(filter_var($value, FILTER_VALIDATE_IP)) {
13
+
14
+ if(!in_array($value, $ips)) {
15
+
16
+ $ips[] = $value;
17
+ }
18
+
19
+ if(in_array($value, ['127.0.0.1', '0.0.0.0']))
20
+ $server[$key] = $value;
21
+ else
22
+ $server[$key] = 'IP'.array_search($value, $ips);
23
+ }
24
+ }
25
+
26
+ foreach ($server as $server_key => $ip ) {
27
+ $debug_info .= $server_key . ' = ' . $ip . "\n";
28
+ }
29
+ ?>
30
+
31
+ <table class="form-table">
32
+ <tr>
33
+ <th scope="row" valign="top"><?php echo __( 'Debug info', 'limit-login-attempts-reloaded' ); ?></th>
34
+ <td>
35
+ <textarea cols="70" rows="10" onclick="this.select()" readonly><?php echo esc_textarea($debug_info); ?></textarea>
36
+ </td>
37
+ </tr>
38
+ </table>
views/tab-settings.php ADDED
@@ -0,0 +1,267 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if( !defined( 'ABSPATH' ) ) exit();
4
+
5
+ /**
6
+ * @var $this Limit_Login_Attempts
7
+ */
8
+
9
+ $gdpr = $this->get_option( 'gdpr', 0 );
10
+
11
+ $lockouts_total = $this->get_option( 'lockouts_total', 0 );
12
+ $lockouts = $this->get_option( 'login_lockouts' );
13
+ $lockouts_now = is_array( $lockouts ) ? count( $lockouts ) : 0;
14
+
15
+ $v = explode( ',', $this->get_option( 'lockout_notify' ) );
16
+ $log_checked = in_array( 'log', $v ) ? ' checked ' : '';
17
+ $email_checked = in_array( 'email', $v ) ? ' checked ' : '';
18
+
19
+ $white_list_ips = $this->get_option( 'whitelist' );
20
+ $white_list_ips = ( is_array( $white_list_ips ) && !empty( $white_list_ips ) ) ? implode( "\n", $white_list_ips ) : '';
21
+
22
+ $white_list_usernames = $this->get_option( 'whitelist_usernames' );
23
+ $white_list_usernames = ( is_array( $white_list_usernames ) && !empty( $white_list_usernames ) ) ? implode( "\n", $white_list_usernames ) : '';
24
+
25
+ $black_list_ips = $this->get_option( 'blacklist' );
26
+ $black_list_ips = ( is_array( $black_list_ips ) && !empty( $black_list_ips ) ) ? implode( "\n", $black_list_ips ) : '';
27
+
28
+ $black_list_usernames = $this->get_option( 'blacklist_usernames' );
29
+ $black_list_usernames = ( is_array( $black_list_usernames ) && !empty( $black_list_usernames ) ) ? implode( "\n", $black_list_usernames ) : '';
30
+
31
+ $admin_notify_email = $this->get_option( 'admin_notify_email' );
32
+ $admin_email_placeholder = (!is_multisite()) ? get_option( 'admin_email' ) : get_site_option( 'admin_email' );
33
+
34
+ $trusted_ip_origins = $this->get_option( 'trusted_ip_origins' );
35
+ $trusted_ip_origins = ( is_array( $trusted_ip_origins ) && !empty( $trusted_ip_origins ) ) ? implode( ", ", $trusted_ip_origins ) : 'REMOTE_ADDR';
36
+
37
+
38
+ ?>
39
+
40
+ <h3><?php echo __( 'Statistics', 'limit-login-attempts-reloaded' ); ?></h3>
41
+ <form action="<?php echo $this->get_options_page_uri(); ?>" method="post">
42
+ <?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
43
+ <table class="form-table">
44
+ <tr>
45
+ <th scope="row" valign="top"><?php echo __( 'Total lockouts', 'limit-login-attempts-reloaded' ); ?></th>
46
+ <td>
47
+ <?php if( $lockouts_total > 0 ) { ?>
48
+ <input class="button" name="reset_total"
49
+ value="<?php echo __( 'Reset Counter', 'limit-login-attempts-reloaded' ); ?>"
50
+ type="submit"/>
51
+ <?php echo sprintf( _n( '%d lockout since last reset', '%d lockouts since last reset', $lockouts_total, 'limit-login-attempts-reloaded' ), $lockouts_total ); ?>
52
+ <?php } else {
53
+ echo __( 'No lockouts yet', 'limit-login-attempts-reloaded' );
54
+ } ?>
55
+ </td>
56
+ </tr>
57
+ <?php if( $lockouts_now > 0 ) { ?>
58
+ <tr>
59
+ <th scope="row"
60
+ valign="top"><?php echo __( 'Active lockouts', 'limit-login-attempts-reloaded' ); ?></th>
61
+ <td>
62
+ <input class="button" name="reset_current"
63
+ value="<?php echo __( 'Restore Lockouts', 'limit-login-attempts-reloaded' ); ?>"
64
+ type="submit"/>
65
+ <?php echo sprintf( __( '%d IP is currently blocked from trying to log in', 'limit-login-attempts-reloaded' ), $lockouts_now ); ?>
66
+ </td>
67
+ </tr>
68
+ <?php } ?>
69
+ </table>
70
+ </form>
71
+ <h3><?php echo __( 'Options', 'limit-login-attempts-reloaded' ); ?></h3>
72
+ <form action="<?php echo $this->get_options_page_uri(); ?>" method="post">
73
+ <?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
74
+ <?php if ( is_network_admin() ): ?>
75
+ <input type="checkbox" name="allow_local_options" <?php echo $this->get_option( 'allow_local_options' ) ? 'checked' : '' ?> value="1"/> <?php esc_html_e( 'Let network sites use their own settings', 'limit-login-attempts-reloaded' ); ?>
76
+ <p class="description"><?php esc_html_e('If disabled, the global settings will be forcibly applied to the entire network.') ?></p>
77
+ <?php elseif ( $this->network_mode ): ?>
78
+ <input type="checkbox" name="use_global_options" <?php echo $this->get_option('use_local_options' ) ? '' : 'checked' ?> value="1" class="use_global_options"/> <?php echo __( 'Use global settings', 'limit-login-attempts-reloaded' ); ?><br/>
79
+ <script>
80
+ jQuery(function($){
81
+ var first = true;
82
+ $('.use_global_options').change( function(){
83
+ var form = $(this).siblings('table');
84
+ form.stop();
85
+
86
+ if ( this.checked )
87
+ first ? form.hide() : form.fadeOut();
88
+ else
89
+ first ? form.show() : form.fadeIn();
90
+
91
+ first = false;
92
+ }).change();
93
+ });
94
+ </script>
95
+ <?php endif ?>
96
+ <table class="form-table">
97
+ <tr>
98
+ <th scope="row"
99
+ valign="top"><?php echo __( 'GDPR compliance', 'limit-login-attempts-reloaded' ); ?></th>
100
+ <td>
101
+ <input type="checkbox" name="gdpr" value="1" <?php if($gdpr): ?> checked <?php endif; ?>/>
102
+ <?php echo __( 'this makes the plugin <a href="https://gdpr-info.eu/" target="_blank" >GDPR</a> compliant', 'limit-login-attempts-reloaded' ); ?> <br/>
103
+ </td>
104
+ </tr>
105
+ <tr>
106
+ <th scope="row" valign="top"><?php echo __( 'Lockout', 'limit-login-attempts-reloaded' ); ?></th>
107
+ <td>
108
+
109
+ <input type="text" size="3" maxlength="4"
110
+ value="<?php echo( $this->get_option( 'allowed_retries' ) ); ?>"
111
+ name="allowed_retries"/> <?php echo __( 'allowed retries', 'limit-login-attempts-reloaded' ); ?>
112
+ <br/>
113
+ <input type="text" size="3" maxlength="4"
114
+ value="<?php echo( $this->get_option( 'lockout_duration' ) / 60 ); ?>"
115
+ name="lockout_duration"/> <?php echo __( 'minutes lockout', 'limit-login-attempts-reloaded' ); ?>
116
+ <br/>
117
+ <input type="text" size="3" maxlength="4"
118
+ value="<?php echo( $this->get_option( 'allowed_lockouts' ) ); ?>"
119
+ name="allowed_lockouts"/> <?php echo __( 'lockouts increase lockout time to', 'limit-login-attempts-reloaded' ); ?>
120
+ <input type="text" size="3" maxlength="4"
121
+ value="<?php echo( $this->get_option( 'long_duration' ) / 3600 ); ?>"
122
+ name="long_duration"/> <?php echo __( 'hours', 'limit-login-attempts-reloaded' ); ?> <br/>
123
+ <input type="text" size="3" maxlength="4"
124
+ value="<?php echo( $this->get_option( 'valid_duration' ) / 3600 ); ?>"
125
+ name="valid_duration"/> <?php echo __( 'hours until retries are reset', 'limit-login-attempts-reloaded' ); ?>
126
+ </td>
127
+ </tr>
128
+ <tr>
129
+ <th scope="row"
130
+ valign="top"><?php echo __( 'Notify on lockout', 'limit-login-attempts-reloaded' ); ?></th>
131
+ <td>
132
+ <input type="checkbox" name="lockout_notify_log" <?php echo $log_checked; ?>
133
+ value="log"/> <?php echo __( 'Lockout log', 'limit-login-attempts-reloaded' ); ?><br/>
134
+ <input type="checkbox" name="lockout_notify_email" <?php echo $email_checked; ?>
135
+ value="email"/> <?php echo __( 'Email to', 'limit-login-attempts-reloaded' ); ?>
136
+ <input type="email" name="admin_notify_email"
137
+ value="<?php echo esc_attr( $admin_notify_email ) ?>"
138
+ placeholder="<?php echo esc_attr( $admin_email_placeholder ); ?>"/> <?php echo __( 'after', 'limit-login-attempts-reloaded' ); ?>
139
+ <input type="text" size="3" maxlength="4"
140
+ value="<?php echo( $this->get_option( 'notify_email_after' ) ); ?>"
141
+ name="email_after"/> <?php echo __( 'lockouts', 'limit-login-attempts-reloaded' ); ?>
142
+ </td>
143
+ </tr>
144
+ <tr>
145
+ <th scope="row"
146
+ valign="top"><?php echo __( 'Whitelist', 'limit-login-attempts-reloaded' ); ?></th>
147
+ <td>
148
+ <div class="field-col">
149
+ <p class="description"><?php _e( 'One IP or IP range (1.2.3.4-5.6.7.8) per line', 'limit-login-attempts-reloaded' ); ?></p>
150
+ <textarea name="lla_whitelist_ips" rows="10" cols="50"><?php echo esc_textarea( $white_list_ips ); ?></textarea>
151
+ </div>
152
+ <div class="field-col">
153
+ <p class="description"><?php _e( 'One Username per line', 'limit-login-attempts-reloaded' ); ?></p>
154
+ <textarea name="lla_whitelist_usernames" rows="10" cols="50"><?php echo esc_textarea( $white_list_usernames ); ?></textarea>
155
+ </div>
156
+ </td>
157
+ </tr>
158
+ <tr>
159
+ <th scope="row"
160
+ valign="top"><?php echo __( 'Blacklist', 'limit-login-attempts-reloaded' ); ?></th>
161
+ <td>
162
+ <div class="field-col">
163
+ <p class="description"><?php _e( 'One IP or IP range (1.2.3.4-5.6.7.8) per line', 'limit-login-attempts-reloaded' ); ?></p>
164
+ <textarea name="lla_blacklist_ips" rows="10" cols="50"><?php echo esc_textarea( $black_list_ips ); ?></textarea>
165
+ </div>
166
+ <div class="field-col">
167
+ <p class="description"><?php _e( 'One Username per line', 'limit-login-attempts-reloaded' ); ?></p>
168
+ <textarea name="lla_blacklist_usernames" rows="10" cols="50"><?php echo esc_textarea( $black_list_usernames ); ?></textarea>
169
+ </div>
170
+ </td>
171
+ </tr>
172
+ <tr>
173
+ <th scope="row"
174
+ valign="top"><?php echo __( 'Trusted IP Origins', 'limit-login-attempts-reloaded' ); ?></th>
175
+ <td>
176
+ <div class="field-col">
177
+ <input type="text" class="regular-text" style="width: 100%;max-width: 431px;" name="lla_trusted_ip_origins" value="<?php echo esc_attr( $trusted_ip_origins ); ?>">
178
+ <p class="description"><?php _e( 'Specify the origins you trust in order of priority, separated by commas. We strongly recommend that you <b>do not</b> use anything other than REMOTE_ADDR since other origins can be easily faked. Examples: HTTP_X_FORWARDED_FOR, HTTP_CF_CONNECTING_IP, HTTP_X_SUCURI_CLIENTIP', 'limit-login-attempts-reloaded' ); ?></p>
179
+ </div>
180
+ </td>
181
+ </tr>
182
+ </table>
183
+ <p class="submit">
184
+ <input class="button button-primary" name="update_options" value="<?php echo __( 'Save Options', 'limit-login-attempts-reloaded' ); ?>"
185
+ type="submit"/>
186
+ </p>
187
+ </form>
188
+ <?php
189
+ $log = $this->get_option( 'logged' );
190
+ $log = LLA_Helpers::sorted_log_by_date( $log );
191
+
192
+ $lockouts = (array)$this->get_option('lockouts');
193
+
194
+ if( is_array( $log ) && ! empty( $log ) ) { ?>
195
+ <h3><?php echo __( 'Lockout log', 'limit-login-attempts-reloaded' ); ?></h3>
196
+ <form action="<?php echo $this->get_options_page_uri(); ?>" method="post">
197
+ <?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
198
+ <input type="hidden" value="true" name="clear_log"/>
199
+ <p class="submit">
200
+ <input class="button" name="submit" value="<?php echo __( 'Clear Log', 'limit-login-attempts-reloaded' ); ?>"
201
+ type="submit"/>
202
+ </p>
203
+ </form>
204
+
205
+ <div class="limit-login-log">
206
+ <table class="form-table">
207
+ <tr>
208
+ <th scope="col"><?php _e( "Date", 'limit-login-attempts-reloaded' ); ?></th>
209
+ <th scope="col"><?php echo _x( "IP", "Internet address", 'limit-login-attempts-reloaded' ); ?></th>
210
+ <th scope="col"><?php _e( 'Tried to log in as', 'limit-login-attempts-reloaded' ); ?></th>
211
+ <th scope="col"><?php _e( 'Gateway', 'limit-login-attempts-reloaded' ); ?></th>
212
+ <th>
213
+ </tr>
214
+
215
+ <?php foreach ( $log as $date => $user_info ) : ?>
216
+ <tr>
217
+ <td class="limit-login-date"><?php echo date_i18n( 'F d, Y H:i', $date ); ?></td>
218
+ <td class="limit-login-ip">
219
+ <?php echo esc_html( $user_info['ip'] ); ?>
220
+ </td>
221
+ <td class="limit-login-max"><?php echo esc_html( $user_info['username'] ) . ' (' . esc_html( $user_info['counter'] ) .' lockouts)'; ?></td>
222
+ <td class="limit-login-gateway"><?php echo esc_html( $user_info['gateway'] ); ?></td>
223
+ <td>
224
+ <?php if ( !empty( $lockouts[ $user_info['ip'] ] ) && $lockouts[ $user_info['ip'] ] > time() ) : ?>
225
+ <a href="#" class="button limit-login-unlock" data-ip="<?=esc_attr($user_info['ip'])?>" data-username="<?=esc_attr($user_info['username'])?>">Unlock</a>
226
+ <?php elseif ( $user_info['unlocked'] ): ?>
227
+ Unlocked
228
+ <?php endif ?>
229
+ </tr>
230
+ <?php endforeach; ?>
231
+
232
+ </table>
233
+ </div>
234
+ <script>jQuery( function($) {
235
+ $('.limit-login-log .limit-login-unlock').click( function()
236
+ {
237
+ var btn = $(this);
238
+
239
+ if ( btn.hasClass('disabled') )
240
+ return false;
241
+ btn.addClass( 'disabled' );
242
+
243
+ $.post( ajaxurl, {
244
+ action: 'limit-login-unlock',
245
+ sec: '<?=wp_create_nonce('limit-login-unlock') ?>',
246
+ ip: btn.data('ip'),
247
+ username: btn.data('username')
248
+ } )
249
+ .done( function(data) {
250
+ if ( data === true )
251
+ btn.fadeOut( function(){ $(this).parent().text('Unlocked') });
252
+ else
253
+ fail();
254
+ }).fail( fail );
255
+
256
+ function fail() {
257
+ alert('Connection error');
258
+ btn.removeClass('disabled');
259
+ }
260
+
261
+ return false;
262
+ } );
263
+ } )</script>
264
+ <?php
265
+ } /* if showing $log */
266
+ ?>
267
+