PluginProbe
Loginizer / trunk
Loginizer vtrunk
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 1.3.4 All 74 releases
loginizer / main / settings / security.php

security.php in Loginizer trunk, at main/settings/security.php

1,097 lines 40.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if(!defined('ABSPATH')){
4 die('Hacking Attempt!');
5 }
6
7 // Loginizer - Security Settings Page
8 function loginizer_page_security(){
9
10 global $loginizer, $lz_error, $lz_env, $wpdb;
11
12 if(!current_user_can('manage_options')){
13 wp_die('Sorry, but you do not have permissions to change settings.');
14 }
15
16 if(!loginizer_is_premium() && count($_POST) > 0){
17 $lz_error['not_in_free'] = __('This feature is not available in the Free version.', 'loginizer').' <a href="'.LOGINIZER_PRICING_URL.'" target="_blank" style="text-decoration:none; color:green;"><b>'.esc_html__('Upgrade to Pro', 'loginizer').'</b></a>';
18 return loginizer_page_security_T();
19 }
20
21 /* Make sure post was from this page */
22 if(count($_POST) > 0){
23 check_admin_referer('loginizer-options');
24 }
25
26 if(isset($_POST['save_lz'])){
27
28 $option['login_slug'] = lz_optpost('login_slug');
29 $option['rename_login_secret'] = (int) lz_optpost('rename_login_secret');
30 $option['hide_wp_admin'] = !empty($_POST['hide_wp_admin']);
31 $option['login_redirect_url'] = lz_optpost('login_redirect_url');
32 $option['xmlrpc_slug'] = lz_optpost('xmlrpc_slug');
33 $option['xmlrpc_disable'] = (int) lz_optpost('xmlrpc_disable');
34 $option['pingbacks_disable'] = (int) lz_optpost('pingbacks_disable');
35
36 // Login Slug Valid ?
37 if(!empty($option['login_slug'])){
38 if(strlen($option['login_slug']) <= 4 || strlen($option['login_slug']) > 50){
39 $lz_error['login_slug'] = __('The Login slug length must be greater than <b>4</b> chars and upto <b>50</b> chars long', 'loginizer');
40 }
41 }
42
43 // login slug and admin slug cannot be the same
44 $_loginizer_wp_admin = get_option('loginizer_wp_admin');
45 if(!empty($_loginizer_wp_admin['admin_slug']) && $_loginizer_wp_admin['admin_slug'] == $option['login_slug']){
46 $lz_error['lz_same_slug'] = __('The wp-login.php and wp-admin slugs cannot be the same. Choose unique names for login and admin slugs', 'loginizer');
47 return loginizer_page_security_T();
48 }
49
50 // XML-RPC Slug Valid ?
51 if(!empty($option['xmlrpc_slug'])){
52 if(strlen($option['xmlrpc_slug']) <= 4 || strlen($option['xmlrpc_slug']) > 50){
53 $lz_error['xmlrpc_slug'] = __('The XML-RPC slug length must be greater than <b>4</b> chars and upto <b>50</b> chars long', 'loginizer');
54 }
55 }
56
57 // Is there an error ?
58 if(!empty($lz_error)){
59 return loginizer_page_security_T();
60 }
61
62 // Save the options
63 update_option('loginizer_security', $option);
64
65 // Mark as saved
66 $GLOBALS['lz_saved'] = true;
67
68 }
69
70 // Reset the username
71 if(isset($_POST['save_lz_admin'])){
72
73 // Get the new username
74 $current_username = lz_optpost('current_username');
75 $new_username = lz_optpost('new_username');
76
77 if(empty($current_username)){
78 $lz_error['current_username_empty'] = __('Current username is required', 'loginizer');
79 return loginizer_page_security_T();
80 }
81
82 if(empty($new_username)){
83 $lz_error['new_username_empty'] = __('New username is required', 'loginizer');
84 return loginizer_page_security_T();
85 }
86
87 // Is the starting of the username having 'admin' ?
88 if(@strtolower(substr($new_username, 0, 5)) == 'admin'){
89 $lz_error['user_exists'] = __('The username begins with <b>admin</b>. Please change it !', 'loginizer');
90 return loginizer_page_security_T();
91 }
92
93 // Lets check if there is such a user
94 $found = get_user_by('login', $new_username);
95
96 // Found one !
97 if(!empty($found->ID)){
98 $lz_error['user_exists'] = __('The new username is already assigned to another user', 'loginizer');
99 return loginizer_page_security_T();
100 }
101
102 $old_user = get_user_by('login', $current_username);
103
104 if(empty($old_user->ID)){
105 $lz_error['current_username_invalid'] = __('No user found with the current username provided', 'loginizer');
106 return loginizer_page_security_T();
107 }
108
109 if(empty($old_user->caps['administrator'])){
110 $lz_error['user_not_admin'] = __('The user is not an administrator. Only administrator user\'s username can be changed.', 'loginizer');
111 return loginizer_page_security_T();
112 }
113
114 $is_super_admin = 0;
115 if(is_multisite() && is_super_admin($old_user->ID)){
116 $is_super_admin = 1;
117 }
118
119 // Update the username
120 $update_data = array('user_login' => $new_username);
121 $where_data = array('ID' => $old_user->ID);
122
123 $format = array('%s');
124 $where_format = array('%d');
125
126 $wpdb->update($wpdb->prefix.'users', $update_data, $where_data, $format, $where_format);
127
128 // Update the super admins list for multisite
129 if(!empty($is_super_admin)){
130
131 $super_admins = get_site_option('site_admins');
132
133 foreach($super_admins as $sk => $sv){
134 // Remove the existing username from super admins list
135 if($sv == $current_username){
136 unset($super_admins[$sk]);
137 }
138 }
139
140 // Add the new username
141 $super_admins[] = $new_username;
142
143 update_site_option( 'site_admins', $super_admins );
144
145 }
146
147 // Mark as saved
148 $GLOBALS['lz_saved'] = true;
149
150 }
151
152 // Change the wp-admin slug
153 if(isset($_POST['save_lz_wp_admin'])){
154
155 // Get the new username
156 $option['admin_slug'] = lz_optpost('admin_slug');
157 $option['restrict_wp_admin'] = (int) lz_optpost('restrict_wp_admin');
158 $option['wp_admin_msg'] = @stripslashes($_POST['wp_admin_msg']);
159 $lz_wp_admin_docs = (int) lz_optpost('lz_wp_admin_docs');
160
161 // login slug and admin slug cannot be the same
162 $_loginizer_security = get_option('loginizer_security');
163 if(!empty($_loginizer_security['login_slug']) && $_loginizer_security['login_slug'] == $option['admin_slug']){
164 $lz_error['lz_same_slug'] = __('The wp-login.php and wp-admin slugs cannot be the same. Choose unique names for login and admin slugs', 'loginizer');
165 return loginizer_page_security_T();
166 }
167
168 // Did you agree to this ?
169 if(!empty($option['admin_slug']) && empty($lz_wp_admin_docs)){
170 $lz_error['lz_wp_admin_docs'] = __('You have not confirmed that you have read the guide and configured .htaccess. Please read the guide, configure .htaccess and then save these settings and check this checkbox', 'loginizer');
171 return loginizer_page_security_T();
172 }
173
174 // Length
175 if(!empty($option['admin_slug']) && (strlen($option['admin_slug']) <= 4 || strlen($option['admin_slug']) > 50)){
176 $lz_error['admin_slug'] = __('The new Admin slug length must be greater than <b>4</b> chars and upto <b>50</b> chars long', 'loginizer');
177 return loginizer_page_security_T();
178 }
179
180 // Only regular characters
181 if(preg_match('/[^\w\d\-_]/is', $option['admin_slug'])){
182 $lz_error['admin_slug_chars'] = __('Special characters are not allowed', 'loginizer');
183 return loginizer_page_security_T();
184 }
185
186 // Update the option
187 update_option('loginizer_wp_admin', $option);
188
189 // Mark as saved
190 $GLOBALS['lz_saved'] = true;
191
192 }
193
194
195 // Save blacklisted usernames
196 if(isset($_POST['save_lz_bl_users'])){
197
198 $usernames = isset($_POST['lz_bl_users']) && is_array($_POST['lz_bl_users']) ? $_POST['lz_bl_users'] : array();
199
200 // Process the usernames i.e. remove blanks
201 foreach($usernames as $k => $v){
202 $v = trim($v);
203
204 // Unset blank values
205 if(empty($v)){
206 unset($usernames[$k]);
207 }
208
209 // Disallow these special characters to avoid XSS or any other security vulnerability
210 if(preg_match('/[\<\>\"\']/', $v)){
211 unset($usernames[$k]);
212 }
213 }
214
215 // Update the blacklist
216 update_option('loginizer_username_blacklist', array_values($usernames));
217
218 // Mark as saved
219 $GLOBALS['lz_saved'] = true;
220
221 }
222
223
224 // Save blacklisted domains
225 if(isset($_POST['save_lz_bl_domains'])){
226
227 $domains = isset($_POST['lz_bl_domains']) && is_array($_POST['lz_bl_domains']) ? $_POST['lz_bl_domains'] : array();
228
229 // Process the domains i.e. remove blanks
230 foreach($domains as $k => $v){
231 $v = trim($v);
232
233 // Unset blank values
234 if(empty($v)){
235 unset($domains[$k]);
236 }
237
238 // Disallow these special characters to avoid XSS or any other security vulnerability
239 if(preg_match('/[\<\>\"\']/', $v)){
240 unset($domains[$k]);
241 }
242 }
243
244 // Update the blacklist
245 update_option('loginizer_domains_blacklist', array_values($domains));
246
247 // Mark as saved
248 $GLOBALS['lz_saved'] = true;
249
250 }
251
252
253 if(isset($_POST['save_lz_csrf_protection'])){
254 update_option('loginizer_csrf_protection', empty(lz_optpost('enable_csrf_protection')) ? false : true);
255
256 delete_transient('loginizer_csrf_mod_rewrite');
257 $GLOBALS['lz_saved'] = true;
258 }
259
260 if(isset($_POST['save_lz_limit_session'])){
261 $limit_session = map_deep($_POST['limit_session'], 'sanitize_text_field');
262
263 if(empty($limit_session)){
264 delete_option('loginizer_limit_session');
265 } else {
266 update_option('loginizer_limit_session', $limit_session);
267 }
268
269 $GLOBALS['lz_saved'] = true;
270 }
271
272 if(isset($_POST['save_lz_user_enum'])){
273 $user_enum = !empty($_POST['user_enum']) && is_array($_POST['user_enum']) ? map_deep($_POST['user_enum'], 'sanitize_text_field') : [];
274 update_option('loginizer_user_enum', $user_enum);
275 $GLOBALS['lz_saved'] = true;
276 }
277
278 // Call theme
279 loginizer_page_security_T();
280
281 }
282
283 // Loginizer - Security Settings Page Theme
284 function loginizer_page_security_T(){
285
286 global $loginizer, $lz_error, $lz_env;
287
288 // Universal header
289 loginizer_page_header('Security Settings');
290
291 loginizer_feature_available('Security Settings');
292
293 // Saved ?
294 if(!empty($GLOBALS['lz_saved'])){
295 echo '<div id="message" class="updated"><p>'. __('The settings were saved successfully', 'loginizer'). '</p></div><br />';
296 }
297
298 // Any errors ?
299 if(!empty($lz_error)){
300 lz_report_error($lz_error);echo '<br />';
301 }
302
303 $current_admin = get_user_by('id', 1);
304
305 ?>
306
307 <style>
308 input[type="text"], textarea, select {
309 width: 70%;
310 }
311
312 .form-table label{
313 font-weight:bold;
314 }
315
316 .exp{
317 font-size:12px;
318 }
319 </style>
320
321 <form action="" method="post" enctype="multipart/form-data" loginizer-premium-only="1">
322
323 <div id="" class="postbox">
324
325 <div class="postbox-header">
326 <h2 class="hndle ui-sortable-handle">
327 <span><?php echo __('Rename Login Page', 'loginizer'); ?></span>
328 </h2>
329 </div>
330
331 <div class="inside">
332
333 <?php wp_nonce_field('loginizer-options'); ?>
334 <table class="form-table">
335 <tr>
336 <td scope="row" valign="top" colspan="2">
337 <i><?php echo __('You can rename your Login page from','loginizer'). ' <b> '. $loginizer['login_basename'].' </b> '.__(' to anything of your choice e.g. mylogin. This would make it very difficult for automated attack bots to know where to login !','loginizer'); ?></i>
338 </td>
339 </tr>
340 <tr>
341 <td scope="row" valign="top" style="width:40% !important">
342 <label><?php echo __('New Login Slug', 'loginizer'); ?></label><br>
343 <span class="exp"><?php echo __('Set blank to reset to the original login URL', 'loginizer'); ?></span>
344 </td>
345 <td>
346 <input type="text" size="50" value="<?php echo (!empty($loginizer['login_slug']) ? lz_POSTval('login_slug', $loginizer['login_slug']) : ''); ?>" name="login_slug" />
347 </td>
348 </tr>
349
350 <?php
351
352 if(!defined('SITEPAD')){
353
354 ?>
355 <tr>
356 <td scope="row" valign="top" style="width:200px !important">
357 <label><?php echo __('Access Secretly Only', 'loginizer'); ?></label><br>
358 <span class="exp"><?php echo sprintf(__('If set, then all Login URL\'s will still point to %s and users will have to access the New Login Slug by typing it in the browser.', 'loginizer'), esc_html($loginizer['login_basename'])); ?></span>
359 </td>
360 <td>
361 <input type="checkbox" value="1" name="rename_login_secret" <?php echo lz_POSTchecked('rename_login_secret', (empty($loginizer['rename_login_secret']) ? false : true)); ?> />
362 </td>
363 </tr>
364 <tr>
365 <td scope="row" valign="top" style="width:200px !important">
366 <label><?php echo __('Hide WP Admin', 'loginizer'); ?></label><br>
367 <span class="exp"><?php echo __('If the user is not logged in they wont be able to access wp-admin url.', 'loginizer'); ?></span>
368 </td>
369 <td>
370 <input type="checkbox" value="1" name="hide_wp_admin" <?php echo lz_POSTchecked('hide_wp_admin', (empty($loginizer['hide_wp_admin']) ? false : true)); ?> />
371 </td>
372 </tr>
373 <tr>
374 <td scope="row" valign="top" style="width:200px !important">
375 <label><?php echo __('Redirect URL', 'loginizer'); ?></label><br>
376 <span class="exp"><?php echo __('Which page should be shown when someone tries to access wp-admin when it is hidden.', 'loginizer'); ?></span>
377 <span class="exp"><?php echo __('Default: HomePage.', 'loginizer'); ?></span>
378 </td>
379 <td>
380 <?php echo esc_url(home_url('/')); ?>&nbsp;<input type="text" style="width:20%;" name="login_redirect_url" value="<?php echo (!empty($loginizer['login_redirect_url']) ? lz_POSTval('login_redirect_url', $loginizer['login_redirect_url']) : ''); ?>"/>
381 </td>
382 </tr>
383
384 <?php
385
386 }
387
388 ?>
389 </table><br />
390 <center><input name="save_lz" class="button button-primary action" value="<?php echo __('Save Settings', 'loginizer'); ?>" type="submit" /></center>
391
392 </div>
393 </div>
394
395 <?php
396
397 if(!defined('SITEPAD')){
398
399 ?>
400
401 <div id="" class="postbox">
402
403 <div class="postbox-header">
404 <h2 class="hndle ui-sortable-handle">
405 <span><?php echo __('XML-RPC Settings', 'loginizer'); ?></span>
406 </h2>
407 </div>
408
409 <div class="inside">
410
411 <?php wp_nonce_field('loginizer-options'); ?>
412 <table class="form-table">
413 <tr>
414 <td scope="row" valign="top" colspan="2">
415 <i><?php echo __('WordPress\'s XML-RPC feature allows external services to access and modify content on the site. Services like the Jetpack plugin, the WordPress mobile app, pingbacks, etc make use of the XML-RPC feature. If this site does not use a service that requires XML-RPC, please <b>disable</b> the XML-RPC feature as it prevents attackers from using the feature to attack the site. If your service can use a custom XML-RPC URL, you can also <b>rename</b> the XML-RPC page to a <b>custom slug</b>.', 'loginizer'); ?></i>
416 </td>
417 </tr>
418 <tr>
419 <td scope="row" valign="top" style="width:40% !important">
420 <label><?php echo __('Disable XML-RPC', 'loginizer'); ?></label>
421 </td>
422 <td>
423 <input type="checkbox" value="1" name="xmlrpc_disable" <?php echo lz_POSTchecked('xmlrpc_disable', (empty($loginizer['xmlrpc_disable']) ? false : true)); ?> />
424 </td>
425 </tr>
426 <tr>
427 <td scope="row" valign="top" style="width:40% !important">
428 <label><?php echo __('Disable Pingbacks', 'loginizer'); ?></label>
429 </td>
430 <td>
431 <input type="checkbox" value="1" name="pingbacks_disable" <?php echo lz_POSTchecked('pingbacks_disable', (empty($loginizer['pingbacks_disable']) ? false : true)); ?> />
432 </td>
433 </tr>
434 <tr>
435 <td scope="row" valign="top">
436 <label><?php echo __('New XML-RPC Slug', 'loginizer'); ?></label><br>
437 <span class="exp"><?php echo __('Set blank to reset to the original XML-RPC URL', 'loginizer'); ?></span>
438 </td>
439 <td>
440 <input type="text" size="50" value="<?php echo (!empty($loginizer['xmlrpc_slug']) ? lz_optpost('xmlrpc_slug', $loginizer['xmlrpc_slug']) : ''); ?>" name="xmlrpc_slug" />
441 </td>
442 </tr>
443 </table><br />
444 <center><input name="save_lz" class="button button-primary action" value="<?php echo __('Save Settings', 'loginizer'); ?>" type="submit" /></center>
445
446 </div>
447 </div>
448
449 <?php
450
451 }
452
453 ?>
454
455 </form>
456
457 <?php
458
459 if(!defined('SITEPAD')){
460
461 ?>
462
463 <script type="text/javascript">
464
465 function lz_update_htaccess_admin(e){
466
467 var admin_name = jQuery(e).val();
468
469 if(admin_name.length == 0){
470 admin_name = 'wp-admin';
471 }
472
473 var textarea = jQuery('.lz-htaccess-textarea');
474
475 if(textarea.length == 0) {
476 return;
477 }
478
479 var htaccess = textarea.val();
480 htaccess = htaccess.replace(
481 /RewriteRule \^\(?([^\(\s]+)(?=\(-lzs|\()/g,
482 (match, current_slug) => match.replace(current_slug, admin_name)
483 );
484 textarea.val(htaccess);
485
486 }
487
488
489 function dirname(path) {
490 return path.replace(/\\/g, '/').replace(/\/[^/]*\/?$/, '');
491 }
492
493 function lz_test_wp_admin(){
494
495 var data = new Object();
496 data["action"] = "loginizer_wp_admin";
497 data["nonce"] = "<?php echo wp_create_nonce('loginizer_admin_ajax');?>";
498
499 var new_ajaxurl = dirname(dirname(ajaxurl))+'/'+jQuery('#lz_admin_slug').val()+'/admin-ajax.php';
500
501 // AJAX and on success function
502 jQuery.post(new_ajaxurl, data, function(response){
503
504 if(response['result'] == 1){
505 alert("<?php echo __('Everything seems to be good. You can proceed to save the settings !', 'loginizer'); ?>");
506 }
507
508 // Throw an error for failures
509 }).fail(function() {
510 alert("<?php echo __('There was an error connecting to WordPress with the new Admin Slug. Did you configure everything properly ?', 'loginizer'); ?>");
511 });
512 //jQuery.ajax('<input type="text" size="30" value="" name="lz_bl_users[]" class="lz_bl_users" />');
513 return false;
514 };
515
516 </script>
517
518 <form action="" method="post" enctype="multipart/form-data" loginizer-premium-only="1">
519 <div id="" class="postbox">
520
521 <div class="postbox-header">
522 <h2 class="hndle ui-sortable-handle">
523 <span><?php echo __('Rename wp-admin access', 'loginizer'); ?></span>
524 </h2>
525 </div>
526
527 <div class="inside">
528
529 <?php wp_nonce_field('loginizer-options'); ?>
530 <table class="form-table">
531 <?php
532 if(preg_match('/(apache|litespeed|lsws)/is', $_SERVER["SERVER_SOFTWARE"])){
533 // Supported. Do nothing
534 }else{
535 echo '<tr>
536 <td scope="row" valign="top" colspan="2">
537 <div style="color:#a94442; background-color:#f2dede; border-color:#ebccd1; padding:15px; border:1px solid transparent; border-radius:4px;">'.__('Rename wp-admin access feature is supported only on Apache and Litespeed', 'loginizer').'</div>
538 </td>
539 </tr>';
540 }
541
542 if(defined('LOGINIZER_PREMIUM') && !empty($loginizer['enable_csrf_protection']) && empty($loginizer['admin_slug'])){
543
544 echo '<div style="color: #856404; background-color: #fff3cd; border-color: #ffeeba; padding: 15px; font-size:1rem; font-weight:400;">'.esc_html__('Note: Be careful while changing the Admin name as your CSRF Protection is on', 'loginizer').'</div>';
545
546 }
547 ?>
548 <tr>
549 <td scope="row" valign="top" colspan="2">
550 <i><?php echo __('You can rename your WordPress Admin access URL <b>wp-admin</b> to anything of your choice e.g. my-admin. This will require you to change .htaccess, so please follow','loginizer'); ?> <a href="<?php echo LOGINIZER_DOCS;?>Renaming_the_WP-Admin_Area" target="_blank"><?php echo __('our guide','loginizer').'</a> '.__('on how to do so !','loginizer'); ?></i>
551 </td>
552 </tr>
553 <tr>
554 <td scope="row" valign="top" style="width:40% !important">
555 <label><?php echo __('New wp-admin Slug', 'loginizer'); ?></label><br>
556 <span class="exp"><?php echo __('Set blank to reset to the original wp-admin URL', 'loginizer'); ?></span>
557 </td>
558 <td>
559 <input type="text" size="50" value="<?php echo (!empty($loginizer['admin_slug']) ? lz_optpost('admin_slug', $loginizer['admin_slug']) : ''); ?>" name="admin_slug" id="lz_admin_slug" onchange="lz_update_htaccess_admin(this)"/>
560 </td>
561 </tr>
562 <tr>
563 <td scope="row" valign="top" style="width:200px !important">
564 <label><?php echo __('Disable wp-admin access', 'loginizer'); ?></label><br>
565 <span class="exp"><?php echo __('If set, then only the new admin slug will work and access to the Old Admin Slug i.e. wp-admin will be disabled. If anyone accesses wp-admin, a warning will be shown.<br><label>NOTE: Please use this option cautiously !</label>', 'loginizer'); ?></span>
566 </td>
567 <td>
568 <input type="checkbox" id="lz_restrict_wp_admin" onchange="lz_wp_admin_msg_toggle()" value="1" name="restrict_wp_admin" <?php echo lz_POSTchecked('restrict_wp_admin', (empty($loginizer['restrict_wp_admin']) ? false : true)); ?> />
569 </td>
570 </tr>
571 <tr id="lz_wp_admin_msg_row" style="display:none">
572 <td scope="row" valign="top">
573 <label><?php echo __('WP-Admin Error Message', 'loginizer'); ?></label><br>
574 <span class="exp"><?php echo __('Error message to show if someone accesses wp-admin', 'loginizer'); ?></span> Default : <?php echo (!empty($loginizer['wp_admin_d_msg']) ? $loginizer['wp_admin_d_msg'] : ''); ?>
575 </td>
576 <td>
577 <input type="text" size="50" value="<?php echo lz_htmlizer(!empty($_POST['wp_admin_msg']) ? stripslashes($_POST['wp_admin_msg']) : (!empty($loginizer['wp_admin_msg']) ? $loginizer['wp_admin_msg'] : '')); ?>" name="wp_admin_msg" id="lz_wp_admin_msg" />
578 </td>
579 </tr>
580
581 <?php
582 loginizer_htaccess_rules();
583 ?>
584 <tr>
585 <td scope="row" valign="top" style="width:200px !important">
586 <label><?php echo __('I have setup .htaccess', 'loginizer'); ?></label><br>
587 <span class="exp"><?php echo sprintf(__('You need to confirm that you have configured .htaccess as per %sour guide%s so that we can safely enable this feature', 'loginizer'), '<a href="'.LOGINIZER_DOCS.'Renaming_the_WP-Admin_Area" target="_blank">', '</a>'); ?></span>
588 </td>
589 <td>
590 <input type="checkbox" value="1" name="lz_wp_admin_docs" />
591 <input type="button" onclick="lz_test_wp_admin()" class="button" style="background: #5cb85c; color:white; border:#5cb85c" value="<?php echo __('Test New WP-Admin Slug', 'loginizer'); ?>" />
592 </td>
593 </tr>
594 </table><br />
595 <center><input name="save_lz_wp_admin" class="button button-primary action" value="<?php echo __('Save Settings', 'loginizer'); ?>" type="submit" /></center>
596
597 </div>
598 </div>
599 </form>
600
601 <script type="text/javascript">
602 function lz_csrf_htaccess_update(e){
603 event.preventDefault();
604
605 var tb = jQuery(e).closest('table'),
606 csrf_enabled = tb.find('[name="enable_csrf_protection"]'),
607 admin_name = tb.find('#lz_admin_slug');
608
609 var data = new Object();
610
611 // Setting admin name if anything is set
612 if(admin_name && admin_name.val()){
613 data['admin_name'] = admin_name.val();
614 }
615
616 if(csrf_enabled){
617 data['csrf'] = true;
618 } else {
619 data['csrf'] = false;
620 }
621
622 data['action'] = 'loginizer_update_csrf_mod';
623 data['nonce'] = '<?php echo wp_create_nonce('loginizer_admin_ajax');?>';
624
625 var new_ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>'
626
627 // AJAX and on success function
628 jQuery.post(new_ajaxurl, data, function(response){
629
630 if(response['success'] == true){
631 alert("<?php esc_html_e('.htaccess has been updated !', 'loginizer'); ?>");
632 }
633
634 // Throw an error for failures
635 }).fail(function() {
636 alert("<?php esc_html_e('Was unable to update the .htaccess file so please update it manually', 'loginizer'); ?>");
637 });
638
639 return false;
640
641 }
642
643 function lz_show_rewrite_rule(e){
644 event.preventDefault();
645 jQuery(e).closest('td').find('textarea').toggle();
646 }
647
648
649 </script>
650
651 <!-- Begin CSRF Protection -->
652 <form action="" method="post" loginizer-premium-only="1">
653 <div id="" class="postbox">
654
655 <div class="postbox-header">
656 <h2 class="hndle ui-sortable-handle">
657 <span><?php esc_html_e('CSRF Protection', 'loginizer'); ?></span>
658 </h2>
659 </div>
660
661 <div class="inside">
662
663 <?php wp_nonce_field('loginizer-options'); ?>
664 <table class="form-table">
665 <tr>
666 <td scope="row" valign="top" colspan="2">
667 <i><?php esc_html_e('This prevents CSRF attacks by adding a session string to admin URLs, making them nearly impossible for attackers to predict.', 'loginizer'); ?></i>
668 </td>
669 </tr>
670 <tr>
671 <td scope="row" valign="top" style="width:400px !important">
672 <label><?php esc_html_e('Enable CSRF Protection', 'loginizer'); ?></label><br>
673 <span class="exp"><?php esc_html_e('If enabled, it will update the URL of wp-admin with a random session string in the URL making it hard to predict the URL.', 'loginizer'); ?></span>
674 </td>
675 <td valign="top">
676 <input type="checkbox" value="1" name="enable_csrf_protection" <?php echo lz_POSTchecked('enable_csrf_protection', (empty($loginizer['enable_csrf_protection']) ? false : true)); ?> />
677 </td>
678 </tr>
679 <?php
680 loginizer_htaccess_rules(true);
681 ?>
682 </table><br />
683 <div style="text-align: center;"><input name="save_lz_csrf_protection" class="button button-primary action" value="<?php esc_html_e('Save Settings', 'loginizer'); ?>" type="submit" />
684 </div>
685 </div>
686 </div>
687 </form>
688 <!-- End CSRF Protection -->
689
690
691 <script type="text/javascript">
692
693 function lz_wp_admin_msg_toggle(){
694 var ele = jQuery('#lz_restrict_wp_admin')[0];
695 if(ele.checked){
696 jQuery('#lz_wp_admin_msg_row').show();
697 }else{
698 jQuery('#lz_wp_admin_msg_row').hide();
699 }
700 };
701
702 lz_wp_admin_msg_toggle();
703
704 </script>
705
706
707 <form action="" method="post" enctype="multipart/form-data" loginizer-premium-only="1">
708 <div id="" class="postbox">
709
710 <div class="postbox-header">
711 <h2 class="hndle ui-sortable-handle">
712 <span><?php echo __('Change Admin Username', 'loginizer'); ?></span>
713 </h2>
714 </div>
715
716 <div class="inside">
717
718 <?php wp_nonce_field('loginizer-options'); ?>
719 <table class="form-table">
720 <tr>
721 <td scope="row" valign="top" colspan="2">
722 <i><?php echo __('You can change the Admin Username from here to anything of your choice e.g. iamtheboss. This would make it very difficult for automated attack bots to know what is the admin username !', 'loginizer'); ?></i>
723 </td>
724 </tr>
725 <tr>
726 <td scope="row" valign="top" style="width:40% !important">
727 <label for="current_username"><?php echo __('Current Username', 'loginizer'); ?></label><br>
728 <span class="exp"><?php echo __('The current username you want to change', 'loginizer'); ?></span>
729 </td>
730 <td>
731 <input type="text" size="50" value="<?php echo lz_optpost('current_username', (!empty($current_admin->user_login) ? $current_admin->user_login : '')); ?>" name="current_username" id="current_username" />
732 </td>
733 </tr>
734 <tr>
735 <td scope="row" valign="top" style="width:40% !important">
736 <label for="new_username"><?php echo __('New Username', 'loginizer'); ?></label><br>
737 <span class="exp"><?php echo __('The new username you want to set', 'loginizer'); ?></span>
738 </td>
739 <td>
740 <input type="text" size="50" value="<?php echo lz_optpost('new_username', ''); ?>" name="new_username" id="new_username" />
741 </td>
742 </tr>
743 </table><br />
744 <i><?php echo __('Note: Username can be changed only for administrator users.', 'loginizer'); ?></i>
745 <center><input name="save_lz_admin" class="button button-primary action" value="<?php echo __('Set the Username', 'loginizer'); ?>" type="submit" /></center>
746
747 </div>
748 </div>
749 </form>
750
751 <script type="text/javascript">
752 function add_lz_bl_users(){
753 jQuery("#lz_bl_users").append('<input type="text" size="30" value="" name="lz_bl_users[]" class="lz_bl_users" />');
754 return false;
755 };
756 </script>
757
758 <style>
759 .lz_bl_users, .lz_bl_domains{
760 margin-bottom:20px;
761 }
762 </style>
763
764 <form action="" method="post" enctype="multipart/form-data" loginizer-premium-only="1">
765 <div id="" class="postbox">
766
767 <div class="postbox-header">
768 <h2 class="hndle ui-sortable-handle">
769 <span><?php echo __('Username Auto Blacklist', 'loginizer'); ?></span>
770 </h2>
771 </div>
772
773 <div class="inside">
774
775 <?php wp_nonce_field('loginizer-options'); ?>
776 <table class="form-table">
777 <tr>
778 <td scope="row" valign="top" colspan="2">
779 <i><?php echo __('Attackers generally use common usernames like <b>admin, administrator, or variations of your domain name / business name</b>. You can specify such username here and Loginizer will auto-blacklist the IP Address(s) of clients who try to use such username(s).', 'loginizer'); ?></i>
780 </td>
781 </tr>
782 <tr>
783 <td scope="row" valign="top" style="width:40% !important; vertical-align:top !important;">
784 <label><?php echo __('Username(s)', 'loginizer'); ?></label><br>
785 <span class="exp"><?php echo __('You can use - <b>*</b> (Star)- as a wild card as well. Blank fields will be ignored', 'loginizer'); ?></span>
786 </td>
787 <td>
788 <div id="lz_bl_users">
789 <?php
790
791 $usernames = isset($_POST['lz_bl_users']) && is_array($_POST['lz_bl_users']) ? $_POST['lz_bl_users'] : (!empty($loginizer['username_blacklist']) ? $loginizer['username_blacklist'] : []);
792
793 if(empty($usernames)){
794 $usernames = array();
795 $usernames[] = '';
796 }
797
798 foreach($usernames as $_user){
799
800 // Disallow these special characters to avoid XSS or any other security vulnerability
801 if(preg_match('/[\<\>\"\']/', $_user)){
802 continue;
803 }
804
805 echo '<input type="text" size="30" value="'.$_user.'" name="lz_bl_users[]" class="lz_bl_users" />';
806 }
807
808 ?>
809 </div>
810 <br />
811 <input class="button" type="button" value="<?php echo __('Add New Username', 'loginizer'); ?>" onclick="return add_lz_bl_users();" style="float:right" />
812 </td>
813 </tr>
814 </table><br />
815 <center><input name="save_lz_bl_users" class="button button-primary action" value="<?php echo __('Save Username(s)', 'loginizer'); ?>" type="submit" /></center>
816
817 </div>
818 </div>
819 </form>
820
821 <script type="text/javascript">
822 function add_lz_bl_domains(){
823 jQuery("#lz_bl_domains").append('<input type="text" size="30" value="" name="lz_bl_domains[]" class="lz_bl_domains" />');
824 return false;
825 };
826 </script>
827
828
829 <form action="" method="post" enctype="multipart/form-data" loginizer-premium-only="1">
830 <div id="" class="postbox">
831
832 <div class="postbox-header">
833 <h2 class="hndle ui-sortable-handle">
834 <span><?php echo __('New Registration Domain Blacklist', 'loginizer'); ?></span>
835 </h2>
836 </div>
837
838 <div class="inside">
839
840 <?php wp_nonce_field('loginizer-options'); ?>
841 <table class="form-table">
842 <tr>
843 <td scope="row" valign="top" colspan="2">
844 <i>If you would like to ban new registrations from a particular domain, you can use this utility to do so.</i>
845 </td>
846 </tr>
847 <tr>
848 <td scope="row" valign="top" style="width:40% !important; vertical-align:top !important;">
849 <label><?php echo __('Domain(s)', 'loginizer'); ?></label><br>
850 <span class="exp"><?php echo __('You can use - <b>*</b> (Star)- as a wild card as well. Blank fields will be ignored', 'loginizer'); ?></span>
851 </td>
852 <td>
853 <div id="lz_bl_domains">
854 <?php
855
856 $domains = isset($_POST['lz_bl_domains']) && is_array($_POST['lz_bl_domains']) ? $_POST['lz_bl_domains'] : (!empty($loginizer['domains_blacklist']) ? $loginizer['domains_blacklist'] : []);
857
858 if(empty($domains)){
859 $domains = array();
860 $domains[] = '';
861 }
862
863 foreach($domains as $_domain){
864
865 // Disallow these special characters to avoid XSS or any other security vulnerability
866 if(preg_match('/[\<\>\"\']/', $_domain)){
867 continue;
868 }
869
870 echo '<input type="text" size="30" value="'.$_domain.'" name="lz_bl_domains[]" class="lz_bl_domains" />';
871 }
872
873 ?>
874 </div>
875 <br />
876 <input class="button" type="button" value="<?php echo __('Add New Domain', 'loginizer'); ?>" onclick="return add_lz_bl_domains();" style="float:right" />
877 </td>
878 </tr>
879 </table><br />
880 <center><input name="save_lz_bl_domains" class="button button-primary action" value="<?php echo __('Save Domains(s)', 'loginizer'); ?>" type="submit" /></center>
881
882 </div>
883 </div>
884 </form>
885
886 <form action="" method="post" enctype="multipart/form-data" loginizer-premium-only="1">
887 <div id="" class="postbox">
888
889 <div class="postbox-header">
890 <h2 class="hndle ui-sortable-handle">
891 <span><?php echo __('Limit Concurrent Sessions', 'loginizer'); ?>
892 </h2>
893 </div>
894
895 <div class="inside">
896
897 <?php wp_nonce_field('loginizer-options'); ?>
898 <table class="form-table">
899 <tr>
900 <td scope="row" valign="top" colspan="2">
901 <i><?php echo __('This feature will help limit the number of devices your user can login to concurrently', 'loginizer'); ?></i>
902 </td>
903 </tr>
904 <tr>
905 <td scope="row" valign="top" style="width:300px !important">
906 <label><?php echo __('Enable', 'loginizer'); ?></label><br>
907 <span class="exp"><?php echo __('Enabling it will start limiting number of devices the user can login on concurrently', 'loginizer'); ?></span>
908 </td>
909 <td>
910 <input type="checkbox" value="1" name="limit_session[enable]" <?php echo (!empty($_POST['limit_session']['enable']) || (!empty($loginizer['limit_session']['enable']))) ? 'checked' : false; ?> />
911 </td>
912 </tr>
913 <tr>
914 <td scope="row" valign="top" style="width:300px !important">
915 <label><?php echo __('Limit Type', 'loginizer'); ?></label><br>
916 </td>
917 <td>
918 <input type="radio" value="block" name="limit_session[type]" <?php echo ((!empty($_POST['limit_session']['type']) && $_POST['limit_session']['type'] == 'block') || (!empty($loginizer['limit_session']['type']) && $loginizer['limit_session']['type'] == 'block' ) ? 'checked' : false); ?> />
919 <span class="exp"><?php echo '<strong>'.__('Block', 'loginizer') . ' : </strong>' . __('Blocks all the login attempts if limit is reached', 'loginizer'); ?></span><br/>
920 <input type="radio" value="destroy" name="limit_session[type]" <?php echo ((!empty($_POST['limit_session']['type']) && $_POST['limit_session']['type'] == 'destroy') || (!empty($loginizer['limit_session']['type']) && $loginizer['limit_session']['type'] == 'destroy' ) ? 'checked' : false); ?> />
921 <span class="exp"><?php echo '<strong>'.__('Destroy', 'loginizer') . ' : </strong>' . __('Revokes all the sessions on successful login', 'loginizer'); ?></span>
922 </td>
923 </tr>
924 <tr>
925 <td scope="row" valign="top" style="width:40% !important">
926 <label><?php echo __('Max Session Count', 'loginizer'); ?></label><br>
927 <span class="exp"><?php echo __('Set Maximum number of sessions can be created', 'loginizer'); ?></span>
928 </td>
929 <td>
930 <input type="number" min="1" max="10" size="20" value="<?php echo (!empty($_POST['limit_session']['count']) ? esc_attr($_POST['limit_session']['count']) : (!empty($loginizer['limit_session']['count']) ? esc_attr($loginizer['limit_session']['count']) : 1)); ?>" name="limit_session[count]" />
931 </td>
932 </tr>
933 <tr>
934 <tr>
935 <td scope="row" valign="top">
936 <label><?php echo __('Exclude Roles', 'loginizer'); ?></label><br>
937 <span class="exp"><?php echo __('Excluded roles won\'t face session limit checks', 'loginizer'); ?></span>
938 </td>
939 <td>
940 <div style="max-height:120px;; overflow-y:auto;">
941 <?php
942 global $wp_roles;
943
944 foreach($wp_roles->roles as $key => $role){
945 $checked = '';
946
947 if(!empty($_POST['limit_session']['roles']) && in_array($key, $_POST['limit_session']['roles'])
948 || !empty($loginizer['limit_session']['roles']) && in_array($key, $loginizer['limit_session']['roles'])){
949 $checked = 'checked';
950 }
951
952
953 echo '<input type="checkbox" value="'.esc_attr($key).'" name="limit_session[roles][]" '.esc_attr($checked).'/>'. esc_html($role['name']) . '<br/>';
954 }
955 ?>
956 </div>
957 </td>
958 </tr>
959 </table><br/>
960 <center><input name="save_lz_limit_session" class="button button-primary action" value="<?php echo __('Save Settings', 'loginizer'); ?>" type="submit" /></center>
961
962 </div>
963 </div>
964 </form>
965
966 <form action="" method="post" enctype="multipart/form-data" loginizer-premium-only="1">
967 <div id="" class="postbox">
968
969 <div class="postbox-header">
970 <h2 class="hndle ui-sortable-handle">
971 <span><?php echo __('Username Enumeration Protection', 'loginizer'); ?></span>
972 </h2>
973 </div>
974
975 <div class="inside">
976
977 <?php wp_nonce_field('loginizer-options'); ?>
978 <table class="form-table">
979 <tr>
980 <td scope="row" valign="top" colspan="2">
981 <i><?php echo __('WordPress can leak usernames through several channels such as the REST API, author archives, login form errors, lost password form, and oEmbed. Enable the relevant options below to prevent username enumeration via these channels.', 'loginizer'); ?></i>
982 </td>
983 </tr>
984 <?php
985 $lz_user_enum = get_option('loginizer_user_enum', []);
986 $lz_enum_opts = [
987 'disable_rest_users' => [
988 'label' => __('Disable REST API Users endpoint', 'loginizer'),
989 'exp' => __('Blocks the /wp-json/wp/v2/users endpoint for visitors who are not logged in', 'loginizer')
990 ],
991 'disable_author_enum' => [
992 'label' => __('Disable Author Archive enumeration', 'loginizer'),
993 'exp' => __('Shows a 404 for ?author=1 and ?author_name= URLs, which reveal usernames via the author archive', 'loginizer')
994 ],
995 'hide_login_errors' => [
996 'label' => __('Hide Login form errors', 'loginizer'),
997 'exp' => __('Shows one generic error, so a valid username cannot be told apart from a wrong password', 'loginizer')
998 ],
999 'hide_lostpass_errors' => [
1000 'label' => __('Hide Lost Password form errors', 'loginizer'),
1001 'exp' => __('Always shows the same message, so it does not confirm whether a username or email exists', 'loginizer')
1002 ],
1003 'disable_oembed_author' => [
1004 'label' => __('Disable Author info in oEmbed', 'loginizer'),
1005 'exp' => __('Removes the author name and URL from the oEmbed data of your posts', 'loginizer')
1006 ],
1007 ];
1008 foreach($lz_enum_opts as $enum_key => $enum_opt){
1009 $enum_checked = !empty($_POST['user_enum'][$enum_key]) || (!empty($lz_user_enum[$enum_key]) && empty($_POST['save_lz_user_enum']));
1010 ?>
1011 <tr>
1012 <td scope="row" valign="top" style="width:40% !important">
1013 <label><?php echo esc_html($enum_opt['label']); ?></label><br>
1014 <span class="exp"><?php echo esc_html($enum_opt['exp']); ?></span>
1015 </td>
1016 <td>
1017 <input type="checkbox" value="1" name="user_enum[<?php echo esc_attr($enum_key); ?>]" <?php echo $enum_checked ? 'checked' : ''; ?> />
1018 </td>
1019 </tr>
1020 <?php } ?>
1021 </table><br/>
1022 <center><input name="save_lz_user_enum" class="button button-primary action" value="<?php echo __('Save Settings', 'loginizer'); ?>" type="submit" /></center>
1023
1024 </div>
1025 </div>
1026 </form>
1027
1028 <?php
1029
1030 }
1031
1032 loginizer_page_footer();
1033
1034 }
1035
1036 // .htaccess UI options for wp-admin and CSRF
1037 function loginizer_htaccess_rules($is_csrf = false){
1038 global $loginizer;
1039
1040 $admin_slug = 'wp-admin';
1041
1042 if(!empty($loginizer['admin_slug'])){
1043 $admin_slug = $loginizer['admin_slug'];
1044 }
1045
1046 // getting sub directory if any
1047 $home_root = parse_url(home_url());
1048
1049 if(isset($home_root['path'])){
1050 $home_root = trailingslashit($home_root['path']);
1051 } else {
1052 $home_root = '/';
1053 }
1054
1055 // Selecting admin slug
1056 $admin_slug = 'wp-admin';
1057
1058 if(!empty($loginizer['admin_slug'])){
1059 $admin_slug = $loginizer['admin_slug'];
1060 }
1061
1062 // Setting the rule
1063 $rule = '# BEGIN Loginizer' . "\n";
1064 $rule .= '<IfModule mod_rewrite.c>' . "\n";
1065 $rule .= 'RewriteEngine On' . "\n";
1066 $rule .= 'RewriteBase ' . $home_root . "\n\n";
1067 $rule .= 'RewriteRule ^(' . $admin_slug . '(-lzs.{20})?)$ $1/ [R=301,L]' . "\n";
1068 $rule .= 'RewriteRule ^' . $admin_slug . '(-lzs.{20})?(/?)(.*) wp-admin/$3 [L]' . "\n";
1069 $rule .= '</IfModule>' . "\n";
1070 $rule .= '# END Loginizer' . "\n";
1071
1072 if(is_writable(ABSPATH . '/.htaccess')){
1073 echo '<tr>
1074 <td scope="row" valign="top" style="width:400px !important">
1075 <label>'. esc_html__('Update .htaccess', 'loginizer').'</label><br>
1076 <span class="exp">'. (!empty($is_csrf) ? esc_html__('Rewrites rule for CSRF session URL', 'loginizer') : esc_html__('Rewrites rule to change wp-admin and if you have a Multisite then check', 'loginizer') . ' <a href="'.LOGINIZER_DOCS.'Renaming_the_WP-Admin_Area" target="_blank">our guide</a>') . '</span>
1077 </td>
1078 <td valign="top">
1079 <button class="button" style="background: #5cb85c; color:white; border:#5cb85c;" onclick="lz_csrf_htaccess_update(this)">Update .htaccess</button><a onClick="lz_show_rewrite_rule(this)" href="#" style="margin-left:5px; line-height: 2; font-weight:500;">Show Rewrite Rule</a><br/><br/>
1080
1081 <textarea rows="8" readonly style="display:none;" class="lz-htaccess-textarea">' . trim($rule) . '</textarea>
1082 </td>
1083 </tr>';
1084
1085 } else {
1086 echo '<tr>
1087 <td scope="row" valign="top" style="width:400px !important">
1088 <label>'. esc_html__('Manually Update .htaccess', 'loginizer') . '</label><br>
1089 <span class="exp">' . esc_html__('You can manually update your .htaccess by adding the given code at the top of your .htaccess file', 'loginizer'). '</span>
1090 </td>
1091 <td valign="top">
1092 <textarea rows="8" readonly class="lz-htaccess-textarea">' . trim($rule) . '</textarea>
1093 </td>
1094 </tr>';
1095 }
1096
1097 }