Version Description
- Important: The way that Hide Backend functions changes in this release. Previously, if your Hide Backend Login Slug was wplogin, going to example.com/wplogin would result in the URL remaining example.com/wplogin. The new implementation of this feature results in a redirect to a URL that looks as follows: example.com/wp-login.php?itsec-hb-token=wplogin. While this may not be desireable for some users, this change was necessary to fix longstanding compatibility issues with other plugins. Once you access the login page using the Login Slug page, a cookie is set with an expiration time of one hour. As long as the cookie remains, you can access example.com/wp-login.php without having to access the Hide Backend Login Slug first. If you wish to confirm that Hide Backend is working properly on your site, opening up a private browsing window is a quick way to test without having to log out and clear cookies.
- New Feature: Added support for iThemes Sync to run the Security Check feature from inside the Sync service.
- New Feature: Added support for the ITSEC_DISABLE_MODULES define.
- Bug Fix: Removed warning: "Non-static method ITSEC_Setup::uninstall() should not be called statically".
- Bug Fix: Fixed the ability to manually enter a page number to navigate to on the Security > Logs page.
- Bug Fix: Fixed source of warning that could appear when creating a backup while running a PHP version less than 5.4.
- Bug Fix: Fixed source of notice that could appear when reseting a user's password when the Strong Passwords Enforcement feature is enabled.
- Bug Fix: Fixed bugs that prevented reporting of specific error messages related to updating the wp-config.php file.
- Bug Fix: Fixed an infinite loop that could occur when expiring a cookie and Hide Backend is enabled.
- Bug Fix: Fixed compatibility issue with the Jetpack plugin when Hide Backend is enabled which could prevent Jetpack from redirecting users to the wordpress.com login page.
- Bug Fix: Fixed issue where access to wp-admin/admin-post.php when Hide Backend is enabled.
- Bug Fix: Fixed issue that could prevent "Register" and "Lost your password?" links from working properly on the login page when Hide Backend is enabled.
- Bug Fix: Fix fatal error when updating a profile.
- Bug Fix: Fix strong passwords not being recognized as strong on the profile page.
- Bug Fix: Fix fatal error when registering a new user without specifying a role ( iThemes Exchange ).
- Bug Fix: Compatability with JetPack SSO and Password Requirements.
- Bug Fix: Ensure viewport meta is defined when loading the password requirements update password form.
- Bug Fix: Hide Backend is now compatible with Jetpack Single Sign On.
- Bug Fix: Hide Backend now hides registration pages on multisite sites.
- Bug Fix: Fixed password-protected posts not properly handling the password when Hide Backend is enabled.
- Enhancement: Removed AhrefsBot from the HackRepair blacklist as they are legitimate bot.
- Enhancement: Improved efficiency of Hide Backend code, increasing site performance when the feature is enabled.
- Enhancement: Enforce strong passwords during log-in. Can be disabled via the ITSEC_DISABLE_PASSWORD_REQUIREMENTS constant.
- Enhancement: Use canonical roles library to determine if a new user or an updated role requires a strong password.
- Enhancement: Introduce password requirements module to centralize handling of password updates.
- Enhancement: The Hide Backend hidden login URL is no longer leaked by password-protected content.
- Enhancement: Allow for searching through modules and settings.
- Enhancement: Link to other module settings pages without forcing the page to refresh.
- Enhancement: Fire an action, "itsec_change_admin_user_id", when the admin user id changes.
- Enhancement: Changed default Hide Backend Register Slug from wp-register.php to wp-signup.php since WordPress switched from using wp-register.php to wp-signup.php for registrations. This will not affect existing sites.
- Enhancement: Hide Backend functions purely in PHP code now rather than relying half on PHP code and half on .htaccess and nginx.conf modifications. This allows Hide Backend to function on web servers and server configurations that it was previously not compatible with.
- Misc: Updated or added phpDoc to many functions.
- Misc: Updated Disable File Locking description.
Download this release
Release Info
Developer | chrisjean |
Plugin | iThemes Security (formerly Better WP Security) |
Version | 6.3.0 |
Comparing to | |
See all releases |
Code changes from version 6.2.1 to 6.3.0
- better-wp-security.php +2 -2
- core/admin-pages/css/style.css +23 -7
- core/admin-pages/js/script.js +177 -14
- core/admin-pages/module-settings.php +2 -2
- core/admin-pages/page-logs.php +34 -11
- core/admin-pages/page-settings.php +7 -2
- core/{class-itsec-core.php → core.php} +195 -19
- core/{class-itsec-files.php → files.php} +0 -0
- core/history.txt +39 -0
- core/js/scrollTo.js +7 -0
- core/js/url.js +0 -93
- core/{class-itsec-lib.php → lib.php} +81 -13
- core/lib/class-itsec-lib-canonical-roles.php +43 -0
- core/lib/class-itsec-lib-password-requirements.php +532 -0
- core/lib/includes/function.login-header.php +204 -0
- core/lib/includes/index.php +1 -0
- core/{lock.php → lib/lock.php} +0 -0
- core/{class-itsec-lockout.php → lockout.php} +138 -27
- core/{class-itsec-logger-all-logs.php → logger-all-logs.php} +0 -0
- core/{class-itsec-logger.php → logger.php} +13 -13
- core/{class-itsec-modules.php → modules.php} +180 -2
- core/modules/404-detection/class-itsec-four-oh-four.php +1 -0
- core/modules/admin-user/validator.php +9 -0
- core/modules/away-mode/class-itsec-away-mode.php +3 -1
- core/modules/away-mode/utilities.php +39 -0
- core/modules/backup/class-itsec-backup.php +1 -1
- core/modules/ban-users/lists/hackrepair-apache.inc +0 -1
- core/modules/ban-users/lists/hackrepair-litespeed.inc +0 -1
- core/modules/ban-users/lists/hackrepair-nginx.inc +0 -1
- core/modules/brute-force/class-itsec-brute-force.php +5 -0
- core/modules/content-directory/settings-page.php +1 -1
- core/modules/database-prefix/settings-page.php +1 -1
- core/modules/database-prefix/utility.php +2 -2
- core/modules/file-change/class-itsec-file-change.php +1 -1
- core/modules/global/active.php +9 -0
- core/modules/global/settings-page.php +1 -1
- core/modules/hide-backend/class-itsec-hide-backend.php +249 -253
- core/modules/hide-backend/config-generators.php +0 -43
- core/modules/hide-backend/settings-page.php +2 -2
- core/modules/hide-backend/settings.php +2 -2
- core/modules/hide-backend/setup.php +5 -1
- core/modules/hide-backend/validator.php +2 -9
- core/modules/ipcheck/class-itsec-ipcheck.php +4 -0
- core/modules/malware/class-itsec-malware-scanner.php +2 -1
- core/modules/malware/class-itsec-malware.php +1 -1
- core/modules/security-check/active.php +8 -0
- core/modules/security-check/feedback-renderer.php +142 -0
- core/modules/security-check/feedback.php +94 -0
- core/modules/security-check/js/settings-page.js +58 -21
- core/modules/security-check/scanner.php +82 -77
- core/modules/security-check/settings-page.php +12 -24
- core/modules/security-check/sync-verbs/index.php +1 -0
- core/modules/security-check/sync-verbs/itsec-do-security-check.php +12 -0
- core/modules/security-check/sync-verbs/itsec-get-security-check-feedback-response.php +20 -0
- core/modules/security-check/sync-verbs/itsec-get-security-check-modules.php +12 -0
- core/modules/ssl/class-itsec-ssl-admin.php +9 -1
- core/modules/strong-passwords/class-itsec-strong-passwords.php +157 -95
- core/modules/system-tweaks/class-itsec-system-tweaks.php +3 -0
- core/modules/wordpress-tweaks/class-itsec-wordpress-tweaks.php +36 -6
- core/{class-itsec-notify.php → notify.php} +2 -0
- core/{class-itsec-response.php → response.php} +7 -1
- core/{class-itsec-setup.php → setup.php} +1 -2
- core/sidebar-widget-active-lockouts.php +4 -0
- core/sidebar-widget-temp-whitelist.php +2 -0
- core/sync-verbs/itsec-get-temp-whitelist.php +1 -0
- core/sync-verbs/itsec-release-lockout.php +1 -0
- core/sync-verbs/itsec-set-temp-whitelist.php +1 -0
- history.txt +35 -0
- readme.txt +40 -5
better-wp-security.php
CHANGED
@@ -6,7 +6,7 @@
|
|
6 |
* Description: Take the guesswork out of WordPress security. iThemes Security offers 30+ ways to lock down WordPress in an easy-to-use WordPress security plugin.
|
7 |
* Author: iThemes
|
8 |
* Author URI: https://ithemes.com
|
9 |
-
* Version: 6.
|
10 |
* Text Domain: better-wp-security
|
11 |
* Network: True
|
12 |
* License: GPLv2
|
@@ -29,6 +29,6 @@ if ( is_admin() ) {
|
|
29 |
require( "$itsec_dir/lib/icon-fonts/load.php" );
|
30 |
}
|
31 |
|
32 |
-
require( "$itsec_dir/core/
|
33 |
$itsec_core = ITSEC_Core::get_instance();
|
34 |
$itsec_core->init( __FILE__, esc_html__( 'iThemes Security', 'better-wp-security' ) );
|
6 |
* Description: Take the guesswork out of WordPress security. iThemes Security offers 30+ ways to lock down WordPress in an easy-to-use WordPress security plugin.
|
7 |
* Author: iThemes
|
8 |
* Author URI: https://ithemes.com
|
9 |
+
* Version: 6.3.0
|
10 |
* Text Domain: better-wp-security
|
11 |
* Network: True
|
12 |
* License: GPLv2
|
29 |
require( "$itsec_dir/lib/icon-fonts/load.php" );
|
30 |
}
|
31 |
|
32 |
+
require( "$itsec_dir/core/core.php" );
|
33 |
$itsec_core = ITSEC_Core::get_instance();
|
34 |
$itsec_core->init( __FILE__, esc_html__( 'iThemes Security', 'better-wp-security' ) );
|
core/admin-pages/css/style.css
CHANGED
@@ -295,6 +295,14 @@ body.itsec-modal-open {
|
|
295 |
margin-bottom: 1.5em;
|
296 |
}
|
297 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
298 |
|
299 |
|
300 |
/*
|
@@ -322,9 +330,11 @@ body.itsec-modal-open {
|
|
322 |
.itsec-settings-view-toggle a.itsec-selected {
|
323 |
color: #00a0d2;
|
324 |
}
|
325 |
-
.itsec-
|
326 |
float: left;
|
|
|
327 |
}
|
|
|
328 |
.itsec-feature-tabs {
|
329 |
float: right;
|
330 |
margin: 0;
|
@@ -527,8 +537,8 @@ body.itsec-modal-open {
|
|
527 |
.itsec-module-card .module-description {
|
528 |
display: none;
|
529 |
}
|
530 |
-
.itsec-
|
531 |
-
.itsec-
|
532 |
width: 100%;
|
533 |
margin-bottom: 1em;
|
534 |
}
|
@@ -618,12 +628,15 @@ body.itsec-modal-open {
|
|
618 |
margin: -9px 0 0 0;
|
619 |
}
|
620 |
|
621 |
-
.itsec-security-check-container-
|
|
|
|
|
622 |
content: "\f147";
|
623 |
color: #46b450;
|
624 |
}
|
625 |
|
626 |
-
.itsec-security-check-container-incomplete:before
|
|
|
627 |
content: "\f534";
|
628 |
color: #f2dd28;
|
629 |
}
|
@@ -633,11 +646,14 @@ body.itsec-modal-open {
|
|
633 |
color: #dc3232;
|
634 |
}
|
635 |
|
636 |
-
.itsec-security-check-container-
|
|
|
|
|
637 |
border-left-color: #46b450;
|
638 |
}
|
639 |
|
640 |
-
.itsec-security-check-container-incomplete
|
|
|
641 |
border-left-color: #f2dd28;
|
642 |
}
|
643 |
|
295 |
margin-bottom: 1.5em;
|
296 |
}
|
297 |
|
298 |
+
.itsec-settings-module-settings .form-table th {
|
299 |
+
padding-left: 15px;
|
300 |
+
}
|
301 |
+
|
302 |
+
.itsec-settings-module-settings .itsec-highlighted-setting {
|
303 |
+
background: #e5f5fa;
|
304 |
+
}
|
305 |
+
|
306 |
|
307 |
|
308 |
/*
|
330 |
.itsec-settings-view-toggle a.itsec-selected {
|
331 |
color: #00a0d2;
|
332 |
}
|
333 |
+
.itsec-module-search {
|
334 |
float: left;
|
335 |
+
margin-right: 1em;
|
336 |
}
|
337 |
+
|
338 |
.itsec-feature-tabs {
|
339 |
float: right;
|
340 |
margin: 0;
|
537 |
.itsec-module-card .module-description {
|
538 |
display: none;
|
539 |
}
|
540 |
+
.itsec-module-search,
|
541 |
+
.itsec-module-search input {
|
542 |
width: 100%;
|
543 |
margin-bottom: 1em;
|
544 |
}
|
628 |
margin: -9px 0 0 0;
|
629 |
}
|
630 |
|
631 |
+
.itsec-security-check-container-action-taken:before,
|
632 |
+
.itsec-security-check-container-complete:before,
|
633 |
+
.itsec-security-check-container-confirmation:before {
|
634 |
content: "\f147";
|
635 |
color: #46b450;
|
636 |
}
|
637 |
|
638 |
+
.itsec-security-check-container-incomplete:before,
|
639 |
+
.itsec-security-check-container-call-to-action:before {
|
640 |
content: "\f534";
|
641 |
color: #f2dd28;
|
642 |
}
|
646 |
color: #dc3232;
|
647 |
}
|
648 |
|
649 |
+
.itsec-security-check-container-action-taken,
|
650 |
+
.itsec-security-check-container-complete,
|
651 |
+
.itsec-security-check-container-confirmation {
|
652 |
border-left-color: #46b450;
|
653 |
}
|
654 |
|
655 |
+
.itsec-security-check-container-incomplete,
|
656 |
+
.itsec-security-check-container-call-to-action {
|
657 |
border-left-color: #f2dd28;
|
658 |
}
|
659 |
|
core/admin-pages/js/script.js
CHANGED
@@ -40,6 +40,7 @@ var itsecSettingsPage = {
|
|
40 |
$container.on( 'itsec-popstate', '.itsec-module-filter a', this.filterView );
|
41 |
$container.on( 'click', '.itsec-settings-view-toggle a', this.toggleView );
|
42 |
// $container.on( 'click', '.itsec-toggle-settings, .itsec-module-card-content h2', this.toggleSettings );
|
|
|
43 |
$container.on( 'click', '.list .itsec-module-card:not(.itsec-module-pro-upsell) .itsec-module-card-content, .itsec-toggle-settings, .itsec-module-settings-cancel', this.toggleSettings );
|
44 |
$container.on( 'itsec-popstate', '.list .itsec-module-card-content, .itsec-toggle-settings', this.toggleSettings );
|
45 |
$container.on( 'click', '.itsec-close-modal, .itsec-modal-background', this.closeGridSettingsModal );
|
@@ -291,6 +292,35 @@ var itsecSettingsPage = {
|
|
291 |
$cardContainer.fadeIn( 100 );
|
292 |
},
|
293 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
294 |
toggleSettings: function( e ) {
|
295 |
e.stopPropagation();
|
296 |
|
@@ -323,7 +353,28 @@ var itsecSettingsPage = {
|
|
323 |
$container = $container.parents( '.itsec-module-card' ).find( '.itsec-module-card-content' );
|
324 |
}
|
325 |
|
326 |
-
$container.siblings( '.itsec-module-settings-container' )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
327 |
|
328 |
var $button = $container.find( '.itsec-toggle-settings' );
|
329 |
|
@@ -353,23 +404,46 @@ var itsecSettingsPage = {
|
|
353 |
showGridSettingsModal: function( e ) {
|
354 |
e.preventDefault();
|
355 |
|
356 |
-
var $
|
|
|
357 |
$modalBackground = jQuery( '.itsec-modal-background' );
|
358 |
|
359 |
-
$
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
.focus();
|
364 |
|
365 |
jQuery( 'body' ).addClass( 'itsec-modal-open' );
|
366 |
|
|
|
367 |
|
368 |
-
|
369 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
} else {
|
371 |
-
$
|
372 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
373 |
},
|
374 |
|
375 |
closeGridSettingsModal: function( e ) {
|
@@ -382,8 +456,8 @@ var itsecSettingsPage = {
|
|
382 |
}
|
383 |
}
|
384 |
|
385 |
-
jQuery( '.itsec-modal-background' ).
|
386 |
-
jQuery( '.itsec-module-settings-container' ).
|
387 |
jQuery( 'body' ).removeClass( 'itsec-modal-open' );
|
388 |
|
389 |
if ( 'undefined' === typeof e || 'popstate' !== e.type ) {
|
@@ -393,6 +467,10 @@ var itsecSettingsPage = {
|
|
393 |
}
|
394 |
window.history.pushState( {'module':'', 'module_type':module_type}, module_type, '?page=itsec&module_type=' + module_type );
|
395 |
}
|
|
|
|
|
|
|
|
|
396 |
},
|
397 |
|
398 |
toggleModuleActivation: function( e ) {
|
@@ -678,7 +756,7 @@ var itsecSettingsPage = {
|
|
678 |
}
|
679 |
};
|
680 |
|
681 |
-
jQuery(document).ready(function() {
|
682 |
itsecSettingsPage.init();
|
683 |
|
684 |
if ( itsec_page.show_security_check ) {
|
@@ -715,4 +793,89 @@ jQuery(document).ready(function() {
|
|
715 |
jQuery( '.ui-dialog :button' ).blur();
|
716 |
|
717 |
} );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
718 |
});
|
40 |
$container.on( 'itsec-popstate', '.itsec-module-filter a', this.filterView );
|
41 |
$container.on( 'click', '.itsec-settings-view-toggle a', this.toggleView );
|
42 |
// $container.on( 'click', '.itsec-toggle-settings, .itsec-module-card-content h2', this.toggleSettings );
|
43 |
+
$container.on( 'click', 'a[data-module-link]', this.openModuleFromLink );
|
44 |
$container.on( 'click', '.list .itsec-module-card:not(.itsec-module-pro-upsell) .itsec-module-card-content, .itsec-toggle-settings, .itsec-module-settings-cancel', this.toggleSettings );
|
45 |
$container.on( 'itsec-popstate', '.list .itsec-module-card-content, .itsec-toggle-settings', this.toggleSettings );
|
46 |
$container.on( 'click', '.itsec-close-modal, .itsec-modal-background', this.closeGridSettingsModal );
|
292 |
$cardContainer.fadeIn( 100 );
|
293 |
},
|
294 |
|
295 |
+
openModuleFromLink: function( e ) {
|
296 |
+
|
297 |
+
var $link = jQuery( this ), module = $link.data( 'module-link' ),
|
298 |
+
$module = jQuery( '.itsec-module-card[data-module-id="' + module + '"]' );
|
299 |
+
|
300 |
+
if ( ! $module.length ) {
|
301 |
+
return; // safety check
|
302 |
+
}
|
303 |
+
|
304 |
+
e.preventDefault();
|
305 |
+
|
306 |
+
jQuery( '.itsec-module-settings-container:visible' ).hide();
|
307 |
+
|
308 |
+
var $listClassElement = $module.parents( '.itsec-module-cards-container' ),
|
309 |
+
$toggleButton = $module.find( '.itsec-toggle-settings' );
|
310 |
+
|
311 |
+
console.log( $toggleButton );
|
312 |
+
|
313 |
+
if ( $listClassElement.hasClass( 'list' ) ) {
|
314 |
+
itsecSettingsPage.toggleListSettingsCard.call( $toggleButton, e );
|
315 |
+
} else if ( $listClassElement.hasClass( 'grid' ) ) {
|
316 |
+
itsecSettingsPage.showGridSettingsModal.call( $toggleButton, e );
|
317 |
+
}
|
318 |
+
|
319 |
+
var type = $module.hasClass( 'itsec-module-type-advanced' ) ? 'advanced' : 'recommended';
|
320 |
+
|
321 |
+
window.history.pushState( {module: module}, module, '?page=itsec&module=' + module + '&module_type=' + type );
|
322 |
+
},
|
323 |
+
|
324 |
toggleSettings: function( e ) {
|
325 |
e.stopPropagation();
|
326 |
|
353 |
$container = $container.parents( '.itsec-module-card' ).find( '.itsec-module-card-content' );
|
354 |
}
|
355 |
|
356 |
+
var $settings = $container.siblings( '.itsec-module-settings-container' ),
|
357 |
+
isVisible = $settings.is( ':visible' );
|
358 |
+
$settings.stop().slideToggle( 300 );
|
359 |
+
|
360 |
+
if ( ! isVisible ) {
|
361 |
+
var $highlighted = jQuery( '.itsec-highlighted-setting', $settings );
|
362 |
+
|
363 |
+
if ( $highlighted.length ) {
|
364 |
+
setTimeout( function () {
|
365 |
+
jQuery.scrollTo( $highlighted.first(), 'swing', {
|
366 |
+
offset: { top: -30 },
|
367 |
+
onAfter: function() {
|
368 |
+
var $el = jQuery( 'input[type!="button"], textarea, select', $highlighted ).not( ':hidden' ).first();
|
369 |
+
itsecSettingsPage.focus( $el, $highlighted );
|
370 |
+
}
|
371 |
+
} );
|
372 |
+
}, 50 );
|
373 |
+
} else {
|
374 |
+
var $el = jQuery( 'input[type!="button"], textarea, select', $settings ).not( ':hidden' ).first();
|
375 |
+
itsecSettingsPage.focus( $el, $settings );
|
376 |
+
}
|
377 |
+
}
|
378 |
|
379 |
var $button = $container.find( '.itsec-toggle-settings' );
|
380 |
|
404 |
showGridSettingsModal: function( e ) {
|
405 |
e.preventDefault();
|
406 |
|
407 |
+
var $module = jQuery(this).parents( '.itsec-module-card' ),
|
408 |
+
$settingsContainer = $module.find( '.itsec-module-settings-container' ),
|
409 |
$modalBackground = jQuery( '.itsec-modal-background' );
|
410 |
|
411 |
+
$module.show();
|
412 |
+
|
413 |
+
$modalBackground.fadeIn();
|
414 |
+
$settingsContainer.fadeIn( 200 );
|
|
|
415 |
|
416 |
jQuery( 'body' ).addClass( 'itsec-modal-open' );
|
417 |
|
418 |
+
var $highlighted = jQuery( '.itsec-highlighted-setting', $module ).first();
|
419 |
|
420 |
+
if ( $highlighted.length ) {
|
421 |
+
jQuery( '.itsec-module-settings-content-container', $module ).scrollTo( $highlighted, 'swing', {
|
422 |
+
offset: { top: -20 },
|
423 |
+
onAfter: function() {
|
424 |
+
var $el = jQuery( 'input[type!="button"], textarea, select', $highlighted ).not( ':hidden' ).first();
|
425 |
+
itsecSettingsPage.focus( $el, $highlighted );
|
426 |
+
}
|
427 |
+
} );
|
428 |
} else {
|
429 |
+
var $el = jQuery( 'input[type!="button"], textarea, select', $settingsContainer ).not( ':hidden' ).first();
|
430 |
+
itsecSettingsPage.focus( $el, $settingsContainer );
|
431 |
+
}
|
432 |
+
},
|
433 |
+
|
434 |
+
focus: function( $el, $fallback ) {
|
435 |
+
if ( itsecSettingsPage.isElementVisible( $el ) && jQuery( window ).height() > 800 ) {
|
436 |
+
$el.focus();
|
437 |
+
} else {
|
438 |
+
$fallback.prop( 'tabindex', -1 ).focus();
|
439 |
+
}
|
440 |
+
},
|
441 |
+
|
442 |
+
isElementVisible: function( $el ) {
|
443 |
+
|
444 |
+
var $window = jQuery( window ), height = $window.height(), width = $window.width(), offset = $el.offset();
|
445 |
+
|
446 |
+
return offset.top < height && offset.left < width;
|
447 |
},
|
448 |
|
449 |
closeGridSettingsModal: function( e ) {
|
456 |
}
|
457 |
}
|
458 |
|
459 |
+
jQuery( '.itsec-modal-background' ).fadeOut();
|
460 |
+
jQuery( '.itsec-module-settings-container' ).fadeOut( 200 );
|
461 |
jQuery( 'body' ).removeClass( 'itsec-modal-open' );
|
462 |
|
463 |
if ( 'undefined' === typeof e || 'popstate' !== e.type ) {
|
467 |
}
|
468 |
window.history.pushState( {'module':'', 'module_type':module_type}, module_type, '?page=itsec&module_type=' + module_type );
|
469 |
}
|
470 |
+
|
471 |
+
if ( jQuery( '#search' ).val().length ) {
|
472 |
+
jQuery( '#search' ).focus();
|
473 |
+
}
|
474 |
},
|
475 |
|
476 |
toggleModuleActivation: function( e ) {
|
756 |
}
|
757 |
};
|
758 |
|
759 |
+
jQuery(document).ready(function( $ ) {
|
760 |
itsecSettingsPage.init();
|
761 |
|
762 |
if ( itsec_page.show_security_check ) {
|
793 |
jQuery( '.ui-dialog :button' ).blur();
|
794 |
|
795 |
} );
|
796 |
+
|
797 |
+
var regex = /[^\w]/ig;
|
798 |
+
|
799 |
+
var $search = $( '#search' ), $cardsContainer = $( '.itsec-module-cards' ),
|
800 |
+
$cards = $( '.itsec-module-card', $cardsContainer ),
|
801 |
+
$searchFilter = $( '#itsec-module-filter-search' ),
|
802 |
+
$currentFilter = $( '.itsec-feature-tabs .current' ).parent();
|
803 |
+
|
804 |
+
$search.on( 'input', _.debounce( function () {
|
805 |
+
var query = $search.val().trim().replace( regex, ' ' );
|
806 |
+
|
807 |
+
var $maybeCurrent = $( '.itsec-feature-tabs .current' ).parent();
|
808 |
+
|
809 |
+
if ( $maybeCurrent && $maybeCurrent.prop( 'id' ) !== 'itsec-module-filter-search' ) {
|
810 |
+
$currentFilter = $maybeCurrent;
|
811 |
+
}
|
812 |
+
|
813 |
+
$( '.itsec-highlighted-setting', $cards ).removeClass( 'itsec-highlighted-setting' );
|
814 |
+
|
815 |
+
if ( !query.length ) {
|
816 |
+
$searchFilter.addClass( 'hide-if-js' );
|
817 |
+
$( 'a', $searchFilter ).removeClass( 'current' );
|
818 |
+
$( 'a', $currentFilter ).addClass( 'current' );
|
819 |
+
|
820 |
+
var type = $currentFilter.prop( 'id' ).substr( 20 );
|
821 |
+
|
822 |
+
if ( 'all' === type ) {
|
823 |
+
$cards.show();
|
824 |
+
} else {
|
825 |
+
$( '.itsec-module-type-' + type ).show();
|
826 |
+
$( '.itsec-module-card' ).not( '.itsec-module-type-' + type ).hide();
|
827 |
+
}
|
828 |
+
|
829 |
+
return;
|
830 |
+
}
|
831 |
+
|
832 |
+
var $titleMatches = $( ".itsec-module-card-content > h2:itsecContains('" + query + "')", $cards ),
|
833 |
+
$titleMatchesCards = $titleMatches.parents( '.itsec-module-card' );
|
834 |
+
|
835 |
+
var $descriptionMatches = $( ".itsec-module-card-content > p:itsecContains('" + query + "')", $cards ),
|
836 |
+
$descriptionMatchesCards = $descriptionMatches.parents( '.itsec-module-card' );
|
837 |
+
|
838 |
+
var $settingMatches = $( ".itsec-module-settings-container .form-table tr > th > label:itsecContains('" + query + "')", $cards ),
|
839 |
+
$settingMatchesCards = $settingMatches.parents( '.itsec-module-card' );
|
840 |
+
|
841 |
+
|
842 |
+
var $matches = $titleMatchesCards.add( $descriptionMatchesCards ).add( $settingMatchesCards );
|
843 |
+
|
844 |
+
$searchFilter.removeClass( 'hide-if-js' );
|
845 |
+
$( 'a', $currentFilter ).removeClass( 'current' );
|
846 |
+
$( 'a', $searchFilter ).addClass( 'current' );
|
847 |
+
$( '.count', $searchFilter ).text( '(' + $matches.length + ')' );
|
848 |
+
|
849 |
+
$cards.hide();
|
850 |
+
$matches.show();
|
851 |
+
|
852 |
+
$settingMatches.parents( 'tr' ).addClass( 'itsec-highlighted-setting' );
|
853 |
+
|
854 |
+
if ( $matches.length === 1 ) {
|
855 |
+
$( '.itsec-toggle-settings', $matches.first() ).click();
|
856 |
+
}
|
857 |
+
|
858 |
+
}, 250 ) );
|
859 |
+
|
860 |
+
$.expr[":"].itsecContains = $.expr.createPseudo( function ( arg ) {
|
861 |
+
|
862 |
+
return function ( elem ) {
|
863 |
+
|
864 |
+
var candidate = $( elem ).text().toUpperCase().replace( regex, ' ' ), term = arg.toUpperCase();
|
865 |
+
var index = candidate.indexOf( term );
|
866 |
+
|
867 |
+
if ( index === -1 ) {
|
868 |
+
return false;
|
869 |
+
}
|
870 |
+
|
871 |
+
if ( index === 0 ) {
|
872 |
+
return true;
|
873 |
+
}
|
874 |
+
|
875 |
+
var prior = candidate.charAt( index - 1 ), next = candidate.charAt( term.length + index );
|
876 |
+
|
877 |
+
// full word
|
878 |
+
return prior === ' ' && ( next === ' ' || next === '' );
|
879 |
+
};
|
880 |
+
} );
|
881 |
});
|
core/admin-pages/module-settings.php
CHANGED
@@ -183,7 +183,7 @@ class ITSEC_Module_Settings_Page {
|
|
183 |
*
|
184 |
* @access public
|
185 |
*
|
186 |
-
* @param
|
187 |
*/
|
188 |
public function render( $form ) {
|
189 |
|
@@ -224,7 +224,7 @@ class ITSEC_Module_Settings_Page {
|
|
224 |
*
|
225 |
* @access protected
|
226 |
*
|
227 |
-
* @param
|
228 |
*/
|
229 |
protected function render_settings( $form ) {
|
230 |
|
183 |
*
|
184 |
* @access public
|
185 |
*
|
186 |
+
* @param ITSEC_Form $form ITSEC_Form object used to create inputs.
|
187 |
*/
|
188 |
public function render( $form ) {
|
189 |
|
224 |
*
|
225 |
* @access protected
|
226 |
*
|
227 |
+
* @param ITSEC_Form $form ITSEC_Form object used to create inputs.
|
228 |
*/
|
229 |
protected function render_settings( $form ) {
|
230 |
|
core/admin-pages/page-logs.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
|
4 |
final class ITSEC_Logs_Page {
|
5 |
-
private $version = 1.
|
6 |
|
7 |
private $self_url = '';
|
8 |
private $modules = array();
|
@@ -283,7 +283,9 @@ final class ITSEC_Logs_Page {
|
|
283 |
<p><?php $form->add_select( 'filter', $filters ); ?></p>
|
284 |
<?php $form->end_form(); ?>
|
285 |
|
286 |
-
<?php $
|
|
|
|
|
287 |
</div>
|
288 |
<?php endif; ?>
|
289 |
</div>
|
@@ -315,6 +317,8 @@ final class ITSEC_Logs_Page {
|
|
315 |
}
|
316 |
|
317 |
private function show_filtered_logs( $filter ) {
|
|
|
|
|
318 |
foreach ( $this->logger_displays as $display ) {
|
319 |
if ( $display['module'] === $filter ) {
|
320 |
$callback = $display['callback'];
|
@@ -322,11 +326,20 @@ final class ITSEC_Logs_Page {
|
|
322 |
}
|
323 |
}
|
324 |
|
325 |
-
|
326 |
-
|
|
|
|
|
|
|
|
|
|
|
327 |
}
|
328 |
|
329 |
-
|
|
|
|
|
|
|
|
|
330 |
}
|
331 |
|
332 |
/**
|
@@ -334,18 +347,29 @@ final class ITSEC_Logs_Page {
|
|
334 |
*
|
335 |
* @since 4.3
|
336 |
*
|
|
|
|
|
337 |
* @return void
|
338 |
*/
|
339 |
-
public function all_logs_content() {
|
340 |
-
|
341 |
-
global $wpdb;
|
342 |
|
343 |
-
require_once( ITSEC_Core::get_core_dir() . '/
|
344 |
|
345 |
$log_display = new ITSEC_Logger_All_Logs();
|
346 |
$log_display->prepare_items();
|
347 |
$log_display->display();
|
348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
349 |
$log_count = $wpdb->get_var( "SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_log`;" );
|
350 |
|
351 |
?>
|
@@ -371,8 +395,7 @@ final class ITSEC_Logs_Page {
|
|
371 |
</tr>
|
372 |
</table>
|
373 |
</form>
|
374 |
-
|
375 |
-
|
376 |
}
|
377 |
}
|
378 |
|
2 |
|
3 |
|
4 |
final class ITSEC_Logs_Page {
|
5 |
+
private $version = 1.5;
|
6 |
|
7 |
private $self_url = '';
|
8 |
private $modules = array();
|
283 |
<p><?php $form->add_select( 'filter', $filters ); ?></p>
|
284 |
<?php $form->end_form(); ?>
|
285 |
|
286 |
+
<?php $form->start_form( array( 'method' => 'GET' ) ); ?>
|
287 |
+
<?php $this->show_filtered_logs( $filter ); ?>
|
288 |
+
<?php $form->end_form(); ?>
|
289 |
</div>
|
290 |
<?php endif; ?>
|
291 |
</div>
|
317 |
}
|
318 |
|
319 |
private function show_filtered_logs( $filter ) {
|
320 |
+
$callback = null;
|
321 |
+
|
322 |
foreach ( $this->logger_displays as $display ) {
|
323 |
if ( $display['module'] === $filter ) {
|
324 |
$callback = $display['callback'];
|
326 |
}
|
327 |
}
|
328 |
|
329 |
+
echo '<form method="get">';
|
330 |
+
echo '<input type="hidden" name="page" value="' . ( isset( $_GET['page'] ) ? esc_attr( $_GET['page'] ) : '' ) . '">';
|
331 |
+
|
332 |
+
if ( $callback ) {
|
333 |
+
call_user_func( $callback );
|
334 |
+
} else {
|
335 |
+
$this->all_logs_content( false );
|
336 |
}
|
337 |
|
338 |
+
echo '</form>';
|
339 |
+
|
340 |
+
if ( ! $callback ) {
|
341 |
+
$this->clear_logs_form();
|
342 |
+
}
|
343 |
}
|
344 |
|
345 |
/**
|
347 |
*
|
348 |
* @since 4.3
|
349 |
*
|
350 |
+
* @param bool $include_clear_logs_form Whether to include the form to clear all logs.
|
351 |
+
*
|
352 |
* @return void
|
353 |
*/
|
354 |
+
public function all_logs_content( $include_clear_logs_form = true ) {
|
|
|
|
|
355 |
|
356 |
+
require_once( ITSEC_Core::get_core_dir() . '/logger-all-logs.php' );
|
357 |
|
358 |
$log_display = new ITSEC_Logger_All_Logs();
|
359 |
$log_display->prepare_items();
|
360 |
$log_display->display();
|
361 |
|
362 |
+
if ( $include_clear_logs_form ) {
|
363 |
+
$this->clear_logs_form();
|
364 |
+
}
|
365 |
+
}
|
366 |
+
|
367 |
+
/**
|
368 |
+
* Display the clear logs form.
|
369 |
+
*/
|
370 |
+
public function clear_logs_form() {
|
371 |
+
|
372 |
+
global $wpdb;
|
373 |
$log_count = $wpdb->get_var( "SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_log`;" );
|
374 |
|
375 |
?>
|
395 |
</tr>
|
396 |
</table>
|
397 |
</form>
|
398 |
+
<?php
|
|
|
399 |
}
|
400 |
}
|
401 |
|
core/admin-pages/page-settings.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
|
4 |
final class ITSEC_Settings_Page {
|
5 |
-
private $version = 1.
|
6 |
|
7 |
private $self_url = '';
|
8 |
private $modules = array();
|
@@ -83,7 +83,8 @@ final class ITSEC_Settings_Page {
|
|
83 |
}
|
84 |
}
|
85 |
|
86 |
-
wp_enqueue_script( 'itsec-
|
|
|
87 |
wp_localize_script( 'itsec-settings-page-script', 'itsec_page', $vars );
|
88 |
}
|
89 |
|
@@ -465,8 +466,12 @@ final class ITSEC_Settings_Page {
|
|
465 |
<a class="itsec-grid<?php if ( 'grid' === $view ) { echo ' itsec-selected'; } ?>"><span class="dashicons dashicons-grid-view"></span></a>
|
466 |
<a class="itsec-list<?php if ( 'list' === $view ) { echo ' itsec-selected'; } ?>"><span class="dashicons dashicons-list-view"></span></a>
|
467 |
</div>
|
|
|
|
|
|
|
468 |
<ul class="subsubsub itsec-feature-tabs hide-if-no-js">
|
469 |
<?php echo implode( $feature_tabs, " |</li>\n" ) . "</li>\n"; ?>
|
|
|
470 |
</ul>
|
471 |
</div>
|
472 |
<div class="itsec-module-cards-container <?php echo $view; ?> hide-if-js">
|
2 |
|
3 |
|
4 |
final class ITSEC_Settings_Page {
|
5 |
+
private $version = 1.5;
|
6 |
|
7 |
private $self_url = '';
|
8 |
private $modules = array();
|
83 |
}
|
84 |
}
|
85 |
|
86 |
+
wp_enqueue_script( 'itsec-scrollTo', plugins_url( 'js/scrollTo.js', dirname( __FILE__ ) ), array( 'jquery' ) );
|
87 |
+
wp_enqueue_script( 'itsec-settings-page-script', plugins_url( 'js/script.js', __FILE__ ), array( 'underscore' ), $this->version, true );
|
88 |
wp_localize_script( 'itsec-settings-page-script', 'itsec_page', $vars );
|
89 |
}
|
90 |
|
466 |
<a class="itsec-grid<?php if ( 'grid' === $view ) { echo ' itsec-selected'; } ?>"><span class="dashicons dashicons-grid-view"></span></a>
|
467 |
<a class="itsec-list<?php if ( 'list' === $view ) { echo ' itsec-selected'; } ?>"><span class="dashicons dashicons-list-view"></span></a>
|
468 |
</div>
|
469 |
+
<div class="itsec-module-search">
|
470 |
+
<input type="search" placeholder="<?php esc_attr_e( 'Search Modules', 'better-wp-security' ); ?>" id="search" spellcheck="false" autocomplete="off" autofill="off" x-autocomplete="false">
|
471 |
+
</div>
|
472 |
<ul class="subsubsub itsec-feature-tabs hide-if-no-js">
|
473 |
<?php echo implode( $feature_tabs, " |</li>\n" ) . "</li>\n"; ?>
|
474 |
+
<li class="itsec-module-filter hide-if-js" id="itsec-module-filter-search">| <a><?php esc_html_e( 'Search', 'better-wp-security' ); ?></a> <span class="count"></span></li>
|
475 |
</ul>
|
476 |
</div>
|
477 |
<div class="itsec-module-cards-container <?php echo $view; ?> hide-if-js">
|
core/{class-itsec-core.php → core.php}
RENAMED
@@ -25,7 +25,7 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
25 |
*
|
26 |
* @access private
|
27 |
*/
|
28 |
-
private $plugin_build =
|
29 |
|
30 |
/**
|
31 |
* Used to distinguish between a user modifying settings and the API modifying settings (such as from Sync
|
@@ -105,17 +105,18 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
105 |
register_uninstall_hook( $this->plugin_file, array( 'ITSEC_Core', 'handle_uninstall' ) );
|
106 |
|
107 |
|
108 |
-
require( $this->plugin_dir . 'core/
|
109 |
add_action( 'itsec-register-modules', array( $this, 'register_modules' ) );
|
110 |
ITSEC_Modules::init_modules();
|
111 |
|
112 |
-
require( $this->plugin_dir . 'core/
|
113 |
-
require( $this->plugin_dir . 'core/
|
114 |
-
require( $this->plugin_dir . 'core/
|
115 |
-
require( $this->plugin_dir . 'core/
|
116 |
-
require( $this->plugin_dir . 'core/
|
117 |
-
require( $this->plugin_dir . 'core/
|
118 |
require( $this->plugin_dir . 'core/lib/class-itsec-lib-user-activity.php' );
|
|
|
119 |
|
120 |
$this->itsec_files = ITSEC_Files::get_instance();
|
121 |
$this->itsec_notify = new ITSEC_Notify();
|
@@ -138,9 +139,13 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
138 |
|
139 |
add_action( 'plugins_loaded', array( $this, 'continue_init' ), -90 );
|
140 |
add_action( 'wp_login_failed', array( 'ITSEC_Lib', 'handle_wp_login_failed' ) );
|
|
|
141 |
add_action( 'ithemes_sync_register_verbs', array( $this, 'register_sync_verbs' ) );
|
142 |
}
|
143 |
|
|
|
|
|
|
|
144 |
public function continue_init() {
|
145 |
ITSEC_Modules::run_active_modules();
|
146 |
|
@@ -149,24 +154,53 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
149 |
add_action( 'admin_bar_menu', array( $this, 'modify_admin_bar' ), 99 );
|
150 |
}
|
151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
do_action( 'itsec_initialized' );
|
153 |
}
|
154 |
|
|
|
|
|
|
|
|
|
|
|
155 |
public static function get_itsec_files() {
|
156 |
$self = self::get_instance();
|
157 |
return $self->itsec_files;
|
158 |
}
|
159 |
|
|
|
|
|
|
|
|
|
|
|
160 |
public static function get_itsec_notify() {
|
161 |
$self = self::get_instance();
|
162 |
return $self->itsec_notify;
|
163 |
}
|
164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
public static function get_sync_api() {
|
166 |
$self = self::get_instance();
|
167 |
return $self->sync_api;
|
168 |
}
|
169 |
|
|
|
|
|
|
|
|
|
|
|
170 |
public function register_sync_verbs( $sync_api ) {
|
171 |
// For use by the itsec-get-everything verb as it has to run other verbs to get their details.
|
172 |
$this->sync_api = $sync_api;
|
@@ -174,6 +208,9 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
174 |
$sync_api->register( 'itsec-get-everything', 'Ithemes_Sync_Verb_ITSEC_Get_Everything', dirname( __FILE__ ) . '/sync-verbs/itsec-get-everything.php' );
|
175 |
}
|
176 |
|
|
|
|
|
|
|
177 |
public function register_modules() {
|
178 |
$path = dirname( __FILE__ );
|
179 |
|
@@ -218,13 +255,12 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
218 |
*
|
219 |
* @since 4.0
|
220 |
*
|
221 |
-
* @param
|
222 |
* @param string $file String name of current file
|
223 |
*
|
224 |
-
* @return
|
225 |
-
*
|
226 |
*/
|
227 |
-
function add_action_link( $links, $file ) {
|
228 |
|
229 |
static $this_plugin;
|
230 |
|
@@ -264,10 +300,12 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
264 |
}
|
265 |
|
266 |
/**
|
267 |
-
* Add admin bar
|
268 |
*
|
269 |
* @since 4.0
|
270 |
*
|
|
|
|
|
271 |
* @return void
|
272 |
*/
|
273 |
public function modify_admin_bar( $wp_admin_bar ) {
|
@@ -313,28 +351,39 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
313 |
);
|
314 |
}
|
315 |
|
|
|
|
|
|
|
|
|
|
|
316 |
public function handle_upgrade( $build = false ) {
|
317 |
$this->doing_data_upgrade = true;
|
318 |
|
319 |
-
require_once( self::get_core_dir() . '/
|
320 |
ITSEC_Setup::handle_upgrade( $build );
|
321 |
}
|
322 |
|
323 |
public static function handle_activation() {
|
324 |
-
require_once( self::get_core_dir() . '/
|
325 |
ITSEC_Setup::handle_activation();
|
326 |
}
|
327 |
|
328 |
public static function handle_deactivation() {
|
329 |
-
require_once( self::get_core_dir() . '/
|
330 |
ITSEC_Setup::handle_deactivation();
|
331 |
}
|
332 |
|
333 |
public static function handle_uninstall() {
|
334 |
-
require_once( self::get_core_dir() . '/
|
335 |
ITSEC_Setup::handle_uninstall();
|
336 |
}
|
337 |
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
public static function add_notice( $callback, $all_pages = false ) {
|
339 |
global $pagenow, $plugin_page;
|
340 |
|
@@ -358,10 +407,20 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
358 |
}
|
359 |
}
|
360 |
|
|
|
|
|
|
|
|
|
|
|
361 |
public static function get_required_cap() {
|
362 |
return apply_filters( 'itsec_cap_required', is_multisite() ? 'manage_network_options' : 'manage_options' );
|
363 |
}
|
364 |
|
|
|
|
|
|
|
|
|
|
|
365 |
public static function current_user_can_manage() {
|
366 |
return current_user_can( self::get_required_cap() );
|
367 |
}
|
@@ -396,20 +455,46 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
396 |
return $self->plugin_name;
|
397 |
}
|
398 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
399 |
public static function is_pro() {
|
400 |
return is_dir( self::get_plugin_dir() . 'pro' );
|
401 |
}
|
402 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
403 |
public static function get_current_time() {
|
404 |
$self = self::get_instance();
|
405 |
return $self->current_time;
|
406 |
}
|
407 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
408 |
public static function get_current_time_gmt() {
|
409 |
$self = self::get_instance();
|
410 |
return $self->current_time_gmt;
|
411 |
}
|
412 |
|
|
|
|
|
|
|
|
|
|
|
413 |
public static function get_time_offset() {
|
414 |
$self = self::get_instance();
|
415 |
return $self->current_time - $self->current_time_gmt;
|
@@ -447,16 +532,31 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
447 |
return network_admin_url( 'admin.php?page=itsec&module=' . $module );
|
448 |
}
|
449 |
|
|
|
|
|
|
|
|
|
|
|
450 |
public static function set_interactive( $interactive ) {
|
451 |
$self = self::get_instance();
|
452 |
$self->interactive = (bool) $interactive;
|
453 |
}
|
454 |
|
|
|
|
|
|
|
|
|
|
|
455 |
public static function is_interactive() {
|
456 |
$self = self::get_instance();
|
457 |
return $self->interactive;
|
458 |
}
|
459 |
|
|
|
|
|
|
|
|
|
|
|
460 |
public static function is_iwp_call() {
|
461 |
$self = self::get_instance();
|
462 |
|
@@ -485,6 +585,16 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
485 |
return $self->is_iwp_call;
|
486 |
}
|
487 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
488 |
public static function get_wp_upload_dir() {
|
489 |
$self = self::get_instance();
|
490 |
|
@@ -511,6 +621,12 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
511 |
return $self->wp_upload_dir;
|
512 |
}
|
513 |
|
|
|
|
|
|
|
|
|
|
|
|
|
514 |
public static function update_wp_upload_dir( $old_dir, $new_dir ) {
|
515 |
$self = self::get_instance();
|
516 |
|
@@ -523,6 +639,13 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
523 |
delete_site_transient( 'itsec_wp_upload_dir' );
|
524 |
}
|
525 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
526 |
public static function get_storage_dir( $dir = '' ) {
|
527 |
$self = self::get_instance();
|
528 |
|
@@ -549,6 +672,10 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
549 |
}
|
550 |
|
551 |
public static function is_ajax_request() {
|
|
|
|
|
|
|
|
|
552 |
return defined( 'DOING_AJAX' ) && DOING_AJAX;
|
553 |
}
|
554 |
|
@@ -556,6 +683,13 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
556 |
return defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST;
|
557 |
}
|
558 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
559 |
public static function is_rest_api_request() {
|
560 |
if ( isset( $GLOBALS['__itsec_core_is_rest_api_request'] ) ) {
|
561 |
return $GLOBALS['__itsec_core_is_rest_api_request'];
|
@@ -578,23 +712,65 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
578 |
|
579 |
if ( 0 === strpos( $_SERVER['REQUEST_URI'], $rest_api_path ) ) {
|
580 |
$GLOBALS['__itsec_core_is_rest_api_request'] = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
581 |
return true;
|
582 |
}
|
583 |
|
584 |
-
$GLOBALS['__itsec_core_is_rest_api_request'] = false;
|
585 |
return false;
|
586 |
}
|
587 |
|
588 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
589 |
if ( $include_ajax && self::is_ajax_request() ) {
|
590 |
return true;
|
591 |
}
|
592 |
|
|
|
|
|
|
|
|
|
593 |
if ( self::is_rest_api_request() || self::is_xmlrpc_request() ) {
|
594 |
return true;
|
595 |
}
|
596 |
|
597 |
return false;
|
598 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
599 |
}
|
600 |
}
|
25 |
*
|
26 |
* @access private
|
27 |
*/
|
28 |
+
private $plugin_build = 4072;
|
29 |
|
30 |
/**
|
31 |
* Used to distinguish between a user modifying settings and the API modifying settings (such as from Sync
|
105 |
register_uninstall_hook( $this->plugin_file, array( 'ITSEC_Core', 'handle_uninstall' ) );
|
106 |
|
107 |
|
108 |
+
require( $this->plugin_dir . 'core/modules.php' );
|
109 |
add_action( 'itsec-register-modules', array( $this, 'register_modules' ) );
|
110 |
ITSEC_Modules::init_modules();
|
111 |
|
112 |
+
require( $this->plugin_dir . 'core/lib.php' );
|
113 |
+
require( $this->plugin_dir . 'core/logger.php' );
|
114 |
+
require( $this->plugin_dir . 'core/lockout.php' );
|
115 |
+
require( $this->plugin_dir . 'core/files.php' );
|
116 |
+
require( $this->plugin_dir . 'core/notify.php' );
|
117 |
+
require( $this->plugin_dir . 'core/response.php' );
|
118 |
require( $this->plugin_dir . 'core/lib/class-itsec-lib-user-activity.php' );
|
119 |
+
require( $this->plugin_dir . 'core/lib/class-itsec-lib-password-requirements.php' );
|
120 |
|
121 |
$this->itsec_files = ITSEC_Files::get_instance();
|
122 |
$this->itsec_notify = new ITSEC_Notify();
|
139 |
|
140 |
add_action( 'plugins_loaded', array( $this, 'continue_init' ), -90 );
|
141 |
add_action( 'wp_login_failed', array( 'ITSEC_Lib', 'handle_wp_login_failed' ) );
|
142 |
+
|
143 |
add_action( 'ithemes_sync_register_verbs', array( $this, 'register_sync_verbs' ) );
|
144 |
}
|
145 |
|
146 |
+
/**
|
147 |
+
* Perform initialization that requires the plugins_loaded hook to be fired.
|
148 |
+
*/
|
149 |
public function continue_init() {
|
150 |
ITSEC_Modules::run_active_modules();
|
151 |
|
154 |
add_action( 'admin_bar_menu', array( $this, 'modify_admin_bar' ), 99 );
|
155 |
}
|
156 |
|
157 |
+
$disabled = defined( 'ITSEC_DISABLE_PASSWORD_REQUIREMENTS') && ITSEC_DISABLE_PASSWORD_REQUIREMENTS;
|
158 |
+
|
159 |
+
if ( ! $disabled && has_action( 'itsec_validate_password' ) ) {
|
160 |
+
$pass_requirements = new ITSEC_Lib_Password_Requirements();
|
161 |
+
$pass_requirements->run();
|
162 |
+
}
|
163 |
+
|
164 |
do_action( 'itsec_initialized' );
|
165 |
}
|
166 |
|
167 |
+
/**
|
168 |
+
* Retrieve the global instance of the files utility.
|
169 |
+
*
|
170 |
+
* @return ITSEC_Files
|
171 |
+
*/
|
172 |
public static function get_itsec_files() {
|
173 |
$self = self::get_instance();
|
174 |
return $self->itsec_files;
|
175 |
}
|
176 |
|
177 |
+
/**
|
178 |
+
* Retrieve the global instance of the user notification utility.
|
179 |
+
*
|
180 |
+
* @return ITSEC_Notify
|
181 |
+
*/
|
182 |
public static function get_itsec_notify() {
|
183 |
$self = self::get_instance();
|
184 |
return $self->itsec_notify;
|
185 |
}
|
186 |
|
187 |
+
/**
|
188 |
+
* Retrieve the global instance of the Sync API.
|
189 |
+
*
|
190 |
+
* The API is not available until iThemes Sync verbs have been registered ( init#11 ).
|
191 |
+
*
|
192 |
+
* @return Ithemes_Sync_API|null
|
193 |
+
*/
|
194 |
public static function get_sync_api() {
|
195 |
$self = self::get_instance();
|
196 |
return $self->sync_api;
|
197 |
}
|
198 |
|
199 |
+
/**
|
200 |
+
* Register ITSEC verbs with sync.
|
201 |
+
*
|
202 |
+
* @param Ithemes_Sync_API $sync_api
|
203 |
+
*/
|
204 |
public function register_sync_verbs( $sync_api ) {
|
205 |
// For use by the itsec-get-everything verb as it has to run other verbs to get their details.
|
206 |
$this->sync_api = $sync_api;
|
208 |
$sync_api->register( 'itsec-get-everything', 'Ithemes_Sync_Verb_ITSEC_Get_Everything', dirname( __FILE__ ) . '/sync-verbs/itsec-get-everything.php' );
|
209 |
}
|
210 |
|
211 |
+
/**
|
212 |
+
* Register core modules.
|
213 |
+
*/
|
214 |
public function register_modules() {
|
215 |
$path = dirname( __FILE__ );
|
216 |
|
255 |
*
|
256 |
* @since 4.0
|
257 |
*
|
258 |
+
* @param array $links Array of WordPress links
|
259 |
* @param string $file String name of current file
|
260 |
*
|
261 |
+
* @return array Array of WordPress links
|
|
|
262 |
*/
|
263 |
+
public function add_action_link( $links, $file ) {
|
264 |
|
265 |
static $this_plugin;
|
266 |
|
300 |
}
|
301 |
|
302 |
/**
|
303 |
+
* Add admin bar items
|
304 |
*
|
305 |
* @since 4.0
|
306 |
*
|
307 |
+
* @param WP_Admin_Bar $wp_admin_bar
|
308 |
+
*
|
309 |
* @return void
|
310 |
*/
|
311 |
public function modify_admin_bar( $wp_admin_bar ) {
|
351 |
);
|
352 |
}
|
353 |
|
354 |
+
/**
|
355 |
+
* Dispatch a request to upgrade the data schema to another version.
|
356 |
+
*
|
357 |
+
* @param int|bool $build The version of the data storage format. Pass false to default to the current version.
|
358 |
+
*/
|
359 |
public function handle_upgrade( $build = false ) {
|
360 |
$this->doing_data_upgrade = true;
|
361 |
|
362 |
+
require_once( self::get_core_dir() . '/setup.php' );
|
363 |
ITSEC_Setup::handle_upgrade( $build );
|
364 |
}
|
365 |
|
366 |
public static function handle_activation() {
|
367 |
+
require_once( self::get_core_dir() . '/setup.php' );
|
368 |
ITSEC_Setup::handle_activation();
|
369 |
}
|
370 |
|
371 |
public static function handle_deactivation() {
|
372 |
+
require_once( self::get_core_dir() . '/setup.php' );
|
373 |
ITSEC_Setup::handle_deactivation();
|
374 |
}
|
375 |
|
376 |
public static function handle_uninstall() {
|
377 |
+
require_once( self::get_core_dir() . '/setup.php' );
|
378 |
ITSEC_Setup::handle_uninstall();
|
379 |
}
|
380 |
|
381 |
+
/**
|
382 |
+
* Register a notice to be displayed in the WordPress admin.
|
383 |
+
*
|
384 |
+
* @param callable $callback Function that will render a notice.
|
385 |
+
* @param bool $all_pages Display the notice on all pages or only on ITSEC, plugins, and upgrade page.
|
386 |
+
*/
|
387 |
public static function add_notice( $callback, $all_pages = false ) {
|
388 |
global $pagenow, $plugin_page;
|
389 |
|
407 |
}
|
408 |
}
|
409 |
|
410 |
+
/**
|
411 |
+
* Get the required capability to manage ITSEC.
|
412 |
+
*
|
413 |
+
* @return string
|
414 |
+
*/
|
415 |
public static function get_required_cap() {
|
416 |
return apply_filters( 'itsec_cap_required', is_multisite() ? 'manage_network_options' : 'manage_options' );
|
417 |
}
|
418 |
|
419 |
+
/**
|
420 |
+
* Does the current user have permission to manage ITSEC.
|
421 |
+
*
|
422 |
+
* @return bool
|
423 |
+
*/
|
424 |
public static function current_user_can_manage() {
|
425 |
return current_user_can( self::get_required_cap() );
|
426 |
}
|
455 |
return $self->plugin_name;
|
456 |
}
|
457 |
|
458 |
+
/**
|
459 |
+
* Is this an iThemes Security Pro installation.
|
460 |
+
*
|
461 |
+
* This value is not cached.
|
462 |
+
*
|
463 |
+
* @return bool
|
464 |
+
*/
|
465 |
public static function is_pro() {
|
466 |
return is_dir( self::get_plugin_dir() . 'pro' );
|
467 |
}
|
468 |
|
469 |
+
/**
|
470 |
+
* Get the current local timestamp.
|
471 |
+
*
|
472 |
+
* This value will be the same throughout the entire request.
|
473 |
+
*
|
474 |
+
* @return int
|
475 |
+
*/
|
476 |
public static function get_current_time() {
|
477 |
$self = self::get_instance();
|
478 |
return $self->current_time;
|
479 |
}
|
480 |
|
481 |
+
/**
|
482 |
+
* Get the current UTC timestamp.
|
483 |
+
*
|
484 |
+
* This value will be the same throughout the entire request.
|
485 |
+
*
|
486 |
+
* @return int
|
487 |
+
*/
|
488 |
public static function get_current_time_gmt() {
|
489 |
$self = self::get_instance();
|
490 |
return $self->current_time_gmt;
|
491 |
}
|
492 |
|
493 |
+
/**
|
494 |
+
* Get the UTC offset in seconds.
|
495 |
+
*
|
496 |
+
* @return int
|
497 |
+
*/
|
498 |
public static function get_time_offset() {
|
499 |
$self = self::get_instance();
|
500 |
return $self->current_time - $self->current_time_gmt;
|
532 |
return network_admin_url( 'admin.php?page=itsec&module=' . $module );
|
533 |
}
|
534 |
|
535 |
+
/**
|
536 |
+
* Specify whether there is a user modifying settings or if an API is modifying settings.
|
537 |
+
*
|
538 |
+
* @param bool $interactive
|
539 |
+
*/
|
540 |
public static function set_interactive( $interactive ) {
|
541 |
$self = self::get_instance();
|
542 |
$self->interactive = (bool) $interactive;
|
543 |
}
|
544 |
|
545 |
+
/**
|
546 |
+
* Is a user modifying settings or the API modifying settings (such as from Sync requests).
|
547 |
+
*
|
548 |
+
* @return bool
|
549 |
+
*/
|
550 |
public static function is_interactive() {
|
551 |
$self = self::get_instance();
|
552 |
return $self->interactive;
|
553 |
}
|
554 |
|
555 |
+
/**
|
556 |
+
* Determine whether the current request is an Infinite WP API call.
|
557 |
+
*
|
558 |
+
* @return bool
|
559 |
+
*/
|
560 |
public static function is_iwp_call() {
|
561 |
$self = self::get_instance();
|
562 |
|
585 |
return $self->is_iwp_call;
|
586 |
}
|
587 |
|
588 |
+
/**
|
589 |
+
* Get the configured WordPress upload directory of the main site.
|
590 |
+
*
|
591 |
+
* This value is cached for both the lifetime of the request and possibly indefinitely when WordPress is
|
592 |
+
* using an object cache.
|
593 |
+
*
|
594 |
+
* @see wp_upload_dir
|
595 |
+
*
|
596 |
+
* @return array
|
597 |
+
*/
|
598 |
public static function get_wp_upload_dir() {
|
599 |
$self = self::get_instance();
|
600 |
|
621 |
return $self->wp_upload_dir;
|
622 |
}
|
623 |
|
624 |
+
/**
|
625 |
+
* Set a new upload directory and ensure the previously cached value is cleared.
|
626 |
+
*
|
627 |
+
* @param string $old_dir
|
628 |
+
* @param string $new_dir
|
629 |
+
*/
|
630 |
public static function update_wp_upload_dir( $old_dir, $new_dir ) {
|
631 |
$self = self::get_instance();
|
632 |
|
639 |
delete_site_transient( 'itsec_wp_upload_dir' );
|
640 |
}
|
641 |
|
642 |
+
/**
|
643 |
+
* Retrieve and/or create a directory for ITSEC to store data.
|
644 |
+
*
|
645 |
+
* @param string $dir Optionally specify an additional sub-directory.
|
646 |
+
*
|
647 |
+
* @return string
|
648 |
+
*/
|
649 |
public static function get_storage_dir( $dir = '' ) {
|
650 |
$self = self::get_instance();
|
651 |
|
672 |
}
|
673 |
|
674 |
public static function is_ajax_request() {
|
675 |
+
if ( function_exists( 'wp_doing_ajax' ) ) {
|
676 |
+
return wp_doing_ajax();
|
677 |
+
}
|
678 |
+
|
679 |
return defined( 'DOING_AJAX' ) && DOING_AJAX;
|
680 |
}
|
681 |
|
683 |
return defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST;
|
684 |
}
|
685 |
|
686 |
+
/**
|
687 |
+
* Is this a WordPress REST API request.
|
688 |
+
*
|
689 |
+
* This function is suitable to be used immediately, not just after REST_REQUEST has been defined.
|
690 |
+
*
|
691 |
+
* @return bool
|
692 |
+
*/
|
693 |
public static function is_rest_api_request() {
|
694 |
if ( isset( $GLOBALS['__itsec_core_is_rest_api_request'] ) ) {
|
695 |
return $GLOBALS['__itsec_core_is_rest_api_request'];
|
712 |
|
713 |
if ( 0 === strpos( $_SERVER['REQUEST_URI'], $rest_api_path ) ) {
|
714 |
$GLOBALS['__itsec_core_is_rest_api_request'] = true;
|
715 |
+
} else {
|
716 |
+
$GLOBALS['__itsec_core_is_rest_api_request'] = false;
|
717 |
+
}
|
718 |
+
|
719 |
+
return $GLOBALS['__itsec_core_is_rest_api_request'];
|
720 |
+
}
|
721 |
+
|
722 |
+
/**
|
723 |
+
* Is this a request to wp-admin/admin-post.php?
|
724 |
+
*
|
725 |
+
* @return bool
|
726 |
+
*/
|
727 |
+
public static function is_admin_post_php_request() {
|
728 |
+
if ( 'wp-admin/admin-post.php' === ITSEC_Lib::get_request_path() ) {
|
729 |
return true;
|
730 |
}
|
731 |
|
|
|
732 |
return false;
|
733 |
}
|
734 |
|
735 |
+
/**
|
736 |
+
* Is the current request being made by a WordPress API.
|
737 |
+
*
|
738 |
+
* @param bool $include_ajax Whether to include Ajax requests as a subset of API requests.
|
739 |
+
* @param bool $include_admin_post_php Whether to include wp-admin/admin-post.php requests as a subset of API
|
740 |
+
* requests.
|
741 |
+
*
|
742 |
+
* @return bool
|
743 |
+
*/
|
744 |
+
public static function is_api_request( $include_ajax = true, $include_admin_post_php = true ) {
|
745 |
if ( $include_ajax && self::is_ajax_request() ) {
|
746 |
return true;
|
747 |
}
|
748 |
|
749 |
+
if ( $include_admin_post_php && self::is_admin_post_php_request() ) {
|
750 |
+
return true;
|
751 |
+
}
|
752 |
+
|
753 |
if ( self::is_rest_api_request() || self::is_xmlrpc_request() ) {
|
754 |
return true;
|
755 |
}
|
756 |
|
757 |
return false;
|
758 |
}
|
759 |
+
|
760 |
+
/**
|
761 |
+
* Check to see if the define to disable all active modules is set.
|
762 |
+
*
|
763 |
+
* Note that the ITSEC_DISABLE_MODULES should only be used to gain access to a site that you are locked out of.
|
764 |
+
* Once logged in, you should remove the define to re-enable the protections offered by iThemes Security.
|
765 |
+
*
|
766 |
+
* @return bool true if the define is set to a truthy value, false otherwise.
|
767 |
+
*/
|
768 |
+
public static function is_temp_disable_modules_set() {
|
769 |
+
if ( defined( 'ITSEC_DISABLE_MODULES' ) && ITSEC_DISABLE_MODULES ) {
|
770 |
+
return true;
|
771 |
+
}
|
772 |
+
|
773 |
+
return false;
|
774 |
+
}
|
775 |
}
|
776 |
}
|
core/{class-itsec-files.php → files.php}
RENAMED
File without changes
|
core/history.txt
CHANGED
@@ -509,3 +509,42 @@
|
|
509 |
Bug Fix: When a requesting IP address cannot be found, default to 127.0.0.1. This fixes issues with some alternate cron setups.
|
510 |
Bug Fix: Having more than one iThemes Security modification in a .htaccess, nginx.conf, or wp-config.php file will no longer result in having all the file content between each section removed when updating the file.
|
511 |
Bug Fix: Modifications to the wp-config.php file added by W3 Total Cache now have their Windows-style newlines preserved when iThemes Security updates the file.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
509 |
Bug Fix: When a requesting IP address cannot be found, default to 127.0.0.1. This fixes issues with some alternate cron setups.
|
510 |
Bug Fix: Having more than one iThemes Security modification in a .htaccess, nginx.conf, or wp-config.php file will no longer result in having all the file content between each section removed when updating the file.
|
511 |
Bug Fix: Modifications to the wp-config.php file added by W3 Total Cache now have their Windows-style newlines preserved when iThemes Security updates the file.
|
512 |
+
3.1.3 - 2017-04-11 - Chris Jean
|
513 |
+
Bug Fix: Removed warning: "Non-static method ITSEC_Setup::uninstall() should not be called statically".
|
514 |
+
Enhancement: Removed AhrefsBot from the HackRepair blacklist as they are legitimate bot.
|
515 |
+
3.2.1 - 2017-05-25 - Chris Jean & Timothy Jacobs
|
516 |
+
New Feature: Added support for iThemes Sync to run the Security Check feature from inside the Sync service.
|
517 |
+
Bug Fix: Fixed the ability to manually enter a page number to navigate to on the Security > Logs page.
|
518 |
+
Bug Fix: Fixed source of warning that could appear when creating a backup while running a PHP version less than 5.4.
|
519 |
+
Bug Fix: Fixed source of notice that could appear when reseting a user's password when the Strong Passwords Enforcement feature is enabled.
|
520 |
+
Bug Fix: Fixed bugs that prevented reporting of specific error messages related to updating the wp-config.php file.
|
521 |
+
Misc : Updated or added phpDoc to many functions.
|
522 |
+
3.3.0 - 2017-06-21 - Chris Jean & Timothy Jacobs
|
523 |
+
Bug Fix: Fixed an infinite loop that could occur when expiring a cookie and Hide Backend is enabled.
|
524 |
+
Bug Fix: Fixed compatibility issue with the Jetpack plugin when Hide Backend is enabled which could prevent Jetpack from redirecting users to the wordpress.com login page.
|
525 |
+
Bug Fix: Fixed issue where access to wp-admin/admin-post.php when Hide Backend is enabled.
|
526 |
+
Enhancement: Improved efficiency of Hide Backend code, increasing site performance when the feature is enabled.
|
527 |
+
Enhancement: Enforce strong passwords during log-in. Can be disabled via the ITSEC_DISABLE_PASSWORD_REQUIREMENTS constant.
|
528 |
+
Enhancement: Use canonical roles library to determine if a new user or an updated role requires a strong password.
|
529 |
+
Enhancement: Introduce password requirements module to centralize handling of password updates.
|
530 |
+
Misc: Updated Disable File Locking description.
|
531 |
+
3.4.0 - 2017-07-05 - Chris Jean & Timothy Jacobs
|
532 |
+
Important: The way that Hide Backend functions changes in this release. Previously, if your Hide Backend Login Slug was wplogin, going to example.com/wplogin would result in the URL remaining example.com/wplogin. The new implementation of this feature results in a redirect to a URL that looks as follows: example.com/wp-login.php?itsec-hb-token=wplogin. While this may not be desireable for some users, this change was necessary to fix longstanding compatibility issues with other plugins. Once you access the login page using the Login Slug page, a cookie is set with an expiration time of one hour. As long as the cookie remains, you can access example.com/wp-login.php without having to access the Hide Backend Login Slug first. If you wish to confirm that Hide Backend is working properly on your site, opening up a private browsing window is a quick way to test without having to log out and clear cookies.
|
533 |
+
|
534 |
+
Bug Fix: Fixed issue that could prevent "Register" and "Lost your password?" links from working properly on the login page when Hide Backend is enabled.
|
535 |
+
Bug Fix: Fix fatal error when updating a profile.
|
536 |
+
Bug Fix: Fix strong passwords not being recognized as strong on the profile page.
|
537 |
+
Bug Fix: Fix fatal error when registering a new user without specifying a role ( iThemes Exchange ).
|
538 |
+
Bug Fix: Compatability with JetPack SSO and Password Requirements.
|
539 |
+
Bug Fix: Ensure viewport meta is defined when loading the password requirements update password form.
|
540 |
+
Bug Fix: Hide Backend is now compatible with Jetpack Single Sign On.
|
541 |
+
Bug Fix: Hide Backend now hides registration pages on multisite sites.
|
542 |
+
Enhancement: The Hide Backend hidden login URL is no longer leaked by password-protected content.
|
543 |
+
Enhancement: Allow for searching through modules and settings.
|
544 |
+
Enhancement: Link to other module settings pages without forcing the page to refresh.
|
545 |
+
Enhancement: Fire an action, "itsec_change_admin_user_id", when the admin user id changes.
|
546 |
+
Enhancement: Changed default Hide Backend Register Slug from wp-register.php to wp-signup.php since WordPress switched from using wp-register.php to wp-signup.php for registrations. This will not affect existing sites.
|
547 |
+
Enhancement: Hide Backend functions purely in PHP code now rather than relying half on PHP code and half on .htaccess and nginx.conf modifications. This allows Hide Backend to function on web servers and server configurations that it was previously not compatible with.
|
548 |
+
New Feature: Added support for the ITSEC_DISABLE_MODULES define.
|
549 |
+
3.4.1 - 2017-07-05 - Chris Jean & Timothy Jacobs
|
550 |
+
Bug Fix: Fixed password-protected posts not properly handling the password when Hide Backend is enabled.
|
core/js/scrollTo.js
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Copyright (c) 2007-2015 Ariel Flesler - aflesler ○ gmail • com | http://flesler.blogspot.com
|
3 |
+
* Licensed under MIT
|
4 |
+
* @author Ariel Flesler
|
5 |
+
* @version 2.1.3
|
6 |
+
*/
|
7 |
+
;(function(f){"use strict";"function"===typeof define&&define.amd?define(["jquery"],f):"undefined"!==typeof module&&module.exports?module.exports=f(require("jquery")):f(jQuery)})(function($){"use strict";function n(a){return!a.nodeName||-1!==$.inArray(a.nodeName.toLowerCase(),["iframe","#document","html","body"])}function h(a){return $.isFunction(a)||$.isPlainObject(a)?a:{top:a,left:a}}var p=$.scrollTo=function(a,d,b){return $(window).scrollTo(a,d,b)};p.defaults={axis:"xy",duration:0,limit:!0};$.fn.scrollTo=function(a,d,b){"object"=== typeof d&&(b=d,d=0);"function"===typeof b&&(b={onAfter:b});"max"===a&&(a=9E9);b=$.extend({},p.defaults,b);d=d||b.duration;var u=b.queue&&1<b.axis.length;u&&(d/=2);b.offset=h(b.offset);b.over=h(b.over);return this.each(function(){function k(a){var k=$.extend({},b,{queue:!0,duration:d,complete:a&&function(){a.call(q,e,b)}});r.animate(f,k)}if(null!==a){var l=n(this),q=l?this.contentWindow||window:this,r=$(q),e=a,f={},t;switch(typeof e){case "number":case "string":if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(e)){e= h(e);break}e=l?$(e):$(e,q);case "object":if(e.length===0)return;if(e.is||e.style)t=(e=$(e)).offset()}var v=$.isFunction(b.offset)&&b.offset(q,e)||b.offset;$.each(b.axis.split(""),function(a,c){var d="x"===c?"Left":"Top",m=d.toLowerCase(),g="scroll"+d,h=r[g](),n=p.max(q,c);t?(f[g]=t[m]+(l?0:h-r.offset()[m]),b.margin&&(f[g]-=parseInt(e.css("margin"+d),10)||0,f[g]-=parseInt(e.css("border"+d+"Width"),10)||0),f[g]+=v[m]||0,b.over[m]&&(f[g]+=e["x"===c?"width":"height"]()*b.over[m])):(d=e[m],f[g]=d.slice&& "%"===d.slice(-1)?parseFloat(d)/100*n:d);b.limit&&/^\d+$/.test(f[g])&&(f[g]=0>=f[g]?0:Math.min(f[g],n));!a&&1<b.axis.length&&(h===f[g]?f={}:u&&(k(b.onAfterFirst),f={}))});k(b.onAfter)}})};p.max=function(a,d){var b="x"===d?"Width":"Height",h="scroll"+b;if(!n(a))return a[h]-$(a)[b.toLowerCase()]();var b="client"+b,k=a.ownerDocument||a.document,l=k.documentElement,k=k.body;return Math.max(l[h],k[h])-Math.min(l[b],k[b])};$.Tween.propHooks.scrollLeft=$.Tween.propHooks.scrollTop={get:function(a){return $(a.elem)[a.prop]()}, set:function(a){var d=this.get(a);if(a.options.interrupt&&a._last&&a._last!==d)return $(a.elem).stop();var b=Math.round(a.now);d!==b&&($(a.elem)[a.prop](b),a._last=this.get(a))}};return p});
|
core/js/url.js
DELETED
@@ -1,93 +0,0 @@
|
|
1 |
-
/*! URI.js v1.13.1 http://medialize.github.io/URI.js/ */
|
2 |
-
/* build contains: IPv6.js, punycode.js, SecondLevelDomains.js, URI.js, URITemplate.js, jquery.URI.js, URI.fragmentQuery.js */
|
3 |
-
(function(f,g){"object"===typeof exports?module.exports=g():"function"===typeof define&&define.amd?define(g):f.IPv6=g(f)})(this,function(f){var g=f&&f.IPv6;return{best:function(f){f=f.toLowerCase().split(":");var k=f.length,b=8;""===f[0]&&""===f[1]&&""===f[2]?(f.shift(),f.shift()):""===f[0]&&""===f[1]?f.shift():""===f[k-1]&&""===f[k-2]&&f.pop();k=f.length;-1!==f[k-1].indexOf(".")&&(b=7);var g;for(g=0;g<k&&""!==f[g];g++);if(g<b)for(f.splice(g,1,"0000");f.length<b;)f.splice(g,0,"0000");for(g=0;g<b;g++){for(var k=
|
4 |
-
f[g].split(""),r=0;3>r;r++)if("0"===k[0]&&1<k.length)k.splice(0,1);else break;f[g]=k.join("")}var k=-1,q=r=0,h=-1,w=!1;for(g=0;g<b;g++)w?"0"===f[g]?q+=1:(w=!1,q>r&&(k=h,r=q)):"0"===f[g]&&(w=!0,h=g,q=1);q>r&&(k=h,r=q);1<r&&f.splice(k,r,"");k=f.length;b="";""===f[0]&&(b=":");for(g=0;g<k;g++){b+=f[g];if(g===k-1)break;b+=":"}""===f[k-1]&&(b+=":");return b},noConflict:function(){f.IPv6===this&&(f.IPv6=g);return this}}});
|
5 |
-
(function(f){function g(a){throw RangeError(z[a]);}function s(a,c){for(var d=a.length;d--;)a[d]=c(a[d]);return a}function k(a,c){return s(a.split(p),c).join(".")}function b(a){for(var c=[],d=0,b=a.length,p,e;d<b;)p=a.charCodeAt(d++),55296<=p&&56319>=p&&d<b?(e=a.charCodeAt(d++),56320==(e&64512)?c.push(((p&1023)<<10)+(e&1023)+65536):(c.push(p),d--)):c.push(p);return c}function u(a){return s(a,function(a){var c="";65535<a&&(a-=65536,c+=D(a>>>10&1023|55296),a=56320|a&1023);return c+=D(a)}).join("")}function r(a,
|
6 |
-
c){return a+22+75*(26>a)-((0!=c)<<5)}function q(a,c,d){var b=0;a=d?B(a/H):a>>1;for(a+=B(a/c);a>v*y>>1;b+=l)a=B(a/v);return B(b+(v+1)*a/(a+E))}function h(c){var d=[],b=c.length,p,e=0,f=F,z=C,h,m,v,n,k;h=c.lastIndexOf(a);0>h&&(h=0);for(m=0;m<h;++m)128<=c.charCodeAt(m)&&g("not-basic"),d.push(c.charCodeAt(m));for(h=0<h?h+1:0;h<b;){m=e;p=1;for(v=l;;v+=l){h>=b&&g("invalid-input");n=c.charCodeAt(h++);n=10>n-48?n-22:26>n-65?n-65:26>n-97?n-97:l;(n>=l||n>B((t-e)/p))&&g("overflow");e+=n*p;k=v<=z?x:v>=z+y?y:
|
7 |
-
v-z;if(n<k)break;n=l-k;p>B(t/n)&&g("overflow");p*=n}p=d.length+1;z=q(e-m,p,0==m);B(e/p)>t-f&&g("overflow");f+=B(e/p);e%=p;d.splice(e++,0,f)}return u(d)}function w(c){var d,p,e,f,z,h,m,n,v,k=[],w,s,A;c=b(c);w=c.length;d=F;p=0;z=C;for(h=0;h<w;++h)v=c[h],128>v&&k.push(D(v));for((e=f=k.length)&&k.push(a);e<w;){m=t;for(h=0;h<w;++h)v=c[h],v>=d&&v<m&&(m=v);s=e+1;m-d>B((t-p)/s)&&g("overflow");p+=(m-d)*s;d=m;for(h=0;h<w;++h)if(v=c[h],v<d&&++p>t&&g("overflow"),v==d){n=p;for(m=l;;m+=l){v=m<=z?x:m>=z+y?y:m-z;
|
8 |
-
if(n<v)break;A=n-v;n=l-v;k.push(D(r(v+A%n,0)));n=B(A/n)}k.push(D(r(n,0)));z=q(p,s,e==f);p=0;++e}++p;++d}return k.join("")}var A="object"==typeof exports&&exports,m="object"==typeof module&&module&&module.exports==A&&module,n="object"==typeof global&&global;if(n.global===n||n.window===n)f=n;var e,t=2147483647,l=36,x=1,y=26,E=38,H=700,C=72,F=128,a="-",c=/^xn--/,d=/[^ -~]/,p=/\x2E|\u3002|\uFF0E|\uFF61/g,z={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)",
|
9 |
-
"invalid-input":"Invalid input"},v=l-x,B=Math.floor,D=String.fromCharCode,G;e={version:"1.2.3",ucs2:{decode:b,encode:u},decode:h,encode:w,toASCII:function(a){return k(a,function(a){return d.test(a)?"xn--"+w(a):a})},toUnicode:function(a){return k(a,function(a){return c.test(a)?h(a.slice(4).toLowerCase()):a})}};if("function"==typeof define&&"object"==typeof define.amd&&define.amd)define(function(){return e});else if(A&&!A.nodeType)if(m)m.exports=e;else for(G in e)e.hasOwnProperty(G)&&(A[G]=e[G]);else f.punycode=
|
10 |
-
e})(this);
|
11 |
-
(function(f,g){"object"===typeof exports?module.exports=g():"function"===typeof define&&define.amd?define(g):f.SecondLevelDomains=g(f)})(this,function(f){var g=f&&f.SecondLevelDomains,s={list:{ac:" com gov mil net org ",ae:" ac co gov mil name net org pro sch ",af:" com edu gov net org ",al:" com edu gov mil net org ",ao:" co ed gv it og pb ",ar:" com edu gob gov int mil net org tur ",at:" ac co gv or ",au:" asn com csiro edu gov id net org ",ba:" co com edu gov mil net org rs unbi unmo unsa untz unze ",bb:" biz co com edu gov info net org store tv ",
|
12 |
-
bh:" biz cc com edu gov info net org ",bn:" com edu gov net org ",bo:" com edu gob gov int mil net org tv ",br:" adm adv agr am arq art ato b bio blog bmd cim cng cnt com coop ecn edu eng esp etc eti far flog fm fnd fot fst g12 ggf gov imb ind inf jor jus lel mat med mil mus net nom not ntr odo org ppg pro psc psi qsl rec slg srv tmp trd tur tv vet vlog wiki zlg ",bs:" com edu gov net org ",bz:" du et om ov rg ",ca:" ab bc mb nb nf nl ns nt nu on pe qc sk yk ",ck:" biz co edu gen gov info net org ",
|
13 |
-
cn:" ac ah bj com cq edu fj gd gov gs gx gz ha hb he hi hl hn jl js jx ln mil net nm nx org qh sc sd sh sn sx tj tw xj xz yn zj ",co:" com edu gov mil net nom org ",cr:" ac c co ed fi go or sa ",cy:" ac biz com ekloges gov ltd name net org parliament press pro tm ","do":" art com edu gob gov mil net org sld web ",dz:" art asso com edu gov net org pol ",ec:" com edu fin gov info med mil net org pro ",eg:" com edu eun gov mil name net org sci ",er:" com edu gov ind mil net org rochest w ",es:" com edu gob nom org ",
|
14 |
-
et:" biz com edu gov info name net org ",fj:" ac biz com info mil name net org pro ",fk:" ac co gov net nom org ",fr:" asso com f gouv nom prd presse tm ",gg:" co net org ",gh:" com edu gov mil org ",gn:" ac com gov net org ",gr:" com edu gov mil net org ",gt:" com edu gob ind mil net org ",gu:" com edu gov net org ",hk:" com edu gov idv net org ",id:" ac co go mil net or sch web ",il:" ac co gov idf k12 muni net org ","in":" ac co edu ernet firm gen gov i ind mil net nic org res ",iq:" com edu gov i mil net org ",
|
15 |
-
ir:" ac co dnssec gov i id net org sch ",it:" edu gov ",je:" co net org ",jo:" com edu gov mil name net org sch ",jp:" ac ad co ed go gr lg ne or ",ke:" ac co go info me mobi ne or sc ",kh:" com edu gov mil net org per ",ki:" biz com de edu gov info mob net org tel ",km:" asso com coop edu gouv k medecin mil nom notaires pharmaciens presse tm veterinaire ",kn:" edu gov net org ",kr:" ac busan chungbuk chungnam co daegu daejeon es gangwon go gwangju gyeongbuk gyeonggi gyeongnam hs incheon jeju jeonbuk jeonnam k kg mil ms ne or pe re sc seoul ulsan ",
|
16 |
-
kw:" com edu gov net org ",ky:" com edu gov net org ",kz:" com edu gov mil net org ",lb:" com edu gov net org ",lk:" assn com edu gov grp hotel int ltd net ngo org sch soc web ",lr:" com edu gov net org ",lv:" asn com conf edu gov id mil net org ",ly:" com edu gov id med net org plc sch ",ma:" ac co gov m net org press ",mc:" asso tm ",me:" ac co edu gov its net org priv ",mg:" com edu gov mil nom org prd tm ",mk:" com edu gov inf name net org pro ",ml:" com edu gov net org presse ",mn:" edu gov org ",
|
17 |
-
mo:" com edu gov net org ",mt:" com edu gov net org ",mv:" aero biz com coop edu gov info int mil museum name net org pro ",mw:" ac co com coop edu gov int museum net org ",mx:" com edu gob net org ",my:" com edu gov mil name net org sch ",nf:" arts com firm info net other per rec store web ",ng:" biz com edu gov mil mobi name net org sch ",ni:" ac co com edu gob mil net nom org ",np:" com edu gov mil net org ",nr:" biz com edu gov info net org ",om:" ac biz co com edu gov med mil museum net org pro sch ",
|
18 |
-
pe:" com edu gob mil net nom org sld ",ph:" com edu gov i mil net ngo org ",pk:" biz com edu fam gob gok gon gop gos gov net org web ",pl:" art bialystok biz com edu gda gdansk gorzow gov info katowice krakow lodz lublin mil net ngo olsztyn org poznan pwr radom slupsk szczecin torun warszawa waw wroc wroclaw zgora ",pr:" ac biz com edu est gov info isla name net org pro prof ",ps:" com edu gov net org plo sec ",pw:" belau co ed go ne or ",ro:" arts com firm info nom nt org rec store tm www ",rs:" ac co edu gov in org ",
|
19 |
-
sb:" com edu gov net org ",sc:" com edu gov net org ",sh:" co com edu gov net nom org ",sl:" com edu gov net org ",st:" co com consulado edu embaixada gov mil net org principe saotome store ",sv:" com edu gob org red ",sz:" ac co org ",tr:" av bbs bel biz com dr edu gen gov info k12 name net org pol tel tsk tv web ",tt:" aero biz cat co com coop edu gov info int jobs mil mobi museum name net org pro tel travel ",tw:" club com ebiz edu game gov idv mil net org ",mu:" ac co com gov net or org ",mz:" ac co edu gov org ",
|
20 |
-
na:" co com ",nz:" ac co cri geek gen govt health iwi maori mil net org parliament school ",pa:" abo ac com edu gob ing med net nom org sld ",pt:" com edu gov int net nome org publ ",py:" com edu gov mil net org ",qa:" com edu gov mil net org ",re:" asso com nom ",ru:" ac adygeya altai amur arkhangelsk astrakhan bashkiria belgorod bir bryansk buryatia cbg chel chelyabinsk chita chukotka chuvashia com dagestan e-burg edu gov grozny int irkutsk ivanovo izhevsk jar joshkar-ola kalmykia kaluga kamchatka karelia kazan kchr kemerovo khabarovsk khakassia khv kirov koenig komi kostroma kranoyarsk kuban kurgan kursk lipetsk magadan mari mari-el marine mil mordovia mosreg msk murmansk nalchik net nnov nov novosibirsk nsk omsk orenburg org oryol penza perm pp pskov ptz rnd ryazan sakhalin samara saratov simbirsk smolensk spb stavropol stv surgut tambov tatarstan tom tomsk tsaritsyn tsk tula tuva tver tyumen udm udmurtia ulan-ude vladikavkaz vladimir vladivostok volgograd vologda voronezh vrn vyatka yakutia yamal yekaterinburg yuzhno-sakhalinsk ",
|
21 |
-
rw:" ac co com edu gouv gov int mil net ",sa:" com edu gov med net org pub sch ",sd:" com edu gov info med net org tv ",se:" a ac b bd c d e f g h i k l m n o org p parti pp press r s t tm u w x y z ",sg:" com edu gov idn net org per ",sn:" art com edu gouv org perso univ ",sy:" com edu gov mil net news org ",th:" ac co go in mi net or ",tj:" ac biz co com edu go gov info int mil name net nic org test web ",tn:" agrinet com defense edunet ens fin gov ind info intl mincom nat net org perso rnrt rns rnu tourism ",
|
22 |
-
tz:" ac co go ne or ",ua:" biz cherkassy chernigov chernovtsy ck cn co com crimea cv dn dnepropetrovsk donetsk dp edu gov if in ivano-frankivsk kh kharkov kherson khmelnitskiy kiev kirovograd km kr ks kv lg lugansk lutsk lviv me mk net nikolaev od odessa org pl poltava pp rovno rv sebastopol sumy te ternopil uzhgorod vinnica vn zaporizhzhe zhitomir zp zt ",ug:" ac co go ne or org sc ",uk:" ac bl british-library co cym gov govt icnet jet lea ltd me mil mod national-library-scotland nel net nhs nic nls org orgn parliament plc police sch scot soc ",
|
23 |
-
us:" dni fed isa kids nsn ",uy:" com edu gub mil net org ",ve:" co com edu gob info mil net org web ",vi:" co com k12 net org ",vn:" ac biz com edu gov health info int name net org pro ",ye:" co com gov ltd me net org plc ",yu:" ac co edu gov org ",za:" ac agric alt bourse city co cybernet db edu gov grondar iaccess imt inca landesign law mil net ngo nis nom olivetti org pix school tm web ",zm:" ac co com edu gov net org sch "},has:function(f){var b=f.lastIndexOf(".");if(0>=b||b>=f.length-1)return!1;
|
24 |
-
var g=f.lastIndexOf(".",b-1);if(0>=g||g>=b-1)return!1;var r=s.list[f.slice(b+1)];return r?0<=r.indexOf(" "+f.slice(g+1,b)+" "):!1},is:function(f){var b=f.lastIndexOf(".");if(0>=b||b>=f.length-1||0<=f.lastIndexOf(".",b-1))return!1;var g=s.list[f.slice(b+1)];return g?0<=g.indexOf(" "+f.slice(0,b)+" "):!1},get:function(f){var b=f.lastIndexOf(".");if(0>=b||b>=f.length-1)return null;var g=f.lastIndexOf(".",b-1);if(0>=g||g>=b-1)return null;var r=s.list[f.slice(b+1)];return!r||0>r.indexOf(" "+f.slice(g+
|
25 |
-
1,b)+" ")?null:f.slice(g+1)},noConflict:function(){f.SecondLevelDomains===this&&(f.SecondLevelDomains=g);return this}};return s});
|
26 |
-
(function(f,g){"object"===typeof exports?module.exports=g(require("./punycode"),require("./IPv6"),require("./SecondLevelDomains")):"function"===typeof define&&define.amd?define(["./punycode","./IPv6","./SecondLevelDomains"],g):f.URI=g(f.punycode,f.IPv6,f.SecondLevelDomains,f)})(this,function(f,g,s,k){function b(a,c){if(!(this instanceof b))return new b(a,c);void 0===a&&(a="undefined"!==typeof location?location.href+"":"");this.href(a);return void 0!==c?this.absoluteTo(c):this}function u(a){return a.replace(/([.*+?^=!:${}()|[\]\/\\])/g,
|
27 |
-
"\\$1")}function r(a){return void 0===a?"Undefined":String(Object.prototype.toString.call(a)).slice(8,-1)}function q(a){return"Array"===r(a)}function h(a,c){var d,b;if(q(c)){d=0;for(b=c.length;d<b;d++)if(!h(a,c[d]))return!1;return!0}var e=r(c);d=0;for(b=a.length;d<b;d++)if("RegExp"===e){if("string"===typeof a[d]&&a[d].match(c))return!0}else if(a[d]===c)return!0;return!1}function w(a,c){if(!q(a)||!q(c)||a.length!==c.length)return!1;a.sort();c.sort();for(var d=0,b=a.length;d<b;d++)if(a[d]!==c[d])return!1;
|
28 |
-
return!0}function A(a){return escape(a)}function m(a){return encodeURIComponent(a).replace(/[!'()*]/g,A).replace(/\*/g,"%2A")}var n=k&&k.URI;b.version="1.13.1";var e=b.prototype,t=Object.prototype.hasOwnProperty;b._parts=function(){return{protocol:null,username:null,password:null,hostname:null,urn:null,port:null,path:null,query:null,fragment:null,duplicateQueryParameters:b.duplicateQueryParameters,escapeQuerySpace:b.escapeQuerySpace}};b.duplicateQueryParameters=!1;b.escapeQuerySpace=!0;b.protocol_expression=
|
29 |
-
/^[a-z][a-z0-9.+-]*$/i;b.idn_expression=/[^a-z0-9\.-]/i;b.punycode_expression=/(xn--)/i;b.ip4_expression=/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;b.ip6_expression=/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;
|
30 |
-
b.find_uri_expression=/\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?\u00ab\u00bb\u201c\u201d\u2018\u2019]))/ig;b.findUri={start:/\b(?:([a-z][a-z0-9.+-]*:\/\/)|www\.)/gi,end:/[\s\r\n]|$/,trim:/[`!()\[\]{};:'".,<>?\u00ab\u00bb\u201c\u201d\u201e\u2018\u2019]+$/};b.defaultPorts={http:"80",https:"443",ftp:"21",gopher:"70",ws:"80",wss:"443"};b.invalid_hostname_characters=
|
31 |
-
/[^a-zA-Z0-9\.-]/;b.domAttributes={a:"href",blockquote:"cite",link:"href",base:"href",script:"src",form:"action",img:"src",area:"href",iframe:"src",embed:"src",source:"src",track:"src",input:"src"};b.getDomAttribute=function(a){if(a&&a.nodeName){var c=a.nodeName.toLowerCase();return"input"===c&&"image"!==a.type?void 0:b.domAttributes[c]}};b.encode=m;b.decode=decodeURIComponent;b.iso8859=function(){b.encode=escape;b.decode=unescape};b.unicode=function(){b.encode=m;b.decode=decodeURIComponent};b.characters=
|
32 |
-
{pathname:{encode:{expression:/%(24|26|2B|2C|3B|3D|3A|40)/ig,map:{"%24":"$","%26":"&","%2B":"+","%2C":",","%3B":";","%3D":"=","%3A":":","%40":"@"}},decode:{expression:/[\/\?#]/g,map:{"/":"%2F","?":"%3F","#":"%23"}}},reserved:{encode:{expression:/%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig,map:{"%3A":":","%2F":"/","%3F":"?","%23":"#","%5B":"[","%5D":"]","%40":"@","%21":"!","%24":"$","%26":"&","%27":"'","%28":"(","%29":")","%2A":"*","%2B":"+","%2C":",","%3B":";","%3D":"="}}}};b.encodeQuery=
|
33 |
-
function(a,c){var d=b.encode(a+"");void 0===c&&(c=b.escapeQuerySpace);return c?d.replace(/%20/g,"+"):d};b.decodeQuery=function(a,c){a+="";void 0===c&&(c=b.escapeQuerySpace);try{return b.decode(c?a.replace(/\+/g,"%20"):a)}catch(d){return a}};b.recodePath=function(a){a=(a+"").split("/");for(var c=0,d=a.length;c<d;c++)a[c]=b.encodePathSegment(b.decode(a[c]));return a.join("/")};b.decodePath=function(a){a=(a+"").split("/");for(var c=0,d=a.length;c<d;c++)a[c]=b.decodePathSegment(a[c]);return a.join("/")};
|
34 |
-
var l={encode:"encode",decode:"decode"},x,y=function(a,c){return function(d){return b[c](d+"").replace(b.characters[a][c].expression,function(d){return b.characters[a][c].map[d]})}};for(x in l)b[x+"PathSegment"]=y("pathname",l[x]);b.encodeReserved=y("reserved","encode");b.parse=function(a,c){var d;c||(c={});d=a.indexOf("#");-1<d&&(c.fragment=a.substring(d+1)||null,a=a.substring(0,d));d=a.indexOf("?");-1<d&&(c.query=a.substring(d+1)||null,a=a.substring(0,d));"//"===a.substring(0,2)?(c.protocol=null,
|
35 |
-
a=a.substring(2),a=b.parseAuthority(a,c)):(d=a.indexOf(":"),-1<d&&(c.protocol=a.substring(0,d)||null,c.protocol&&!c.protocol.match(b.protocol_expression)?c.protocol=void 0:"file"===c.protocol?a=a.substring(d+3):"//"===a.substring(d+1,d+3)?(a=a.substring(d+3),a=b.parseAuthority(a,c)):(a=a.substring(d+1),c.urn=!0)));c.path=a;return c};b.parseHost=function(a,c){var d=a.indexOf("/"),b;-1===d&&(d=a.length);"["===a.charAt(0)?(b=a.indexOf("]"),c.hostname=a.substring(1,b)||null,c.port=a.substring(b+2,d)||
|
36 |
-
null,"/"===c.port&&(c.port=null)):a.indexOf(":")!==a.lastIndexOf(":")?(c.hostname=a.substring(0,d)||null,c.port=null):(b=a.substring(0,d).split(":"),c.hostname=b[0]||null,c.port=b[1]||null);c.hostname&&"/"!==a.substring(d).charAt(0)&&(d++,a="/"+a);return a.substring(d)||"/"};b.parseAuthority=function(a,c){a=b.parseUserinfo(a,c);return b.parseHost(a,c)};b.parseUserinfo=function(a,c){var d=a.indexOf("/"),p=-1<d?a.lastIndexOf("@",d):a.indexOf("@");-1<p&&(-1===d||p<d)?(d=a.substring(0,p).split(":"),c.username=
|
37 |
-
d[0]?b.decode(d[0]):null,d.shift(),c.password=d[0]?b.decode(d.join(":")):null,a=a.substring(p+1)):(c.username=null,c.password=null);return a};b.parseQuery=function(a,c){if(!a)return{};a=a.replace(/&+/g,"&").replace(/^\?*&*|&+$/g,"");if(!a)return{};for(var d={},p=a.split("&"),e=p.length,f,h,m=0;m<e;m++)f=p[m].split("="),h=b.decodeQuery(f.shift(),c),f=f.length?b.decodeQuery(f.join("="),c):null,d[h]?("string"===typeof d[h]&&(d[h]=[d[h]]),d[h].push(f)):d[h]=f;return d};b.build=function(a){var c="";a.protocol&&
|
38 |
-
(c+=a.protocol+":");a.urn||!c&&!a.hostname||(c+="//");c+=b.buildAuthority(a)||"";"string"===typeof a.path&&("/"!==a.path.charAt(0)&&"string"===typeof a.hostname&&(c+="/"),c+=a.path);"string"===typeof a.query&&a.query&&(c+="?"+a.query);"string"===typeof a.fragment&&a.fragment&&(c+="#"+a.fragment);return c};b.buildHost=function(a){var c="";if(a.hostname)c=b.ip6_expression.test(a.hostname)?c+("["+a.hostname+"]"):c+a.hostname;else return"";a.port&&(c+=":"+a.port);return c};b.buildAuthority=function(a){return b.buildUserinfo(a)+
|
39 |
-
b.buildHost(a)};b.buildUserinfo=function(a){var c="";a.username&&(c+=b.encode(a.username),a.password&&(c+=":"+b.encode(a.password)),c+="@");return c};b.buildQuery=function(a,c,d){var p="",f,e,h,m;for(e in a)if(t.call(a,e)&&e)if(q(a[e]))for(f={},h=0,m=a[e].length;h<m;h++)void 0!==a[e][h]&&void 0===f[a[e][h]+""]&&(p+="&"+b.buildQueryParameter(e,a[e][h],d),!0!==c&&(f[a[e][h]+""]=!0));else void 0!==a[e]&&(p+="&"+b.buildQueryParameter(e,a[e],d));return p.substring(1)};b.buildQueryParameter=function(a,
|
40 |
-
c,d){return b.encodeQuery(a,d)+(null!==c?"="+b.encodeQuery(c,d):"")};b.addQuery=function(a,c,d){if("object"===typeof c)for(var p in c)t.call(c,p)&&b.addQuery(a,p,c[p]);else if("string"===typeof c)void 0===a[c]?a[c]=d:("string"===typeof a[c]&&(a[c]=[a[c]]),q(d)||(d=[d]),a[c]=a[c].concat(d));else throw new TypeError("URI.addQuery() accepts an object, string as the name parameter");};b.removeQuery=function(a,c,d){var p;if(q(c))for(d=0,p=c.length;d<p;d++)a[c[d]]=void 0;else if("object"===typeof c)for(p in c)t.call(c,
|
41 |
-
p)&&b.removeQuery(a,p,c[p]);else if("string"===typeof c)if(void 0!==d)if(a[c]===d)a[c]=void 0;else{if(q(a[c])){p=a[c];var e={},f,h;if(q(d))for(f=0,h=d.length;f<h;f++)e[d[f]]=!0;else e[d]=!0;f=0;for(h=p.length;f<h;f++)void 0!==e[p[f]]&&(p.splice(f,1),h--,f--);a[c]=p}}else a[c]=void 0;else throw new TypeError("URI.addQuery() accepts an object, string as the first parameter");};b.hasQuery=function(a,c,d,e){if("object"===typeof c){for(var f in c)if(t.call(c,f)&&!b.hasQuery(a,f,c[f]))return!1;return!0}if("string"!==
|
42 |
-
typeof c)throw new TypeError("URI.hasQuery() accepts an object, string as the name parameter");switch(r(d)){case "Undefined":return c in a;case "Boolean":return a=Boolean(q(a[c])?a[c].length:a[c]),d===a;case "Function":return!!d(a[c],c,a);case "Array":return q(a[c])?(e?h:w)(a[c],d):!1;case "RegExp":return q(a[c])?e?h(a[c],d):!1:Boolean(a[c]&&a[c].match(d));case "Number":d=String(d);case "String":return q(a[c])?e?h(a[c],d):!1:a[c]===d;default:throw new TypeError("URI.hasQuery() accepts undefined, boolean, string, number, RegExp, Function as the value parameter");
|
43 |
-
}};b.commonPath=function(a,c){var d=Math.min(a.length,c.length),b;for(b=0;b<d;b++)if(a.charAt(b)!==c.charAt(b)){b--;break}if(1>b)return a.charAt(0)===c.charAt(0)&&"/"===a.charAt(0)?"/":"";if("/"!==a.charAt(b)||"/"!==c.charAt(b))b=a.substring(0,b).lastIndexOf("/");return a.substring(0,b+1)};b.withinString=function(a,c,d){d||(d={});var e=d.start||b.findUri.start,f=d.end||b.findUri.end,h=d.trim||b.findUri.trim,m=/[a-z0-9-]=["']?$/i;for(e.lastIndex=0;;){var g=e.exec(a);if(!g)break;g=g.index;if(d.ignoreHtml){var n=
|
44 |
-
a.slice(Math.max(g-3,0),g);if(n&&m.test(n))continue}var n=g+a.slice(g).search(f),l=a.slice(g,n).replace(h,"");d.ignore&&d.ignore.test(l)||(n=g+l.length,l=c(l,g,n,a),a=a.slice(0,g)+l+a.slice(n),e.lastIndex=g+l.length)}e.lastIndex=0;return a};b.ensureValidHostname=function(a){if(a.match(b.invalid_hostname_characters)){if(!f)throw new TypeError('Hostname "'+a+'" contains characters other than [A-Z0-9.-] and Punycode.js is not available');if(f.toASCII(a).match(b.invalid_hostname_characters))throw new TypeError('Hostname "'+
|
45 |
-
a+'" contains characters other than [A-Z0-9.-]');}};b.noConflict=function(a){if(a)return a={URI:this.noConflict()},k.URITemplate&&"function"===typeof k.URITemplate.noConflict&&(a.URITemplate=k.URITemplate.noConflict()),k.IPv6&&"function"===typeof k.IPv6.noConflict&&(a.IPv6=k.IPv6.noConflict()),k.SecondLevelDomains&&"function"===typeof k.SecondLevelDomains.noConflict&&(a.SecondLevelDomains=k.SecondLevelDomains.noConflict()),a;k.URI===this&&(k.URI=n);return this};e.build=function(a){if(!0===a)this._deferred_build=
|
46 |
-
!0;else if(void 0===a||this._deferred_build)this._string=b.build(this._parts),this._deferred_build=!1;return this};e.clone=function(){return new b(this)};e.valueOf=e.toString=function(){return this.build(!1)._string};l={protocol:"protocol",username:"username",password:"password",hostname:"hostname",port:"port"};y=function(a){return function(c,d){if(void 0===c)return this._parts[a]||"";this._parts[a]=c||null;this.build(!d);return this}};for(x in l)e[x]=y(l[x]);l={query:"?",fragment:"#"};y=function(a,
|
47 |
-
c){return function(d,b){if(void 0===d)return this._parts[a]||"";null!==d&&(d+="",d.charAt(0)===c&&(d=d.substring(1)));this._parts[a]=d;this.build(!b);return this}};for(x in l)e[x]=y(x,l[x]);l={search:["?","query"],hash:["#","fragment"]};y=function(a,c){return function(d,b){var e=this[a](d,b);return"string"===typeof e&&e.length?c+e:e}};for(x in l)e[x]=y(l[x][1],l[x][0]);e.pathname=function(a,c){if(void 0===a||!0===a){var d=this._parts.path||(this._parts.hostname?"/":"");return a?b.decodePath(d):d}this._parts.path=
|
48 |
-
a?b.recodePath(a):"/";this.build(!c);return this};e.path=e.pathname;e.href=function(a,c){var d;if(void 0===a)return this.toString();this._string="";this._parts=b._parts();var e=a instanceof b,f="object"===typeof a&&(a.hostname||a.path||a.pathname);a.nodeName&&(f=b.getDomAttribute(a),a=a[f]||"",f=!1);!e&&f&&void 0!==a.pathname&&(a=a.toString());if("string"===typeof a)this._parts=b.parse(a,this._parts);else if(e||f)for(d in e=e?a._parts:a,e)t.call(this._parts,d)&&(this._parts[d]=e[d]);else throw new TypeError("invalid input");
|
49 |
-
this.build(!c);return this};e.is=function(a){var c=!1,d=!1,e=!1,f=!1,h=!1,m=!1,g=!1,n=!this._parts.urn;this._parts.hostname&&(n=!1,d=b.ip4_expression.test(this._parts.hostname),e=b.ip6_expression.test(this._parts.hostname),c=d||e,h=(f=!c)&&s&&s.has(this._parts.hostname),m=f&&b.idn_expression.test(this._parts.hostname),g=f&&b.punycode_expression.test(this._parts.hostname));switch(a.toLowerCase()){case "relative":return n;case "absolute":return!n;case "domain":case "name":return f;case "sld":return h;
|
50 |
-
case "ip":return c;case "ip4":case "ipv4":case "inet4":return d;case "ip6":case "ipv6":case "inet6":return e;case "idn":return m;case "url":return!this._parts.urn;case "urn":return!!this._parts.urn;case "punycode":return g}return null};var E=e.protocol,H=e.port,C=e.hostname;e.protocol=function(a,c){if(void 0!==a&&a&&(a=a.replace(/:(\/\/)?$/,""),!a.match(b.protocol_expression)))throw new TypeError('Protocol "'+a+"\" contains characters other than [A-Z0-9.+-] or doesn't start with [A-Z]");return E.call(this,
|
51 |
-
a,c)};e.scheme=e.protocol;e.port=function(a,c){if(this._parts.urn)return void 0===a?"":this;if(void 0!==a&&(0===a&&(a=null),a&&(a+="",":"===a.charAt(0)&&(a=a.substring(1)),a.match(/[^0-9]/))))throw new TypeError('Port "'+a+'" contains characters other than [0-9]');return H.call(this,a,c)};e.hostname=function(a,c){if(this._parts.urn)return void 0===a?"":this;if(void 0!==a){var d={};b.parseHost(a,d);a=d.hostname}return C.call(this,a,c)};e.host=function(a,c){if(this._parts.urn)return void 0===a?"":this;
|
52 |
-
if(void 0===a)return this._parts.hostname?b.buildHost(this._parts):"";b.parseHost(a,this._parts);this.build(!c);return this};e.authority=function(a,c){if(this._parts.urn)return void 0===a?"":this;if(void 0===a)return this._parts.hostname?b.buildAuthority(this._parts):"";b.parseAuthority(a,this._parts);this.build(!c);return this};e.userinfo=function(a,c){if(this._parts.urn)return void 0===a?"":this;if(void 0===a){if(!this._parts.username)return"";var d=b.buildUserinfo(this._parts);return d.substring(0,
|
53 |
-
d.length-1)}"@"!==a[a.length-1]&&(a+="@");b.parseUserinfo(a,this._parts);this.build(!c);return this};e.resource=function(a,c){var d;if(void 0===a)return this.path()+this.search()+this.hash();d=b.parse(a);this._parts.path=d.path;this._parts.query=d.query;this._parts.fragment=d.fragment;this.build(!c);return this};e.subdomain=function(a,c){if(this._parts.urn)return void 0===a?"":this;if(void 0===a){if(!this._parts.hostname||this.is("IP"))return"";var d=this._parts.hostname.length-this.domain().length-
|
54 |
-
1;return this._parts.hostname.substring(0,d)||""}d=this._parts.hostname.length-this.domain().length;d=this._parts.hostname.substring(0,d);d=new RegExp("^"+u(d));a&&"."!==a.charAt(a.length-1)&&(a+=".");a&&b.ensureValidHostname(a);this._parts.hostname=this._parts.hostname.replace(d,a);this.build(!c);return this};e.domain=function(a,c){if(this._parts.urn)return void 0===a?"":this;"boolean"===typeof a&&(c=a,a=void 0);if(void 0===a){if(!this._parts.hostname||this.is("IP"))return"";var d=this._parts.hostname.match(/\./g);
|
55 |
-
if(d&&2>d.length)return this._parts.hostname;d=this._parts.hostname.length-this.tld(c).length-1;d=this._parts.hostname.lastIndexOf(".",d-1)+1;return this._parts.hostname.substring(d)||""}if(!a)throw new TypeError("cannot set domain empty");b.ensureValidHostname(a);!this._parts.hostname||this.is("IP")?this._parts.hostname=a:(d=new RegExp(u(this.domain())+"$"),this._parts.hostname=this._parts.hostname.replace(d,a));this.build(!c);return this};e.tld=function(a,c){if(this._parts.urn)return void 0===a?
|
56 |
-
"":this;"boolean"===typeof a&&(c=a,a=void 0);if(void 0===a){if(!this._parts.hostname||this.is("IP"))return"";var d=this._parts.hostname.lastIndexOf("."),d=this._parts.hostname.substring(d+1);return!0!==c&&s&&s.list[d.toLowerCase()]?s.get(this._parts.hostname)||d:d}if(a)if(a.match(/[^a-zA-Z0-9-]/))if(s&&s.is(a))d=new RegExp(u(this.tld())+"$"),this._parts.hostname=this._parts.hostname.replace(d,a);else throw new TypeError('TLD "'+a+'" contains characters other than [A-Z0-9]');else{if(!this._parts.hostname||
|
57 |
-
this.is("IP"))throw new ReferenceError("cannot set TLD on non-domain host");d=new RegExp(u(this.tld())+"$");this._parts.hostname=this._parts.hostname.replace(d,a)}else throw new TypeError("cannot set TLD empty");this.build(!c);return this};e.directory=function(a,c){if(this._parts.urn)return void 0===a?"":this;if(void 0===a||!0===a){if(!this._parts.path&&!this._parts.hostname)return"";if("/"===this._parts.path)return"/";var d=this._parts.path.length-this.filename().length-1,d=this._parts.path.substring(0,
|
58 |
-
d)||(this._parts.hostname?"/":"");return a?b.decodePath(d):d}d=this._parts.path.length-this.filename().length;d=this._parts.path.substring(0,d);d=new RegExp("^"+u(d));this.is("relative")||(a||(a="/"),"/"!==a.charAt(0)&&(a="/"+a));a&&"/"!==a.charAt(a.length-1)&&(a+="/");a=b.recodePath(a);this._parts.path=this._parts.path.replace(d,a);this.build(!c);return this};e.filename=function(a,c){if(this._parts.urn)return void 0===a?"":this;if(void 0===a||!0===a){if(!this._parts.path||"/"===this._parts.path)return"";
|
59 |
-
var d=this._parts.path.lastIndexOf("/"),d=this._parts.path.substring(d+1);return a?b.decodePathSegment(d):d}d=!1;"/"===a.charAt(0)&&(a=a.substring(1));a.match(/\.?\//)&&(d=!0);var e=new RegExp(u(this.filename())+"$");a=b.recodePath(a);this._parts.path=this._parts.path.replace(e,a);d?this.normalizePath(c):this.build(!c);return this};e.suffix=function(a,c){if(this._parts.urn)return void 0===a?"":this;if(void 0===a||!0===a){if(!this._parts.path||"/"===this._parts.path)return"";var d=this.filename(),
|
60 |
-
e=d.lastIndexOf(".");if(-1===e)return"";d=d.substring(e+1);d=/^[a-z0-9%]+$/i.test(d)?d:"";return a?b.decodePathSegment(d):d}"."===a.charAt(0)&&(a=a.substring(1));if(d=this.suffix())e=a?new RegExp(u(d)+"$"):new RegExp(u("."+d)+"$");else{if(!a)return this;this._parts.path+="."+b.recodePath(a)}e&&(a=b.recodePath(a),this._parts.path=this._parts.path.replace(e,a));this.build(!c);return this};e.segment=function(a,c,d){var b=this._parts.urn?":":"/",e=this.path(),f="/"===e.substring(0,1),e=e.split(b);void 0!==
|
61 |
-
a&&"number"!==typeof a&&(d=c,c=a,a=void 0);if(void 0!==a&&"number"!==typeof a)throw Error('Bad segment "'+a+'", must be 0-based integer');f&&e.shift();0>a&&(a=Math.max(e.length+a,0));if(void 0===c)return void 0===a?e:e[a];if(null===a||void 0===e[a])if(q(c)){e=[];a=0;for(var h=c.length;a<h;a++)if(c[a].length||e.length&&e[e.length-1].length)e.length&&!e[e.length-1].length&&e.pop(),e.push(c[a])}else{if(c||"string"===typeof c)""===e[e.length-1]?e[e.length-1]=c:e.push(c)}else c||"string"===typeof c&&c.length?
|
62 |
-
e[a]=c:e.splice(a,1);f&&e.unshift("");return this.path(e.join(b),d)};e.segmentCoded=function(a,c,d){var e,f;"number"!==typeof a&&(d=c,c=a,a=void 0);if(void 0===c){a=this.segment(a,c,d);if(q(a))for(e=0,f=a.length;e<f;e++)a[e]=b.decode(a[e]);else a=void 0!==a?b.decode(a):void 0;return a}if(q(c))for(e=0,f=c.length;e<f;e++)c[e]=b.decode(c[e]);else c="string"===typeof c?b.encode(c):c;return this.segment(a,c,d)};var F=e.query;e.query=function(a,c){if(!0===a)return b.parseQuery(this._parts.query,this._parts.escapeQuerySpace);
|
63 |
-
if("function"===typeof a){var d=b.parseQuery(this._parts.query,this._parts.escapeQuerySpace),e=a.call(this,d);this._parts.query=b.buildQuery(e||d,this._parts.duplicateQueryParameters,this._parts.escapeQuerySpace);this.build(!c);return this}return void 0!==a&&"string"!==typeof a?(this._parts.query=b.buildQuery(a,this._parts.duplicateQueryParameters,this._parts.escapeQuerySpace),this.build(!c),this):F.call(this,a,c)};e.setQuery=function(a,c,d){var e=b.parseQuery(this._parts.query,this._parts.escapeQuerySpace);
|
64 |
-
if("object"===typeof a)for(var f in a)t.call(a,f)&&(e[f]=a[f]);else if("string"===typeof a)e[a]=void 0!==c?c:null;else throw new TypeError("URI.addQuery() accepts an object, string as the name parameter");this._parts.query=b.buildQuery(e,this._parts.duplicateQueryParameters,this._parts.escapeQuerySpace);"string"!==typeof a&&(d=c);this.build(!d);return this};e.addQuery=function(a,c,d){var e=b.parseQuery(this._parts.query,this._parts.escapeQuerySpace);b.addQuery(e,a,void 0===c?null:c);this._parts.query=
|
65 |
-
b.buildQuery(e,this._parts.duplicateQueryParameters,this._parts.escapeQuerySpace);"string"!==typeof a&&(d=c);this.build(!d);return this};e.removeQuery=function(a,c,d){var e=b.parseQuery(this._parts.query,this._parts.escapeQuerySpace);b.removeQuery(e,a,c);this._parts.query=b.buildQuery(e,this._parts.duplicateQueryParameters,this._parts.escapeQuerySpace);"string"!==typeof a&&(d=c);this.build(!d);return this};e.hasQuery=function(a,c,d){var e=b.parseQuery(this._parts.query,this._parts.escapeQuerySpace);
|
66 |
-
return b.hasQuery(e,a,c,d)};e.setSearch=e.setQuery;e.addSearch=e.addQuery;e.removeSearch=e.removeQuery;e.hasSearch=e.hasQuery;e.normalize=function(){return this._parts.urn?this.normalizeProtocol(!1).normalizeQuery(!1).normalizeFragment(!1).build():this.normalizeProtocol(!1).normalizeHostname(!1).normalizePort(!1).normalizePath(!1).normalizeQuery(!1).normalizeFragment(!1).build()};e.normalizeProtocol=function(a){"string"===typeof this._parts.protocol&&(this._parts.protocol=this._parts.protocol.toLowerCase(),
|
67 |
-
this.build(!a));return this};e.normalizeHostname=function(a){this._parts.hostname&&(this.is("IDN")&&f?this._parts.hostname=f.toASCII(this._parts.hostname):this.is("IPv6")&&g&&(this._parts.hostname=g.best(this._parts.hostname)),this._parts.hostname=this._parts.hostname.toLowerCase(),this.build(!a));return this};e.normalizePort=function(a){"string"===typeof this._parts.protocol&&this._parts.port===b.defaultPorts[this._parts.protocol]&&(this._parts.port=null,this.build(!a));return this};e.normalizePath=
|
68 |
-
function(a){if(this._parts.urn||!this._parts.path||"/"===this._parts.path)return this;var c,d=this._parts.path,e="",f,h;"/"!==d.charAt(0)&&(c=!0,d="/"+d);d=d.replace(/(\/(\.\/)+)|(\/\.$)/g,"/").replace(/\/{2,}/g,"/");c&&(e=d.substring(1).match(/^(\.\.\/)+/)||"")&&(e=e[0]);for(;;){f=d.indexOf("/..");if(-1===f)break;else if(0===f){d=d.substring(3);continue}h=d.substring(0,f).lastIndexOf("/");-1===h&&(h=f);d=d.substring(0,h)+d.substring(f+3)}c&&this.is("relative")&&(d=e+d.substring(1));d=b.recodePath(d);
|
69 |
-
this._parts.path=d;this.build(!a);return this};e.normalizePathname=e.normalizePath;e.normalizeQuery=function(a){"string"===typeof this._parts.query&&(this._parts.query.length?this.query(b.parseQuery(this._parts.query,this._parts.escapeQuerySpace)):this._parts.query=null,this.build(!a));return this};e.normalizeFragment=function(a){this._parts.fragment||(this._parts.fragment=null,this.build(!a));return this};e.normalizeSearch=e.normalizeQuery;e.normalizeHash=e.normalizeFragment;e.iso8859=function(){var a=
|
70 |
-
b.encode,c=b.decode;b.encode=escape;b.decode=decodeURIComponent;this.normalize();b.encode=a;b.decode=c;return this};e.unicode=function(){var a=b.encode,c=b.decode;b.encode=m;b.decode=unescape;this.normalize();b.encode=a;b.decode=c;return this};e.readable=function(){var a=this.clone();a.username("").password("").normalize();var c="";a._parts.protocol&&(c+=a._parts.protocol+"://");a._parts.hostname&&(a.is("punycode")&&f?(c+=f.toUnicode(a._parts.hostname),a._parts.port&&(c+=":"+a._parts.port)):c+=a.host());
|
71 |
-
a._parts.hostname&&a._parts.path&&"/"!==a._parts.path.charAt(0)&&(c+="/");c+=a.path(!0);if(a._parts.query){for(var d="",e=0,h=a._parts.query.split("&"),m=h.length;e<m;e++){var g=(h[e]||"").split("="),d=d+("&"+b.decodeQuery(g[0],this._parts.escapeQuerySpace).replace(/&/g,"%26"));void 0!==g[1]&&(d+="="+b.decodeQuery(g[1],this._parts.escapeQuerySpace).replace(/&/g,"%26"))}c+="?"+d.substring(1)}return c+=b.decodeQuery(a.hash(),!0)};e.absoluteTo=function(a){var c=this.clone(),d=["protocol","username",
|
72 |
-
"password","hostname","port"],e,f;if(this._parts.urn)throw Error("URNs do not have any generally defined hierarchical components");a instanceof b||(a=new b(a));c._parts.protocol||(c._parts.protocol=a._parts.protocol);if(this._parts.hostname)return c;for(e=0;f=d[e];e++)c._parts[f]=a._parts[f];c._parts.path?".."===c._parts.path.substring(-2)&&(c._parts.path+="/"):(c._parts.path=a._parts.path,c._parts.query||(c._parts.query=a._parts.query));"/"!==c.path().charAt(0)&&(a=a.directory(),c._parts.path=(a?
|
73 |
-
a+"/":"")+c._parts.path,c.normalizePath());c.build();return c};e.relativeTo=function(a){var c=this.clone().normalize(),d,e,f,h;if(c._parts.urn)throw Error("URNs do not have any generally defined hierarchical components");a=(new b(a)).normalize();d=c._parts;e=a._parts;f=c.path();h=a.path();if("/"!==f.charAt(0))throw Error("URI is already relative");if("/"!==h.charAt(0))throw Error("Cannot calculate a URI relative to another relative URI");d.protocol===e.protocol&&(d.protocol=null);if(d.username===
|
74 |
-
e.username&&d.password===e.password&&null===d.protocol&&null===d.username&&null===d.password&&d.hostname===e.hostname&&d.port===e.port)d.hostname=null,d.port=null;else return c.build();if(f===h)return d.path="",c.build();a=b.commonPath(c.path(),a.path());if(!a)return c.build();e=e.path.substring(a.length).replace(/[^\/]*$/,"").replace(/.*?\//g,"../");d.path=e+d.path.substring(a.length);return c.build()};e.equals=function(a){var c=this.clone();a=new b(a);var d={},e={},f={},h;c.normalize();a.normalize();
|
75 |
-
if(c.toString()===a.toString())return!0;d=c.query();e=a.query();c.query("");a.query("");if(c.toString()!==a.toString()||d.length!==e.length)return!1;d=b.parseQuery(d,this._parts.escapeQuerySpace);e=b.parseQuery(e,this._parts.escapeQuerySpace);for(h in d)if(t.call(d,h)){if(!q(d[h])){if(d[h]!==e[h])return!1}else if(!w(d[h],e[h]))return!1;f[h]=!0}for(h in e)if(t.call(e,h)&&!f[h])return!1;return!0};e.duplicateQueryParameters=function(a){this._parts.duplicateQueryParameters=!!a;return this};e.escapeQuerySpace=
|
76 |
-
function(a){this._parts.escapeQuerySpace=!!a;return this};return b});
|
77 |
-
(function(f,g){"object"===typeof exports?module.exports=g(require("./URI")):"function"===typeof define&&define.amd?define(["./URI"],g):f.URITemplate=g(f.URI,f)})(this,function(f,g){function s(b){if(s._cache[b])return s._cache[b];if(!(this instanceof s))return new s(b);this.expression=b;s._cache[b]=this;return this}function k(b){this.data=b;this.cache={}}var b=g&&g.URITemplate,u=Object.prototype.hasOwnProperty,r=s.prototype,q={"":{prefix:"",separator:",",named:!1,empty_name_separator:!1,encode:"encode"},
|
78 |
-
"+":{prefix:"",separator:",",named:!1,empty_name_separator:!1,encode:"encodeReserved"},"#":{prefix:"#",separator:",",named:!1,empty_name_separator:!1,encode:"encodeReserved"},".":{prefix:".",separator:".",named:!1,empty_name_separator:!1,encode:"encode"},"/":{prefix:"/",separator:"/",named:!1,empty_name_separator:!1,encode:"encode"},";":{prefix:";",separator:";",named:!0,empty_name_separator:!1,encode:"encode"},"?":{prefix:"?",separator:"&",named:!0,empty_name_separator:!0,encode:"encode"},"&":{prefix:"&",
|
79 |
-
separator:"&",named:!0,empty_name_separator:!0,encode:"encode"}};s._cache={};s.EXPRESSION_PATTERN=/\{([^a-zA-Z0-9%_]?)([^\}]+)(\}|$)/g;s.VARIABLE_PATTERN=/^([^*:]+)((\*)|:(\d+))?$/;s.VARIABLE_NAME_PATTERN=/[^a-zA-Z0-9%_]/;s.expand=function(b,f){var g=q[b.operator],m=g.named?"Named":"Unnamed",n=b.variables,e=[],t,l,k;for(k=0;l=n[k];k++)t=f.get(l.name),t.val.length?e.push(s["expand"+m](t,g,l.explode,l.explode&&g.separator||",",l.maxlength,l.name)):t.type&&e.push("");return e.length?g.prefix+e.join(g.separator):
|
80 |
-
""};s.expandNamed=function(b,g,k,m,n,e){var t="",l=g.encode;g=g.empty_name_separator;var s=!b[l].length,q=2===b.type?"":f[l](e),r,u,C;u=0;for(C=b.val.length;u<C;u++)n?(r=f[l](b.val[u][1].substring(0,n)),2===b.type&&(q=f[l](b.val[u][0].substring(0,n)))):s?(r=f[l](b.val[u][1]),2===b.type?(q=f[l](b.val[u][0]),b[l].push([q,r])):b[l].push([void 0,r])):(r=b[l][u][1],2===b.type&&(q=b[l][u][0])),t&&(t+=m),k?t+=q+(g||r?"=":"")+r:(u||(t+=f[l](e)+(g||r?"=":"")),2===b.type&&(t+=q+","),t+=r);return t};s.expandUnnamed=
|
81 |
-
function(b,g,k,m,n){var e="",t=g.encode;g=g.empty_name_separator;var l=!b[t].length,s,q,r,u;r=0;for(u=b.val.length;r<u;r++)n?q=f[t](b.val[r][1].substring(0,n)):l?(q=f[t](b.val[r][1]),b[t].push([2===b.type?f[t](b.val[r][0]):void 0,q])):q=b[t][r][1],e&&(e+=m),2===b.type&&(s=n?f[t](b.val[r][0].substring(0,n)):b[t][r][0],e+=s,e=k?e+(g||q?"=":""):e+","),e+=q;return e};s.noConflict=function(){g.URITemplate===s&&(g.URITemplate=b);return s};r.expand=function(b){var f="";this.parts&&this.parts.length||this.parse();
|
82 |
-
b instanceof k||(b=new k(b));for(var g=0,m=this.parts.length;g<m;g++)f+="string"===typeof this.parts[g]?this.parts[g]:s.expand(this.parts[g],b);return f};r.parse=function(){var b=this.expression,f=s.EXPRESSION_PATTERN,g=s.VARIABLE_PATTERN,m=s.VARIABLE_NAME_PATTERN,n=[],e=0,k,l,r;for(f.lastIndex=0;;){l=f.exec(b);if(null===l){n.push(b.substring(e));break}else n.push(b.substring(e,l.index)),e=l.index+l[0].length;if(!q[l[1]])throw Error('Unknown Operator "'+l[1]+'" in "'+l[0]+'"');if(!l[3])throw Error('Unclosed Expression "'+
|
83 |
-
l[0]+'"');k=l[2].split(",");for(var u=0,E=k.length;u<E;u++){r=k[u].match(g);if(null===r)throw Error('Invalid Variable "'+k[u]+'" in "'+l[0]+'"');if(r[1].match(m))throw Error('Invalid Variable Name "'+r[1]+'" in "'+l[0]+'"');k[u]={name:r[1],explode:!!r[3],maxlength:r[4]&&parseInt(r[4],10)}}if(!k.length)throw Error('Expression Missing Variable(s) "'+l[0]+'"');n.push({expression:l[0],operator:l[1],variables:k})}n.length||n.push(b);this.parts=n;return this};k.prototype.get=function(b){var f=this.data,
|
84 |
-
g={type:0,val:[],encode:[],encodeReserved:[]},m;if(void 0!==this.cache[b])return this.cache[b];this.cache[b]=g;f="[object Function]"===String(Object.prototype.toString.call(f))?f(b):"[object Function]"===String(Object.prototype.toString.call(f[b]))?f[b](b):f[b];if(void 0!==f&&null!==f)if("[object Array]"===String(Object.prototype.toString.call(f))){m=0;for(b=f.length;m<b;m++)void 0!==f[m]&&null!==f[m]&&g.val.push([void 0,String(f[m])]);g.val.length&&(g.type=3)}else if("[object Object]"===String(Object.prototype.toString.call(f))){for(m in f)u.call(f,
|
85 |
-
m)&&void 0!==f[m]&&null!==f[m]&&g.val.push([m,String(f[m])]);g.val.length&&(g.type=2)}else g.type=1,g.val.push([void 0,String(f)]);return g};f.expand=function(b,g){var k=(new s(b)).expand(g);return new f(k)};return s});
|
86 |
-
(function(f,g){"object"===typeof exports?module.exports=g(require("jquery","./URI")):"function"===typeof define&&define.amd?define(["jquery","./URI"],g):g(f.jQuery,f.URI)})(this,function(f,g){function s(b){return b.replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")}function k(b){var f=b.nodeName.toLowerCase();return"input"===f&&"image"!==b.type?void 0:g.domAttributes[f]}function b(b){return{get:function(g){return f(g).uri()[b]()},set:function(g,e){f(g).uri()[b](e);return e}}}function u(b,g){var e,h,l;if(!k(b)||
|
87 |
-
!g)return!1;e=g.match(A);if(!e||!e[5]&&":"!==e[2]&&!q[e[2]])return!1;l=f(b).uri();if(e[5])return l.is(e[5]);if(":"===e[2])return h=e[1].toLowerCase()+":",q[h]?q[h](l,e[4]):!1;h=e[1].toLowerCase();return r[h]?q[e[2]](l[h](),e[4],h):!1}var r={},q={"=":function(b,f){return b===f},"^=":function(b,f){return!!(b+"").match(new RegExp("^"+s(f),"i"))},"$=":function(b,f){return!!(b+"").match(new RegExp(s(f)+"$","i"))},"*=":function(b,f,e){"directory"===e&&(b+="/");return!!(b+"").match(new RegExp(s(f),"i"))},
|
88 |
-
"equals:":function(b,f){return b.equals(f)},"is:":function(b,f){return b.is(f)}};f.each("authority directory domain filename fragment hash host hostname href password path pathname port protocol query resource scheme search subdomain suffix tld username".split(" "),function(g,h){r[h]=!0;f.attrHooks["uri:"+h]=b(h)});var h=function(b,g){return f(b).uri().href(g).toString()};f.each(["src","href","action","uri","cite"],function(b,g){f.attrHooks[g]={set:h}});f.attrHooks.uri.get=function(b){return f(b).uri()};
|
89 |
-
f.fn.uri=function(b){var f=this.first(),e=f.get(0),h=k(e);if(!h)throw Error('Element "'+e.nodeName+'" does not have either property: href, src, action, cite');if(void 0!==b){var l=f.data("uri");if(l)return l.href(b);b instanceof g||(b=g(b||""))}else{if(b=f.data("uri"))return b;b=g(f.attr(h)||"")}b._dom_element=e;b._dom_attribute=h;b.normalize();f.data("uri",b);return b};g.prototype.build=function(b){if(this._dom_element)this._string=g.build(this._parts),this._deferred_build=!1,this._dom_element.setAttribute(this._dom_attribute,
|
90 |
-
this._string),this._dom_element[this._dom_attribute]=this._string;else if(!0===b)this._deferred_build=!0;else if(void 0===b||this._deferred_build)this._string=g.build(this._parts),this._deferred_build=!1;return this};var w,A=/^([a-zA-Z]+)\s*([\^\$*]?=|:)\s*(['"]?)(.+)\3|^\s*([a-zA-Z0-9]+)\s*$/;w=f.expr.createPseudo?f.expr.createPseudo(function(b){return function(f){return u(f,b)}}):function(b,f,e){return u(b,e[3])};f.expr[":"].uri=w;return f});
|
91 |
-
(function(f,g){"object"===typeof exports?module.exports=g(require("./URI")):"function"===typeof define&&define.amd?define(["./URI"],g):g(f.URI)})(this,function(f){var g=f.prototype,s=g.fragment;f.fragmentPrefix="?";var k=f._parts;f._parts=function(){var b=k();b.fragmentPrefix=f.fragmentPrefix;return b};g.fragmentPrefix=function(b){this._parts.fragmentPrefix=b;return this};g.fragment=function(b,g){var k=this._parts.fragmentPrefix,q=this._parts.fragment||"";return!0===b?q.substring(0,k.length)!==k?
|
92 |
-
{}:f.parseQuery(q.substring(k.length)):void 0!==b&&"string"!==typeof b?(this._parts.fragment=k+f.buildQuery(b),this.build(!g),this):s.call(this,b,g)};g.addFragment=function(b,g,k){var q=this._parts.fragmentPrefix,h=f.parseQuery((this._parts.fragment||"").substring(q.length));f.addQuery(h,b,g);this._parts.fragment=q+f.buildQuery(h);"string"!==typeof b&&(k=g);this.build(!k);return this};g.removeFragment=function(b,g,k){var q=this._parts.fragmentPrefix,h=f.parseQuery((this._parts.fragment||"").substring(q.length));
|
93 |
-
f.removeQuery(h,b,g);this._parts.fragment=q+f.buildQuery(h);"string"!==typeof b&&(k=g);this.build(!k);return this};g.addHash=g.addFragment;g.removeHash=g.removeFragment;return f});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
core/{class-itsec-lib.php → lib.php}
RENAMED
@@ -260,29 +260,26 @@ final class ITSEC_Lib {
|
|
260 |
/**
|
261 |
* Returns the root of the WordPress install.
|
262 |
*
|
263 |
-
*
|
264 |
*
|
265 |
* @since 4.0.6
|
266 |
*
|
267 |
* @return string the root folder
|
268 |
*/
|
269 |
public static function get_home_root() {
|
|
|
|
|
|
|
270 |
|
271 |
-
|
272 |
-
$home_root = parse_url( site_url() );
|
273 |
-
|
274 |
-
if ( isset( $home_root['path'] ) ) {
|
275 |
-
|
276 |
-
$home_root = trailingslashit( $home_root['path'] );
|
277 |
|
|
|
|
|
278 |
} else {
|
279 |
-
|
280 |
-
$home_root = '/';
|
281 |
-
|
282 |
}
|
283 |
|
284 |
-
return $
|
285 |
-
|
286 |
}
|
287 |
|
288 |
/**
|
@@ -496,13 +493,15 @@ final class ITSEC_Lib {
|
|
496 |
/**
|
497 |
* Determines whether a given IP address is whiteliste
|
498 |
*
|
499 |
-
* @param string $
|
500 |
* @param array $whitelisted_ips ip list to compare to if not yet saved to options
|
501 |
* @param boolean $current whether to whitelist the current ip or not (due to saving, etc)
|
502 |
*
|
503 |
* @return boolean true if whitelisted or false
|
504 |
*/
|
505 |
public static function is_ip_whitelisted( $ip, $whitelisted_ips = null, $current = false ) {
|
|
|
|
|
506 |
global $itsec_lockout;
|
507 |
|
508 |
$ip = sanitize_text_field( $ip );
|
@@ -869,6 +868,14 @@ final class ITSEC_Lib {
|
|
869 |
echo "<div class=\"error inline\"><p><strong>$message</strong></p></div>\n";
|
870 |
}
|
871 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
872 |
public static function get_user( $user = false ) {
|
873 |
if ( $user instanceof WP_User ) {
|
874 |
return $user;
|
@@ -880,6 +887,8 @@ final class ITSEC_Lib {
|
|
880 |
$user = get_user_by( 'id', $user );
|
881 |
} else if ( is_string( $user ) ) {
|
882 |
$user = get_user_by( 'login', $user );
|
|
|
|
|
883 |
} else {
|
884 |
if ( is_object( $user ) ) {
|
885 |
$type = 'object(' . get_class( $user ) . ')';
|
@@ -899,6 +908,14 @@ final class ITSEC_Lib {
|
|
899 |
return false;
|
900 |
}
|
901 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
902 |
public static function get_password_strength_results( $password, $penalty_strings = array() ) {
|
903 |
if ( ! isset( $GLOBALS['itsec_zxcvbn'] ) ) {
|
904 |
require_once( ITSEC_Core::get_core_dir() . '/lib/itsec-zxcvbn-php/zxcvbn.php' );
|
@@ -908,6 +925,13 @@ final class ITSEC_Lib {
|
|
908 |
return $GLOBALS['itsec_zxcvbn']->test_password( $password, $penalty_strings );
|
909 |
}
|
910 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
911 |
public static function get_trace_ip_link( $ip = false ) {
|
912 |
if ( empty( $ip ) ) {
|
913 |
return 'http://www.traceip.net/';
|
@@ -916,6 +940,11 @@ final class ITSEC_Lib {
|
|
916 |
}
|
917 |
}
|
918 |
|
|
|
|
|
|
|
|
|
|
|
919 |
public static function handle_wp_login_failed( $username ) {
|
920 |
$authentication_types = array();
|
921 |
|
@@ -957,4 +986,43 @@ final class ITSEC_Lib {
|
|
957 |
|
958 |
do_action( 'itsec-handle-failed-login', $username, $details );
|
959 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
960 |
}
|
260 |
/**
|
261 |
* Returns the root of the WordPress install.
|
262 |
*
|
263 |
+
* Gets the URI path to the WordPress installation.
|
264 |
*
|
265 |
* @since 4.0.6
|
266 |
*
|
267 |
* @return string the root folder
|
268 |
*/
|
269 |
public static function get_home_root() {
|
270 |
+
if ( isset( $GLOBALS['__itsec_lib_get_home_root'] ) ) {
|
271 |
+
return $GLOBALS['__itsec_lib_get_home_root'];
|
272 |
+
}
|
273 |
|
274 |
+
$url_parts = parse_url( site_url() );
|
|
|
|
|
|
|
|
|
|
|
275 |
|
276 |
+
if ( isset( $url_parts['path'] ) ) {
|
277 |
+
$GLOBALS['__itsec_lib_get_home_root'] = trailingslashit( $url_parts['path'] );
|
278 |
} else {
|
279 |
+
$GLOBALS['__itsec_lib_get_home_root'] = '/';
|
|
|
|
|
280 |
}
|
281 |
|
282 |
+
return $GLOBALS['__itsec_lib_get_home_root'];
|
|
|
283 |
}
|
284 |
|
285 |
/**
|
493 |
/**
|
494 |
* Determines whether a given IP address is whiteliste
|
495 |
*
|
496 |
+
* @param string $ip ip to check (can be in CIDR notation)
|
497 |
* @param array $whitelisted_ips ip list to compare to if not yet saved to options
|
498 |
* @param boolean $current whether to whitelist the current ip or not (due to saving, etc)
|
499 |
*
|
500 |
* @return boolean true if whitelisted or false
|
501 |
*/
|
502 |
public static function is_ip_whitelisted( $ip, $whitelisted_ips = null, $current = false ) {
|
503 |
+
|
504 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
505 |
global $itsec_lockout;
|
506 |
|
507 |
$ip = sanitize_text_field( $ip );
|
868 |
echo "<div class=\"error inline\"><p><strong>$message</strong></p></div>\n";
|
869 |
}
|
870 |
|
871 |
+
/**
|
872 |
+
* Get a WordPress user object.
|
873 |
+
*
|
874 |
+
* @param int|string|WP_User|bool $user Either the user ID ( must be an int ), the username, a WP_User object,
|
875 |
+
* or false to retrieve the currently logged-in user.
|
876 |
+
*
|
877 |
+
* @return WP_User|false
|
878 |
+
*/
|
879 |
public static function get_user( $user = false ) {
|
880 |
if ( $user instanceof WP_User ) {
|
881 |
return $user;
|
887 |
$user = get_user_by( 'id', $user );
|
888 |
} else if ( is_string( $user ) ) {
|
889 |
$user = get_user_by( 'login', $user );
|
890 |
+
} else if ( is_object( $user ) && isset( $user->ID ) ) {
|
891 |
+
$user = get_user_by( 'id', $user->ID );
|
892 |
} else {
|
893 |
if ( is_object( $user ) ) {
|
894 |
$type = 'object(' . get_class( $user ) . ')';
|
908 |
return false;
|
909 |
}
|
910 |
|
911 |
+
/**
|
912 |
+
* Evaluate a password's strength.
|
913 |
+
*
|
914 |
+
* @param string $password
|
915 |
+
* @param array $penalty_strings Additional strings that if found within the password, will decrease the strength.
|
916 |
+
*
|
917 |
+
* @return ITSEC_Zxcvbn_Results
|
918 |
+
*/
|
919 |
public static function get_password_strength_results( $password, $penalty_strings = array() ) {
|
920 |
if ( ! isset( $GLOBALS['itsec_zxcvbn'] ) ) {
|
921 |
require_once( ITSEC_Core::get_core_dir() . '/lib/itsec-zxcvbn-php/zxcvbn.php' );
|
925 |
return $GLOBALS['itsec_zxcvbn']->test_password( $password, $penalty_strings );
|
926 |
}
|
927 |
|
928 |
+
/**
|
929 |
+
* Retrieve the URL to a website to lookup the location of an IP address.
|
930 |
+
*
|
931 |
+
* @param string|bool $ip IP address to lookup, or false to return a URL to their home page.
|
932 |
+
*
|
933 |
+
* @return string
|
934 |
+
*/
|
935 |
public static function get_trace_ip_link( $ip = false ) {
|
936 |
if ( empty( $ip ) ) {
|
937 |
return 'http://www.traceip.net/';
|
940 |
}
|
941 |
}
|
942 |
|
943 |
+
/**
|
944 |
+
* Whenever a login fails, collect details of the attempt, and forward them to modules.
|
945 |
+
*
|
946 |
+
* @param string $username
|
947 |
+
*/
|
948 |
public static function handle_wp_login_failed( $username ) {
|
949 |
$authentication_types = array();
|
950 |
|
986 |
|
987 |
do_action( 'itsec-handle-failed-login', $username, $details );
|
988 |
}
|
989 |
+
|
990 |
+
/**
|
991 |
+
* Reliably provides the URL path.
|
992 |
+
*
|
993 |
+
* It optionally takes a prefix that will be stripped from the path, if present. This is useful for use to get site
|
994 |
+
* URL paths without the site's subdirectory.
|
995 |
+
*
|
996 |
+
* Trailing slashes are not preserved.
|
997 |
+
*
|
998 |
+
* @param string $url The URL to pull the path from.
|
999 |
+
* @param string $prefix [optional] A string prefix to be removed from the path.
|
1000 |
+
*
|
1001 |
+
* @return string The URL path.
|
1002 |
+
*/
|
1003 |
+
public static function get_url_path( $url, $prefix = '' ) {
|
1004 |
+
$path = (string) parse_url( $url, PHP_URL_PATH );
|
1005 |
+
$path = untrailingslashit( $path );
|
1006 |
+
|
1007 |
+
if ( ! empty( $prefix ) && 0 === strpos( $path, $prefix ) ) {
|
1008 |
+
return substr( $path, strlen( $prefix ) );
|
1009 |
+
}
|
1010 |
+
|
1011 |
+
return '';
|
1012 |
+
}
|
1013 |
+
|
1014 |
+
/**
|
1015 |
+
* Returns the current request path without the protocol, domain, site subdirectories, or query args.
|
1016 |
+
*
|
1017 |
+
* This function returns "wp-login.php" when requesting http://example.com/site-path/wp-login.php?action=register.
|
1018 |
+
*
|
1019 |
+
* @return string The requested site path.
|
1020 |
+
*/
|
1021 |
+
public static function get_request_path() {
|
1022 |
+
if ( ! isset( $GLOBALS['__itsec_lib_get_request_path'] ) ) {
|
1023 |
+
$GLOBALS['__itsec_lib_get_request_path'] = self::get_url_path( $_SERVER['REQUEST_URI'], self::get_home_root() );
|
1024 |
+
}
|
1025 |
+
|
1026 |
+
return $GLOBALS['__itsec_lib_get_request_path'];
|
1027 |
+
}
|
1028 |
}
|
core/lib/class-itsec-lib-canonical-roles.php
CHANGED
@@ -1,6 +1,15 @@
|
|
1 |
<?php
|
2 |
|
3 |
final class ITSEC_Lib_Canonical_Roles {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
public static function is_canonical_role_at_least( $min_role, $role ) {
|
5 |
$roles = array(
|
6 |
'super-admin' => 6,
|
@@ -23,6 +32,14 @@ final class ITSEC_Lib_Canonical_Roles {
|
|
23 |
return false;
|
24 |
}
|
25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
public static function is_user_at_least( $role, $user = false ) {
|
27 |
$roles = array(
|
28 |
'super-admin' => 6,
|
@@ -47,6 +64,15 @@ final class ITSEC_Lib_Canonical_Roles {
|
|
47 |
return false;
|
48 |
}
|
49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
public static function get_role_from_caps( $caps ) {
|
51 |
if ( is_string( $caps ) ) {
|
52 |
$caps = array( $caps );
|
@@ -65,6 +91,13 @@ final class ITSEC_Lib_Canonical_Roles {
|
|
65 |
return '';
|
66 |
}
|
67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
public static function get_user_role( $user = false ) {
|
69 |
$user = ITSEC_Lib::get_user( $user );
|
70 |
|
@@ -89,6 +122,11 @@ final class ITSEC_Lib_Canonical_Roles {
|
|
89 |
return '';
|
90 |
}
|
91 |
|
|
|
|
|
|
|
|
|
|
|
92 |
public static function get_unique_capabilities() {
|
93 |
return array(
|
94 |
'administrator' => array(
|
@@ -165,6 +203,11 @@ final class ITSEC_Lib_Canonical_Roles {
|
|
165 |
);
|
166 |
}
|
167 |
|
|
|
|
|
|
|
|
|
|
|
168 |
public static function get_capabilities() {
|
169 |
return array(
|
170 |
'administrator' => array(
|
1 |
<?php
|
2 |
|
3 |
final class ITSEC_Lib_Canonical_Roles {
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Check if a given role is at least as or equally as powerful as a given role.
|
7 |
+
*
|
8 |
+
* @param string $min_role
|
9 |
+
* @param string $role
|
10 |
+
*
|
11 |
+
* @return bool
|
12 |
+
*/
|
13 |
public static function is_canonical_role_at_least( $min_role, $role ) {
|
14 |
$roles = array(
|
15 |
'super-admin' => 6,
|
32 |
return false;
|
33 |
}
|
34 |
|
35 |
+
/**
|
36 |
+
* Check if a user's role is at least as or equally as powerful as a given role.
|
37 |
+
*
|
38 |
+
* @param string $role
|
39 |
+
* @param int|string|WP_User|false $user
|
40 |
+
*
|
41 |
+
* @return bool
|
42 |
+
*/
|
43 |
public static function is_user_at_least( $role, $user = false ) {
|
44 |
$roles = array(
|
45 |
'super-admin' => 6,
|
64 |
return false;
|
65 |
}
|
66 |
|
67 |
+
/**
|
68 |
+
* Retrieve the default WordPress role that would be associated with the given capabilities list.
|
69 |
+
*
|
70 |
+
* This checks the caps list for containing at least one of the unique capabilities from each default role.
|
71 |
+
*
|
72 |
+
* @param string[] $caps
|
73 |
+
*
|
74 |
+
* @return int|string
|
75 |
+
*/
|
76 |
public static function get_role_from_caps( $caps ) {
|
77 |
if ( is_string( $caps ) ) {
|
78 |
$caps = array( $caps );
|
91 |
return '';
|
92 |
}
|
93 |
|
94 |
+
/**
|
95 |
+
* Retrieve a user's equivalent default WordPress role from their capabilities.
|
96 |
+
*
|
97 |
+
* @param bool $user
|
98 |
+
*
|
99 |
+
* @return int|string
|
100 |
+
*/
|
101 |
public static function get_user_role( $user = false ) {
|
102 |
$user = ITSEC_Lib::get_user( $user );
|
103 |
|
122 |
return '';
|
123 |
}
|
124 |
|
125 |
+
/**
|
126 |
+
* Get a list of all of the capabilities that are unique to each role.
|
127 |
+
*
|
128 |
+
* @return array
|
129 |
+
*/
|
130 |
public static function get_unique_capabilities() {
|
131 |
return array(
|
132 |
'administrator' => array(
|
203 |
);
|
204 |
}
|
205 |
|
206 |
+
/**
|
207 |
+
* Get a list of all of the capabilities each default WordPress role has.
|
208 |
+
*
|
209 |
+
* @return array
|
210 |
+
*/
|
211 |
public static function get_capabilities() {
|
212 |
return array(
|
213 |
'administrator' => array(
|
core/lib/class-itsec-lib-password-requirements.php
ADDED
@@ -0,0 +1,532 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Tool to manage password requirements across modules.
|
4 |
+
*
|
5 |
+
* @since 3.9.0
|
6 |
+
* @license GPLv2+
|
7 |
+
*/
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Class ITSEC_Lib_Password_Requirements
|
11 |
+
*/
|
12 |
+
class ITSEC_Lib_Password_Requirements {
|
13 |
+
|
14 |
+
const LOGIN_ACTION = 'itsec_update_password';
|
15 |
+
const META_KEY = '_itsec_update_password_key';
|
16 |
+
|
17 |
+
/** @var string */
|
18 |
+
private $error_message = '';
|
19 |
+
|
20 |
+
public function run() {
|
21 |
+
|
22 |
+
add_action( 'user_profile_update_errors', array( $this, 'forward_profile_pass_update' ), 0, 3 );
|
23 |
+
add_action( 'validate_password_reset', array( $this, 'forward_reset_pass' ), 10, 2 );
|
24 |
+
add_action( 'profile_update', array( $this, 'set_password_last_updated' ), 10, 2 );
|
25 |
+
|
26 |
+
add_action( 'wp_login', array( $this, 'wp_login' ), 12, 2 );
|
27 |
+
add_filter( 'wp_login_errors', array( $this, 'token_expired_message' ) );
|
28 |
+
add_action( 'login_form_' . self::LOGIN_ACTION, array( $this, 'handle_update_password_form' ), 9 );
|
29 |
+
add_action( 'login_form_' . self::LOGIN_ACTION, array( $this, 'display_update_password_form' ) );
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* When a user's password is updated, or a new user created, verify that the new password is valid.
|
34 |
+
*
|
35 |
+
* @param WP_Error $errors
|
36 |
+
* @param bool $update
|
37 |
+
* @param WP_User|stdClass $user
|
38 |
+
*/
|
39 |
+
public function forward_profile_pass_update( $errors, $update, $user ) {
|
40 |
+
|
41 |
+
if ( ! isset( $user->user_pass ) ) {
|
42 |
+
return;
|
43 |
+
}
|
44 |
+
|
45 |
+
if ( ! $update ) {
|
46 |
+
$context = 'admin-user-create';
|
47 |
+
} elseif ( isset( $user->ID ) && $user->ID === get_current_user_id() ) {
|
48 |
+
$context = 'profile-update';
|
49 |
+
} else {
|
50 |
+
$context = 'admin-profile-update';
|
51 |
+
}
|
52 |
+
|
53 |
+
$args = array(
|
54 |
+
'error' => $errors,
|
55 |
+
'context' => $context
|
56 |
+
);
|
57 |
+
|
58 |
+
if ( isset( $user->role ) ) {
|
59 |
+
$args['role'] = $user->role;
|
60 |
+
}
|
61 |
+
|
62 |
+
self::validate_password( $user, $user->user_pass, $args );
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* When a user attempts to reset their password, verify that the new password is valid.
|
67 |
+
*
|
68 |
+
* @param WP_Error $errors
|
69 |
+
* @param WP_User $user
|
70 |
+
*/
|
71 |
+
public function forward_reset_pass( $errors, $user ) {
|
72 |
+
|
73 |
+
if ( ! isset( $_POST['pass1'] ) ) {
|
74 |
+
// The validate_password_reset action fires when first rendering the reset page and when handling the form
|
75 |
+
// submissions. Since the pass1 data is missing, this must be the initial page render. So, we don't need to
|
76 |
+
// do anything yet.
|
77 |
+
return;
|
78 |
+
}
|
79 |
+
|
80 |
+
self::validate_password( $user, $user->user_pass, array(
|
81 |
+
'error' => $errors,
|
82 |
+
'context' => 'reset-password',
|
83 |
+
) );
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Whenever a user object is updated, set when their password was last updated.
|
88 |
+
*
|
89 |
+
* @param int $user_id
|
90 |
+
* @param object $old_user_data
|
91 |
+
*/
|
92 |
+
public function set_password_last_updated( $user_id, $old_user_data ) {
|
93 |
+
|
94 |
+
$user = get_userdata( $user_id );
|
95 |
+
|
96 |
+
if ( $user->user_pass === $old_user_data->user_pass ) {
|
97 |
+
return;
|
98 |
+
}
|
99 |
+
|
100 |
+
delete_user_meta( $user_id, 'itsec_password_change_required' );
|
101 |
+
update_user_meta( $user_id, 'itsec_last_password_change', ITSEC_Core::get_current_time_gmt() );
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Whenever a user logs in, check if their password needs to be changed. If so, mark that the user must change
|
106 |
+
* their password.
|
107 |
+
*
|
108 |
+
* @since 1.8
|
109 |
+
*
|
110 |
+
* @param string $username the username attempted
|
111 |
+
* @param WP_User $user wp_user the user
|
112 |
+
*
|
113 |
+
* @return void
|
114 |
+
*/
|
115 |
+
public function wp_login( $username, $user = null ) {
|
116 |
+
|
117 |
+
//Get a valid user or terminate the hook (all we care about is forcing the password change... Let brute force protection handle the rest
|
118 |
+
if ( null !== $user ) {
|
119 |
+
$current_user = $user;
|
120 |
+
} elseif ( is_user_logged_in() ) {
|
121 |
+
$current_user = wp_get_current_user();
|
122 |
+
} else {
|
123 |
+
return;
|
124 |
+
}
|
125 |
+
|
126 |
+
if ( ! self::password_change_required( $current_user ) ) {
|
127 |
+
return;
|
128 |
+
}
|
129 |
+
|
130 |
+
$token = $this->set_update_password_key( $current_user );
|
131 |
+
$this->destroy_session( $current_user );
|
132 |
+
|
133 |
+
$this->login_html( $current_user, $token );
|
134 |
+
exit;
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Add a message that the update password token has expired and they must login again.
|
139 |
+
*
|
140 |
+
* @param WP_Error $errors
|
141 |
+
*
|
142 |
+
* @return WP_Error
|
143 |
+
*/
|
144 |
+
public function token_expired_message( $errors ) {
|
145 |
+
|
146 |
+
if ( ! empty( $_GET['itsec_update_pass_expired'] ) ) {
|
147 |
+
$errors->add(
|
148 |
+
'itsec_update_pass_expired',
|
149 |
+
esc_html__( 'Sorry, the update password request has expired. Please log in again.', 'better-wp-security' )
|
150 |
+
);
|
151 |
+
}
|
152 |
+
|
153 |
+
return $errors;
|
154 |
+
}
|
155 |
+
|
156 |
+
/**
|
157 |
+
* Handle the request to update the user's password.
|
158 |
+
*/
|
159 |
+
public function handle_update_password_form() {
|
160 |
+
|
161 |
+
if ( empty( $_POST['itsec_update_password'] ) || empty( $_POST['itsec_update_password_user'] ) || empty( $_POST['pass1'] ) ) {
|
162 |
+
return;
|
163 |
+
}
|
164 |
+
|
165 |
+
$user = get_userdata( $_POST['itsec_update_password_user'] );
|
166 |
+
|
167 |
+
if ( ! $user || empty( $_POST['itsec_update_password_token'] ) || ! $this->verify_update_password_key( $user, $_POST['itsec_update_password_token'] ) ) {
|
168 |
+
|
169 |
+
$url = add_query_arg( 'itsec_update_pass_expired', 1, wp_login_url() );
|
170 |
+
wp_safe_redirect( set_url_scheme( $url, 'login_post' ) );
|
171 |
+
die();
|
172 |
+
}
|
173 |
+
|
174 |
+
$error = self::validate_password( $user, $_POST['pass1'] );
|
175 |
+
|
176 |
+
if ( $error->get_error_message() ) {
|
177 |
+
$this->error_message = $error->get_error_message();
|
178 |
+
|
179 |
+
return;
|
180 |
+
}
|
181 |
+
|
182 |
+
$user->user_pass = $_POST['pass1'];
|
183 |
+
$error = wp_update_user( $user );
|
184 |
+
|
185 |
+
if ( is_wp_error( $error ) ) {
|
186 |
+
$this->error_message = $error->get_error_message();
|
187 |
+
|
188 |
+
return;
|
189 |
+
}
|
190 |
+
|
191 |
+
$this->delete_update_password_key( $user );
|
192 |
+
wp_set_auth_cookie( $user->ID, ! empty( $_REQUEST['rememberme'] ) );
|
193 |
+
|
194 |
+
if ( ! empty( $_REQUEST['redirect_to'] ) ) {
|
195 |
+
$redirect_to = apply_filters( 'login_redirect', $_REQUEST['redirect_to'], $_REQUEST['redirect_to'], $user );
|
196 |
+
wp_safe_redirect( $redirect_to );
|
197 |
+
} else {
|
198 |
+
wp_safe_redirect( admin_url( 'index.php' ) );
|
199 |
+
}
|
200 |
+
|
201 |
+
exit;
|
202 |
+
}
|
203 |
+
|
204 |
+
/**
|
205 |
+
* When the login page is loaded with the 'itsec_update_password' action, maybe display the update password form,
|
206 |
+
* or redirect to a standard login page.
|
207 |
+
*/
|
208 |
+
public function display_update_password_form() {
|
209 |
+
|
210 |
+
$user = null;
|
211 |
+
$token = '';
|
212 |
+
|
213 |
+
if ( is_user_logged_in() ) {
|
214 |
+
$user = wp_get_current_user();
|
215 |
+
$token = $this->set_update_password_key( $user );
|
216 |
+
$this->destroy_session( $user );
|
217 |
+
} elseif ( ! empty( $_POST['itsec_update_password_user'] ) ) {
|
218 |
+
$user = get_userdata( $_POST['itsec_update_password_user'] );
|
219 |
+
$token = empty( $_POST['itsec_update_password_token'] ) ? '' : $_POST['itsec_update_password_token'];
|
220 |
+
}
|
221 |
+
|
222 |
+
if ( ! $user ) {
|
223 |
+
wp_safe_redirect( set_url_scheme( wp_login_url(), 'login_post' ) );
|
224 |
+
die();
|
225 |
+
}
|
226 |
+
|
227 |
+
if ( ! self::password_change_required( $user ) ) {
|
228 |
+
wp_safe_redirect( set_url_scheme( wp_login_url(), 'login_post' ) );
|
229 |
+
die();
|
230 |
+
}
|
231 |
+
|
232 |
+
$this->login_html( $user, $token );
|
233 |
+
exit;
|
234 |
+
}
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Destroy the session for a user.
|
238 |
+
*
|
239 |
+
* @param WP_User $user
|
240 |
+
*/
|
241 |
+
private function destroy_session( $user ) {
|
242 |
+
WP_Session_Tokens::get_instance( $user->ID )->destroy_all();
|
243 |
+
wp_clear_auth_cookie();
|
244 |
+
}
|
245 |
+
|
246 |
+
/**
|
247 |
+
* Verify that the update password key is valid.
|
248 |
+
*
|
249 |
+
* @param WP_User $user
|
250 |
+
* @param string $key
|
251 |
+
*
|
252 |
+
* @return bool
|
253 |
+
*/
|
254 |
+
private function verify_update_password_key( $user, $key ) {
|
255 |
+
$expected = get_user_meta( $user->ID, self::META_KEY, true );
|
256 |
+
|
257 |
+
if ( ! $expected || ! is_array( $expected ) ) {
|
258 |
+
return false;
|
259 |
+
}
|
260 |
+
|
261 |
+
if ( empty( $expected['expires'] ) || $expected['expires'] < ITSEC_Core::get_current_time_gmt() ) {
|
262 |
+
return false;
|
263 |
+
}
|
264 |
+
|
265 |
+
return hash_equals( $expected['key'], $key );
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* Set the update password key for a user.
|
270 |
+
*
|
271 |
+
* @param WP_User $user
|
272 |
+
*
|
273 |
+
* @return string
|
274 |
+
*/
|
275 |
+
private function set_update_password_key( $user ) {
|
276 |
+
$key = $this->generate_update_password_key();
|
277 |
+
|
278 |
+
update_user_meta( $user->ID, self::META_KEY, array(
|
279 |
+
'key' => $key,
|
280 |
+
'expires' => ITSEC_Core::get_current_time_gmt() + HOUR_IN_SECONDS
|
281 |
+
) );
|
282 |
+
|
283 |
+
return $key;
|
284 |
+
}
|
285 |
+
|
286 |
+
/**
|
287 |
+
* Generate a token to be used to verify intent of updating password.
|
288 |
+
*
|
289 |
+
* We can't use nonces here because the WordPress Session Tokens won't be initialized yet.
|
290 |
+
*
|
291 |
+
* @return string
|
292 |
+
*/
|
293 |
+
private function generate_update_password_key() {
|
294 |
+
return wp_generate_password( 32, true, false );
|
295 |
+
}
|
296 |
+
|
297 |
+
/**
|
298 |
+
* Delete the update password key for a user.
|
299 |
+
*
|
300 |
+
* @param WP_User $user
|
301 |
+
*/
|
302 |
+
private function delete_update_password_key( $user ) {
|
303 |
+
delete_user_meta( $user->ID, self::META_KEY );
|
304 |
+
}
|
305 |
+
|
306 |
+
/**
|
307 |
+
* Display an interstitial form during the login process to force a user to update their password.
|
308 |
+
*
|
309 |
+
* @param WP_User $user
|
310 |
+
* @param string $token
|
311 |
+
*/
|
312 |
+
protected function login_html( $user, $token ) {
|
313 |
+
|
314 |
+
$wp_login_url = set_url_scheme( wp_login_url(), 'login_post' );
|
315 |
+
$wp_login_url = add_query_arg( 'action', self::LOGIN_ACTION, $wp_login_url );
|
316 |
+
|
317 |
+
if ( isset( $_GET['wpe-login'] ) && ! preg_match( '/[&?]wpe-login=/', $wp_login_url ) ) {
|
318 |
+
$wp_login_url = add_query_arg( 'wpe-login', $_GET['wpe-login'], $wp_login_url );
|
319 |
+
}
|
320 |
+
|
321 |
+
$interim_login = isset( $_REQUEST['interim-login'] );
|
322 |
+
$redirect_to = '';
|
323 |
+
|
324 |
+
$rememberme = ! empty( $_REQUEST['rememberme'] );
|
325 |
+
|
326 |
+
wp_enqueue_script( 'user-profile' );
|
327 |
+
|
328 |
+
// Prevent JetPack from attempting to SSO the update password form.
|
329 |
+
add_filter( 'jetpack_sso_allowed_actions', '__return_empty_array' );
|
330 |
+
|
331 |
+
if ( ! function_exists( 'login_header' ) ) {
|
332 |
+
require_once( dirname( __FILE__ ) . '/includes/function.login-header.php' );
|
333 |
+
}
|
334 |
+
|
335 |
+
login_header();
|
336 |
+
|
337 |
+
$type = self::password_change_required( $user );
|
338 |
+
// Modules are responsible for providing escaped reason messages
|
339 |
+
$reason = $this->get_message_for_password_change_reason( $type );
|
340 |
+
?>
|
341 |
+
|
342 |
+
<?php if ( $this->error_message ) : ?>
|
343 |
+
<div id="login-error" class="message" style="border-left-color: #dc3232;">
|
344 |
+
<?php echo $this->error_message; ?>
|
345 |
+
</div>
|
346 |
+
<?php else: ?>
|
347 |
+
<p class="message"><?php echo $reason; ?></p>
|
348 |
+
<?php endif; ?>
|
349 |
+
|
350 |
+
<form name="resetpassform" id="resetpassform" action="<?php echo esc_url( $wp_login_url ); ?>" method="post"
|
351 |
+
autocomplete="off">
|
352 |
+
|
353 |
+
<div class="user-pass1-wrap">
|
354 |
+
<p><label for="pass1"><?php _e( 'New Password', 'better-wp-security' ); ?></label></p>
|
355 |
+
</div>
|
356 |
+
|
357 |
+
<div class="wp-pwd">
|
358 |
+
<span class="password-input-wrapper">
|
359 |
+
<input type="password" data-reveal="1"
|
360 |
+
data-pw="<?php echo esc_attr( wp_generate_password( 16 ) ); ?>" name="pass1" id="pass1"
|
361 |
+
class="input" size="20" value="" autocomplete="off" aria-describedby="pass-strength-result"/>
|
362 |
+
</span>
|
363 |
+
<div id="pass-strength-result" class="hide-if-no-js" aria-live="polite"><?php _e( 'Strength indicator', 'better-wp-security' ); ?></div>
|
364 |
+
</div>
|
365 |
+
|
366 |
+
<p class="user-pass2-wrap">
|
367 |
+
<label for="pass2"><?php _e( 'Confirm new password' ) ?></label><br/>
|
368 |
+
<input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="off"/>
|
369 |
+
</p>
|
370 |
+
|
371 |
+
<p class="description indicator-hint"><?php echo wp_get_password_hint(); ?></p>
|
372 |
+
<br class="clear"/>
|
373 |
+
|
374 |
+
<p class="submit">
|
375 |
+
<input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large"
|
376 |
+
value="<?php esc_attr_e( 'Update Password', 'better-wp-security' ); ?>"/>
|
377 |
+
</p>
|
378 |
+
|
379 |
+
<?php if ( $interim_login ) : ?>
|
380 |
+
<input type="hidden" name="interim-login" value="1"/>
|
381 |
+
<?php else : ?>
|
382 |
+
<input type="hidden" name="redirect_to" value="<?php echo esc_url( $redirect_to ); ?>"/>
|
383 |
+
<?php endif; ?>
|
384 |
+
|
385 |
+
<input type="hidden" name="rememberme" id="rememberme" value="<?php echo esc_attr( $rememberme ); ?>"/>
|
386 |
+
<input type="hidden" name="itsec_update_password" value="1">
|
387 |
+
<input type="hidden" name="itsec_update_password_token" value="<?php echo esc_attr( $token ); ?>">
|
388 |
+
<input type="hidden" name="itsec_update_password_user" value="<?php echo esc_attr( $user->ID ); ?>">
|
389 |
+
</form>
|
390 |
+
|
391 |
+
<p id="backtoblog">
|
392 |
+
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php esc_attr_e( 'Are you lost?', 'better-wp-security' ); ?>">
|
393 |
+
<?php echo esc_html( sprintf( __( '← Back to %s', 'better-wp-security' ), get_bloginfo( 'title', 'display' ) ) ); ?>
|
394 |
+
</a>
|
395 |
+
</p>
|
396 |
+
|
397 |
+
</div>
|
398 |
+
<?php do_action( 'login_footer' ); ?>
|
399 |
+
<div class="clear"></div>
|
400 |
+
</body>
|
401 |
+
</html>
|
402 |
+
<?php
|
403 |
+
}
|
404 |
+
|
405 |
+
/**
|
406 |
+
* Get a message indicating to the user why a password change is required.
|
407 |
+
*
|
408 |
+
* @param string $reason
|
409 |
+
*
|
410 |
+
* @return string
|
411 |
+
*/
|
412 |
+
protected function get_message_for_password_change_reason( $reason ) {
|
413 |
+
|
414 |
+
/**
|
415 |
+
* Retrieve a human readable description as to why a password change has been required for the current user.
|
416 |
+
*
|
417 |
+
* Modules MUST HTML escape their reason strings before returning them with this filter.
|
418 |
+
*
|
419 |
+
* @param string $message
|
420 |
+
*/
|
421 |
+
$message = apply_filters( "itsec_password_change_requirement_description_for_{$reason}", '' );
|
422 |
+
|
423 |
+
if ( $message ) {
|
424 |
+
return $message;
|
425 |
+
}
|
426 |
+
|
427 |
+
return esc_html__( 'A password change is required for your account.', 'better-wp-security' );
|
428 |
+
}
|
429 |
+
|
430 |
+
/**
|
431 |
+
* Validate a user's password.
|
432 |
+
*
|
433 |
+
* @param WP_User|stdClass|int $user
|
434 |
+
* @param string $new_password
|
435 |
+
* @param array $args
|
436 |
+
*
|
437 |
+
* @return WP_Error Error object with new errors.
|
438 |
+
*/
|
439 |
+
public static function validate_password( $user, $new_password, $args = array() ) {
|
440 |
+
|
441 |
+
$args = wp_parse_args( $args, array(
|
442 |
+
'error' => new WP_Error(),
|
443 |
+
'context' => ''
|
444 |
+
) );
|
445 |
+
|
446 |
+
$error = isset( $args['error'] ) ? $args['error'] : new WP_Error();
|
447 |
+
|
448 |
+
$user = $user instanceof stdClass ? $user : ITSEC_Lib::get_user( $user );
|
449 |
+
|
450 |
+
if ( ! $user ) {
|
451 |
+
$error->add( 'invalid_user', esc_html__( 'Invalid User', 'better-wp-security' ) );
|
452 |
+
|
453 |
+
return $error;
|
454 |
+
}
|
455 |
+
|
456 |
+
/**
|
457 |
+
* Fires when modules should validate a password according to their rules.
|
458 |
+
*
|
459 |
+
* @since 3.9.0
|
460 |
+
*
|
461 |
+
* @param \WP_Error $error
|
462 |
+
* @param \WP_User|stdClass $user
|
463 |
+
* @param string $new_password
|
464 |
+
* @param array $args
|
465 |
+
*/
|
466 |
+
do_action( 'itsec_validate_password', $error, $user, $new_password, $args );
|
467 |
+
|
468 |
+
return $error;
|
469 |
+
}
|
470 |
+
|
471 |
+
/**
|
472 |
+
* Flag that a password change is required for a user.
|
473 |
+
*
|
474 |
+
* @param WP_User|int $user
|
475 |
+
* @param string $reason
|
476 |
+
*/
|
477 |
+
public static function flag_password_change_required( $user, $reason ) {
|
478 |
+
$user = ITSEC_Lib::get_user( $user );
|
479 |
+
|
480 |
+
if ( $user ) {
|
481 |
+
update_user_meta( $user->ID, 'itsec_password_change_required', $reason );
|
482 |
+
}
|
483 |
+
}
|
484 |
+
|
485 |
+
/**
|
486 |
+
* Check if a password change is required for the given user.
|
487 |
+
*
|
488 |
+
* @param WP_User|int $user
|
489 |
+
*
|
490 |
+
* @return string|false Either the reason code a change is required, or false.
|
491 |
+
*/
|
492 |
+
public static function password_change_required( $user ) {
|
493 |
+
$user = ITSEC_Lib::get_user( $user );
|
494 |
+
|
495 |
+
if ( ! $user ) {
|
496 |
+
return false;
|
497 |
+
}
|
498 |
+
|
499 |
+
$reason = get_user_meta( $user->ID, 'itsec_password_change_required', true );
|
500 |
+
|
501 |
+
if ( ! $reason ) {
|
502 |
+
return false;
|
503 |
+
}
|
504 |
+
|
505 |
+
return $reason;
|
506 |
+
}
|
507 |
+
|
508 |
+
/**
|
509 |
+
* Get the GMT time the user's password has last been changed.
|
510 |
+
*
|
511 |
+
* @param WP_User|int $user
|
512 |
+
*
|
513 |
+
* @return int
|
514 |
+
*/
|
515 |
+
public static function password_last_changed( $user ) {
|
516 |
+
|
517 |
+
$user = ITSEC_Lib::get_user( $user );
|
518 |
+
|
519 |
+
if ( ! $user ) {
|
520 |
+
return 0;
|
521 |
+
}
|
522 |
+
|
523 |
+
$changed = (int) get_user_meta( $user->ID, 'itsec_last_password_change', true );
|
524 |
+
$deprecated = (int) get_user_meta( $user->ID, 'itsec-password-updated', true );
|
525 |
+
|
526 |
+
if ( $deprecated > $changed ) {
|
527 |
+
return $deprecated;
|
528 |
+
}
|
529 |
+
|
530 |
+
return $changed;
|
531 |
+
}
|
532 |
+
}
|
core/lib/includes/function.login-header.php
ADDED
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Output the login page header.
|
4 |
+
*
|
5 |
+
* @param string $title Optional. WordPress login Page title to display in the `<title>` element.
|
6 |
+
* Default 'Log In'.
|
7 |
+
* @param string $message Optional. Message to display in header. Default empty.
|
8 |
+
* @param WP_Error $wp_error Optional. The error to pass. Default empty.
|
9 |
+
*/
|
10 |
+
function login_header( $title = 'Log In', $message = '', $wp_error = '' ) {
|
11 |
+
global $error, $interim_login, $action;
|
12 |
+
|
13 |
+
// Don't index any of these forms
|
14 |
+
add_action( 'login_head', 'wp_no_robots' );
|
15 |
+
|
16 |
+
add_action( 'login_head', 'wp_login_viewport_meta' );
|
17 |
+
|
18 |
+
if ( empty($wp_error) )
|
19 |
+
$wp_error = new WP_Error();
|
20 |
+
|
21 |
+
// Shake it!
|
22 |
+
$shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password' );
|
23 |
+
/**
|
24 |
+
* Filters the error codes array for shaking the login form.
|
25 |
+
*
|
26 |
+
* @since 3.0.0
|
27 |
+
*
|
28 |
+
* @param array $shake_error_codes Error codes that shake the login form.
|
29 |
+
*/
|
30 |
+
$shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
|
31 |
+
|
32 |
+
if ( $shake_error_codes && $wp_error->get_error_code() && in_array( $wp_error->get_error_code(), $shake_error_codes ) )
|
33 |
+
add_action( 'login_head', 'wp_shake_js', 12 );
|
34 |
+
|
35 |
+
$separator = is_rtl() ? ' › ' : ' ‹ ';
|
36 |
+
|
37 |
+
?><!DOCTYPE html>
|
38 |
+
<!--[if IE 8]>
|
39 |
+
<html xmlns="http://www.w3.org/1999/xhtml" class="ie8" <?php language_attributes(); ?>>
|
40 |
+
<![endif]-->
|
41 |
+
<!--[if !(IE 8) ]><!-->
|
42 |
+
<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
|
43 |
+
<!--<![endif]-->
|
44 |
+
<head>
|
45 |
+
<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
|
46 |
+
<title><?php echo get_bloginfo( 'name', 'display' ) . $separator . $title; ?></title>
|
47 |
+
<?php
|
48 |
+
|
49 |
+
wp_enqueue_style( 'login' );
|
50 |
+
|
51 |
+
/*
|
52 |
+
* Remove all stored post data on logging out.
|
53 |
+
* This could be added by add_action('login_head'...) like wp_shake_js(),
|
54 |
+
* but maybe better if it's not removable by plugins
|
55 |
+
*/
|
56 |
+
if ( 'loggedout' == $wp_error->get_error_code() ) {
|
57 |
+
?>
|
58 |
+
<script>if("sessionStorage" in window){try{for(var key in sessionStorage){if(key.indexOf("wp-autosave-")!=-1){sessionStorage.removeItem(key)}}}catch(e){}};</script>
|
59 |
+
<?php
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Enqueue scripts and styles for the login page.
|
64 |
+
*
|
65 |
+
* @since 3.1.0
|
66 |
+
*/
|
67 |
+
do_action( 'login_enqueue_scripts' );
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Fires in the login page header after scripts are enqueued.
|
71 |
+
*
|
72 |
+
* @since 2.1.0
|
73 |
+
*/
|
74 |
+
do_action( 'login_head' );
|
75 |
+
|
76 |
+
if ( is_multisite() ) {
|
77 |
+
$login_header_url = network_home_url();
|
78 |
+
$login_header_title = get_network()->site_name;
|
79 |
+
} else {
|
80 |
+
$login_header_url = __( 'https://wordpress.org/' );
|
81 |
+
$login_header_title = __( 'Powered by WordPress' );
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Filters link URL of the header logo above login form.
|
86 |
+
*
|
87 |
+
* @since 2.1.0
|
88 |
+
*
|
89 |
+
* @param string $login_header_url Login header logo URL.
|
90 |
+
*/
|
91 |
+
$login_header_url = apply_filters( 'login_headerurl', $login_header_url );
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Filters the title attribute of the header logo above login form.
|
95 |
+
*
|
96 |
+
* @since 2.1.0
|
97 |
+
*
|
98 |
+
* @param string $login_header_title Login header logo title attribute.
|
99 |
+
*/
|
100 |
+
$login_header_title = apply_filters( 'login_headertitle', $login_header_title );
|
101 |
+
|
102 |
+
$classes = array( 'login-action-' . $action, 'wp-core-ui' );
|
103 |
+
if ( is_rtl() )
|
104 |
+
$classes[] = 'rtl';
|
105 |
+
if ( $interim_login ) {
|
106 |
+
$classes[] = 'interim-login';
|
107 |
+
?>
|
108 |
+
<style type="text/css">html{background-color: transparent;}</style>
|
109 |
+
<?php
|
110 |
+
|
111 |
+
if ( 'success' === $interim_login )
|
112 |
+
$classes[] = 'interim-login-success';
|
113 |
+
}
|
114 |
+
$classes[] =' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Filters the login page body classes.
|
118 |
+
*
|
119 |
+
* @since 3.5.0
|
120 |
+
*
|
121 |
+
* @param array $classes An array of body classes.
|
122 |
+
* @param string $action The action that brought the visitor to the login page.
|
123 |
+
*/
|
124 |
+
$classes = apply_filters( 'login_body_class', $classes, $action );
|
125 |
+
|
126 |
+
?>
|
127 |
+
</head>
|
128 |
+
<body class="login <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
|
129 |
+
<?php
|
130 |
+
/**
|
131 |
+
* Fires in the login page header after the body tag is opened.
|
132 |
+
*
|
133 |
+
* @since 4.6.0
|
134 |
+
*/
|
135 |
+
do_action( 'login_header' );
|
136 |
+
?>
|
137 |
+
<div id="login">
|
138 |
+
<h1><a href="<?php echo esc_url( $login_header_url ); ?>" title="<?php echo esc_attr( $login_header_title ); ?>" tabindex="-1"><?php bloginfo( 'name' ); ?></a></h1>
|
139 |
+
<?php
|
140 |
+
|
141 |
+
unset( $login_header_url, $login_header_title );
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Filters the message to display above the login form.
|
145 |
+
*
|
146 |
+
* @since 2.1.0
|
147 |
+
*
|
148 |
+
* @param string $message Login message text.
|
149 |
+
*/
|
150 |
+
$message = apply_filters( 'login_message', $message );
|
151 |
+
if ( !empty( $message ) )
|
152 |
+
echo $message . "\n";
|
153 |
+
|
154 |
+
// In case a plugin uses $error rather than the $wp_errors object
|
155 |
+
if ( !empty( $error ) ) {
|
156 |
+
$wp_error->add('error', $error);
|
157 |
+
unset($error);
|
158 |
+
}
|
159 |
+
|
160 |
+
if ( $wp_error->get_error_code() ) {
|
161 |
+
$errors = '';
|
162 |
+
$messages = '';
|
163 |
+
foreach ( $wp_error->get_error_codes() as $code ) {
|
164 |
+
$severity = $wp_error->get_error_data( $code );
|
165 |
+
foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
|
166 |
+
if ( 'message' == $severity )
|
167 |
+
$messages .= ' ' . $error_message . "<br />\n";
|
168 |
+
else
|
169 |
+
$errors .= ' ' . $error_message . "<br />\n";
|
170 |
+
}
|
171 |
+
}
|
172 |
+
if ( ! empty( $errors ) ) {
|
173 |
+
/**
|
174 |
+
* Filters the error messages displayed above the login form.
|
175 |
+
*
|
176 |
+
* @since 2.1.0
|
177 |
+
*
|
178 |
+
* @param string $errors Login error message.
|
179 |
+
*/
|
180 |
+
echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
|
181 |
+
}
|
182 |
+
if ( ! empty( $messages ) ) {
|
183 |
+
/**
|
184 |
+
* Filters instructional messages displayed above the login form.
|
185 |
+
*
|
186 |
+
* @since 2.5.0
|
187 |
+
*
|
188 |
+
* @param string $messages Login messages.
|
189 |
+
*/
|
190 |
+
echo '<p class="message">' . apply_filters( 'login_messages', $messages ) . "</p>\n";
|
191 |
+
}
|
192 |
+
}
|
193 |
+
} // End of login_header()
|
194 |
+
|
195 |
+
if ( ! function_exists( 'wp_login_viewport_meta' ) ) :
|
196 |
+
/**
|
197 |
+
* @since 3.7.0
|
198 |
+
*/
|
199 |
+
function wp_login_viewport_meta() {
|
200 |
+
?>
|
201 |
+
<meta name="viewport" content="width=device-width" />
|
202 |
+
<?php
|
203 |
+
}
|
204 |
+
endif;
|
core/lib/includes/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden.
|
core/{lock.php → lib/lock.php}
RENAMED
File without changes
|
core/{class-itsec-lockout.php → lockout.php}
RENAMED
@@ -1,18 +1,72 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
/**
|
4 |
* Handles lockouts for modules and core
|
5 |
*
|
6 |
* @package iThemes-Security
|
7 |
* @since 4.0
|
8 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
final class ITSEC_Lockout {
|
10 |
|
11 |
-
|
12 |
-
|
13 |
-
$lockout_modules;
|
14 |
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
$this->core = $core;
|
18 |
$this->lockout_modules = array(); //array to hold information on modules using this feature
|
@@ -56,6 +110,14 @@ final class ITSEC_Lockout {
|
|
56 |
require_once( dirname( __FILE__ ) . '/sidebar-widget-active-lockouts.php' );
|
57 |
}
|
58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
public function check_authenticate_lockout( $user ) {
|
60 |
if ( ! ( $user instanceof WP_User ) ) {
|
61 |
return $user;
|
@@ -130,16 +192,18 @@ final class ITSEC_Lockout {
|
|
130 |
}
|
131 |
|
132 |
/**
|
133 |
-
*
|
|
|
|
|
134 |
*
|
135 |
* @since 4.0
|
136 |
*
|
137 |
-
* @param string $module
|
138 |
-
* @param string $
|
139 |
*
|
140 |
* @return void
|
141 |
*/
|
142 |
-
public function do_lockout( $module, $
|
143 |
|
144 |
global $wpdb, $itsec_globals;
|
145 |
|
@@ -184,9 +248,9 @@ final class ITSEC_Lockout {
|
|
184 |
|
185 |
}
|
186 |
|
187 |
-
if ( $
|
188 |
|
189 |
-
$user_id = username_exists( sanitize_text_field( $
|
190 |
|
191 |
if ( $user_id !== false ) {
|
192 |
|
@@ -197,7 +261,7 @@ final class ITSEC_Lockout {
|
|
197 |
'temp_date' => date( 'Y-m-d H:i:s', $itsec_globals['current_time'] ),
|
198 |
'temp_date_gmt' => date( 'Y-m-d H:i:s', $itsec_globals['current_time_gmt'] ),
|
199 |
'temp_user' => intval( $user_id ),
|
200 |
-
'temp_username' => sanitize_text_field( $
|
201 |
)
|
202 |
);
|
203 |
|
@@ -205,7 +269,7 @@ final class ITSEC_Lockout {
|
|
205 |
$wpdb->prepare(
|
206 |
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` > '%s' AND `temp_username`='%s' OR `temp_user`=%s;",
|
207 |
date( 'Y-m-d H:i:s', $itsec_globals['current_time_gmt'] - ( $options['period'] * 60 ) ),
|
208 |
-
sanitize_text_field( $
|
209 |
intval( $user_id )
|
210 |
)
|
211 |
);
|
@@ -218,7 +282,7 @@ final class ITSEC_Lockout {
|
|
218 |
|
219 |
} else {
|
220 |
|
221 |
-
$
|
222 |
|
223 |
$wpdb->insert(
|
224 |
$wpdb->base_prefix . 'itsec_temp',
|
@@ -226,7 +290,7 @@ final class ITSEC_Lockout {
|
|
226 |
'temp_type' => $options['type'],
|
227 |
'temp_date' => date( 'Y-m-d H:i:s', $itsec_globals['current_time'] ),
|
228 |
'temp_date_gmt' => date( 'Y-m-d H:i:s', $itsec_globals['current_time_gmt'] ),
|
229 |
-
'temp_username' => $
|
230 |
)
|
231 |
);
|
232 |
|
@@ -234,13 +298,13 @@ final class ITSEC_Lockout {
|
|
234 |
$wpdb->prepare(
|
235 |
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` > '%s' AND `temp_username`='%s';",
|
236 |
date( 'Y-m-d H:i:s', $itsec_globals['current_time_gmt'] - ( $options['period'] * 60 ) ),
|
237 |
-
$
|
238 |
)
|
239 |
);
|
240 |
|
241 |
if ( $user_count >= $options['user'] ) {
|
242 |
|
243 |
-
$lock_username = $
|
244 |
|
245 |
}
|
246 |
|
@@ -271,7 +335,8 @@ final class ITSEC_Lockout {
|
|
271 |
/**
|
272 |
* Executes lockout (locks user out)
|
273 |
*
|
274 |
-
* @param
|
|
|
275 |
*
|
276 |
* @return void
|
277 |
*/
|
@@ -350,7 +415,7 @@ final class ITSEC_Lockout {
|
|
350 |
|
351 |
$description = '<h4>' . __( 'About Lockouts', 'better-wp-security' ) . '</h4>';
|
352 |
$description .= '<p>';
|
353 |
-
$description .= sprintf( __( 'Your lockout settings can be configured in <a href="%s">Global Settings</a>.', 'better-wp-security' ), esc_url( $global_settings_url ) );
|
354 |
$description .= '<br />';
|
355 |
$description .= __( 'Your current settings are configured as follows:', 'better-wp-security' );
|
356 |
$description .= '<ul><li>';
|
@@ -439,6 +504,11 @@ final class ITSEC_Lockout {
|
|
439 |
|
440 |
}
|
441 |
|
|
|
|
|
|
|
|
|
|
|
442 |
public function get_temp_whitelist() {
|
443 |
$whitelist = get_site_option( 'itsec_temp_whitelist_ip', false );
|
444 |
|
@@ -458,6 +528,9 @@ final class ITSEC_Lockout {
|
|
458 |
return $whitelist;
|
459 |
}
|
460 |
|
|
|
|
|
|
|
461 |
public function update_temp_whitelist() {
|
462 |
if ( ! ITSEC_Core::current_user_can_manage() ) {
|
463 |
// Only add IP's of users that can manage Security settings.
|
@@ -468,6 +541,13 @@ final class ITSEC_Lockout {
|
|
468 |
$this->add_to_temp_whitelist( $ip );
|
469 |
}
|
470 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
471 |
public function add_to_temp_whitelist( $ip ) {
|
472 |
$whitelist = $this->get_temp_whitelist();
|
473 |
$expiration = ITSEC_Core::get_current_time_gmt() + DAY_IN_SECONDS;
|
@@ -490,6 +570,11 @@ final class ITSEC_Lockout {
|
|
490 |
update_site_option( 'itsec_temp_whitelist_ip', $whitelist );
|
491 |
}
|
492 |
|
|
|
|
|
|
|
|
|
|
|
493 |
public function remove_from_temp_whitelist( $ip ) {
|
494 |
$whitelist = $this->get_temp_whitelist();
|
495 |
|
@@ -502,10 +587,18 @@ final class ITSEC_Lockout {
|
|
502 |
update_site_option( 'itsec_temp_whitelist_ip', $whitelist );
|
503 |
}
|
504 |
|
505 |
-
|
|
|
|
|
|
|
506 |
update_site_option( 'itsec_temp_whitelist_ip', array() );
|
507 |
}
|
508 |
|
|
|
|
|
|
|
|
|
|
|
509 |
public function is_visitor_temp_whitelisted() {
|
510 |
global $itsec_globals;
|
511 |
|
@@ -520,7 +613,12 @@ final class ITSEC_Lockout {
|
|
520 |
}
|
521 |
|
522 |
/**
|
523 |
-
*
|
|
|
|
|
|
|
|
|
|
|
524 |
*
|
525 |
* @since 4.0
|
526 |
*
|
@@ -542,6 +640,7 @@ final class ITSEC_Lockout {
|
|
542 |
$user_expiration = null;
|
543 |
$username = sanitize_text_field( trim( $username ) );
|
544 |
|
|
|
545 |
if ( $itsec_files->get_file_lock( 'lockout_' . $host . $user . $username ) ) {
|
546 |
|
547 |
//Do we have a good host to lock out or not
|
@@ -769,9 +868,9 @@ final class ITSEC_Lockout {
|
|
769 |
/**
|
770 |
* Register 404 and file change detection for logger
|
771 |
*
|
772 |
-
* @param
|
773 |
*
|
774 |
-
* @return array
|
775 |
*/
|
776 |
public function register_logger( $logger_modules ) {
|
777 |
|
@@ -789,7 +888,7 @@ final class ITSEC_Lockout {
|
|
789 |
*
|
790 |
* @since 3.6.0
|
791 |
*
|
792 |
-
* @param Ithemes_Sync_API
|
793 |
*/
|
794 |
public function register_sync_verbs( $api ) {
|
795 |
$api->register( 'itsec-get-lockouts', 'Ithemes_Sync_Verb_ITSEC_Get_Lockouts', dirname( __FILE__ ) . '/sync-verbs/itsec-get-lockouts.php' );
|
@@ -803,7 +902,7 @@ final class ITSEC_Lockout {
|
|
803 |
*
|
804 |
* @since 3.6.0
|
805 |
*
|
806 |
-
* @param array
|
807 |
*
|
808 |
* @return array Array of verbs.
|
809 |
*/
|
@@ -815,14 +914,24 @@ final class ITSEC_Lockout {
|
|
815 |
}
|
816 |
|
817 |
/**
|
818 |
-
* Register modules that will use the lockout service
|
819 |
*
|
820 |
* @return void
|
821 |
*/
|
822 |
public function register_modules() {
|
823 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
824 |
$this->lockout_modules = apply_filters( 'itsec_lockout_modules', $this->lockout_modules );
|
825 |
-
|
826 |
}
|
827 |
|
828 |
/**
|
@@ -830,6 +939,8 @@ final class ITSEC_Lockout {
|
|
830 |
*
|
831 |
* @since 4.0
|
832 |
*
|
|
|
|
|
833 |
* @return bool true on success or false
|
834 |
*/
|
835 |
public function release_lockout( $id = null ) {
|
1 |
<?php
|
|
|
2 |
/**
|
3 |
* Handles lockouts for modules and core
|
4 |
*
|
5 |
* @package iThemes-Security
|
6 |
* @since 4.0
|
7 |
*/
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Class ITSEC_Lockout
|
11 |
+
*
|
12 |
+
* The ITSEC Lockout class is the centralized controller for detecting and blocking already locked-out users. Other
|
13 |
+
* iThemes Security modules instruct ITSEC_Lockout to save a lock out to storage, but ITSEC Lockout will never lock
|
14 |
+
* out a user itself.
|
15 |
+
*
|
16 |
+
* If a user attempts to login with valid credentials and their user ID is marked as locked out, they will be prevented
|
17 |
+
* from logging in and the lock will remain in effect until its expiration.
|
18 |
+
*
|
19 |
+
* There are three types of lockouts.
|
20 |
+
*
|
21 |
+
* - User ID
|
22 |
+
* - Username
|
23 |
+
* - Host
|
24 |
+
*
|
25 |
+
* = User ID =
|
26 |
+
* User ID lockouts are used whenever an attacker tries to repeatedly log in with a valid username, but incorrect password.
|
27 |
+
* By default, a host lockout will occur first ( assuming the attacker does not alter their IPs ). This is done because
|
28 |
+
* a user ID lockout can lock out a legitimate user from signing into their account.
|
29 |
+
*
|
30 |
+
* = Username =
|
31 |
+
* Username lockouts are used whenever an attacker tried to repeatedly log in with a non-existent username. Or, if
|
32 |
+
* enabled, uses the 'admin' username. This is separate from the User ID lock out type, however the lockout message
|
33 |
+
* is shared between the two.
|
34 |
+
*
|
35 |
+
* = Host =
|
36 |
+
* Host lockouts are used whenever an IP address is flagged as an attacker. This is done via repeated 404 errors or
|
37 |
+
* failed captcha validations. If an IP address is whitelisted, an event will be logged, but the user will not be
|
38 |
+
* locked out. By default, host lockouts have the lowest threshold before locking out the host. The Network Brute Force
|
39 |
+
* module does NOT create host lockouts, but utilizes ITSEC_Lockout::execute_lock() to prevent the attacker from
|
40 |
+
* accessing the site.
|
41 |
+
*
|
42 |
+
* ITSEC_Lockout will store a record whenever ITSEC Lockout is instructed to perform a lockout via ::do_lockout() in the
|
43 |
+
* itsec_temp database table. If the threshold for that lockout type has been met – the most recently added one counts –
|
44 |
+
* an actual lockout will be saved to the itsec_lockouts table. If enabled, and enough lockouts have occurred
|
45 |
+
* ( configurable via settings ), a host will be blacklisted instead of added to the itsec_lockouts table. Blacklisted
|
46 |
+
* IPs are blocked at the server level. This is handled by the ban-users module.
|
47 |
+
*
|
48 |
+
* After the lockout has been stored, the request will be immediately exited.
|
49 |
+
*
|
50 |
+
* iThemes Security supports two types of whitelists. Temporary and permanent whitelists. Permanent whitelists are
|
51 |
+
* configured in the Global Settings module and will permanently prevent a user with that IP from being locked out.
|
52 |
+
* The temporary whitelist is a global list of admin level user's IP addresses. Whenever an admin user is logged-in and
|
53 |
+
* using the site, their IP will be added to the whitelist for 24 hours.
|
54 |
+
*
|
55 |
+
* This controller also provides a number of methods to retrieve a list or clear both lockouts and temporary whitelists.
|
56 |
+
*/
|
57 |
final class ITSEC_Lockout {
|
58 |
|
59 |
+
/** @var ITSEC_Core */
|
60 |
+
private $core;
|
|
|
61 |
|
62 |
+
private $lockout_modules;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* ITSEC_Lockout constructor.
|
66 |
+
*
|
67 |
+
* @param ITSEC_Core $core
|
68 |
+
*/
|
69 |
+
public function __construct( $core ) {
|
70 |
|
71 |
$this->core = $core;
|
72 |
$this->lockout_modules = array(); //array to hold information on modules using this feature
|
110 |
require_once( dirname( __FILE__ ) . '/sidebar-widget-active-lockouts.php' );
|
111 |
}
|
112 |
|
113 |
+
/**
|
114 |
+
* Check if a user has successfully logged-in, and prevent them from accessing the site if they
|
115 |
+
* still have a lockout in effect.
|
116 |
+
*
|
117 |
+
* @param \WP_User|\WP_Error|null $user
|
118 |
+
*
|
119 |
+
* @return WP_User|WP_Error|null
|
120 |
+
*/
|
121 |
public function check_authenticate_lockout( $user ) {
|
122 |
if ( ! ( $user instanceof WP_User ) ) {
|
123 |
return $user;
|
192 |
}
|
193 |
|
194 |
/**
|
195 |
+
* This persists a lockout to storage or performs a permanent ban if appropriate.
|
196 |
+
*
|
197 |
+
* The user will be immediately locked out by this method if their IP is not whitelisted.
|
198 |
*
|
199 |
* @since 4.0
|
200 |
*
|
201 |
+
* @param string $module string name of the calling module
|
202 |
+
* @param string $username username of user
|
203 |
*
|
204 |
* @return void
|
205 |
*/
|
206 |
+
public function do_lockout( $module, $username = null ) {
|
207 |
|
208 |
global $wpdb, $itsec_globals;
|
209 |
|
248 |
|
249 |
}
|
250 |
|
251 |
+
if ( $username !== null && isset( $options['user'] ) && $options['user'] > 0 ) {
|
252 |
|
253 |
+
$user_id = username_exists( sanitize_text_field( $username ) );
|
254 |
|
255 |
if ( $user_id !== false ) {
|
256 |
|
261 |
'temp_date' => date( 'Y-m-d H:i:s', $itsec_globals['current_time'] ),
|
262 |
'temp_date_gmt' => date( 'Y-m-d H:i:s', $itsec_globals['current_time_gmt'] ),
|
263 |
'temp_user' => intval( $user_id ),
|
264 |
+
'temp_username' => sanitize_text_field( $username ),
|
265 |
)
|
266 |
);
|
267 |
|
269 |
$wpdb->prepare(
|
270 |
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` > '%s' AND `temp_username`='%s' OR `temp_user`=%s;",
|
271 |
date( 'Y-m-d H:i:s', $itsec_globals['current_time_gmt'] - ( $options['period'] * 60 ) ),
|
272 |
+
sanitize_text_field( $username ),
|
273 |
intval( $user_id )
|
274 |
)
|
275 |
);
|
282 |
|
283 |
} else {
|
284 |
|
285 |
+
$username = sanitize_text_field( $username );
|
286 |
|
287 |
$wpdb->insert(
|
288 |
$wpdb->base_prefix . 'itsec_temp',
|
290 |
'temp_type' => $options['type'],
|
291 |
'temp_date' => date( 'Y-m-d H:i:s', $itsec_globals['current_time'] ),
|
292 |
'temp_date_gmt' => date( 'Y-m-d H:i:s', $itsec_globals['current_time_gmt'] ),
|
293 |
+
'temp_username' => $username,
|
294 |
)
|
295 |
);
|
296 |
|
298 |
$wpdb->prepare(
|
299 |
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` > '%s' AND `temp_username`='%s';",
|
300 |
date( 'Y-m-d H:i:s', $itsec_globals['current_time_gmt'] - ( $options['period'] * 60 ) ),
|
301 |
+
$username
|
302 |
)
|
303 |
);
|
304 |
|
305 |
if ( $user_count >= $options['user'] ) {
|
306 |
|
307 |
+
$lock_username = $username;
|
308 |
|
309 |
}
|
310 |
|
335 |
/**
|
336 |
* Executes lockout (locks user out)
|
337 |
*
|
338 |
+
* @param bool $user Is a specific user being locked out.
|
339 |
+
* @param bool $network Was the host flagged by the Security Network.
|
340 |
*
|
341 |
* @return void
|
342 |
*/
|
415 |
|
416 |
$description = '<h4>' . __( 'About Lockouts', 'better-wp-security' ) . '</h4>';
|
417 |
$description .= '<p>';
|
418 |
+
$description .= sprintf( __( 'Your lockout settings can be configured in <a href="%s" data-module-link="global">Global Settings</a>.', 'better-wp-security' ), esc_url( $global_settings_url ) );
|
419 |
$description .= '<br />';
|
420 |
$description .= __( 'Your current settings are configured as follows:', 'better-wp-security' );
|
421 |
$description .= '<ul><li>';
|
504 |
|
505 |
}
|
506 |
|
507 |
+
/**
|
508 |
+
* Retrieve a list of the temporary whitelisted IP addresses.
|
509 |
+
*
|
510 |
+
* @return array A map of IP addresses to their expiration time.
|
511 |
+
*/
|
512 |
public function get_temp_whitelist() {
|
513 |
$whitelist = get_site_option( 'itsec_temp_whitelist_ip', false );
|
514 |
|
528 |
return $whitelist;
|
529 |
}
|
530 |
|
531 |
+
/**
|
532 |
+
* If the current user has permission to manage ITSEC, add them to the temporary whitelist.
|
533 |
+
*/
|
534 |
public function update_temp_whitelist() {
|
535 |
if ( ! ITSEC_Core::current_user_can_manage() ) {
|
536 |
// Only add IP's of users that can manage Security settings.
|
541 |
$this->add_to_temp_whitelist( $ip );
|
542 |
}
|
543 |
|
544 |
+
/**
|
545 |
+
* Add an IP address to the temporary whitelist for 24 hours.
|
546 |
+
*
|
547 |
+
* This method will also remove any expired IPs from storage.
|
548 |
+
*
|
549 |
+
* @param string $ip
|
550 |
+
*/
|
551 |
public function add_to_temp_whitelist( $ip ) {
|
552 |
$whitelist = $this->get_temp_whitelist();
|
553 |
$expiration = ITSEC_Core::get_current_time_gmt() + DAY_IN_SECONDS;
|
570 |
update_site_option( 'itsec_temp_whitelist_ip', $whitelist );
|
571 |
}
|
572 |
|
573 |
+
/**
|
574 |
+
* Remove a given IP address from the temporary whitelist.
|
575 |
+
*
|
576 |
+
* @param string $ip
|
577 |
+
*/
|
578 |
public function remove_from_temp_whitelist( $ip ) {
|
579 |
$whitelist = $this->get_temp_whitelist();
|
580 |
|
587 |
update_site_option( 'itsec_temp_whitelist_ip', $whitelist );
|
588 |
}
|
589 |
|
590 |
+
/**
|
591 |
+
* Completely clear the temporary whitelist of all IP addresses.
|
592 |
+
*/
|
593 |
+
public function clear_temp_whitelist() {
|
594 |
update_site_option( 'itsec_temp_whitelist_ip', array() );
|
595 |
}
|
596 |
|
597 |
+
/**
|
598 |
+
* Check if the current user is temporarily whitelisted.
|
599 |
+
*
|
600 |
+
* @return bool
|
601 |
+
*/
|
602 |
public function is_visitor_temp_whitelisted() {
|
603 |
global $itsec_globals;
|
604 |
|
613 |
}
|
614 |
|
615 |
/**
|
616 |
+
* Store a record of the locked out user/host or permanently ban the host.
|
617 |
+
*
|
618 |
+
* Permanently banned hosts will be forwarded to the ban-users module via the itsec-new-blacklisted-ip hook and
|
619 |
+
* not persisted to the database.
|
620 |
+
*
|
621 |
+
* If configured, notifies the configured email addresses of the lockout.
|
622 |
*
|
623 |
* @since 4.0
|
624 |
*
|
640 |
$user_expiration = null;
|
641 |
$username = sanitize_text_field( trim( $username ) );
|
642 |
|
643 |
+
// Acquire a lock to prevent a lockout being created more than once by a particularly fast attacker.
|
644 |
if ( $itsec_files->get_file_lock( 'lockout_' . $host . $user . $username ) ) {
|
645 |
|
646 |
//Do we have a good host to lock out or not
|
868 |
/**
|
869 |
* Register 404 and file change detection for logger
|
870 |
*
|
871 |
+
* @param array $logger_modules array of logger modules
|
872 |
*
|
873 |
+
* @return array
|
874 |
*/
|
875 |
public function register_logger( $logger_modules ) {
|
876 |
|
888 |
*
|
889 |
* @since 3.6.0
|
890 |
*
|
891 |
+
* @param Ithemes_Sync_API $api API object.
|
892 |
*/
|
893 |
public function register_sync_verbs( $api ) {
|
894 |
$api->register( 'itsec-get-lockouts', 'Ithemes_Sync_Verb_ITSEC_Get_Lockouts', dirname( __FILE__ ) . '/sync-verbs/itsec-get-lockouts.php' );
|
902 |
*
|
903 |
* @since 3.6.0
|
904 |
*
|
905 |
+
* @param array $verbs of verbs.
|
906 |
*
|
907 |
* @return array Array of verbs.
|
908 |
*/
|
914 |
}
|
915 |
|
916 |
/**
|
917 |
+
* Register modules that will use the lockout service.
|
918 |
*
|
919 |
* @return void
|
920 |
*/
|
921 |
public function register_modules() {
|
922 |
|
923 |
+
/**
|
924 |
+
* Filter the available lockout modules.
|
925 |
+
*
|
926 |
+
* @param array $lockout_modules Each lockout module should be an array containing 'type', 'reason' and
|
927 |
+
* 'period' options. The type is a unique string referring to the type of lockout.
|
928 |
+
* 'reason' is a human readable label describing the reason for the lockout.
|
929 |
+
* 'period' is the number of days to check for lockouts to decide if the host
|
930 |
+
* should be permanently banned. Additionally, the 'user' and 'host' options instruct
|
931 |
+
* security to wait for that many temporary lockout events to occur before executing
|
932 |
+
* the lockout.
|
933 |
+
*/
|
934 |
$this->lockout_modules = apply_filters( 'itsec_lockout_modules', $this->lockout_modules );
|
|
|
935 |
}
|
936 |
|
937 |
/**
|
939 |
*
|
940 |
* @since 4.0
|
941 |
*
|
942 |
+
* @param int $id
|
943 |
+
*
|
944 |
* @return bool true on success or false
|
945 |
*/
|
946 |
public function release_lockout( $id = null ) {
|
core/{class-itsec-logger-all-logs.php → logger-all-logs.php}
RENAMED
File without changes
|
core/{class-itsec-logger.php → logger.php}
RENAMED
@@ -19,7 +19,7 @@ final class ITSEC_Logger {
|
|
19 |
*
|
20 |
* @var array Events that need to be logged to a file but couldn't
|
21 |
*/
|
22 |
-
private $
|
23 |
|
24 |
function __construct() {
|
25 |
|
@@ -157,11 +157,11 @@ final class ITSEC_Logger {
|
|
157 |
$type = ITSEC_Modules::get_setting( 'global', 'log_type' );
|
158 |
|
159 |
if ( 'database' === $type || 'both' === $type ) {
|
160 |
-
$this->
|
161 |
}
|
162 |
|
163 |
if ( 'file' === $type || 'both' === $type ) {
|
164 |
-
$this->
|
165 |
}
|
166 |
|
167 |
}
|
@@ -170,7 +170,7 @@ final class ITSEC_Logger {
|
|
170 |
|
171 |
}
|
172 |
|
173 |
-
private function
|
174 |
global $wpdb, $itsec_globals;
|
175 |
|
176 |
$options = $this->logger_modules[ $module ];
|
@@ -210,12 +210,12 @@ final class ITSEC_Logger {
|
|
210 |
$wpdb->show_errors( $cached_show_errors_setting );
|
211 |
}
|
212 |
|
213 |
-
private function
|
214 |
global $itsec_globals;
|
215 |
|
216 |
// If the file can't be prepared, store the events up to write later (at plugins_loaded)
|
217 |
-
if ( false === $this->
|
218 |
-
$this->
|
219 |
return;
|
220 |
}
|
221 |
|
@@ -241,8 +241,8 @@ final class ITSEC_Logger {
|
|
241 |
}
|
242 |
|
243 |
public function write_pending_events_to_file() {
|
244 |
-
foreach ( $this->
|
245 |
-
call_user_func_array( array( $this, '
|
246 |
}
|
247 |
}
|
248 |
|
@@ -404,8 +404,9 @@ final class ITSEC_Logger {
|
|
404 |
*/
|
405 |
private function rotate_log() {
|
406 |
$log_file = $this->get_log_file();
|
|
|
407 |
|
408 |
-
if ( ! @file_exists( $log_file ) || @filesize( $log_file ) <
|
409 |
return;
|
410 |
}
|
411 |
|
@@ -445,7 +446,7 @@ final class ITSEC_Logger {
|
|
445 |
|
446 |
}
|
447 |
|
448 |
-
$this->
|
449 |
|
450 |
}
|
451 |
|
@@ -494,7 +495,6 @@ final class ITSEC_Logger {
|
|
494 |
private function get_log_file() {
|
495 |
if ( isset( $this->log_file ) ) {
|
496 |
return $this->log_file;
|
497 |
-
$this->rotate_log();
|
498 |
}
|
499 |
|
500 |
$log_location = ITSEC_Modules::get_setting( 'global', 'log_location' );
|
@@ -522,7 +522,7 @@ final class ITSEC_Logger {
|
|
522 |
*
|
523 |
* @return void
|
524 |
*/
|
525 |
-
private function
|
526 |
$log_file = $this->get_log_file();
|
527 |
|
528 |
// We can't prepare a file if we can't get the file name
|
19 |
*
|
20 |
* @var array Events that need to be logged to a file but couldn't
|
21 |
*/
|
22 |
+
private $events_to_log_to_file = array();
|
23 |
|
24 |
function __construct() {
|
25 |
|
157 |
$type = ITSEC_Modules::get_setting( 'global', 'log_type' );
|
158 |
|
159 |
if ( 'database' === $type || 'both' === $type ) {
|
160 |
+
$this->log_event_to_db( $module, $priority, $data, $host, $username, $user, $url, $referrer );
|
161 |
}
|
162 |
|
163 |
if ( 'file' === $type || 'both' === $type ) {
|
164 |
+
$this->log_event_to_file( $module, $priority, $data, $host, $username, $user, $url, $referrer );
|
165 |
}
|
166 |
|
167 |
}
|
170 |
|
171 |
}
|
172 |
|
173 |
+
private function log_event_to_db( $module, $priority, $data, $host, $username, $user, $url, $referrer ) {
|
174 |
global $wpdb, $itsec_globals;
|
175 |
|
176 |
$options = $this->logger_modules[ $module ];
|
210 |
$wpdb->show_errors( $cached_show_errors_setting );
|
211 |
}
|
212 |
|
213 |
+
private function log_event_to_file( $module, $priority = 5, $data = array(), $host = '', $username = '', $user = '', $url = '', $referrer = '' ) {
|
214 |
global $itsec_globals;
|
215 |
|
216 |
// If the file can't be prepared, store the events up to write later (at plugins_loaded)
|
217 |
+
if ( false === $this->prepare_log_file() ) {
|
218 |
+
$this->events_to_log_to_file[] = compact( 'module', 'priority', 'data', 'host', 'username', 'user', 'url', 'referrer' );
|
219 |
return;
|
220 |
}
|
221 |
|
241 |
}
|
242 |
|
243 |
public function write_pending_events_to_file() {
|
244 |
+
foreach ( $this->events_to_log_to_file as $event ) {
|
245 |
+
call_user_func_array( array( $this, 'log_event_to_file' ), $event );
|
246 |
}
|
247 |
}
|
248 |
|
404 |
*/
|
405 |
private function rotate_log() {
|
406 |
$log_file = $this->get_log_file();
|
407 |
+
$max_size = 1024 * 1024 * 10; // 10MiB
|
408 |
|
409 |
+
if ( ! @file_exists( $log_file ) || @filesize( $log_file ) < $max_size ) {
|
410 |
return;
|
411 |
}
|
412 |
|
446 |
|
447 |
}
|
448 |
|
449 |
+
$this->prepare_log_file();
|
450 |
|
451 |
}
|
452 |
|
495 |
private function get_log_file() {
|
496 |
if ( isset( $this->log_file ) ) {
|
497 |
return $this->log_file;
|
|
|
498 |
}
|
499 |
|
500 |
$log_location = ITSEC_Modules::get_setting( 'global', 'log_location' );
|
522 |
*
|
523 |
* @return void
|
524 |
*/
|
525 |
+
private function prepare_log_file() {
|
526 |
$log_file = $this->get_log_file();
|
527 |
|
528 |
// We can't prepare a file if we can't get the file name
|
core/{class-itsec-modules.php → modules.php}
RENAMED
@@ -27,6 +27,8 @@ final class ITSEC_Modules {
|
|
27 |
|
28 |
/**
|
29 |
* Function to instantiate our class and make it a singleton
|
|
|
|
|
30 |
*/
|
31 |
public static function get_instance() {
|
32 |
if ( ! self::$instance ) {
|
@@ -52,7 +54,7 @@ final class ITSEC_Modules {
|
|
52 |
$slug = sanitize_title_with_dashes( $slug );
|
53 |
|
54 |
if ( ! is_dir( $path ) ) {
|
55 |
-
trigger_error( sprintf( __( 'An attempt to register the %1$s module failed since the supplied path (%
|
56 |
return false;
|
57 |
}
|
58 |
|
@@ -94,6 +96,14 @@ final class ITSEC_Modules {
|
|
94 |
return false;
|
95 |
}
|
96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
public static function update_module_paths( $old_dir, $new_dir ) {
|
98 |
$self = self::get_instance();
|
99 |
|
@@ -102,11 +112,25 @@ final class ITSEC_Modules {
|
|
102 |
}
|
103 |
}
|
104 |
|
|
|
|
|
|
|
|
|
|
|
105 |
public static function register_settings( $settings ) {
|
106 |
$self = self::get_instance();
|
107 |
$self->_module_settings[ $settings->get_id() ] = $settings;
|
108 |
}
|
109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
public static function get_settings_obj( $slug ) {
|
111 |
$self = self::get_instance();
|
112 |
|
@@ -121,6 +145,13 @@ final class ITSEC_Modules {
|
|
121 |
return $self->_module_settings[ $slug ];
|
122 |
}
|
123 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
public static function get_defaults( $slug ) {
|
125 |
$self = self::get_instance();
|
126 |
|
@@ -133,6 +164,15 @@ final class ITSEC_Modules {
|
|
133 |
return $settings_obj->get_defaults();
|
134 |
}
|
135 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
public static function get_default( $slug, $name, $default = null ) {
|
137 |
$self = self::get_instance();
|
138 |
|
@@ -145,6 +185,13 @@ final class ITSEC_Modules {
|
|
145 |
return $default;
|
146 |
}
|
147 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
148 |
public static function get_settings( $slug ) {
|
149 |
$self = self::get_instance();
|
150 |
|
@@ -157,6 +204,16 @@ final class ITSEC_Modules {
|
|
157 |
return $settings_obj->get_all();
|
158 |
}
|
159 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
public static function get_setting( $slug, $name, $default = null ) {
|
161 |
$self = self::get_instance();
|
162 |
|
@@ -169,6 +226,16 @@ final class ITSEC_Modules {
|
|
169 |
return $settings_obj->get( $name, $default );
|
170 |
}
|
171 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
172 |
public static function set_settings( $slug, $settings ) {
|
173 |
$self = self::get_instance();
|
174 |
|
@@ -184,6 +251,17 @@ final class ITSEC_Modules {
|
|
184 |
return $settings_obj->set_all( $settings );
|
185 |
}
|
186 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
public static function set_setting( $slug, $name, $value ) {
|
188 |
$self = self::get_instance();
|
189 |
|
@@ -197,11 +275,27 @@ final class ITSEC_Modules {
|
|
197 |
return $settings_obj->set( $name, $value );
|
198 |
}
|
199 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
200 |
public static function register_validator( $validator ) {
|
201 |
$self = self::get_instance();
|
202 |
$self->_module_validators[ $validator->get_id() ] = $validator;
|
203 |
}
|
204 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
public static function get_validator( $slug ) {
|
206 |
$self = self::get_instance();
|
207 |
|
@@ -217,6 +311,13 @@ final class ITSEC_Modules {
|
|
217 |
return $self->_module_validators[ $slug ];
|
218 |
}
|
219 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
public static function get_available_modules() {
|
221 |
$self = self::get_instance();
|
222 |
|
@@ -233,6 +334,13 @@ final class ITSEC_Modules {
|
|
233 |
return $self->_available_modules;
|
234 |
}
|
235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
public static function get_active_modules() {
|
237 |
$self = self::get_instance();
|
238 |
|
@@ -286,11 +394,23 @@ final class ITSEC_Modules {
|
|
286 |
return $self->_active_modules_list;
|
287 |
}
|
288 |
|
|
|
|
|
|
|
|
|
|
|
289 |
public static function get_always_active_modules() {
|
290 |
$self = self::get_instance();
|
291 |
return array_keys( $self->_always_active_modules );
|
292 |
}
|
293 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
294 |
public static function is_always_active( $module_id ) {
|
295 |
$self = self::get_instance();
|
296 |
|
@@ -301,6 +421,13 @@ final class ITSEC_Modules {
|
|
301 |
return false;
|
302 |
}
|
303 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
304 |
public static function is_active( $module_id ) {
|
305 |
$self = self::get_instance();
|
306 |
|
@@ -385,6 +512,15 @@ final class ITSEC_Modules {
|
|
385 |
return $was_active;
|
386 |
}
|
387 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
388 |
public static function set_active_modules( $new_active_modules ) {
|
389 |
$self = self::get_instance();
|
390 |
|
@@ -413,13 +549,29 @@ final class ITSEC_Modules {
|
|
413 |
return true;
|
414 |
}
|
415 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
416 |
public static function load_module_file( $file, $modules = ':all' ) {
|
417 |
$self = self::get_instance();
|
418 |
|
419 |
if ( ':all' === $modules ) {
|
420 |
$modules = self::get_available_modules();
|
421 |
} else if ( ':active' === $modules ) {
|
422 |
-
|
|
|
|
|
|
|
|
|
423 |
|
424 |
$modules = array_merge( $modules, array_keys( $self->_always_active_modules ) );
|
425 |
$modules = array_unique( $modules );
|
@@ -438,39 +590,65 @@ final class ITSEC_Modules {
|
|
438 |
return true;
|
439 |
}
|
440 |
|
|
|
|
|
|
|
441 |
public static function init_modules() {
|
442 |
do_action( 'itsec-register-modules' );
|
443 |
}
|
444 |
|
|
|
|
|
|
|
445 |
public static function run_active_modules() {
|
446 |
// The active.php file is for code that will only run when the module is active.
|
447 |
self::load_module_file( 'active.php', ':active' );
|
448 |
}
|
449 |
|
|
|
|
|
|
|
450 |
public function run_activation() {
|
451 |
self::load_module_file( 'setup.php' );
|
452 |
|
453 |
do_action( 'itsec_modules_do_plugin_activation' );
|
454 |
}
|
455 |
|
|
|
|
|
|
|
456 |
public function run_deactivation() {
|
457 |
self::load_module_file( 'setup.php' );
|
458 |
|
459 |
do_action( 'itsec_modules_do_plugin_deactivation' );
|
460 |
}
|
461 |
|
|
|
|
|
|
|
462 |
public static function run_uninstall() {
|
463 |
self::load_module_file( 'setup.php' );
|
464 |
|
465 |
do_action( 'itsec_modules_do_plugin_uninstall' );
|
466 |
}
|
467 |
|
|
|
|
|
|
|
|
|
|
|
|
|
468 |
public function run_upgrade( $old_version, $new_version ) {
|
469 |
self::load_module_file( 'setup.php' );
|
470 |
|
471 |
do_action( 'itsec_modules_do_plugin_upgrade', $old_version, $new_version );
|
472 |
}
|
473 |
|
|
|
|
|
|
|
|
|
|
|
474 |
public function load_settings_page() {
|
475 |
if ( $this->_settings_files_loaded ) {
|
476 |
return;
|
27 |
|
28 |
/**
|
29 |
* Function to instantiate our class and make it a singleton
|
30 |
+
*
|
31 |
+
* @return ITSEC_Modules
|
32 |
*/
|
33 |
public static function get_instance() {
|
34 |
if ( ! self::$instance ) {
|
54 |
$slug = sanitize_title_with_dashes( $slug );
|
55 |
|
56 |
if ( ! is_dir( $path ) ) {
|
57 |
+
trigger_error( sprintf( __( 'An attempt to register the %1$s module failed since the supplied path (%2$s) is invalid. This could indicate an invalid modification or incomplete installation of the iThemes Security plugin. Please reinstall the plugin and try again.', 'better-wp-security' ), $slug, $path ) );
|
58 |
return false;
|
59 |
}
|
60 |
|
96 |
return false;
|
97 |
}
|
98 |
|
99 |
+
/**
|
100 |
+
* Update the stored paths for each module.
|
101 |
+
*
|
102 |
+
* This is predominantly used when changing the WordPress content directory.
|
103 |
+
*
|
104 |
+
* @param string $old_dir
|
105 |
+
* @param string $new_dir
|
106 |
+
*/
|
107 |
public static function update_module_paths( $old_dir, $new_dir ) {
|
108 |
$self = self::get_instance();
|
109 |
|
112 |
}
|
113 |
}
|
114 |
|
115 |
+
/**
|
116 |
+
* Register a module's settings controller.
|
117 |
+
*
|
118 |
+
* @param ITSEC_Settings $settings
|
119 |
+
*/
|
120 |
public static function register_settings( $settings ) {
|
121 |
$self = self::get_instance();
|
122 |
$self->_module_settings[ $settings->get_id() ] = $settings;
|
123 |
}
|
124 |
|
125 |
+
/**
|
126 |
+
* Retrieve a module's settings controller.
|
127 |
+
*
|
128 |
+
* This will load a module's settings file if it has not yet been loaded.
|
129 |
+
*
|
130 |
+
* @param string $slug The module slug.
|
131 |
+
*
|
132 |
+
* @return ITSEC_Settings|null
|
133 |
+
*/
|
134 |
public static function get_settings_obj( $slug ) {
|
135 |
$self = self::get_instance();
|
136 |
|
145 |
return $self->_module_settings[ $slug ];
|
146 |
}
|
147 |
|
148 |
+
/**
|
149 |
+
* Get the default settings for a module.
|
150 |
+
*
|
151 |
+
* @param string $slug The module slug.
|
152 |
+
*
|
153 |
+
* @return array
|
154 |
+
*/
|
155 |
public static function get_defaults( $slug ) {
|
156 |
$self = self::get_instance();
|
157 |
|
164 |
return $settings_obj->get_defaults();
|
165 |
}
|
166 |
|
167 |
+
/**
|
168 |
+
* Retrieve the default value of specific setting in a module.
|
169 |
+
*
|
170 |
+
* @param string $slug The module slug.
|
171 |
+
* @param string $name The name of the setting.
|
172 |
+
* @param mixed|null $default Optionally, specify a default value to be used if the module did not declare one.
|
173 |
+
*
|
174 |
+
* @return mixed
|
175 |
+
*/
|
176 |
public static function get_default( $slug, $name, $default = null ) {
|
177 |
$self = self::get_instance();
|
178 |
|
185 |
return $default;
|
186 |
}
|
187 |
|
188 |
+
/**
|
189 |
+
* Retrieve all of the settings for a module.
|
190 |
+
*
|
191 |
+
* @param string $slug The module slug.
|
192 |
+
*
|
193 |
+
* @return array
|
194 |
+
*/
|
195 |
public static function get_settings( $slug ) {
|
196 |
$self = self::get_instance();
|
197 |
|
204 |
return $settings_obj->get_all();
|
205 |
}
|
206 |
|
207 |
+
/**
|
208 |
+
* Retrieve the value of a specific setting in a module.
|
209 |
+
*
|
210 |
+
* @param string $slug The module slug.
|
211 |
+
* @param string $name The name of the setting.
|
212 |
+
* @param mixed|null $default Optionally, specify a default value to be used if the requested setting does not
|
213 |
+
* exist.
|
214 |
+
*
|
215 |
+
* @return mixed
|
216 |
+
*/
|
217 |
public static function get_setting( $slug, $name, $default = null ) {
|
218 |
$self = self::get_instance();
|
219 |
|
226 |
return $settings_obj->get( $name, $default );
|
227 |
}
|
228 |
|
229 |
+
/**
|
230 |
+
* Update all of a module's settings at once.
|
231 |
+
*
|
232 |
+
* The values will be validated, updated in-memory, and persisted.
|
233 |
+
*
|
234 |
+
* @param string $slug The module slug.
|
235 |
+
* @param array $settings New settings values.
|
236 |
+
*
|
237 |
+
* @return array|WP_Error
|
238 |
+
*/
|
239 |
public static function set_settings( $slug, $settings ) {
|
240 |
$self = self::get_instance();
|
241 |
|
251 |
return $settings_obj->set_all( $settings );
|
252 |
}
|
253 |
|
254 |
+
/**
|
255 |
+
* Update a single setting in a module.
|
256 |
+
*
|
257 |
+
* The new value will be validated, updated- in-memory, and persisted.
|
258 |
+
*
|
259 |
+
* @param string $slug The module slug.
|
260 |
+
* @param string $name The setting name to updated.
|
261 |
+
* @param mixed $value The settings' new value.
|
262 |
+
*
|
263 |
+
* @return array|false
|
264 |
+
*/
|
265 |
public static function set_setting( $slug, $name, $value ) {
|
266 |
$self = self::get_instance();
|
267 |
|
275 |
return $settings_obj->set( $name, $value );
|
276 |
}
|
277 |
|
278 |
+
/**
|
279 |
+
* Register a module's validator controller.
|
280 |
+
*
|
281 |
+
* Only one validator per-module is supported.
|
282 |
+
*
|
283 |
+
* @param ITSEC_Validator $validator
|
284 |
+
*/
|
285 |
public static function register_validator( $validator ) {
|
286 |
$self = self::get_instance();
|
287 |
$self->_module_validators[ $validator->get_id() ] = $validator;
|
288 |
}
|
289 |
|
290 |
+
/**
|
291 |
+
* Retrieve the validator for a given module.
|
292 |
+
*
|
293 |
+
* This will load a module's validator component if not yet loaded.
|
294 |
+
*
|
295 |
+
* @param string $slug The module slug.
|
296 |
+
*
|
297 |
+
* @return ITSEC_Validator|null
|
298 |
+
*/
|
299 |
public static function get_validator( $slug ) {
|
300 |
$self = self::get_instance();
|
301 |
|
311 |
return $self->_module_validators[ $slug ];
|
312 |
}
|
313 |
|
314 |
+
/**
|
315 |
+
* Retrieve the slugs of all modules available to the plugin.
|
316 |
+
*
|
317 |
+
* This function is internally cached.
|
318 |
+
*
|
319 |
+
* @return string[]
|
320 |
+
*/
|
321 |
public static function get_available_modules() {
|
322 |
$self = self::get_instance();
|
323 |
|
334 |
return $self->_available_modules;
|
335 |
}
|
336 |
|
337 |
+
/**
|
338 |
+
* Retrieve the slugs of all active modules.
|
339 |
+
*
|
340 |
+
* This includes user activated and default activated modules. The result is internally cached.
|
341 |
+
*
|
342 |
+
* @return string[]
|
343 |
+
*/
|
344 |
public static function get_active_modules() {
|
345 |
$self = self::get_instance();
|
346 |
|
394 |
return $self->_active_modules_list;
|
395 |
}
|
396 |
|
397 |
+
/**
|
398 |
+
* Retrieve the slugs of all modules that are required to be active.
|
399 |
+
*
|
400 |
+
* @return string[]
|
401 |
+
*/
|
402 |
public static function get_always_active_modules() {
|
403 |
$self = self::get_instance();
|
404 |
return array_keys( $self->_always_active_modules );
|
405 |
}
|
406 |
|
407 |
+
/**
|
408 |
+
* Check if a module is configured to be always active.
|
409 |
+
*
|
410 |
+
* @param string $module_id The module slug.
|
411 |
+
*
|
412 |
+
* @return bool
|
413 |
+
*/
|
414 |
public static function is_always_active( $module_id ) {
|
415 |
$self = self::get_instance();
|
416 |
|
421 |
return false;
|
422 |
}
|
423 |
|
424 |
+
/**
|
425 |
+
* Check if a module is active.
|
426 |
+
*
|
427 |
+
* @param string $module_id The module slug.
|
428 |
+
*
|
429 |
+
* @return bool
|
430 |
+
*/
|
431 |
public static function is_active( $module_id ) {
|
432 |
$self = self::get_instance();
|
433 |
|
512 |
return $was_active;
|
513 |
}
|
514 |
|
515 |
+
/**
|
516 |
+
* Change the active and deactivate modules in bulk.
|
517 |
+
*
|
518 |
+
* The deactivation routine for no-longer active modules will NOT be run.
|
519 |
+
*
|
520 |
+
* @param string[] $new_active_modules
|
521 |
+
*
|
522 |
+
* @return bool
|
523 |
+
*/
|
524 |
public static function set_active_modules( $new_active_modules ) {
|
525 |
$self = self::get_instance();
|
526 |
|
549 |
return true;
|
550 |
}
|
551 |
|
552 |
+
/**
|
553 |
+
* Attempt to load a module(s)'s file.
|
554 |
+
*
|
555 |
+
* The file will only be loaded once and will not error if does not exist.
|
556 |
+
*
|
557 |
+
* @param string $file The file name to load, including extension.
|
558 |
+
* @param string|string[] $modules The modules to load the files from. Accepts either a module slug, an array of
|
559 |
+
* module slugs, ':all' to load the files from all modules, or ':active' to load the
|
560 |
+
* files from active modules.
|
561 |
+
*
|
562 |
+
* @return bool True if a module matching the $modules parameter is found, false otherwise.
|
563 |
+
*/
|
564 |
public static function load_module_file( $file, $modules = ':all' ) {
|
565 |
$self = self::get_instance();
|
566 |
|
567 |
if ( ':all' === $modules ) {
|
568 |
$modules = self::get_available_modules();
|
569 |
} else if ( ':active' === $modules ) {
|
570 |
+
if ( ITSEC_Core::is_temp_disable_modules_set() ) {
|
571 |
+
$modules = array();
|
572 |
+
} else {
|
573 |
+
$modules = self::get_active_modules();
|
574 |
+
}
|
575 |
|
576 |
$modules = array_merge( $modules, array_keys( $self->_always_active_modules ) );
|
577 |
$modules = array_unique( $modules );
|
590 |
return true;
|
591 |
}
|
592 |
|
593 |
+
/**
|
594 |
+
* Fires an action to begin the registration of modules.
|
595 |
+
*/
|
596 |
public static function init_modules() {
|
597 |
do_action( 'itsec-register-modules' );
|
598 |
}
|
599 |
|
600 |
+
/**
|
601 |
+
* Load and run all active modules.
|
602 |
+
*/
|
603 |
public static function run_active_modules() {
|
604 |
// The active.php file is for code that will only run when the module is active.
|
605 |
self::load_module_file( 'active.php', ':active' );
|
606 |
}
|
607 |
|
608 |
+
/**
|
609 |
+
* Run the activation routine for all registered modules.
|
610 |
+
*/
|
611 |
public function run_activation() {
|
612 |
self::load_module_file( 'setup.php' );
|
613 |
|
614 |
do_action( 'itsec_modules_do_plugin_activation' );
|
615 |
}
|
616 |
|
617 |
+
/**
|
618 |
+
* Run the deactivation routine for all registered modules.
|
619 |
+
*/
|
620 |
public function run_deactivation() {
|
621 |
self::load_module_file( 'setup.php' );
|
622 |
|
623 |
do_action( 'itsec_modules_do_plugin_deactivation' );
|
624 |
}
|
625 |
|
626 |
+
/**
|
627 |
+
* Run the uninstall routine for all registered modules.
|
628 |
+
*/
|
629 |
public static function run_uninstall() {
|
630 |
self::load_module_file( 'setup.php' );
|
631 |
|
632 |
do_action( 'itsec_modules_do_plugin_uninstall' );
|
633 |
}
|
634 |
|
635 |
+
/**
|
636 |
+
* Run the upgrade routine for all registered modules.
|
637 |
+
*
|
638 |
+
* @param int $old_version
|
639 |
+
* @param int $new_version
|
640 |
+
*/
|
641 |
public function run_upgrade( $old_version, $new_version ) {
|
642 |
self::load_module_file( 'setup.php' );
|
643 |
|
644 |
do_action( 'itsec_modules_do_plugin_upgrade', $old_version, $new_version );
|
645 |
}
|
646 |
|
647 |
+
/**
|
648 |
+
* Load the settings controller for all registered modules.
|
649 |
+
*
|
650 |
+
* This function can only be run once per-request.
|
651 |
+
*/
|
652 |
public function load_settings_page() {
|
653 |
if ( $this->_settings_files_loaded ) {
|
654 |
return;
|
core/modules/404-detection/class-itsec-four-oh-four.php
CHANGED
@@ -23,6 +23,7 @@ class ITSEC_Four_Oh_Four {
|
|
23 |
*/
|
24 |
public function check_404() {
|
25 |
|
|
|
26 |
global $itsec_logger, $itsec_lockout;
|
27 |
|
28 |
if ( ! is_404() ) {
|
23 |
*/
|
24 |
public function check_404() {
|
25 |
|
26 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
27 |
global $itsec_logger, $itsec_lockout;
|
28 |
|
29 |
if ( ! is_404() ) {
|
core/modules/admin-user/validator.php
CHANGED
@@ -139,6 +139,15 @@ final class ITSEC_Admin_User_Validator extends ITSEC_Validator {
|
|
139 |
$wpdb->query( "UPDATE `" . $wpdb->comments . "` SET user_id = '" . $new_user . "' WHERE user_id = 1;" );
|
140 |
$wpdb->query( "UPDATE `" . $wpdb->links . "` SET link_owner = '" . $new_user . "' WHERE link_owner = 1;" );
|
141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
$itsec_files->release_file_lock( 'admin_user' );
|
143 |
|
144 |
return true;
|
139 |
$wpdb->query( "UPDATE `" . $wpdb->comments . "` SET user_id = '" . $new_user . "' WHERE user_id = 1;" );
|
140 |
$wpdb->query( "UPDATE `" . $wpdb->links . "` SET link_owner = '" . $new_user . "' WHERE link_owner = 1;" );
|
141 |
|
142 |
+
/**
|
143 |
+
* Fires when the admin user with id of #1 has been changed.
|
144 |
+
*
|
145 |
+
* @since 6.3.0
|
146 |
+
*
|
147 |
+
* @param int $new_user The new user's ID.
|
148 |
+
*/
|
149 |
+
do_action( 'itsec_change_admin_user_id', $new_user );
|
150 |
+
|
151 |
$itsec_files->release_file_lock( 'admin_user' );
|
152 |
|
153 |
return true;
|
core/modules/away-mode/class-itsec-away-mode.php
CHANGED
@@ -51,6 +51,8 @@ final class ITSEC_Away_Mode {
|
|
51 |
}
|
52 |
}
|
53 |
|
|
|
|
|
54 |
if ( ! $details['has_active_file'] ) {
|
55 |
$details['active'] = false;
|
56 |
$details['remaining'] = false;
|
@@ -126,7 +128,7 @@ final class ITSEC_Away_Mode {
|
|
126 |
*
|
127 |
* @since 3.6.0
|
128 |
*
|
129 |
-
* @param Ithemes_Sync_API
|
130 |
*/
|
131 |
public function register_sync_verbs( $api ) {
|
132 |
$api->register( 'itsec-get-away-mode', 'Ithemes_Sync_Verb_ITSEC_Get_Away_Mode', dirname( __FILE__ ) . '/sync-verbs/itsec-get-away-mode.php' );
|
51 |
}
|
52 |
}
|
53 |
|
54 |
+
// If the active file does not exist, completely disable the away mode feature to allow an administrator
|
55 |
+
// to regain access to their site.
|
56 |
if ( ! $details['has_active_file'] ) {
|
57 |
$details['active'] = false;
|
58 |
$details['remaining'] = false;
|
128 |
*
|
129 |
* @since 3.6.0
|
130 |
*
|
131 |
+
* @param Ithemes_Sync_API $api API object.
|
132 |
*/
|
133 |
public function register_sync_verbs( $api ) {
|
134 |
$api->register( 'itsec-get-away-mode', 'Ithemes_Sync_Verb_ITSEC_Get_Away_Mode', dirname( __FILE__ ) . '/sync-verbs/itsec-get-away-mode.php' );
|
core/modules/away-mode/utilities.php
CHANGED
@@ -1,6 +1,12 @@
|
|
1 |
<?php
|
2 |
|
3 |
final class ITSEC_Away_Mode_Utilities {
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
public static function has_active_file() {
|
5 |
if ( @file_exists( self::get_active_file_name() ) ) {
|
6 |
return true;
|
@@ -9,6 +15,11 @@ final class ITSEC_Away_Mode_Utilities {
|
|
9 |
}
|
10 |
}
|
11 |
|
|
|
|
|
|
|
|
|
|
|
12 |
public static function create_active_file() {
|
13 |
if ( self::has_active_file() ) {
|
14 |
return true;
|
@@ -25,6 +36,11 @@ final class ITSEC_Away_Mode_Utilities {
|
|
25 |
}
|
26 |
}
|
27 |
|
|
|
|
|
|
|
|
|
|
|
28 |
public static function delete_active_file() {
|
29 |
if ( ! self::has_active_file() ) {
|
30 |
return true;
|
@@ -35,12 +51,26 @@ final class ITSEC_Away_Mode_Utilities {
|
|
35 |
return @unlink( $file );
|
36 |
}
|
37 |
|
|
|
|
|
|
|
|
|
|
|
38 |
public static function get_active_file_name() {
|
39 |
$file_name = apply_filters( 'itsec_filer_away_mode_active_file', ITSEC_Core::get_storage_dir() . '/itsec_away.confg' );
|
40 |
|
41 |
return $file_name;
|
42 |
}
|
43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
public static function is_current_timestamp_active( $start, $end, $include_details = false ) {
|
45 |
$now = ITSEC_Core::get_current_time_gmt();
|
46 |
|
@@ -80,6 +110,15 @@ final class ITSEC_Away_Mode_Utilities {
|
|
80 |
return compact( 'active', 'remaining', 'next', 'length', 'error' );
|
81 |
}
|
82 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
public static function is_current_time_active( $start, $end, $include_details = false ) {
|
84 |
$current_time = ITSEC_Core::get_current_time();
|
85 |
$now = $current_time - strtotime( date( 'Y-m-d', $current_time ) );
|
1 |
<?php
|
2 |
|
3 |
final class ITSEC_Away_Mode_Utilities {
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Check if the config file signaling away mode is active exists.
|
7 |
+
*
|
8 |
+
* @return bool
|
9 |
+
*/
|
10 |
public static function has_active_file() {
|
11 |
if ( @file_exists( self::get_active_file_name() ) ) {
|
12 |
return true;
|
15 |
}
|
16 |
}
|
17 |
|
18 |
+
/**
|
19 |
+
* Create a config file specifying that away mode is active.
|
20 |
+
*
|
21 |
+
* @return bool
|
22 |
+
*/
|
23 |
public static function create_active_file() {
|
24 |
if ( self::has_active_file() ) {
|
25 |
return true;
|
36 |
}
|
37 |
}
|
38 |
|
39 |
+
/**
|
40 |
+
* Delete the config file specifying that away mode is active.
|
41 |
+
*
|
42 |
+
* @return bool
|
43 |
+
*/
|
44 |
public static function delete_active_file() {
|
45 |
if ( ! self::has_active_file() ) {
|
46 |
return true;
|
51 |
return @unlink( $file );
|
52 |
}
|
53 |
|
54 |
+
/**
|
55 |
+
* Get the file name for the config file specifying that away mode is active,
|
56 |
+
*
|
57 |
+
* @return string
|
58 |
+
*/
|
59 |
public static function get_active_file_name() {
|
60 |
$file_name = apply_filters( 'itsec_filer_away_mode_active_file', ITSEC_Core::get_storage_dir() . '/itsec_away.confg' );
|
61 |
|
62 |
return $file_name;
|
63 |
}
|
64 |
|
65 |
+
/**
|
66 |
+
* Check if the current UTC time falls between the two specified times, inclusive.
|
67 |
+
*
|
68 |
+
* @param int $start The UTC timestamp signalling the beginning of the active window.
|
69 |
+
* @param int $end The UTC timestamp signalling the end of the active window.
|
70 |
+
* @param bool $include_details Whether to include additional details about the active window.
|
71 |
+
*
|
72 |
+
* @return array|bool
|
73 |
+
*/
|
74 |
public static function is_current_timestamp_active( $start, $end, $include_details = false ) {
|
75 |
$now = ITSEC_Core::get_current_time_gmt();
|
76 |
|
110 |
return compact( 'active', 'remaining', 'next', 'length', 'error' );
|
111 |
}
|
112 |
|
113 |
+
/**
|
114 |
+
* Check if the current local time falls between the two specified times, inclusive.
|
115 |
+
*
|
116 |
+
* @param int $start The local timestamp signalling the beginning of the active window.
|
117 |
+
* @param int $end The local timestamp signalling the end of the active window.
|
118 |
+
* @param bool $include_details Whether to include additional details about the active window.
|
119 |
+
*
|
120 |
+
* @return array|bool
|
121 |
+
*/
|
122 |
public static function is_current_time_active( $start, $end, $include_details = false ) {
|
123 |
$current_time = ITSEC_Core::get_current_time();
|
124 |
$now = $current_time - strtotime( date( 'Y-m-d', $current_time ) );
|
core/modules/backup/class-itsec-backup.php
CHANGED
@@ -233,7 +233,7 @@ class ITSEC_Backup {
|
|
233 |
if ( 1 === $this->settings['method'] ) {
|
234 |
@unlink( $file );
|
235 |
} else if ( $this->settings['retain'] > 0 ) {
|
236 |
-
$files = scandir( $dir,
|
237 |
|
238 |
if ( is_array( $files ) && count( $files ) > 0 ) {
|
239 |
$count = 0;
|
233 |
if ( 1 === $this->settings['method'] ) {
|
234 |
@unlink( $file );
|
235 |
} else if ( $this->settings['retain'] > 0 ) {
|
236 |
+
$files = scandir( $dir, 1 );
|
237 |
|
238 |
if ( is_array( $files ) && count( $files ) > 0 ) {
|
239 |
$count = 0;
|
core/modules/ban-users/lists/hackrepair-apache.inc
CHANGED
@@ -125,7 +125,6 @@ RewriteCond %{HTTP_USER_AGENT} "^Xaldon WebSpider" [NC,OR]
|
|
125 |
RewriteCond %{HTTP_USER_AGENT} "^Zeus" [NC,OR]
|
126 |
RewriteCond %{HTTP_USER_AGENT} "^zmeu" [NC,OR]
|
127 |
RewriteCond %{HTTP_USER_AGENT} "360Spider" [NC,OR]
|
128 |
-
RewriteCond %{HTTP_USER_AGENT} "AhrefsBot" [NC,OR]
|
129 |
RewriteCond %{HTTP_USER_AGENT} "CazoodleBot" [NC,OR]
|
130 |
RewriteCond %{HTTP_USER_AGENT} "discobot" [NC,OR]
|
131 |
RewriteCond %{HTTP_USER_AGENT} "EasouSpider" [NC,OR]
|
125 |
RewriteCond %{HTTP_USER_AGENT} "^Zeus" [NC,OR]
|
126 |
RewriteCond %{HTTP_USER_AGENT} "^zmeu" [NC,OR]
|
127 |
RewriteCond %{HTTP_USER_AGENT} "360Spider" [NC,OR]
|
|
|
128 |
RewriteCond %{HTTP_USER_AGENT} "CazoodleBot" [NC,OR]
|
129 |
RewriteCond %{HTTP_USER_AGENT} "discobot" [NC,OR]
|
130 |
RewriteCond %{HTTP_USER_AGENT} "EasouSpider" [NC,OR]
|
core/modules/ban-users/lists/hackrepair-litespeed.inc
CHANGED
@@ -125,7 +125,6 @@ RewriteCond %{HTTP_USER_AGENT} "^Xaldon WebSpider" [NC,OR]
|
|
125 |
RewriteCond %{HTTP_USER_AGENT} "^Zeus" [NC,OR]
|
126 |
RewriteCond %{HTTP_USER_AGENT} "^zmeu" [NC,OR]
|
127 |
RewriteCond %{HTTP_USER_AGENT} "360Spider" [NC,OR]
|
128 |
-
RewriteCond %{HTTP_USER_AGENT} "AhrefsBot" [NC,OR]
|
129 |
RewriteCond %{HTTP_USER_AGENT} "CazoodleBot" [NC,OR]
|
130 |
RewriteCond %{HTTP_USER_AGENT} "discobot" [NC,OR]
|
131 |
RewriteCond %{HTTP_USER_AGENT} "EasouSpider" [NC,OR]
|
125 |
RewriteCond %{HTTP_USER_AGENT} "^Zeus" [NC,OR]
|
126 |
RewriteCond %{HTTP_USER_AGENT} "^zmeu" [NC,OR]
|
127 |
RewriteCond %{HTTP_USER_AGENT} "360Spider" [NC,OR]
|
|
|
128 |
RewriteCond %{HTTP_USER_AGENT} "CazoodleBot" [NC,OR]
|
129 |
RewriteCond %{HTTP_USER_AGENT} "discobot" [NC,OR]
|
130 |
RewriteCond %{HTTP_USER_AGENT} "EasouSpider" [NC,OR]
|
core/modules/ban-users/lists/hackrepair-nginx.inc
CHANGED
@@ -124,7 +124,6 @@ if ($http_user_agent ~* "^Xaldon WebSpider"){return 403;}
|
|
124 |
if ($http_user_agent ~* "^Zeus"){return 403;}
|
125 |
if ($http_user_agent ~* "^zmeu"){return 403;}
|
126 |
if ($http_user_agent ~* "360Spider"){return 403;}
|
127 |
-
if ($http_user_agent ~* "AhrefsBot"){return 403;}
|
128 |
if ($http_user_agent ~* "CazoodleBot"){return 403;}
|
129 |
if ($http_user_agent ~* "discobot"){return 403;}
|
130 |
if ($http_user_agent ~* "EasouSpider"){return 403;}
|
124 |
if ($http_user_agent ~* "^Zeus"){return 403;}
|
125 |
if ($http_user_agent ~* "^zmeu"){return 403;}
|
126 |
if ($http_user_agent ~* "360Spider"){return 403;}
|
|
|
127 |
if ($http_user_agent ~* "CazoodleBot"){return 403;}
|
128 |
if ($http_user_agent ~* "discobot"){return 403;}
|
129 |
if ($http_user_agent ~* "EasouSpider"){return 403;}
|
core/modules/brute-force/class-itsec-brute-force.php
CHANGED
@@ -35,6 +35,8 @@ class ITSEC_Brute_Force {
|
|
35 |
*/
|
36 |
public function authenticate( $user, $username = '', $password = '' ) {
|
37 |
|
|
|
|
|
38 |
global $itsec_lockout, $itsec_logger;
|
39 |
|
40 |
//Look for the "admin" user name and ban it if it is set to auto-ban
|
@@ -151,6 +153,7 @@ class ITSEC_Brute_Force {
|
|
151 |
*/
|
152 |
public function wp_login( $username, $user = null ) {
|
153 |
|
|
|
154 |
global $itsec_lockout;
|
155 |
|
156 |
if ( ! $user === null ) {
|
@@ -177,6 +180,8 @@ class ITSEC_Brute_Force {
|
|
177 |
* @return void
|
178 |
*/
|
179 |
public function handle_failed_login( $username, $details ) {
|
|
|
|
|
180 |
global $itsec_lockout, $itsec_logger;
|
181 |
|
182 |
$user_id = username_exists( $username );
|
35 |
*/
|
36 |
public function authenticate( $user, $username = '', $password = '' ) {
|
37 |
|
38 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
39 |
+
/** @var ITSEC_Logger $itsec_logger */
|
40 |
global $itsec_lockout, $itsec_logger;
|
41 |
|
42 |
//Look for the "admin" user name and ban it if it is set to auto-ban
|
153 |
*/
|
154 |
public function wp_login( $username, $user = null ) {
|
155 |
|
156 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
157 |
global $itsec_lockout;
|
158 |
|
159 |
if ( ! $user === null ) {
|
180 |
* @return void
|
181 |
*/
|
182 |
public function handle_failed_login( $username, $details ) {
|
183 |
+
|
184 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
185 |
global $itsec_lockout, $itsec_logger;
|
186 |
|
187 |
$user_id = username_exists( $username );
|
core/modules/content-directory/settings-page.php
CHANGED
@@ -53,7 +53,7 @@ final class ITSEC_Content_Directory_Settings_Page extends ITSEC_Module_Settings_
|
|
53 |
<?php if ( ITSEC_Content_Directory_Utility::is_custom_directory() || ITSEC_Content_Directory_Utility::is_modified_by_it_security() ) : ?>
|
54 |
<?php $this->show_current_wp_content_dir(); ?>
|
55 |
|
56 |
-
<div class="itsec-warning-message"><?php printf( __( '<span>IMPORTANT:</span> Ensure that you <a href="%s">create a database backup</a> before undoing the Content Directory change.', 'better-wp-security' ), ITSEC_Core::get_backup_creation_page_url() ); ?></div>
|
57 |
<div class="itsec-warning-message"><?php _e( '<span>WARNING:</span> Undoing the Content Directory change when images and other content were added after the change <strong>will break your site</strong>. Only undo the Content Directory change if absolutely necessary.', 'better-wp-security' ); ?></div>
|
58 |
|
59 |
<table class="form-table itsec-settings-section">
|
53 |
<?php if ( ITSEC_Content_Directory_Utility::is_custom_directory() || ITSEC_Content_Directory_Utility::is_modified_by_it_security() ) : ?>
|
54 |
<?php $this->show_current_wp_content_dir(); ?>
|
55 |
|
56 |
+
<div class="itsec-warning-message"><?php printf( __( '<span>IMPORTANT:</span> Ensure that you <a href="%s" data-module-link="backup">create a database backup</a> before undoing the Content Directory change.', 'better-wp-security' ), ITSEC_Core::get_backup_creation_page_url() ); ?></div>
|
57 |
<div class="itsec-warning-message"><?php _e( '<span>WARNING:</span> Undoing the Content Directory change when images and other content were added after the change <strong>will break your site</strong>. Only undo the Content Directory change if absolutely necessary.', 'better-wp-security' ); ?></div>
|
58 |
|
59 |
<table class="form-table itsec-settings-section">
|
core/modules/database-prefix/settings-page.php
CHANGED
@@ -18,7 +18,7 @@ final class ITSEC_Database_Prefix_Settings_Page extends ITSEC_Module_Settings_Pa
|
|
18 |
?>
|
19 |
<p><?php _e( 'By default, WordPress assigns the prefix <code>wp_</code> to all tables in the database where your content, users, and objects exist. For potential attackers, this means it is easier to write scripts that can target WordPress databases as all the important table names for 95% of sites are already known. Changing the <code>wp_</code> prefix makes it more difficult for tools that are trying to take advantage of vulnerabilities in other places to affect the database of your site. <strong>Before using this tool, we strongly recommend creating a backup of your database.</strong>', 'better-wp-security' ); ?></p>
|
20 |
<p><?php _e( 'Note: The use of this tool requires quite a bit of system memory which may be more than some hosts can handle. If you back your database up you can\'t do any permanent damage but without a proper backup you risk breaking your site and having to perform a rather difficult fix.', 'better-wp-security' ); ?></p>
|
21 |
-
<div class="itsec-warning-message"><?php printf( __( '<span>WARNING: </span><a href="%1$s">Backup your database</a> before using this tool.', 'better-wp-security' ), ITSEC_Core::get_backup_creation_page_url() ); ?></div>
|
22 |
<?php
|
23 |
|
24 |
}
|
18 |
?>
|
19 |
<p><?php _e( 'By default, WordPress assigns the prefix <code>wp_</code> to all tables in the database where your content, users, and objects exist. For potential attackers, this means it is easier to write scripts that can target WordPress databases as all the important table names for 95% of sites are already known. Changing the <code>wp_</code> prefix makes it more difficult for tools that are trying to take advantage of vulnerabilities in other places to affect the database of your site. <strong>Before using this tool, we strongly recommend creating a backup of your database.</strong>', 'better-wp-security' ); ?></p>
|
20 |
<p><?php _e( 'Note: The use of this tool requires quite a bit of system memory which may be more than some hosts can handle. If you back your database up you can\'t do any permanent damage but without a proper backup you risk breaking your site and having to perform a rather difficult fix.', 'better-wp-security' ); ?></p>
|
21 |
+
<div class="itsec-warning-message"><?php printf( __( '<span>WARNING: </span><a href="%1$s" data-module-link="backup">Backup your database</a> before using this tool.', 'better-wp-security' ), ITSEC_Core::get_backup_creation_page_url() ); ?></div>
|
22 |
<?php
|
23 |
|
24 |
}
|
core/modules/database-prefix/utility.php
CHANGED
@@ -51,7 +51,7 @@ final class ITSEC_Database_Prefix_Utility {
|
|
51 |
|
52 |
if ( is_wp_error( $config ) ) {
|
53 |
/* translators: 1: Specific error details */
|
54 |
-
$response['errors'][] = new WP_Error( $
|
55 |
return $response;
|
56 |
}
|
57 |
|
@@ -63,7 +63,7 @@ final class ITSEC_Database_Prefix_Utility {
|
|
63 |
|
64 |
if ( is_wp_error( $write_result ) ) {
|
65 |
/* translators: 1: Specific error details */
|
66 |
-
$response['errors'][] = new WP_Error( $
|
67 |
return $response;
|
68 |
}
|
69 |
|
51 |
|
52 |
if ( is_wp_error( $config ) ) {
|
53 |
/* translators: 1: Specific error details */
|
54 |
+
$response['errors'][] = new WP_Error( $config->get_error_code(), sprintf( __( 'Unable to read the <code>wp-config.php</code> file in order to update the Database Prefix. Error details as follows: %1$s', 'better-wp-security' ), $config->get_error_message() ) );
|
55 |
return $response;
|
56 |
}
|
57 |
|
63 |
|
64 |
if ( is_wp_error( $write_result ) ) {
|
65 |
/* translators: 1: Specific error details */
|
66 |
+
$response['errors'][] = new WP_Error( $write_result->get_error_code(), sprintf( __( 'Unable to update the <code>wp-config.php</code> file in order to update the Database Prefix. Error details as follows: %1$s', 'better-wp-security' ), $config->get_error_message() ) );
|
67 |
return $response;
|
68 |
}
|
69 |
|
core/modules/file-change/class-itsec-file-change.php
CHANGED
@@ -164,7 +164,7 @@ class ITSEC_File_Change {
|
|
164 |
*
|
165 |
* @since 3.6.0
|
166 |
*
|
167 |
-
* @param Ithemes_Sync_API Sync API object.
|
168 |
*/
|
169 |
public function register_sync_verbs( $api ) {
|
170 |
$api->register( 'itsec-perform-file-scan', 'Ithemes_Sync_Verb_ITSEC_Perform_File_Scan', dirname( __FILE__ ) . '/sync-verbs/itsec-perform-file-scan.php' );
|
164 |
*
|
165 |
* @since 3.6.0
|
166 |
*
|
167 |
+
* @param Ithemes_Sync_API $api Sync API object.
|
168 |
*/
|
169 |
public function register_sync_verbs( $api ) {
|
170 |
$api->register( 'itsec-perform-file-scan', 'Ithemes_Sync_Verb_ITSEC_Perform_File_Scan', dirname( __FILE__ ) . '/sync-verbs/itsec-perform-file-scan.php' );
|
core/modules/global/active.php
CHANGED
@@ -10,6 +10,11 @@ function itsec_global_add_notice() {
|
|
10 |
if ( ITSEC_Modules::get_setting( 'global', 'show_new_dashboard_notice' ) && current_user_can( ITSEC_Core::get_required_cap() ) ) {
|
11 |
ITSEC_Core::add_notice( 'itsec_global_show_new_dashboard_notice' );
|
12 |
}
|
|
|
|
|
|
|
|
|
|
|
13 |
}
|
14 |
add_action( 'admin_init', 'itsec_global_add_notice', 0 );
|
15 |
|
@@ -54,3 +59,7 @@ function itsec_network_brute_force_dismiss_notice() {
|
|
54 |
wp_send_json_error();
|
55 |
}
|
56 |
add_action( 'wp_ajax_itsec-dismiss-notice-brute_force_network', 'itsec_network_brute_force_dismiss_notice' );
|
|
|
|
|
|
|
|
10 |
if ( ITSEC_Modules::get_setting( 'global', 'show_new_dashboard_notice' ) && current_user_can( ITSEC_Core::get_required_cap() ) ) {
|
11 |
ITSEC_Core::add_notice( 'itsec_global_show_new_dashboard_notice' );
|
12 |
}
|
13 |
+
|
14 |
+
if ( ITSEC_Core::is_temp_disable_modules_set() && ITSEC_Core::current_user_can_manage() ) {
|
15 |
+
ITSEC_Core::add_notice( 'itsec_show_temp_disable_modules_notice', true );
|
16 |
+
}
|
17 |
+
|
18 |
}
|
19 |
add_action( 'admin_init', 'itsec_global_add_notice', 0 );
|
20 |
|
59 |
wp_send_json_error();
|
60 |
}
|
61 |
add_action( 'wp_ajax_itsec-dismiss-notice-brute_force_network', 'itsec_network_brute_force_dismiss_notice' );
|
62 |
+
|
63 |
+
function itsec_show_temp_disable_modules_notice() {
|
64 |
+
ITSEC_Lib::show_error_message( esc_html__( 'The ITSEC_DISABLE_MODULES define is set. All iThemes Security protections are disabled. Please make the necessary settings changes and remove the define as quickly as possible.', 'better-wp-security' ) );
|
65 |
+
}
|
core/modules/global/settings-page.php
CHANGED
@@ -248,7 +248,7 @@ final class ITSEC_Global_Settings_Page extends ITSEC_Module_Settings_Page {
|
|
248 |
<td>
|
249 |
<?php $form->add_checkbox( 'lock_file' ); ?>
|
250 |
<label for="itsec-global-lock_file"><?php _e( 'Disable File Locking', 'better-wp-security' ); ?></label>
|
251 |
-
<p class="description"><?php _e( '
|
252 |
</td>
|
253 |
</tr>
|
254 |
<tr>
|
248 |
<td>
|
249 |
<?php $form->add_checkbox( 'lock_file' ); ?>
|
250 |
<label for="itsec-global-lock_file"><?php _e( 'Disable File Locking', 'better-wp-security' ); ?></label>
|
251 |
+
<p class="description"><?php _e( 'iThemes Security uses file locking to prevent operations from being executed twice. We do not recommend disabling file locking unless your host prevents it from working correctly.', 'better-wp-security' ); ?></p>
|
252 |
</td>
|
253 |
</tr>
|
254 |
<tr>
|
core/modules/hide-backend/class-itsec-hide-backend.php
CHANGED
@@ -1,357 +1,353 @@
|
|
1 |
<?php
|
2 |
|
3 |
class ITSEC_Hide_Backend {
|
|
|
|
|
4 |
|
5 |
-
private
|
6 |
-
$settings,
|
7 |
-
$auth_cookie_expired;
|
8 |
-
|
9 |
-
function run() {
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
$this->settings = ITSEC_Modules::get_settings( 'hide-backend' );
|
12 |
|
13 |
-
add_filter( 'itsec_filter_apache_server_config_modification', array( $this, 'filter_apache_server_config_modification' ) );
|
14 |
-
add_filter( 'itsec_filter_litespeed_server_config_modification', array( $this, 'filter_apache_server_config_modification' ) );
|
15 |
-
add_filter( 'itsec_filter_nginx_server_config_modification', array( $this, 'filter_nginx_server_config_modification' ) );
|
16 |
-
|
17 |
if ( ! $this->settings['enabled'] ) {
|
18 |
return;
|
19 |
}
|
20 |
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
if ( is_multisite() && function_exists( 'is_plugin_active_for_network' ) ) { //see if Jetpack is active
|
25 |
|
26 |
-
|
|
|
|
|
|
|
27 |
|
28 |
-
|
29 |
-
|
30 |
-
$is_jetpack_active = in_array( 'jetpack/jetpack.php', (array) get_option( 'active_plugins', array() ) );
|
31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
}
|
33 |
|
34 |
-
|
35 |
-
|
36 |
-
$
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
$_GET['action'] == 'jetpack_json_api_authorization'
|
41 |
-
)
|
42 |
-
) {
|
43 |
-
|
44 |
-
$this->auth_cookie_expired = false;
|
45 |
-
|
46 |
-
add_action( 'auth_cookie_expired', array( $this, 'auth_cookie_expired' ) );
|
47 |
-
add_action( 'init', array( $this, 'execute_hide_backend' ), 1000 );
|
48 |
-
add_action( 'login_init', array( $this, 'execute_hide_backend_login' ) );
|
49 |
-
add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 11 );
|
50 |
-
|
51 |
-
add_filter( 'body_class', array( $this, 'remove_admin_bar' ) );
|
52 |
-
add_filter( 'loginout', array( $this, 'filter_loginout' ) );
|
53 |
-
add_filter( 'wp_redirect', array( $this, 'filter_login_url' ), 10, 2 );
|
54 |
-
add_filter( 'lostpassword_url', array( $this, 'filter_login_url' ), 10, 2 );
|
55 |
-
add_filter( 'site_url', array( $this, 'filter_login_url' ), 10, 2 );
|
56 |
-
add_filter( 'retrieve_password_message', array( $this, 'retrieve_password_message' ) );
|
57 |
-
add_filter( 'comment_moderation_text', array( $this, 'comment_moderation_text' ) );
|
58 |
-
|
59 |
-
remove_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
|
60 |
-
|
61 |
}
|
62 |
|
63 |
-
|
64 |
-
|
65 |
-
public function filter_apache_server_config_modification( $modification ) {
|
66 |
-
require_once( dirname( __FILE__ ) . '/config-generators.php' );
|
67 |
-
|
68 |
-
return ITSEC_Hide_Backend_Config_Generators::filter_apache_server_config_modification( $modification );
|
69 |
-
}
|
70 |
-
|
71 |
-
public function filter_nginx_server_config_modification( $modification ) {
|
72 |
-
require_once( dirname( __FILE__ ) . '/config-generators.php' );
|
73 |
-
|
74 |
-
return ITSEC_Hide_Backend_Config_Generators::filter_nginx_server_config_modification( $modification );
|
75 |
}
|
76 |
|
77 |
/**
|
78 |
-
*
|
79 |
*
|
80 |
-
*
|
|
|
|
|
|
|
|
|
81 |
*
|
82 |
* @return void
|
83 |
*/
|
84 |
-
public function
|
|
|
|
|
|
|
85 |
|
86 |
-
$
|
87 |
-
wp_clear_auth_cookie();
|
88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
}
|
90 |
|
91 |
/**
|
92 |
-
*
|
93 |
*
|
94 |
-
* @
|
95 |
-
*
|
96 |
-
* @param sting $notify_message Notification message
|
97 |
-
*
|
98 |
-
* @return string Notification message
|
99 |
*/
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
if ( isset( $urls ) && is_array( $urls ) && isset( $urls[0] ) ) {
|
105 |
-
|
106 |
-
foreach ( $urls[0] as $url ) {
|
107 |
-
|
108 |
-
$notify_message = str_replace( trim( $url ), wp_login_url( trim( $url ) ), $notify_message );
|
109 |
-
|
110 |
-
}
|
111 |
-
|
112 |
}
|
113 |
|
114 |
-
|
115 |
-
|
116 |
}
|
117 |
|
118 |
/**
|
119 |
-
*
|
120 |
-
*
|
121 |
-
* @since 4.0
|
122 |
*
|
123 |
* @return void
|
124 |
*/
|
125 |
-
|
126 |
-
|
127 |
-
if ( get_site_option( 'users_can_register' ) == 1 && isset( $_SERVER['REQUEST_URI'] ) && $_SERVER['REQUEST_URI'] == ITSEC_Lib::get_home_root() . $this->settings['register'] ) {
|
128 |
-
|
129 |
-
wp_redirect( wp_login_url() . '?action=register' );
|
130 |
-
exit;
|
131 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
}
|
133 |
|
134 |
-
|
135 |
-
|
136 |
-
(
|
137 |
-
(
|
138 |
-
get_site_option( 'users_can_register' ) == false &&
|
139 |
-
(
|
140 |
-
isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], 'wp-register.php' ) ||
|
141 |
-
isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], 'wp-signup.php' )
|
142 |
-
)
|
143 |
-
) ||
|
144 |
-
(
|
145 |
-
isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) && is_user_logged_in() !== true
|
146 |
-
) ||
|
147 |
-
( is_admin() && is_user_logged_in() !== true ) ||
|
148 |
-
(
|
149 |
-
$this->settings['register'] != 'wp-register.php' &&
|
150 |
-
strpos( $_SERVER['REQUEST_URI'], 'wp-register.php' ) !== false ||
|
151 |
-
strpos( $_SERVER['REQUEST_URI'], 'wp-signup.php' ) !== false ||
|
152 |
-
(
|
153 |
-
isset( $_REQUEST['redirect_to'] ) &&
|
154 |
-
strpos( $_REQUEST['redirect_to'], 'wp-admin/customize.php' ) !== false
|
155 |
-
|
156 |
-
)
|
157 |
-
)
|
158 |
-
) &&
|
159 |
-
strpos( $_SERVER['REQUEST_URI'], 'admin-ajax.php' ) === false
|
160 |
-
&& $this->auth_cookie_expired === false
|
161 |
-
) {
|
162 |
-
|
163 |
-
global $itsec_is_old_admin;
|
164 |
-
|
165 |
-
$itsec_is_old_admin = true;
|
166 |
-
|
167 |
-
if ( isset( $this->settings['theme_compat'] ) && $this->settings['theme_compat'] === true ) { //theme compat (process theme and redirect to a 404)
|
168 |
-
|
169 |
-
wp_redirect( ITSEC_Lib::get_home_root() . sanitize_title( isset( $this->settings['theme_compat_slug'] ) ? $this->settings['theme_compat_slug'] : 'not_found' ), 302 );
|
170 |
-
exit;
|
171 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
172 |
} else {
|
173 |
-
|
174 |
-
// Throw a 403 forbidden
|
175 |
-
wp_die( __( 'This has been disabled.', 'better-wp-security' ), 403 );
|
176 |
-
|
177 |
}
|
178 |
-
|
179 |
}
|
|
|
180 |
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
if ( isset( $this->settings['post_logout_slug'] ) && strlen( trim( $this->settings['post_logout_slug'] ) ) > 0 && isset( $_GET['action'] ) && sanitize_text_field( $_GET['action'] ) == trim( $this->settings['post_logout_slug'] ) ) {
|
191 |
-
do_action( 'itsec_custom_login_slug' ); //add hook here for custom users
|
192 |
-
}
|
193 |
-
|
194 |
-
//suppress error messages due to timing
|
195 |
-
error_reporting( 0 );
|
196 |
-
@ini_set( 'display_errors', 0 );
|
197 |
-
|
198 |
-
status_header( 200 );
|
199 |
-
|
200 |
-
//don't allow domain mapping to redirect
|
201 |
-
if ( defined( 'DOMAIN_MAPPING' ) && DOMAIN_MAPPING == 1 ) {
|
202 |
-
remove_action( 'login_head', 'redirect_login_to_orig' );
|
203 |
-
}
|
204 |
-
|
205 |
-
if ( ! function_exists( 'login_header' ) ) {
|
206 |
-
|
207 |
-
include( ABSPATH . 'wp-login.php' );
|
208 |
-
exit;
|
209 |
-
|
210 |
-
}
|
211 |
-
|
212 |
-
} elseif ( ! isset( $_GET['action'] ) || ( sanitize_text_field( $_GET['action'] ) != 'logout' && sanitize_text_field( $_GET['action'] ) != 'postpass' && ( isset( $this->settings['post_logout_slug'] ) && strlen( trim( $this->settings['post_logout_slug'] ) ) > 0 && sanitize_text_field( $_GET['action'] ) != trim( $this->settings['post_logout_slug'] ) ) ) ) {
|
213 |
-
//Just redirect them to the dashboard (for logged in users)
|
214 |
-
|
215 |
-
if ( $this->auth_cookie_expired === false ) {
|
216 |
-
|
217 |
-
wp_redirect( get_admin_url() );
|
218 |
-
exit();
|
219 |
-
|
220 |
-
}
|
221 |
-
|
222 |
-
} elseif ( isset( $_GET['action'] ) && ( sanitize_text_field( $_GET['action'] ) == 'postpass' || ( isset( $this->settings['post_logout_slug'] ) && strlen( trim( $this->settings['post_logout_slug'] ) ) > 0 && sanitize_text_field( $_GET['action'] ) == trim( $this->settings['post_logout_slug'] ) ) ) ) {
|
223 |
-
//handle private posts for
|
224 |
-
|
225 |
-
if ( isset( $this->settings['post_logout_slug'] ) && strlen( trim( $this->settings['post_logout_slug'] ) ) > 0 && sanitize_text_field( $_GET['action'] ) == trim( $this->settings['post_logout_slug'] ) ) {
|
226 |
-
do_action( 'itsec_custom_login_slug' ); //add hook here for custom users
|
227 |
-
}
|
228 |
-
|
229 |
-
//suppress error messages due to timing
|
230 |
-
error_reporting( 0 );
|
231 |
-
@ini_set( 'display_errors', 0 );
|
232 |
-
|
233 |
-
status_header( 200 ); //its a good login page. make sure we say so
|
234 |
-
|
235 |
-
//include the login page where we need it
|
236 |
-
if ( ! function_exists( 'login_header' ) ) {
|
237 |
-
include( ABSPATH . '/wp-login.php' );
|
238 |
-
exit;
|
239 |
-
}
|
240 |
-
|
241 |
-
//Take them back to the page if we need to
|
242 |
-
if ( isset( $_SERVER['HTTP_REFERRER'] ) ) {
|
243 |
-
wp_redirect( sanitize_text_field( $_SERVER['HTTP_REFERRER'] ) );
|
244 |
-
exit();
|
245 |
-
}
|
246 |
|
247 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
|
|
|
|
|
|
|
249 |
}
|
250 |
|
|
|
251 |
}
|
252 |
|
253 |
/**
|
254 |
-
*
|
|
|
|
|
255 |
*
|
256 |
* @return void
|
257 |
*/
|
258 |
-
public function
|
|
|
|
|
|
|
259 |
|
260 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
261 |
|
262 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
|
264 |
-
|
|
|
|
|
|
|
265 |
|
266 |
-
|
|
|
267 |
|
|
|
|
|
|
|
|
|
268 |
}
|
269 |
|
|
|
|
|
270 |
}
|
271 |
|
272 |
/**
|
273 |
-
*
|
274 |
-
*
|
275 |
-
* @since 4.0
|
276 |
*
|
277 |
-
* @param
|
|
|
278 |
*
|
279 |
-
* @return string
|
280 |
*/
|
281 |
-
public function
|
|
|
|
|
|
|
|
|
|
|
282 |
|
283 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
284 |
|
|
|
285 |
}
|
286 |
|
287 |
/**
|
288 |
-
* Filter
|
289 |
*
|
290 |
-
* @
|
291 |
*
|
292 |
-
* @
|
293 |
-
*
|
294 |
-
* @return string the link
|
295 |
*/
|
296 |
-
public function
|
297 |
-
|
298 |
-
return str_replace( 'wp-login.php', $this->settings['slug'], $link );
|
299 |
-
|
300 |
}
|
301 |
|
302 |
/**
|
303 |
-
*
|
304 |
*
|
305 |
-
*
|
|
|
306 |
*
|
307 |
-
* @return
|
308 |
*/
|
309 |
-
|
|
|
310 |
|
311 |
-
|
|
|
312 |
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
$redirect_to = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?loggedout=true';
|
317 |
-
wp_safe_redirect( $redirect_to );
|
318 |
-
exit();
|
319 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
320 |
}
|
321 |
-
|
322 |
}
|
323 |
|
324 |
/**
|
325 |
-
*
|
326 |
*
|
327 |
-
* @param
|
|
|
328 |
*
|
329 |
-
* @return
|
330 |
*/
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
foreach ( $classes as $key => $value ) {
|
336 |
-
|
337 |
-
if ( $value == 'admin-bar' ) {
|
338 |
-
unset( $classes[ $key ] );
|
339 |
-
}
|
340 |
-
|
341 |
-
}
|
342 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
343 |
}
|
344 |
|
345 |
-
return
|
346 |
-
|
347 |
}
|
348 |
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
354 |
|
|
|
355 |
}
|
356 |
-
|
357 |
}
|
1 |
<?php
|
2 |
|
3 |
class ITSEC_Hide_Backend {
|
4 |
+
private $disable_filters = false;
|
5 |
+
private $token_var = 'itsec-hb-token';
|
6 |
|
7 |
+
private $settings;
|
|
|
|
|
|
|
|
|
8 |
|
9 |
+
/**
|
10 |
+
* Bootstrap Hide Backend functionality if the module is active.
|
11 |
+
*
|
12 |
+
* @return void
|
13 |
+
*/
|
14 |
+
public function run() {
|
15 |
$this->settings = ITSEC_Modules::get_settings( 'hide-backend' );
|
16 |
|
|
|
|
|
|
|
|
|
17 |
if ( ! $this->settings['enabled'] ) {
|
18 |
return;
|
19 |
}
|
20 |
|
21 |
|
22 |
+
add_action( 'init', array( $this, 'handle_specific_page_requests' ), 1000 );
|
23 |
+
add_action( 'signup_hidden_fields', array( $this, 'add_token_to_registration_form' ) );
|
|
|
24 |
|
25 |
+
add_filter( 'site_url', array( $this, 'filter_generated_url' ), 100, 2 );
|
26 |
+
add_filter( 'network_site_url', array( $this, 'filter_generated_url' ), 100, 2 );
|
27 |
+
add_filter( 'wp_redirect', array( $this, 'filter_redirect' ) );
|
28 |
+
add_filter( 'comment_moderation_text', array( $this, 'filter_comment_moderation_text' ) );
|
29 |
|
30 |
+
remove_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
|
31 |
+
}
|
|
|
32 |
|
33 |
+
/**
|
34 |
+
* Filters emailed comment moderation links to use modified login links with redirection.
|
35 |
+
*
|
36 |
+
* Comment moderation links link directly to wp-admin pages. Since direct requests to wp-admin are blocked by Hide
|
37 |
+
* Backend, these links are updated to link to the login page with a redirect to the wp-admin page.
|
38 |
+
*
|
39 |
+
* @since 4.5
|
40 |
+
*
|
41 |
+
* @param string $text Comment moderation email text.
|
42 |
+
*
|
43 |
+
* @return string Comment moderation email text.
|
44 |
+
*/
|
45 |
+
public function filter_comment_moderation_text( $text ) {
|
46 |
+
if ( $this->disable_filters ) {
|
47 |
+
return $location;
|
48 |
}
|
49 |
|
50 |
+
// The email is plain text and the links are at the end of lines, so a lazy match can be used.
|
51 |
+
if ( preg_match_all( '|(https?:\/\/((.*)wp-admin(.*)))|', $text, $urls ) ) {
|
52 |
+
foreach ( $urls[0] as $url ) {
|
53 |
+
$url = trim( $url );
|
54 |
+
$text = str_replace( $url, wp_login_url( $url ), $text );
|
55 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
}
|
57 |
|
58 |
+
return $text;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
}
|
60 |
|
61 |
/**
|
62 |
+
* Ensure that login and registration pages and their aliases are handled properly.
|
63 |
*
|
64 |
+
* This function is responsible for identifying if the current page request is for wp-login.php, wp-signup.php, a
|
65 |
+
* canonical alias for one of those pages, a wp-admin request, or one of Hide Backend's replacements pages. If a
|
66 |
+
* matching page page is found, the appropriate function is called to handle the rest of the processing.
|
67 |
+
*
|
68 |
+
* @since 4.0
|
69 |
*
|
70 |
* @return void
|
71 |
*/
|
72 |
+
public function handle_specific_page_requests() {
|
73 |
+
if ( ITSEC_Core::is_api_request() ) {
|
74 |
+
return;
|
75 |
+
}
|
76 |
|
77 |
+
$request_path = ITSEC_Lib::get_request_path();
|
|
|
78 |
|
79 |
+
if ( $request_path === $this->settings['slug'] ) {
|
80 |
+
$this->handle_login_alias();
|
81 |
+
} else if ( in_array( $request_path, array( 'wp-login', 'wp-login.php' ) ) ) {
|
82 |
+
$this->handle_canonical_login_page();
|
83 |
+
} else if ( 'wp-admin' === $request_path || 'wp-admin/' === substr( $request_path, 0, 9 ) ) {
|
84 |
+
$this->handle_wp_admin_page();
|
85 |
+
} else if ( 'wp-signup.php' === $this->settings['register'] ) {
|
86 |
+
// Only "hide" the signup page if a different slug was chosen for it.
|
87 |
+
return;
|
88 |
+
} else if ( $request_path === $this->settings['register'] ) {
|
89 |
+
$this->handle_registration_alias();
|
90 |
+
} else if ( 'wp-signup.php' === $request_path ) {
|
91 |
+
$this->handle_canonical_signup_page();
|
92 |
+
}
|
93 |
}
|
94 |
|
95 |
/**
|
96 |
+
* Handle a request for the Hide Backend replacement login page slug.
|
97 |
*
|
98 |
+
* @return void
|
|
|
|
|
|
|
|
|
99 |
*/
|
100 |
+
private function handle_login_alias() {
|
101 |
+
if ( isset( $_GET['action'] ) && $_GET['action'] === trim( $this->settings['post_logout_slug'] ) ) {
|
102 |
+
// I'm not sure if this feature is still needed or if anyone still uses it. - Chris
|
103 |
+
do_action( 'itsec_custom_login_slug' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
}
|
105 |
|
106 |
+
$this->do_redirect_with_token( 'login', 'wp-login.php' );
|
|
|
107 |
}
|
108 |
|
109 |
/**
|
110 |
+
* Handle a request for wp-login.php or a canonical alias for it.
|
|
|
|
|
111 |
*
|
112 |
* @return void
|
113 |
*/
|
114 |
+
private function handle_canonical_login_page() {
|
115 |
+
$action = isset( $_GET['action'] ) ? $_GET['action'] : '';
|
|
|
|
|
|
|
|
|
116 |
|
117 |
+
if ( 'postpass' === $action ) {
|
118 |
+
return;
|
119 |
+
} else if ( 'register' === $action ) {
|
120 |
+
$this->block_access( 'register' );
|
121 |
+
return;
|
122 |
+
} else if ( 'jetpack_json_api_authorization' === $action && has_filter( 'login_form_jetpack_json_api_authorization' ) ) {
|
123 |
+
// Jetpack handles authentication for this action. Processing is left to it.
|
124 |
+
return;
|
125 |
+
} else if ( 'jetpack-sso' === $action && has_filter( 'login_form_jetpack-sso' ) ) {
|
126 |
+
// Jetpack's SSO redirects from wordpress.com to wp-login.php on the site. Only allow this process to
|
127 |
+
// continue if they successfully log in, which should happen by login_init in Jetpack which happens just
|
128 |
+
// before this action fires.
|
129 |
+
add_action( 'login_form_jetpack-sso', array( $this, 'block_access' ) );
|
130 |
+
return;
|
131 |
}
|
132 |
|
133 |
+
$this->block_access( 'login' );
|
134 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
|
136 |
+
/**
|
137 |
+
* Handle a request for the Hide Backend replacement register page slug.
|
138 |
+
*
|
139 |
+
* @return void
|
140 |
+
*/
|
141 |
+
private function handle_registration_alias() {
|
142 |
+
if ( get_option( 'users_can_register' ) ) {
|
143 |
+
if ( is_multisite() ) {
|
144 |
+
$this->do_redirect_with_token( 'register', 'wp-signup.php' );
|
145 |
} else {
|
146 |
+
$this->do_redirect_with_token( 'register', 'wp-login.php?action=register' );
|
|
|
|
|
|
|
147 |
}
|
|
|
148 |
}
|
149 |
+
}
|
150 |
|
151 |
+
/**
|
152 |
+
* Handle a request for wp-signup.php.
|
153 |
+
*
|
154 |
+
* @return void
|
155 |
+
*/
|
156 |
+
private function handle_canonical_signup_page() {
|
157 |
+
$this->block_access( 'register' );
|
158 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
|
160 |
+
/**
|
161 |
+
* Handle a request for any wp-admin directory request.
|
162 |
+
*
|
163 |
+
* @return void
|
164 |
+
*/
|
165 |
+
private function handle_wp_admin_page() {
|
166 |
+
$request_path = ITSEC_Lib::get_request_path();
|
167 |
|
168 |
+
if ( 'wp-admin/maint/repair.php' === $request_path && defined( 'WP_ALLOW_REPAIR' ) ) {
|
169 |
+
// Make sure to only allow access if the page would function.
|
170 |
+
return;
|
171 |
}
|
172 |
|
173 |
+
$this->block_access( 'login' );
|
174 |
}
|
175 |
|
176 |
/**
|
177 |
+
* Block access to the page if the visitor is not a logged in user and the request fails validation.
|
178 |
+
*
|
179 |
+
* @param string $type The type of request to be validated.
|
180 |
*
|
181 |
* @return void
|
182 |
*/
|
183 |
+
public function block_access( $type = 'login' ) {
|
184 |
+
if ( is_user_logged_in() || $this->is_validated( $type ) ) {
|
185 |
+
return;
|
186 |
+
}
|
187 |
|
188 |
+
if ( $this->settings['theme_compat'] ) {
|
189 |
+
// The "Enable Redirection" setting is enabled. Redirect to the "Redirection Slug" setting.
|
190 |
+
wp_redirect( ITSEC_Lib::get_home_root() . $this->settings['theme_compat_slug'], 302 );
|
191 |
+
exit;
|
192 |
+
} else {
|
193 |
+
// The "Enable Redirection" setting is disabled. Return a 403 error.
|
194 |
+
wp_die( __( 'This has been disabled.', 'better-wp-security' ), 403 );
|
195 |
+
}
|
196 |
+
}
|
197 |
|
198 |
+
/**
|
199 |
+
* Redirect to requested path with the token query arg added to ensure that the redirected request is validated.
|
200 |
+
*
|
201 |
+
* This function will also set an appropriate cookie when doing the redirect. The presence of the cookie and query
|
202 |
+
* arg should ensure that the redirect request validates properly.
|
203 |
+
*
|
204 |
+
* @param string $type The type of request to add an access token for.
|
205 |
+
* @param string $path The path to redirect to.
|
206 |
+
*
|
207 |
+
* @return void
|
208 |
+
*/
|
209 |
+
private function do_redirect_with_token( $type, $path ) {
|
210 |
+
// Set the cookie so that access via unknown integrations works more smoothly.
|
211 |
+
$this->set_cookie( $type );
|
212 |
|
213 |
+
// Preserve existing query vars and add access token query arg.
|
214 |
+
$query_vars = $_GET;
|
215 |
+
$query_vars[$this->token_var] = $this->get_access_token( $type );
|
216 |
+
$query = http_build_query( $query_vars, null, '&' );
|
217 |
|
218 |
+
// Disable the Hide Backend URL filters to prevent infinite loops when calling site_url().
|
219 |
+
$this->disable_filters = true;
|
220 |
|
221 |
+
if ( false === strpos( $path, '?' ) ) {
|
222 |
+
$url = site_url( "$path?$query" );
|
223 |
+
} else {
|
224 |
+
$url = site_url( "$path&$query" );
|
225 |
}
|
226 |
|
227 |
+
wp_redirect( $url );
|
228 |
+
exit;
|
229 |
}
|
230 |
|
231 |
/**
|
232 |
+
* Filter generated login and signup URLs to include the access token query arg.
|
|
|
|
|
233 |
*
|
234 |
+
* @param string $url The complete URL to be filtered.
|
235 |
+
* @param string $path The path submitted by the originating function call.
|
236 |
*
|
237 |
+
* @return string The complete URL with conditionally added access token query arg.
|
238 |
*/
|
239 |
+
public function filter_generated_url( $url, $path ) {
|
240 |
+
if ( $this->disable_filters ) {
|
241 |
+
return $url;
|
242 |
+
}
|
243 |
+
|
244 |
+
list( $clean_path ) = explode( '?', $path );
|
245 |
|
246 |
+
if ( 'wp-login.php' === $clean_path && 'wp-login.php' !== $this->settings['slug'] ) {
|
247 |
+
if ( false !== strpos( $path, 'action=postpass' ) ) {
|
248 |
+
// No special handling is needed for a password-protected post.
|
249 |
+
return $url;
|
250 |
+
} else if ( false !== strpos( $path, 'action=register' ) ) {
|
251 |
+
$url = $this->add_token_to_url( $url, 'register' );
|
252 |
+
} else {
|
253 |
+
$url = $this->add_token_to_url( $url, 'login' );
|
254 |
+
}
|
255 |
+
} else if ( 'wp-signup.php' === $clean_path && 'wp-signup.php' !== $this->settings['register'] ) {
|
256 |
+
$url = $this->add_token_to_url( $url, 'register' );
|
257 |
+
}
|
258 |
|
259 |
+
return $url;
|
260 |
}
|
261 |
|
262 |
/**
|
263 |
+
* Filter redirection URLs to login and signup pages to include the access token query arg.
|
264 |
*
|
265 |
+
* @param string $location The relative path to redirect to.
|
266 |
*
|
267 |
+
* @return string The location with conditionally added access token query arg.
|
|
|
|
|
268 |
*/
|
269 |
+
public function filter_redirect( $location ) {
|
270 |
+
return $this->filter_generated_url( $location, $location );
|
|
|
|
|
271 |
}
|
272 |
|
273 |
/**
|
274 |
+
* Add the access token query arg to the URL.
|
275 |
*
|
276 |
+
* @param string $url The URL to modify.
|
277 |
+
* @param string $type The type of request to add an access token for.
|
278 |
*
|
279 |
+
* @return string The URL with the added access token query arg.
|
280 |
*/
|
281 |
+
private function add_token_to_url( $url, $type ) {
|
282 |
+
$token = $this->get_access_token( $type );
|
283 |
|
284 |
+
$url .= ( false === strpos( $url, '?' ) ) ? '?' : '&';
|
285 |
+
$url .= $this->token_var . '=' . urlencode( $token );
|
286 |
|
287 |
+
return $url;
|
288 |
+
}
|
|
|
|
|
|
|
|
|
289 |
|
290 |
+
/**
|
291 |
+
* Add a hidden input containing the appropriate access token name and value.
|
292 |
+
*
|
293 |
+
* This function is only used on multisite user signup pages. It is needed since the code that generates the form on
|
294 |
+
* that page does not use site_url() or network_site_url() to generate a full URL for form's action URL.
|
295 |
+
*
|
296 |
+
* @param string $context The type of signup form being rendered.
|
297 |
+
*
|
298 |
+
* @return null
|
299 |
+
*/
|
300 |
+
public function add_token_to_registration_form( $context ) {
|
301 |
+
if ( 'validate-user' === $context ) {
|
302 |
+
echo '<input type="hidden" name="' . esc_attr( $this->token_var ) . '" value="' . esc_attr( $this->get_access_token( 'register' ) ) . '" />' . "\n";
|
303 |
}
|
|
|
304 |
}
|
305 |
|
306 |
/**
|
307 |
+
* Creates a cookie to validate future requests.
|
308 |
*
|
309 |
+
* @param string $type The type of request to add an access token for.
|
310 |
+
* @param int $duration Number of seconds that the key will be valid.
|
311 |
*
|
312 |
+
* @return null
|
313 |
*/
|
314 |
+
private function set_cookie( $type, $duration = 3600 /* 1 hour */ ) {
|
315 |
+
$expires = time() + $duration;
|
316 |
+
setcookie( "itsec-hb-$type-" . COOKIEHASH, $this->get_access_token( $type ), $expires, ITSEC_Lib::get_home_root(), COOKIE_DOMAIN, is_ssl(), true );
|
317 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
318 |
|
319 |
+
/**
|
320 |
+
* Checks to see if a cookie or query arg value validates the current request for the type being checked.
|
321 |
+
*
|
322 |
+
* @param string $type The type of request to add an access token to validate.
|
323 |
+
*
|
324 |
+
* @return bool true if the request is validated, false otherwise.
|
325 |
+
*/
|
326 |
+
private function is_validated( $type ) {
|
327 |
+
$token = $this->get_access_token( $type );
|
328 |
+
|
329 |
+
if ( isset( $_REQUEST[$this->token_var] ) && $_REQUEST[$this->token_var] === $token ) {
|
330 |
+
$this->set_cookie( $type );
|
331 |
+
return true;
|
332 |
+
} else if ( isset( $_COOKIE["itsec-hb-$type-" . COOKIEHASH] ) && $_COOKIE["itsec-hb-$type-" . COOKIEHASH] === $token ) {
|
333 |
+
return true;
|
334 |
}
|
335 |
|
336 |
+
return false;
|
|
|
337 |
}
|
338 |
|
339 |
+
/**
|
340 |
+
* The access token to use for the specific request.
|
341 |
+
*
|
342 |
+
* @param string $type The type of request to create an access token for.
|
343 |
+
*
|
344 |
+
* @return string The access token.
|
345 |
+
*/
|
346 |
+
private function get_access_token( $type ) {
|
347 |
+
if ( isset( $this->settings[$type] ) ) {
|
348 |
+
return $this->settings[$type];
|
349 |
+
}
|
350 |
|
351 |
+
return $this->settings['slug'];
|
352 |
}
|
|
|
353 |
}
|
core/modules/hide-backend/config-generators.php
DELETED
@@ -1,43 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
final class ITSEC_Hide_Backend_Config_Generators {
|
4 |
-
public static function filter_apache_server_config_modification( $modification ) {
|
5 |
-
$settings = ITSEC_Modules::get_settings( 'hide-backend' );
|
6 |
-
|
7 |
-
if ( ! $settings['enabled'] ) {
|
8 |
-
return $modification;
|
9 |
-
}
|
10 |
-
|
11 |
-
$home_root = ITSEC_Lib::get_home_root();
|
12 |
-
|
13 |
-
$modification .= "\n";
|
14 |
-
$modification .= "\t# " . __( 'Enable the hide backend feature - Security > Settings > Hide Login Area > Hide Backend', 'better-wp-security' ) . "\n";
|
15 |
-
$modification .= "\tRewriteRule ^($home_root)?{$settings['slug']}/?$ {$home_root}wp-login.php [QSA,L]\n";
|
16 |
-
|
17 |
-
if ( 'wp-register.php' != $settings['register'] ) {
|
18 |
-
$modification .= "\tRewriteRule ^($home_root)?{$settings['register']}/?$ /wplogin?action=register [QSA,L]\n";
|
19 |
-
}
|
20 |
-
|
21 |
-
return $modification;
|
22 |
-
}
|
23 |
-
|
24 |
-
public static function filter_nginx_server_config_modification( $modification ) {
|
25 |
-
$settings = ITSEC_Modules::get_settings( 'hide-backend' );
|
26 |
-
|
27 |
-
if ( ! $settings['enabled'] ) {
|
28 |
-
return $modification;
|
29 |
-
}
|
30 |
-
|
31 |
-
$home_root = ITSEC_Lib::get_home_root();
|
32 |
-
|
33 |
-
$modification .= "\n";
|
34 |
-
$modification .= "\t# " . __( 'Enable the hide backend feature - Security > Settings > Hide Login Area > Hide Backend', 'better-wp-security' ) . "\n";
|
35 |
-
$modification .= "\trewrite ^($home_root)?{$settings['slug']}/?$ {$home_root}wp-login.php?\$query_string break;\n";
|
36 |
-
|
37 |
-
if ( 'wp-register.php' != $settings['register'] ) {
|
38 |
-
$modification .= "\trewrite ^($home_root)?{$settings['register']}/?$ {$home_root}{$settings['slug']}?action=register break;\n";
|
39 |
-
}
|
40 |
-
|
41 |
-
return $modification;
|
42 |
-
}
|
43 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
core/modules/hide-backend/settings-page.php
CHANGED
@@ -84,13 +84,13 @@ final class ITSEC_Hide_Backend_Settings_Page extends ITSEC_Module_Settings_Page
|
|
84 |
<p class="description"><em><?php _e( 'Note: The output is limited to alphanumeric characters, underscore (_) and dash (-). Special characters such as "." and "/" are not allowed and will be converted in the same manner as a post title. Please review your selection before logging out.', 'better-wp-security' ); ?></em></p>
|
85 |
</td>
|
86 |
</tr>
|
87 |
-
<?php if (
|
88 |
<tr>
|
89 |
<th scope="row"><label for="itsec-hide-backend-register"><?php _e( 'Register Slug', 'better-wp-security' ); ?></label></th>
|
90 |
<td>
|
91 |
<?php $form->add_text( 'register', array( 'class' => 'text code' ) ); ?>
|
92 |
<br />
|
93 |
-
<label for="itsec-hide-backend-register"><?php printf( __( 'Registration URL: %s', 'better-wp-security' ), trailingslashit( get_option( 'siteurl' ) ) . '<span style="color: #4AA02C">' .
|
94 |
</td>
|
95 |
</tr>
|
96 |
<?php endif; ?>
|
84 |
<p class="description"><em><?php _e( 'Note: The output is limited to alphanumeric characters, underscore (_) and dash (-). Special characters such as "." and "/" are not allowed and will be converted in the same manner as a post title. Please review your selection before logging out.', 'better-wp-security' ); ?></em></p>
|
85 |
</td>
|
86 |
</tr>
|
87 |
+
<?php if ( get_option( 'users_can_register' ) ) : ?>
|
88 |
<tr>
|
89 |
<th scope="row"><label for="itsec-hide-backend-register"><?php _e( 'Register Slug', 'better-wp-security' ); ?></label></th>
|
90 |
<td>
|
91 |
<?php $form->add_text( 'register', array( 'class' => 'text code' ) ); ?>
|
92 |
<br />
|
93 |
+
<label for="itsec-hide-backend-register"><?php printf( __( 'Registration URL: %s', 'better-wp-security' ), trailingslashit( get_option( 'siteurl' ) ) . '<span style="color: #4AA02C">' . esc_html( $settings['register'] ) . '</span>' ); ?></label>
|
94 |
</td>
|
95 |
</tr>
|
96 |
<?php endif; ?>
|
core/modules/hide-backend/settings.php
CHANGED
@@ -4,12 +4,12 @@ final class ITSEC_Hide_Backend_Settings extends ITSEC_Settings {
|
|
4 |
public function get_id() {
|
5 |
return 'hide-backend';
|
6 |
}
|
7 |
-
|
8 |
public function get_defaults() {
|
9 |
return array(
|
10 |
'enabled' => false,
|
11 |
'slug' => 'wplogin',
|
12 |
-
'register' => 'wp-
|
13 |
'theme_compat' => true,
|
14 |
'theme_compat_slug' => 'not_found',
|
15 |
'post_logout_slug' => '',
|
4 |
public function get_id() {
|
5 |
return 'hide-backend';
|
6 |
}
|
7 |
+
|
8 |
public function get_defaults() {
|
9 |
return array(
|
10 |
'enabled' => false,
|
11 |
'slug' => 'wplogin',
|
12 |
+
'register' => 'wp-signup.php',
|
13 |
'theme_compat' => true,
|
14 |
'theme_compat_slug' => 'not_found',
|
15 |
'post_logout_slug' => '',
|
core/modules/hide-backend/setup.php
CHANGED
@@ -64,7 +64,7 @@ if ( ! class_exists( 'ITSEC_Hide_Backend_Setup' ) ) {
|
|
64 |
if ( false !== $current_options ) {
|
65 |
|
66 |
$current_options['enabled'] = isset( $itsec_bwps_options['hb_enabled'] ) && $itsec_bwps_options['hb_enabled'] == 1 ? true : false;
|
67 |
-
$current_options['register'] = isset( $itsec_bwps_options['hb_register'] ) ? sanitize_text_field( $itsec_bwps_options['hb_register'] ) : 'wp-
|
68 |
|
69 |
if ( $current_options['enabled'] === true ) {
|
70 |
|
@@ -124,6 +124,10 @@ if ( ! class_exists( 'ITSEC_Hide_Backend_Setup' ) ) {
|
|
124 |
if ( $itsec_old_version < 4070 ) {
|
125 |
delete_site_option( 'itsec_hide_backend' );
|
126 |
}
|
|
|
|
|
|
|
|
|
127 |
}
|
128 |
|
129 |
/**
|
64 |
if ( false !== $current_options ) {
|
65 |
|
66 |
$current_options['enabled'] = isset( $itsec_bwps_options['hb_enabled'] ) && $itsec_bwps_options['hb_enabled'] == 1 ? true : false;
|
67 |
+
$current_options['register'] = isset( $itsec_bwps_options['hb_register'] ) ? sanitize_text_field( $itsec_bwps_options['hb_register'] ) : 'wp-signup.php';
|
68 |
|
69 |
if ( $current_options['enabled'] === true ) {
|
70 |
|
124 |
if ( $itsec_old_version < 4070 ) {
|
125 |
delete_site_option( 'itsec_hide_backend' );
|
126 |
}
|
127 |
+
|
128 |
+
if ( $itsec_old_version < 4072 ) {
|
129 |
+
ITSEC_Response::regenerate_server_config();
|
130 |
+
}
|
131 |
}
|
132 |
|
133 |
/**
|
core/modules/hide-backend/validator.php
CHANGED
@@ -21,10 +21,11 @@ final class ITSEC_Hide_Backend_Validator extends ITSEC_Validator {
|
|
21 |
|
22 |
if ( ! isset( $this->settings['register'] ) ) {
|
23 |
$this->settings['register'] = $this->previous_settings['register'];
|
|
|
|
|
24 |
}
|
25 |
|
26 |
$this->sanitize_setting( 'non-empty-title', 'slug', __( 'Login Slug', 'better-wp-security' ) );
|
27 |
-
$this->sanitize_setting( 'non-empty-title', 'register', __( 'Register Slug', 'better-wp-security' ) );
|
28 |
$this->sanitize_setting( 'bool', 'theme_compat', __( 'Enable Redirection', 'better-wp-security' ) );
|
29 |
$this->sanitize_setting( 'non-empty-title', 'theme_compat_slug', __( 'Redirection Slug', 'better-wp-security' ) );
|
30 |
$this->sanitize_setting( 'title', 'post_logout_slug', __( 'Custom Login Action', 'better-wp-security' ) );
|
@@ -61,14 +62,6 @@ final class ITSEC_Hide_Backend_Validator extends ITSEC_Validator {
|
|
61 |
ITSEC_Response::prevent_modal_close();
|
62 |
}
|
63 |
|
64 |
-
if (
|
65 |
-
$this->settings['enabled'] !== $this->previous_settings['enabled'] ||
|
66 |
-
$this->settings['slug'] !== $this->previous_settings['slug'] ||
|
67 |
-
$this->settings['register'] !== $this->previous_settings['register']
|
68 |
-
) {
|
69 |
-
ITSEC_Response::regenerate_server_config();
|
70 |
-
}
|
71 |
-
|
72 |
|
73 |
ITSEC_Response::reload_module( $this->get_id() );
|
74 |
}
|
21 |
|
22 |
if ( ! isset( $this->settings['register'] ) ) {
|
23 |
$this->settings['register'] = $this->previous_settings['register'];
|
24 |
+
} else if ( 'wp-signup.php' !== $this->settings['register'] ) {
|
25 |
+
$this->sanitize_setting( 'non-empty-title', 'register', __( 'Register Slug', 'better-wp-security' ) );
|
26 |
}
|
27 |
|
28 |
$this->sanitize_setting( 'non-empty-title', 'slug', __( 'Login Slug', 'better-wp-security' ) );
|
|
|
29 |
$this->sanitize_setting( 'bool', 'theme_compat', __( 'Enable Redirection', 'better-wp-security' ) );
|
30 |
$this->sanitize_setting( 'non-empty-title', 'theme_compat_slug', __( 'Redirection Slug', 'better-wp-security' ) );
|
31 |
$this->sanitize_setting( 'title', 'post_logout_slug', __( 'Custom Login Action', 'better-wp-security' ) );
|
62 |
ITSEC_Response::prevent_modal_close();
|
63 |
}
|
64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
|
66 |
ITSEC_Response::reload_module( $this->get_id() );
|
67 |
}
|
core/modules/ipcheck/class-itsec-ipcheck.php
CHANGED
@@ -226,6 +226,8 @@ class ITSEC_IPCheck {
|
|
226 |
* @return void
|
227 |
*/
|
228 |
public function wp_login() {
|
|
|
|
|
229 |
global $itsec_logger, $itsec_lockout;
|
230 |
|
231 |
$this->load_settings();
|
@@ -244,6 +246,8 @@ class ITSEC_IPCheck {
|
|
244 |
* @return void
|
245 |
*/
|
246 |
public function handle_failed_login( $username, $details ) {
|
|
|
|
|
247 |
global $itsec_logger, $itsec_lockout;
|
248 |
|
249 |
$this->load_settings();
|
226 |
* @return void
|
227 |
*/
|
228 |
public function wp_login() {
|
229 |
+
|
230 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
231 |
global $itsec_logger, $itsec_lockout;
|
232 |
|
233 |
$this->load_settings();
|
246 |
* @return void
|
247 |
*/
|
248 |
public function handle_failed_login( $username, $details ) {
|
249 |
+
|
250 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
251 |
global $itsec_logger, $itsec_lockout;
|
252 |
|
253 |
$this->load_settings();
|
core/modules/malware/class-itsec-malware-scanner.php
CHANGED
@@ -63,7 +63,8 @@ final class ITSEC_Malware_Scanner {
|
|
63 |
$scan_url = "$scanner_url?" . http_build_query( $query_args, '', '&' );
|
64 |
|
65 |
$req_args = array(
|
66 |
-
'
|
|
|
67 |
);
|
68 |
|
69 |
if ( defined( 'ITSEC_TEST_MALWARE_SCAN_DISABLE_SSLVERIFY' ) && ITSEC_TEST_MALWARE_SCAN_DISABLE_SSLVERIFY ) {
|
63 |
$scan_url = "$scanner_url?" . http_build_query( $query_args, '', '&' );
|
64 |
|
65 |
$req_args = array(
|
66 |
+
'connect_timeout' => 30, // Placeholder for when WordPress implements support.
|
67 |
+
'timeout' => 300,
|
68 |
);
|
69 |
|
70 |
if ( defined( 'ITSEC_TEST_MALWARE_SCAN_DISABLE_SSLVERIFY' ) && ITSEC_TEST_MALWARE_SCAN_DISABLE_SSLVERIFY ) {
|
core/modules/malware/class-itsec-malware.php
CHANGED
@@ -16,7 +16,7 @@ class ITSEC_Malware {
|
|
16 |
*
|
17 |
* @since 3.6.0
|
18 |
*
|
19 |
-
* @param Ithemes_Sync_API Sync API object.
|
20 |
*/
|
21 |
public function register_sync_verbs( $api ) {
|
22 |
$api->register( 'itsec-do-malware-scan', 'Ithemes_Sync_Verb_ITSEC_Malware_Do_Scan', dirname( __FILE__ ) . '/sync-verbs/itsec-do-malware-scan.php' );
|
16 |
*
|
17 |
* @since 3.6.0
|
18 |
*
|
19 |
+
* @param Ithemes_Sync_API $api Sync API object.
|
20 |
*/
|
21 |
public function register_sync_verbs( $api ) {
|
22 |
$api->register( 'itsec-do-malware-scan', 'Ithemes_Sync_Verb_ITSEC_Malware_Do_Scan', dirname( __FILE__ ) . '/sync-verbs/itsec-do-malware-scan.php' );
|
core/modules/security-check/active.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
function itsec_security_check_register_sync_verbs( $api ) {
|
4 |
+
$api->register( 'itsec-do-security-check', 'Ithemes_Sync_Verb_ITSEC_Do_Security_Check', dirname( __FILE__ ) . '/sync-verbs/itsec-do-security-check.php' );
|
5 |
+
$api->register( 'itsec-get-security-check-feedback-response', 'Ithemes_Sync_Verb_ITSEC_Get_Security_Check_Feedback_Response', dirname( __FILE__ ) . '/sync-verbs/itsec-get-security-check-feedback-response.php' );
|
6 |
+
$api->register( 'itsec-get-security-check-modules', 'Ithemes_Sync_Verb_ITSEC_Get_Security_Check_Modules', dirname( __FILE__ ) . '/sync-verbs/itsec-get-security-check-modules.php' );
|
7 |
+
}
|
8 |
+
add_action( 'ithemes_sync_register_verbs', 'itsec_security_check_register_sync_verbs' );
|
core/modules/security-check/feedback-renderer.php
ADDED
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
final class ITSEC_Security_Check_Feedback_Renderer {
|
4 |
+
public static function render( $data ) {
|
5 |
+
$section_groups = array();
|
6 |
+
|
7 |
+
foreach ( $data['sections'] as $name => $args ) {
|
8 |
+
$section_groups[$args['status']][$name] = $args;
|
9 |
+
}
|
10 |
+
|
11 |
+
if ( isset( $section_groups['call-to-action'] ) ) {
|
12 |
+
self::render_sections( 'call-to-action', $section_groups['call-to-action'] );
|
13 |
+
}
|
14 |
+
if ( isset( $section_groups['action-taken'] ) ) {
|
15 |
+
self::render_sections( 'action-taken', $section_groups['action-taken'] );
|
16 |
+
}
|
17 |
+
if ( isset( $section_groups['confirmation'] ) ) {
|
18 |
+
self::render_sections( 'confirmation', $section_groups['confirmation'] );
|
19 |
+
}
|
20 |
+
}
|
21 |
+
|
22 |
+
private static function render_sections( $status, $sections ) {
|
23 |
+
foreach ( $sections as $name => $args ) {
|
24 |
+
$classes = array( 'itsec-security-check-container', "itsec-security-check-container-$status" );
|
25 |
+
|
26 |
+
if ( $args['interactive'] ) {
|
27 |
+
$classes[] = 'itsec-security-check-container-is-interactive';
|
28 |
+
}
|
29 |
+
|
30 |
+
echo '<div class="' . self::esc_attr( implode( ' ', $classes ) ) . '"';
|
31 |
+
|
32 |
+
if ( ! empty( $id ) ) {
|
33 |
+
echo " id=\"$id\"";
|
34 |
+
}
|
35 |
+
|
36 |
+
echo ">\n";
|
37 |
+
|
38 |
+
if ( $args['interactive'] ) {
|
39 |
+
echo '<div class="itsec-security-check-feedback"></div>';
|
40 |
+
}
|
41 |
+
|
42 |
+
foreach ( $args['entries'] as $entry ) {
|
43 |
+
self::render_entry( $entry );
|
44 |
+
}
|
45 |
+
|
46 |
+
echo "</div>\n";
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
private static function render_entry( $entry ) {
|
51 |
+
if ( empty( $entry['type'] ) ) {
|
52 |
+
return;
|
53 |
+
}
|
54 |
+
|
55 |
+
if ( 'text' === $entry['type'] ) {
|
56 |
+
if ( isset( $entry['value'] ) ) {
|
57 |
+
echo "<p>{$entry['value']}</p>\n";
|
58 |
+
}
|
59 |
+
} else if ( 'input' === $entry['type'] ) {
|
60 |
+
if ( empty( $entry['input'] ) ) {
|
61 |
+
return;
|
62 |
+
}
|
63 |
+
|
64 |
+
$defaults = array(
|
65 |
+
'format' => '%1$s',
|
66 |
+
'value' => '',
|
67 |
+
'style_class' => '',
|
68 |
+
'data' => array(),
|
69 |
+
);
|
70 |
+
$entry = array_merge( $defaults, $entry );
|
71 |
+
|
72 |
+
if ( ! empty( $entry['value_alias'] ) ) {
|
73 |
+
$entry['value'] = self::get_alias_value( $entry['value_alias'] );
|
74 |
+
}
|
75 |
+
|
76 |
+
$data_attrs = array();
|
77 |
+
|
78 |
+
foreach ( (array) $entry['data'] as $key => $val ) {
|
79 |
+
$key = preg_replace( '/[^a-zA-Z0-9\-_]+/', '', $key );
|
80 |
+
$val = self::esc_attr( $val );
|
81 |
+
|
82 |
+
$data_attrs[] = " data-$key=\"$val\"";
|
83 |
+
}
|
84 |
+
|
85 |
+
|
86 |
+
if ( 'select' === $entry['input'] ) {
|
87 |
+
if ( empty( $entry['name'] ) || empty( $entry['options'] ) ) {
|
88 |
+
return;
|
89 |
+
}
|
90 |
+
|
91 |
+
$options = "\n";
|
92 |
+
|
93 |
+
foreach ( $entry['options'] as $value => $description ) {
|
94 |
+
$option = '<option value="' . self::esc_attr( $value ) . '"';
|
95 |
+
|
96 |
+
if ( $value === $entry['value'] ) {
|
97 |
+
$option .= ' selected="selected"';
|
98 |
+
}
|
99 |
+
|
100 |
+
$option .= '>' . self::esc_html( $description ) . "</option>\n";
|
101 |
+
|
102 |
+
$options .= $option;
|
103 |
+
}
|
104 |
+
|
105 |
+
$input_format = '<select name="%1$s" class="%2$s"%3$s>%4$s</select>';
|
106 |
+
$input = sprintf( $input_format, self::esc_attr( $entry['name'] ), self::esc_attr( $entry['style_class'] ), implode( '', $data_attrs ), $options );
|
107 |
+
} else if ( 'textarea' === $entry['input'] ) {
|
108 |
+
if ( empty( $entry['name'] ) ) {
|
109 |
+
return;
|
110 |
+
}
|
111 |
+
|
112 |
+
$input_format = '<textarea name="%1$s" class="%2$s"%3$s>%4$s</textarea>';
|
113 |
+
$input = sprintf( $input_format, self::esc_attr( $entry['name'] ), self::esc_attr( $entry['style_class'] ), implode( '', $data_attrs ), self::esc_html( $entry['value'] ) );
|
114 |
+
} else {
|
115 |
+
if ( empty( $entry['name'] ) ) {
|
116 |
+
return;
|
117 |
+
}
|
118 |
+
|
119 |
+
$input_format = '<input type="%1$s" name="%2$s" value="%3$s" class="%4$s"%5$s />';
|
120 |
+
$input = sprintf( $input_format, self::esc_attr( $entry['input'] ), self::esc_attr( $entry['name'] ), self::esc_attr( $entry['value'] ), self::esc_attr( $entry['style_class'] ), implode( '', $data_attrs ) );
|
121 |
+
}
|
122 |
+
|
123 |
+
echo '<p><label>';
|
124 |
+
printf( $entry['format'], $input );
|
125 |
+
echo "</label></p>\n";
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
private static function esc_attr( $attr ) {
|
130 |
+
return esc_attr( $attr );
|
131 |
+
}
|
132 |
+
|
133 |
+
private static function esc_html( $html ) {
|
134 |
+
return esc_html( $html );
|
135 |
+
}
|
136 |
+
|
137 |
+
private static function get_alias_value( $alias ) {
|
138 |
+
if ( 'email' === $alias ) {
|
139 |
+
return get_option( 'admin_email' );
|
140 |
+
}
|
141 |
+
}
|
142 |
+
}
|
core/modules/security-check/feedback.php
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
final class ITSEC_Security_Check_Feedback {
|
4 |
+
private $sections = array();
|
5 |
+
private $current_section = '';
|
6 |
+
|
7 |
+
public function __construct( $raw_data = false ) {
|
8 |
+
if ( is_array( $raw_data ) && isset( $raw_data['sections'] ) && is_array( $raw_data['sections'] ) ) {
|
9 |
+
$this->sections = $raw_data['sections'];
|
10 |
+
}
|
11 |
+
}
|
12 |
+
|
13 |
+
public function add_section( $name, $args = array() ) {
|
14 |
+
if ( ! isset( $this->sections[$name] ) ) {
|
15 |
+
$default_args = array(
|
16 |
+
'interactive' => false,
|
17 |
+
'status' => 'confirmation',
|
18 |
+
'entries' => array(),
|
19 |
+
);
|
20 |
+
|
21 |
+
$args = array_merge( $default_args, $args );
|
22 |
+
|
23 |
+
$this->sections[$name] = $args;
|
24 |
+
}
|
25 |
+
|
26 |
+
$this->current_section = $name;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function switch_section( $name ) {
|
30 |
+
if ( isset( $this->sections[$name] ) ) {
|
31 |
+
$this->current_section = $name;
|
32 |
+
return true;
|
33 |
+
} else {
|
34 |
+
$this->current_section = '';
|
35 |
+
return false;
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
public function set_section_arg( $arg, $value, $name = false ) {
|
40 |
+
if ( false === $name ) {
|
41 |
+
$name = $this->current_section;
|
42 |
+
}
|
43 |
+
|
44 |
+
if ( ! isset( $this->sections[$name] ) ) {
|
45 |
+
return false;
|
46 |
+
}
|
47 |
+
|
48 |
+
$this->sections[$name][$arg] = $value;
|
49 |
+
return true;
|
50 |
+
}
|
51 |
+
|
52 |
+
public function add_entry( $entry ) {
|
53 |
+
if ( empty( $this->current_section ) ) {
|
54 |
+
return false;
|
55 |
+
}
|
56 |
+
|
57 |
+
$this->sections[$this->current_section]['entries'][] = $entry;
|
58 |
+
return true;
|
59 |
+
}
|
60 |
+
|
61 |
+
public function add_text( $text ) {
|
62 |
+
$entry = array(
|
63 |
+
'type' => 'text',
|
64 |
+
'value' => $text,
|
65 |
+
);
|
66 |
+
|
67 |
+
$this->add_entry( $entry );
|
68 |
+
}
|
69 |
+
|
70 |
+
public function add_input( $input, $name, $args = array() ) {
|
71 |
+
$entry = array(
|
72 |
+
'type' => 'input',
|
73 |
+
'input' => $input,
|
74 |
+
'name' => $name,
|
75 |
+
'format' => '%1$s',
|
76 |
+
'value' => '',
|
77 |
+
'style_class' => '',
|
78 |
+
);
|
79 |
+
|
80 |
+
if ( 'select' === $input ) {
|
81 |
+
$entry['options'] = array();
|
82 |
+
}
|
83 |
+
|
84 |
+
$entry = array_merge( $entry, $args );
|
85 |
+
|
86 |
+
$this->add_entry( $entry );
|
87 |
+
}
|
88 |
+
|
89 |
+
public function get_raw_data() {
|
90 |
+
return array(
|
91 |
+
'sections' => $this->sections,
|
92 |
+
);
|
93 |
+
}
|
94 |
+
}
|
core/modules/security-check/js/settings-page.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
jQuery( document ).ready( function ( $ ) {
|
2 |
-
var $container = $( '#itsec-module-card-security-check' )
|
3 |
|
4 |
$container.on( 'click', '#itsec-security-check-secure_site', function( e ) {
|
5 |
e.preventDefault();
|
@@ -27,47 +27,77 @@ jQuery( document ).ready( function ( $ ) {
|
|
27 |
} );
|
28 |
} );
|
29 |
|
30 |
-
$container.on( 'click', '
|
31 |
e.preventDefault();
|
32 |
|
33 |
-
var
|
|
|
|
|
|
|
34 |
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
.removeClass( 'button-primary' )
|
37 |
.addClass( 'button-secondary' )
|
38 |
-
.attr( 'value', itsec_security_check_settings.activating_network_brute_force )
|
39 |
.prop( 'disabled', true );
|
40 |
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
}
|
46 |
|
47 |
-
itsecSettingsPage.sendModuleAJAXRequest
|
48 |
-
|
49 |
-
|
|
|
|
|
|
|
|
|
|
|
50 |
.removeClass( 'button-secondary' )
|
51 |
-
.
|
52 |
.prop( 'disabled', false );
|
53 |
|
54 |
-
$( '
|
55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
if ( results.errors && results.errors.length > 0 ) {
|
58 |
$container
|
59 |
-
.removeClass( 'itsec-security-check-container-
|
60 |
-
.removeClass( 'itsec-security-check-container-
|
61 |
.addClass( 'itsec-security-check-container-error' );
|
62 |
|
63 |
$.each( results.errors, function( index, error ) {
|
64 |
-
$
|
65 |
} );
|
66 |
} else {
|
67 |
$container
|
68 |
-
.removeClass( 'itsec-security-check-container-
|
69 |
.removeClass( 'itsec-security-check-container-error' )
|
70 |
-
.addClass( 'itsec-security-check-container-
|
71 |
|
72 |
$container.html( results.response );
|
73 |
$( '#itsec-notice-network-brute-force' ).hide();
|
@@ -75,3 +105,10 @@ jQuery( document ).ready( function ( $ ) {
|
|
75 |
} );
|
76 |
} );
|
77 |
} );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
jQuery( document ).ready( function ( $ ) {
|
2 |
+
var $container = $( '#itsec-module-card-security-check' );
|
3 |
|
4 |
$container.on( 'click', '#itsec-security-check-secure_site', function( e ) {
|
5 |
e.preventDefault();
|
27 |
} );
|
28 |
} );
|
29 |
|
30 |
+
$container.on( 'click', '.itsec-security-check-container-is-interactive :submit', function( e ) {
|
31 |
e.preventDefault();
|
32 |
|
33 |
+
var $button = $( this );
|
34 |
+
var $container = $( this ).parents( '.itsec-security-check-container-is-interactive' );
|
35 |
+
var inputs = $container.find( ':input' ).serializeArray();
|
36 |
+
var data = {};
|
37 |
|
38 |
+
for ( var i = 0; i < inputs.length; i++ ) {
|
39 |
+
var input = inputs[i];
|
40 |
+
|
41 |
+
if ( '[]' === input.name.substr( -2 ) ) {
|
42 |
+
var name = input.name.substr( 0, input.name.length - 2 );
|
43 |
+
|
44 |
+
if ( data[name] ) {
|
45 |
+
data[name].push( input.value );
|
46 |
+
} else {
|
47 |
+
data[name] = [input.value];
|
48 |
+
}
|
49 |
+
} else {
|
50 |
+
data[input.name] = input.value;
|
51 |
+
}
|
52 |
+
};
|
53 |
+
|
54 |
+
|
55 |
+
$button
|
56 |
.removeClass( 'button-primary' )
|
57 |
.addClass( 'button-secondary' )
|
|
|
58 |
.prop( 'disabled', true );
|
59 |
|
60 |
+
if ( $button.data( 'clicked-value' ) ) {
|
61 |
+
$button
|
62 |
+
.data( 'original-value', $( this ).val() )
|
63 |
+
.attr( 'value', $( this ).data( 'clicked-value' ) )
|
64 |
+
}
|
65 |
|
66 |
+
var ajaxFunction = itsecSettingsPage.sendModuleAJAXRequest;
|
67 |
+
|
68 |
+
if ( 'undefined' !== typeof itsecSecurityCheckAJAXRequest ) {
|
69 |
+
ajaxFunction = itsecSecurityCheckAJAXRequest;
|
70 |
+
}
|
71 |
+
|
72 |
+
ajaxFunction( 'security-check', data, function( results ) {
|
73 |
+
$button
|
74 |
.removeClass( 'button-secondary' )
|
75 |
+
.addClass( 'button-primary' )
|
76 |
.prop( 'disabled', false );
|
77 |
|
78 |
+
if ( $button.data( 'original-value' ) ) {
|
79 |
+
$button
|
80 |
+
.attr( 'value', $( this ).data( 'original-value' ) )
|
81 |
+
}
|
82 |
+
|
83 |
+
|
84 |
+
var $feedback = $container.find( '.itsec-security-check-feedback' );
|
85 |
+
$feedback.html( '' );
|
86 |
|
87 |
if ( results.errors && results.errors.length > 0 ) {
|
88 |
$container
|
89 |
+
.removeClass( 'itsec-security-check-container-call-to-action' )
|
90 |
+
.removeClass( 'itsec-security-check-container-confirmation' )
|
91 |
.addClass( 'itsec-security-check-container-error' );
|
92 |
|
93 |
$.each( results.errors, function( index, error ) {
|
94 |
+
$feedback.append( '<div class="error inline"><p><strong>' + error + '</strong></p></div>' );
|
95 |
} );
|
96 |
} else {
|
97 |
$container
|
98 |
+
.removeClass( 'itsec-security-check-container-call-to-action' )
|
99 |
.removeClass( 'itsec-security-check-container-error' )
|
100 |
+
.addClass( 'itsec-security-check-container-confirmation' );
|
101 |
|
102 |
$container.html( results.response );
|
103 |
$( '#itsec-notice-network-brute-force' ).hide();
|
105 |
} );
|
106 |
} );
|
107 |
} );
|
108 |
+
|
109 |
+
/*
|
110 |
+
function itsecSecurityCheckAJAXRequest( type, data, callback ) {
|
111 |
+
console.log( 'Override called' );
|
112 |
+
itsecSettingsPage.sendModuleAJAXRequest( type, data, callback );
|
113 |
+
}
|
114 |
+
*/
|
core/modules/security-check/scanner.php
CHANGED
@@ -2,12 +2,44 @@
|
|
2 |
|
3 |
final class ITSEC_Security_Check_Scanner {
|
4 |
private static $available_modules;
|
5 |
-
private static $
|
6 |
-
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
|
|
9 |
|
10 |
-
public static function run() {
|
11 |
self::$available_modules = ITSEC_Modules::get_available_modules();
|
12 |
|
13 |
self::enforce_activation( 'ban-users', __( 'Banned Users', 'better-wp-security' ) );
|
@@ -34,15 +66,6 @@ final class ITSEC_Security_Check_Scanner {
|
|
34 |
self::enforce_setting( 'wordpress-tweaks', 'rest_api', 'restrict-access', __( 'Changed the REST API setting in WordPress Tweaks to "Restricted Access".', 'better-wp-security' ) );
|
35 |
|
36 |
self::enforce_setting( 'global', 'write_files', true, __( 'Enabled the Write to Files setting in Global Settings.', 'better-wp-security' ) );
|
37 |
-
|
38 |
-
|
39 |
-
ob_start();
|
40 |
-
|
41 |
-
echo implode( "\n", self::$calls_to_action );
|
42 |
-
echo implode( "\n", self::$actions_taken );
|
43 |
-
echo implode( "\n", self::$confirmations );
|
44 |
-
|
45 |
-
ITSEC_Response::set_response( ob_get_clean() );
|
46 |
}
|
47 |
|
48 |
private static function add_network_brute_force_signup() {
|
@@ -59,37 +82,28 @@ final class ITSEC_Security_Check_Scanner {
|
|
59 |
}
|
60 |
|
61 |
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
ob_start();
|
85 |
-
$form->add_button( 'enable_network_brute_force', array( 'class' => 'button-primary', 'value' => __( 'Activate Network Brute Force Protection', 'better-wp-security' ) ) );
|
86 |
-
echo '<p>' . ob_get_clean() . '</p>';
|
87 |
-
|
88 |
-
echo '<div id="itsec-security-check-network-brute-force-errors"></div>';
|
89 |
-
|
90 |
-
echo '</div>';
|
91 |
-
|
92 |
-
self::$calls_to_action[] = ob_get_clean();
|
93 |
}
|
94 |
|
95 |
private static function enforce_setting( $module, $setting_name, $setting_value, $description ) {
|
@@ -97,19 +111,17 @@ final class ITSEC_Security_Check_Scanner {
|
|
97 |
return;
|
98 |
}
|
99 |
|
100 |
-
if ( ITSEC_Modules::get_setting( $module, $setting_name )
|
101 |
-
|
|
|
102 |
|
103 |
-
ob_start();
|
104 |
|
105 |
-
|
106 |
-
echo "<p>$description</p>";
|
107 |
-
echo '</div>';
|
108 |
|
109 |
-
|
|
|
110 |
|
111 |
-
|
112 |
-
}
|
113 |
}
|
114 |
|
115 |
private static function enforce_activation( $module, $name ) {
|
@@ -117,37 +129,40 @@ final class ITSEC_Security_Check_Scanner {
|
|
117 |
return;
|
118 |
}
|
119 |
|
|
|
|
|
120 |
if ( ITSEC_Modules::is_active( $module ) ) {
|
121 |
/* Translators: 1: feature name */
|
122 |
$text = __( '%1$s is enabled as recommended.', 'better-wp-security' );
|
123 |
-
$took_action = false;
|
124 |
} else {
|
125 |
ITSEC_Modules::activate( $module );
|
126 |
ITSEC_Response::add_js_function_call( 'setModuleToActive', $module );
|
127 |
|
128 |
/* Translators: 1: feature name */
|
129 |
$text = __( 'Enabled %1$s.', 'better-wp-security' );
|
130 |
-
|
|
|
131 |
}
|
132 |
|
133 |
-
|
|
|
134 |
|
135 |
-
|
136 |
-
|
137 |
-
|
|
|
|
|
138 |
|
139 |
-
if ( $
|
140 |
-
|
141 |
-
|
142 |
-
self::$confirmations[] = ob_get_clean();
|
143 |
}
|
144 |
-
}
|
145 |
|
146 |
-
|
147 |
$settings = ITSEC_Modules::get_settings( 'network-brute-force' );
|
148 |
|
149 |
-
$settings['email'] = $
|
150 |
-
$settings['updates_optin'] = $
|
151 |
$settings['api_nag'] = false;
|
152 |
|
153 |
$results = ITSEC_Modules::set_settings( 'network-brute-force', $settings );
|
@@ -160,14 +175,4 @@ final class ITSEC_Security_Check_Scanner {
|
|
160 |
ITSEC_Response::set_response( '<p>' . __( 'Your site is now using Network Brute Force Protection.', 'better-wp-security' ) . '</p>' );
|
161 |
}
|
162 |
}
|
163 |
-
|
164 |
-
private static function open_container( $status = 'complete', $id = '' ) {
|
165 |
-
echo '<div class="itsec-security-check-container itsec-security-check-container-' . $status . '"';
|
166 |
-
|
167 |
-
if ( ! empty( $id ) ) {
|
168 |
-
echo ' id="' . $id . '"';
|
169 |
-
}
|
170 |
-
|
171 |
-
echo '>';
|
172 |
-
}
|
173 |
}
|
2 |
|
3 |
final class ITSEC_Security_Check_Scanner {
|
4 |
private static $available_modules;
|
5 |
+
private static $feedback;
|
6 |
+
|
7 |
+
|
8 |
+
public static function get_supported_modules() {
|
9 |
+
$available_modules = ITSEC_Modules::get_available_modules();
|
10 |
+
|
11 |
+
$modules = array(
|
12 |
+
'ban-users' => __( 'Banned Users', 'better-wp-security' ),
|
13 |
+
'backup' => __( 'Database Backups', 'better-wp-security' ),
|
14 |
+
'brute-force' => __( 'Local Brute Force Protection', 'better-wp-security' ),
|
15 |
+
'malware-scheduling' => __( 'Malware Scan Scheduling', 'better-wp-security' ),
|
16 |
+
'network-brute-force' => __( 'Network Brute Force Protection', 'better-wp-security' ),
|
17 |
+
'strong-passwords' => __( 'Strong Passwords', 'better-wp-security' ),
|
18 |
+
'two-factor' => __( 'Two-Factor Authentication', 'better-wp-security' ),
|
19 |
+
'user-logging' => __( 'User Logging', 'better-wp-security' ),
|
20 |
+
'wordpress-tweaks' => __( 'WordPress Tweaks', 'better-wp-security' ),
|
21 |
+
);
|
22 |
+
|
23 |
+
foreach ( $modules as $module => $val ) {
|
24 |
+
if ( ! in_array( $module, $available_modules ) ) {
|
25 |
+
unset( $modules[$module] );
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
return $modules;
|
30 |
+
}
|
31 |
+
|
32 |
+
public static function get_results() {
|
33 |
+
self::run_scan();
|
34 |
+
|
35 |
+
return self::$feedback->get_raw_data();
|
36 |
+
}
|
37 |
+
|
38 |
+
public static function run_scan() {
|
39 |
+
require_once( dirname( __FILE__ ) . '/feedback.php' );
|
40 |
|
41 |
+
self::$feedback = new ITSEC_Security_Check_Feedback();
|
42 |
|
|
|
43 |
self::$available_modules = ITSEC_Modules::get_available_modules();
|
44 |
|
45 |
self::enforce_activation( 'ban-users', __( 'Banned Users', 'better-wp-security' ) );
|
66 |
self::enforce_setting( 'wordpress-tweaks', 'rest_api', 'restrict-access', __( 'Changed the REST API setting in WordPress Tweaks to "Restricted Access".', 'better-wp-security' ) );
|
67 |
|
68 |
self::enforce_setting( 'global', 'write_files', true, __( 'Enabled the Write to Files setting in Global Settings.', 'better-wp-security' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
}
|
70 |
|
71 |
private static function add_network_brute_force_signup() {
|
82 |
}
|
83 |
|
84 |
|
85 |
+
self::$feedback->add_section( 'network-brute-force-signup', array( 'interactive' => true, 'status' => 'call-to-action' ) );
|
86 |
+
self::$feedback->add_text( __( 'With Network Brute Force Protection, your site is protected against attackers found by other sites running iThemes Security. If your site identifies a new attacker, it automatically notifies the network so that other sites are protected as well. To join this site to the network and enable the protection, click the button below.', 'better-wp-security' ) );
|
87 |
+
self::$feedback->add_input( 'text', 'email', array(
|
88 |
+
'format' => __( 'Email Address: %1$s', 'better-wp-security' ),
|
89 |
+
'value_alias' => 'email',
|
90 |
+
'style_class' => 'regular-text',
|
91 |
+
) );
|
92 |
+
self::$feedback->add_input( 'select', 'updates_optin', array(
|
93 |
+
'format' => __( 'Receive email updates about WordPress Security from iThemes: %1$s', 'better-wp-security' ),
|
94 |
+
'options' => array( 'true' => __( 'Yes', 'better-wp-security' ), 'false' => __( 'No', 'better-wp-security' ) ),
|
95 |
+
'value' => 'true',
|
96 |
+
) );
|
97 |
+
self::$feedback->add_input( 'hidden', 'method', array(
|
98 |
+
'value' => 'activate-network-brute-force',
|
99 |
+
) );
|
100 |
+
self::$feedback->add_input( 'submit', 'enable_network_brute_force', array(
|
101 |
+
'value' => __( 'Activate Network Brute Force Protection', 'better-wp-security' ),
|
102 |
+
'style_class' => 'button-primary',
|
103 |
+
'data' => array(
|
104 |
+
'clicked-value' => __( 'Activating Network Brute Force Protection...', 'better-wp-security' ),
|
105 |
+
),
|
106 |
+
) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
}
|
108 |
|
109 |
private static function enforce_setting( $module, $setting_name, $setting_value, $description ) {
|
111 |
return;
|
112 |
}
|
113 |
|
114 |
+
if ( ITSEC_Modules::get_setting( $module, $setting_name ) === $setting_value ) {
|
115 |
+
return;
|
116 |
+
}
|
117 |
|
|
|
118 |
|
119 |
+
ITSEC_Modules::set_setting( $module, $setting_name, $setting_value );
|
|
|
|
|
120 |
|
121 |
+
self::$feedback->add_section( "enforce-setting-$module-$setting_name", array( 'status' => 'action-taken' ) );
|
122 |
+
self::$feedback->add_text( $description );
|
123 |
|
124 |
+
ITSEC_Response::reload_module( $module );
|
|
|
125 |
}
|
126 |
|
127 |
private static function enforce_activation( $module, $name ) {
|
129 |
return;
|
130 |
}
|
131 |
|
132 |
+
self::$feedback->add_section( "$module-activation" );
|
133 |
+
|
134 |
if ( ITSEC_Modules::is_active( $module ) ) {
|
135 |
/* Translators: 1: feature name */
|
136 |
$text = __( '%1$s is enabled as recommended.', 'better-wp-security' );
|
|
|
137 |
} else {
|
138 |
ITSEC_Modules::activate( $module );
|
139 |
ITSEC_Response::add_js_function_call( 'setModuleToActive', $module );
|
140 |
|
141 |
/* Translators: 1: feature name */
|
142 |
$text = __( 'Enabled %1$s.', 'better-wp-security' );
|
143 |
+
|
144 |
+
self::$feedback->set_section_arg( 'status', 'action-taken' );
|
145 |
}
|
146 |
|
147 |
+
self::$feedback->add_text( sprintf( $text, $name ) );
|
148 |
+
}
|
149 |
|
150 |
+
public static function activate_network_brute_force( $data ) {
|
151 |
+
if ( ! isset( $data['email'] ) ) {
|
152 |
+
ITSEC_Response::add_error( new WP_Error( 'itsec-security-check-missing-email', __( 'The email value is missing.', 'better-wp-security' ) ) );
|
153 |
+
return;
|
154 |
+
}
|
155 |
|
156 |
+
if ( ! isset( $data['updates_optin'] ) ) {
|
157 |
+
ITSEC_Response::add_error( new WP_Error( 'itsec-security-check-missing-updates_optin', __( 'The updates_optin value is missing.', 'better-wp-security' ) ) );
|
158 |
+
return;
|
|
|
159 |
}
|
|
|
160 |
|
161 |
+
|
162 |
$settings = ITSEC_Modules::get_settings( 'network-brute-force' );
|
163 |
|
164 |
+
$settings['email'] = $data['email'];
|
165 |
+
$settings['updates_optin'] = $data['updates_optin'];
|
166 |
$settings['api_nag'] = false;
|
167 |
|
168 |
$results = ITSEC_Modules::set_settings( 'network-brute-force', $settings );
|
175 |
ITSEC_Response::set_response( '<p>' . __( 'Your site is now using Network Brute Force Protection.', 'better-wp-security' ) . '</p>' );
|
176 |
}
|
177 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
178 |
}
|
core/modules/security-check/settings-page.php
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<?php
|
2 |
|
3 |
final class ITSEC_Security_Check_Settings_Page extends ITSEC_Module_Settings_Page {
|
4 |
-
private $script_version =
|
5 |
|
6 |
|
7 |
public function __construct() {
|
@@ -17,9 +17,8 @@ final class ITSEC_Security_Check_Settings_Page extends ITSEC_Module_Settings_Pag
|
|
17 |
|
18 |
public function enqueue_scripts_and_styles() {
|
19 |
$vars = array(
|
20 |
-
'securing_site'
|
21 |
-
'rerun_secure_site'
|
22 |
-
'activating_network_brute_force' => __( 'Activating Network Brute Force Protection...', 'better-wp-security' ),
|
23 |
);
|
24 |
|
25 |
wp_enqueue_script( 'itsec-security-check-settings-script', plugins_url( 'js/settings-page.js', __FILE__ ), array( 'jquery' ), $this->script_version, true );
|
@@ -29,37 +28,26 @@ final class ITSEC_Security_Check_Settings_Page extends ITSEC_Module_Settings_Pag
|
|
29 |
public function handle_ajax_request( $data ) {
|
30 |
if ( 'secure-site' === $data['method'] ) {
|
31 |
require_once( dirname( __FILE__ ) . '/scanner.php' );
|
|
|
32 |
|
33 |
-
ITSEC_Security_Check_Scanner::
|
|
|
|
|
|
|
|
|
34 |
} else if ( 'activate-network-brute-force' === $data['method'] ) {
|
35 |
require_once( dirname( __FILE__ ) . '/scanner.php' );
|
36 |
|
37 |
-
ITSEC_Security_Check_Scanner::activate_network_brute_force();
|
38 |
}
|
39 |
}
|
40 |
|
41 |
protected function render_description( $form ) {}
|
42 |
|
43 |
protected function render_settings( $form ) {
|
44 |
-
|
45 |
-
|
46 |
-
$modules_to_activate = array(
|
47 |
-
'ban-users' => __( 'Banned Users', 'better-wp-security' ),
|
48 |
-
'backup' => __( 'Database Backups', 'better-wp-security' ),
|
49 |
-
'brute-force' => __( 'Local Brute Force Protection', 'better-wp-security' ),
|
50 |
-
'malware-scheduling' => __( 'Malware Scan Scheduling', 'better-wp-security' ),
|
51 |
-
'network-brute-force' => __( 'Network Brute Force Protection', 'better-wp-security' ),
|
52 |
-
'strong-passwords' => __( 'Strong Passwords', 'better-wp-security' ),
|
53 |
-
'two-factor' => __( 'Two-Factor Authentication', 'better-wp-security' ),
|
54 |
-
'user-logging' => __( 'User Logging', 'better-wp-security' ),
|
55 |
-
'wordpress-tweaks' => __( 'WordPress Tweaks', 'better-wp-security' ),
|
56 |
-
);
|
57 |
|
58 |
-
|
59 |
-
if ( ! in_array( $module, $available_modules ) ) {
|
60 |
-
unset( $modules_to_activate[$module] );
|
61 |
-
}
|
62 |
-
}
|
63 |
|
64 |
?>
|
65 |
<div id="itsec-security-check-details-container">
|
1 |
<?php
|
2 |
|
3 |
final class ITSEC_Security_Check_Settings_Page extends ITSEC_Module_Settings_Page {
|
4 |
+
private $script_version = 2;
|
5 |
|
6 |
|
7 |
public function __construct() {
|
17 |
|
18 |
public function enqueue_scripts_and_styles() {
|
19 |
$vars = array(
|
20 |
+
'securing_site' => __( 'Securing Site...', 'better-wp-security' ),
|
21 |
+
'rerun_secure_site' => __( 'Run Secure Site Again', 'better-wp-security' ),
|
|
|
22 |
);
|
23 |
|
24 |
wp_enqueue_script( 'itsec-security-check-settings-script', plugins_url( 'js/settings-page.js', __FILE__ ), array( 'jquery' ), $this->script_version, true );
|
28 |
public function handle_ajax_request( $data ) {
|
29 |
if ( 'secure-site' === $data['method'] ) {
|
30 |
require_once( dirname( __FILE__ ) . '/scanner.php' );
|
31 |
+
require_once( dirname( __FILE__ ) . '/feedback-renderer.php' );
|
32 |
|
33 |
+
$results = ITSEC_Security_Check_Scanner::get_results();
|
34 |
+
|
35 |
+
ob_start();
|
36 |
+
ITSEC_Security_Check_Feedback_Renderer::render( $results );
|
37 |
+
ITSEC_Response::set_response( ob_get_clean() );
|
38 |
} else if ( 'activate-network-brute-force' === $data['method'] ) {
|
39 |
require_once( dirname( __FILE__ ) . '/scanner.php' );
|
40 |
|
41 |
+
ITSEC_Security_Check_Scanner::activate_network_brute_force( $_POST['data'] );
|
42 |
}
|
43 |
}
|
44 |
|
45 |
protected function render_description( $form ) {}
|
46 |
|
47 |
protected function render_settings( $form ) {
|
48 |
+
require_once( dirname( __FILE__ ) . '/scanner.php' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
+
$modules_to_activate = ITSEC_Security_Check_Scanner::get_supported_modules();
|
|
|
|
|
|
|
|
|
51 |
|
52 |
?>
|
53 |
<div id="itsec-security-check-details-container">
|
core/modules/security-check/sync-verbs/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden.
|
core/modules/security-check/sync-verbs/itsec-do-security-check.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ithemes_Sync_Verb_ITSEC_Do_Security_Check extends Ithemes_Sync_Verb {
|
4 |
+
public static $name = 'itsec-do-security-check';
|
5 |
+
public static $description = '';
|
6 |
+
|
7 |
+
public function run( $arguments ) {
|
8 |
+
require_once( dirname( dirname( __FILE__ ) ) . '/scanner.php' );
|
9 |
+
|
10 |
+
return ITSEC_Security_Check_Scanner::get_results();
|
11 |
+
}
|
12 |
+
}
|
core/modules/security-check/sync-verbs/itsec-get-security-check-feedback-response.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ithemes_Sync_Verb_ITSEC_Get_Security_Check_Feedback_Response extends Ithemes_Sync_Verb {
|
4 |
+
public static $name = 'itsec-get-security-check-feedback-response';
|
5 |
+
public static $description = '';
|
6 |
+
|
7 |
+
private $default_arguments = array(
|
8 |
+
'data' => array(),
|
9 |
+
);
|
10 |
+
|
11 |
+
public function run( $arguments ) {
|
12 |
+
$arguments = Ithemes_Sync_Functions::merge_defaults( $arguments, $this->default_arguments );
|
13 |
+
|
14 |
+
require_once( dirname( dirname( __FILE__ ) ) . '/scanner.php' );
|
15 |
+
|
16 |
+
ITSEC_Security_Check_Scanner::activate_network_brute_force( $arguments['data'] );
|
17 |
+
|
18 |
+
return ITSEC_Response::get_raw_data();
|
19 |
+
}
|
20 |
+
}
|
core/modules/security-check/sync-verbs/itsec-get-security-check-modules.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ithemes_Sync_Verb_ITSEC_Get_Security_Check_Modules extends Ithemes_Sync_Verb {
|
4 |
+
public static $name = 'itsec-get-security-check-modules';
|
5 |
+
public static $description = '';
|
6 |
+
|
7 |
+
public function run( $arguments ) {
|
8 |
+
require_once( dirname( dirname( __FILE__ ) ) . '/scanner.php' );
|
9 |
+
|
10 |
+
return ITSEC_Security_Check_Scanner::get_supported_modules();
|
11 |
+
}
|
12 |
+
}
|
core/modules/ssl/class-itsec-ssl-admin.php
CHANGED
@@ -47,7 +47,15 @@ class ITSEC_SSL_Admin {
|
|
47 |
|
48 |
if ( isset( $_POST['itsec_admin_save_wp_nonce'] ) ) {
|
49 |
|
50 |
-
if ( ! wp_verify_nonce( $_POST['itsec_admin_save_wp_nonce'], 'ITSEC_Admin_Save' )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
return $id;
|
52 |
}
|
53 |
|
47 |
|
48 |
if ( isset( $_POST['itsec_admin_save_wp_nonce'] ) ) {
|
49 |
|
50 |
+
if ( ! wp_verify_nonce( $_POST['itsec_admin_save_wp_nonce'], 'ITSEC_Admin_Save' ) ) {
|
51 |
+
return $id;
|
52 |
+
}
|
53 |
+
|
54 |
+
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
55 |
+
return $id;
|
56 |
+
}
|
57 |
+
|
58 |
+
if ( ! current_user_can( 'edit_post', $id ) ) {
|
59 |
return $id;
|
60 |
}
|
61 |
|
core/modules/strong-passwords/class-itsec-strong-passwords.php
CHANGED
@@ -2,8 +2,10 @@
|
|
2 |
|
3 |
final class ITSEC_Strong_Passwords {
|
4 |
public function __construct() {
|
|
|
|
|
5 |
add_action( 'user_profile_update_errors', array( $this, 'filter_user_profile_update_errors' ), 0, 3 );
|
6 |
-
add_action( '
|
7 |
|
8 |
add_action( 'admin_enqueue_scripts', array( $this, 'add_scripts' ) );
|
9 |
add_action( 'login_enqueue_scripts', array( $this, 'add_scripts' ) );
|
@@ -20,6 +22,18 @@ final class ITSEC_Strong_Passwords {
|
|
20 |
wp_enqueue_script( 'itsec_strong_passwords', $module_path . 'js/script.js', array( 'jquery' ), ITSEC_Core::get_plugin_build() );
|
21 |
}
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
/**
|
24 |
* Handle submission of a form to create or edit a user.
|
25 |
*
|
@@ -30,153 +44,201 @@ final class ITSEC_Strong_Passwords {
|
|
30 |
* @return WP_Error
|
31 |
*/
|
32 |
public function filter_user_profile_update_errors( $errors, $update, $user ) {
|
|
|
|
|
33 |
if ( $errors->get_error_data( 'pass' ) ) {
|
34 |
-
// An error regarding the password was already found.
|
35 |
return $errors;
|
36 |
}
|
37 |
|
38 |
-
$
|
|
|
|
|
39 |
|
40 |
-
|
41 |
-
|
42 |
-
// This also handles the case where a user's role is being changed to one that requires strong password enforcement.
|
43 |
|
44 |
-
|
45 |
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
}
|
50 |
}
|
51 |
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
|
|
58 |
|
59 |
-
|
|
|
|
|
60 |
|
61 |
-
|
62 |
-
|
63 |
-
if ( ! $wp_roles->is_role( $cap ) ) {
|
64 |
-
$user_caps[] = $cap;
|
65 |
-
}
|
66 |
-
}
|
67 |
-
}
|
68 |
}
|
69 |
|
70 |
-
if (
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
// The current user is being updated, this makes the logic simple as we can simply use $user_obj->allcaps to get a complete list of the user's caps.
|
75 |
-
$caps = array_keys( $user_obj->allcaps );
|
76 |
} else {
|
77 |
-
|
78 |
-
$role = get_option( 'default_role' );
|
79 |
}
|
80 |
|
81 |
-
|
82 |
-
|
|
|
|
|
83 |
|
84 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
|
86 |
-
|
87 |
-
$
|
|
|
|
|
|
|
88 |
|
89 |
-
|
90 |
-
$
|
|
|
|
|
|
|
|
|
|
|
91 |
}
|
92 |
|
93 |
-
if ( $this->
|
94 |
-
|
95 |
-
$errors->add( 'pass', wp_kses( __( '<strong>Error</strong>: Due to site rules, a strong password is required. Please choose a new password that rates as <strong>Strong</strong> on the meter. The user changes have not been saved.', 'better-wp-security' ), array( 'strong' => array() ) ) );
|
96 |
-
} else {
|
97 |
-
$errors->add( 'pass', wp_kses( __( '<strong>Error</strong>: Due to site rules, a strong password is required. Please choose a new password that rates as <strong>Strong</strong> on the meter. The user has not been created.', 'better-wp-security' ), array( 'strong' => array() ) ) );
|
98 |
-
}
|
99 |
}
|
100 |
|
101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
}
|
103 |
|
104 |
/**
|
105 |
-
*
|
106 |
*
|
107 |
-
* @param
|
108 |
-
* @param WP_User
|
109 |
*
|
110 |
-
* @return
|
111 |
*/
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
// submissions. Since the pass1 data is missing, this must be the initial page render. So, we don't need to
|
116 |
-
// do anything yet.
|
117 |
|
118 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
}
|
120 |
|
121 |
-
|
122 |
|
123 |
-
|
124 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
125 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
}
|
127 |
|
128 |
/**
|
129 |
* Determine if the user requires enforcement and if it fails that enforcement.
|
130 |
*
|
131 |
-
* @param WP_User|
|
132 |
* user_login, first_name, last_name, nickname, display_name, user_email, user_url, and
|
133 |
* description. A member of user_pass is required if $password_strength is false.
|
|
|
134 |
* @param int|boolean $password_strength [optional] An integer value representing the password strength, if known, or false.
|
135 |
* Defaults to false.
|
136 |
*
|
137 |
* @return boolean True if the user requires enforcement and has a password weaker than strong. False otherwise.
|
138 |
*/
|
139 |
-
private function fails_enforcement( $user, $
|
140 |
-
require_once( ITSEC_Core::get_core_dir() . '/lib/class-itsec-lib-canonical-roles.php' );
|
141 |
-
$role = ITSEC_Lib_Canonical_Roles::get_role_from_caps( $caps );
|
142 |
-
$min_role = ITSEC_Modules::get_setting( 'strong-passwords', 'role' );
|
143 |
|
144 |
-
if (
|
145 |
-
return
|
146 |
}
|
147 |
|
148 |
-
if (
|
149 |
-
if
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
$user
|
165 |
-
|
166 |
-
$user->description,
|
167 |
-
get_site_option( 'admin_email' ),
|
168 |
-
);
|
169 |
-
|
170 |
-
$results = ITSEC_Lib::get_password_strength_results( $user->user_pass, $penalty_strings );
|
171 |
-
$password_strength = $results->score;
|
172 |
}
|
173 |
-
}
|
174 |
|
175 |
-
|
176 |
-
|
177 |
}
|
178 |
|
179 |
-
return
|
180 |
}
|
181 |
}
|
182 |
|
2 |
|
3 |
final class ITSEC_Strong_Passwords {
|
4 |
public function __construct() {
|
5 |
+
|
6 |
+
add_filter( 'itsec_password_change_requirement_description_for_strength', array( $this, 'strength_reason' ) );
|
7 |
add_action( 'user_profile_update_errors', array( $this, 'filter_user_profile_update_errors' ), 0, 3 );
|
8 |
+
add_action( 'itsec_validate_password', array( $this, 'validate_password' ), 10, 4 );
|
9 |
|
10 |
add_action( 'admin_enqueue_scripts', array( $this, 'add_scripts' ) );
|
11 |
add_action( 'login_enqueue_scripts', array( $this, 'add_scripts' ) );
|
22 |
wp_enqueue_script( 'itsec_strong_passwords', $module_path . 'js/script.js', array( 'jquery' ), ITSEC_Core::get_plugin_build() );
|
23 |
}
|
24 |
|
25 |
+
/**
|
26 |
+
* Get the reason description for why a password change was set to 'strength'.
|
27 |
+
*
|
28 |
+
* @return string
|
29 |
+
*/
|
30 |
+
public function strength_reason() {
|
31 |
+
|
32 |
+
$message = __( 'Due to site rules, a strong password is required for your account. Please choose a new password that rates as <strong>Strong</strong> on the meter.', 'better-wp-security' );
|
33 |
+
|
34 |
+
return wp_kses( $message, array( 'strong' => '' ) );
|
35 |
+
}
|
36 |
+
|
37 |
/**
|
38 |
* Handle submission of a form to create or edit a user.
|
39 |
*
|
44 |
* @return WP_Error
|
45 |
*/
|
46 |
public function filter_user_profile_update_errors( $errors, $update, $user ) {
|
47 |
+
|
48 |
+
// An error regarding the password was already found.
|
49 |
if ( $errors->get_error_data( 'pass' ) ) {
|
|
|
50 |
return $errors;
|
51 |
}
|
52 |
|
53 |
+
if ( isset( $user->user_pass ) || ! $update ) {
|
54 |
+
return $errors;
|
55 |
+
}
|
56 |
|
57 |
+
// The password was not changed, but an update is occurring. Test to see if we need to prompt for a password change.
|
58 |
+
// This also handles the case where a user's role is being changed to one that requires strong password enforcement.
|
|
|
59 |
|
60 |
+
$strength = get_user_meta( $user->ID, 'itsec-password-strength', true );
|
61 |
|
62 |
+
if ( ! is_numeric( $strength ) || $strength < 0 || $strength > 4 ) {
|
63 |
+
// Not enough data to determine whether a change of password is required.
|
64 |
+
return $errors;
|
|
|
65 |
}
|
66 |
|
67 |
+
require_once( ITSEC_Core::get_core_dir() . '/lib/class-itsec-lib-canonical-roles.php' );
|
68 |
+
|
69 |
+
if ( isset( $user->role ) ) {
|
70 |
+
$role = $this->get_canonical_role_from_role_and_user( $user->role, $user );
|
71 |
+
} else {
|
72 |
+
$role = ITSEC_Lib_Canonical_Roles::get_user_role( $user );
|
73 |
+
}
|
74 |
|
75 |
+
if ( ! $this->role_requires_strong_password( $role ) ) {
|
76 |
+
return $errors;
|
77 |
+
}
|
78 |
|
79 |
+
if ( 4 === (int) $strength ) {
|
80 |
+
return $errors;
|
|
|
|
|
|
|
|
|
|
|
81 |
}
|
82 |
|
83 |
+
if ( ! $update ) {
|
84 |
+
$context = 'admin-user-create';
|
85 |
+
} elseif ( $user->ID === get_current_user_id() ) {
|
86 |
+
$context = 'profile-update';
|
|
|
|
|
87 |
} else {
|
88 |
+
$context = 'admin-profile-update';
|
|
|
89 |
}
|
90 |
|
91 |
+
$errors->add( 'pass', $this->make_error_message( $context ) );
|
92 |
+
|
93 |
+
return $errors;
|
94 |
+
}
|
95 |
|
96 |
+
/**
|
97 |
+
* Validate a new password according to the configured strength rules.
|
98 |
+
*
|
99 |
+
* @param WP_Error $error
|
100 |
+
* @param WP_User $user
|
101 |
+
* @param string $new_password
|
102 |
+
* @param array $args
|
103 |
+
*/
|
104 |
+
public function validate_password( $error, $user, $new_password, $args = array() ) {
|
105 |
|
106 |
+
if ( isset( $args['strength'] ) ) {
|
107 |
+
$reported_strength = $args['strength'];
|
108 |
+
} else {
|
109 |
+
$reported_strength = false;
|
110 |
+
}
|
111 |
|
112 |
+
if ( empty( $user->ID ) || ! is_numeric( $user->ID ) ) {
|
113 |
+
$role = isset( $args['role'] ) ? $args['role'] : get_option( 'default_role', 'subscriber' );
|
114 |
+
} elseif ( isset( $args['role'] ) ) {
|
115 |
+
$role = $this->get_canonical_role_from_role_and_user( $args['role'], $user );
|
116 |
+
} else {
|
117 |
+
require_once( ITSEC_Core::get_core_dir() . '/lib/class-itsec-lib-canonical-roles.php' );
|
118 |
+
$role = ITSEC_Lib_Canonical_Roles::get_user_role( $user );
|
119 |
}
|
120 |
|
121 |
+
if ( ! $this->role_requires_strong_password( $role ) ) {
|
122 |
+
return;
|
|
|
|
|
|
|
|
|
123 |
}
|
124 |
|
125 |
+
if ( ! $this->fails_enforcement( $user, $new_password, $reported_strength ) ) {
|
126 |
+
return;
|
127 |
+
}
|
128 |
+
|
129 |
+
$message = $this->make_error_message( $args['context'] );
|
130 |
+
|
131 |
+
$error->add( 'pass', $message );
|
132 |
}
|
133 |
|
134 |
/**
|
135 |
+
* Retrieve a canonical role for a user and a role.
|
136 |
*
|
137 |
+
* @param string $role
|
138 |
+
* @param WP_User $user
|
139 |
*
|
140 |
+
* @return string
|
141 |
*/
|
142 |
+
private function get_canonical_role_from_role_and_user( $role, $user ) {
|
143 |
+
$role_caps = array_keys( array_filter( wp_roles()->get_role( $role )->capabilities ) );
|
144 |
+
$user_caps = array();
|
|
|
|
|
145 |
|
146 |
+
if ( isset( $user->caps ) ) {
|
147 |
+
$wp_roles = wp_roles();
|
148 |
+
|
149 |
+
foreach ( $user->caps as $cap => $has ) {
|
150 |
+
if ( $has && ! $wp_roles->is_role( $cap ) ) {
|
151 |
+
$user_caps[] = $has;
|
152 |
+
}
|
153 |
+
}
|
154 |
}
|
155 |
|
156 |
+
require_once( ITSEC_Core::get_core_dir() . '/lib/class-itsec-lib-canonical-roles.php' );
|
157 |
|
158 |
+
return ITSEC_Lib_Canonical_Roles::get_role_from_caps( array_merge( $role_caps, $user_caps ) );
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Get the strong password error message according to the given context.
|
163 |
+
*
|
164 |
+
* @param string $context
|
165 |
+
*
|
166 |
+
* @return string
|
167 |
+
*/
|
168 |
+
private function make_error_message( $context ) {
|
169 |
+
$message = __( '<strong>Error</strong>: Due to site rules, a strong password is required. Please choose a new password that rates as <strong>Strong</strong> on the meter.', 'better-wp-security' );
|
170 |
+
|
171 |
+
if ( 'admin-user-create' === $context ) {
|
172 |
+
$message .= ' ' . __( 'The user has not been created.', 'better-wp-security' );
|
173 |
+
} elseif ( 'admin-profile-update' === $context ) {
|
174 |
+
$message .= ' ' . __( 'The user changes have not been saved.', 'better-wp-security' );
|
175 |
+
} elseif ( 'profile-update' === $context ) {
|
176 |
+
$message .= ' ' . __( 'Your profile has not been updated.', 'better-wp-security' );
|
177 |
+
} elseif ( 'reset-password' === $context ) {
|
178 |
+
$message .= ' ' . __( 'The password has not been updated.', 'better-wp-security' );
|
179 |
}
|
180 |
+
|
181 |
+
return wp_kses( $message, array( 'strong' => array() ) );
|
182 |
+
}
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Does the given role require a strong password.
|
186 |
+
*
|
187 |
+
* @param string $role The user's canonical role.
|
188 |
+
*
|
189 |
+
* @return bool
|
190 |
+
*/
|
191 |
+
private function role_requires_strong_password( $role ) {
|
192 |
+
require_once( ITSEC_Core::get_core_dir() . '/lib/class-itsec-lib-canonical-roles.php' );
|
193 |
+
|
194 |
+
$min_role = ITSEC_Modules::get_setting( 'strong-passwords', 'role' );
|
195 |
+
|
196 |
+
return ITSEC_Lib_Canonical_Roles::is_canonical_role_at_least( $min_role, $role );
|
197 |
}
|
198 |
|
199 |
/**
|
200 |
* Determine if the user requires enforcement and if it fails that enforcement.
|
201 |
*
|
202 |
+
* @param WP_User|stdClass $user Requires either a valid WP_User object or an object that has the following members:
|
203 |
* user_login, first_name, last_name, nickname, display_name, user_email, user_url, and
|
204 |
* description. A member of user_pass is required if $password_strength is false.
|
205 |
+
* @param string $new_password The user's new password.
|
206 |
* @param int|boolean $password_strength [optional] An integer value representing the password strength, if known, or false.
|
207 |
* Defaults to false.
|
208 |
*
|
209 |
* @return boolean True if the user requires enforcement and has a password weaker than strong. False otherwise.
|
210 |
*/
|
211 |
+
private function fails_enforcement( $user, $new_password, $password_strength = false ) {
|
|
|
|
|
|
|
212 |
|
213 |
+
if ( false !== $password_strength ) {
|
214 |
+
return $password_strength < 4;
|
215 |
}
|
216 |
|
217 |
+
if ( ! empty( $_POST['password_strength'] ) && 'strong' !== $_POST['password_strength'] ) {
|
218 |
+
// We want to validate the password strength if the form data says that the password is strong since we want
|
219 |
+
// to protect against spoofing. If the form data says that the password isn't strong, believe it.
|
220 |
+
|
221 |
+
$password_strength = 1;
|
222 |
+
} else {
|
223 |
+
// The form data does not indicate a password strength or the data claimed that the password is strong,
|
224 |
+
// which is a claim that must be validated. Use the zxcvbn library to find the password strength score.
|
225 |
+
|
226 |
+
$penalty_strings = array(
|
227 |
+
get_site_option( 'admin_email' )
|
228 |
+
);
|
229 |
+
$user_properties = array( 'user_login', 'first_name', 'last_name', 'nickname', 'display_name', 'user_email', 'user_url', 'description' );
|
230 |
+
|
231 |
+
foreach ( $user_properties as $user_property ) {
|
232 |
+
if ( isset( $user->$user_property ) ) {
|
233 |
+
$penalty_strings[] = $user->$user_property;
|
234 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
235 |
}
|
|
|
236 |
|
237 |
+
$results = ITSEC_Lib::get_password_strength_results( $new_password, $penalty_strings );
|
238 |
+
$password_strength = $results->score;
|
239 |
}
|
240 |
|
241 |
+
return $password_strength < 4;
|
242 |
}
|
243 |
}
|
244 |
|
core/modules/system-tweaks/class-itsec-system-tweaks.php
CHANGED
@@ -76,6 +76,9 @@ final class ITSEC_System_Tweaks {
|
|
76 |
return ITSEC_System_Tweaks_Config_Generators::filter_litespeed_server_config_modification( $modification );
|
77 |
}
|
78 |
|
|
|
|
|
|
|
79 |
public function block_long_urls() {
|
80 |
if ( strlen( $_SERVER['REQUEST_URI'] ) <= 255 ) {
|
81 |
return;
|
76 |
return ITSEC_System_Tweaks_Config_Generators::filter_litespeed_server_config_modification( $modification );
|
77 |
}
|
78 |
|
79 |
+
/**
|
80 |
+
* Block long URLs very early in the request cycle on the front-end.
|
81 |
+
*/
|
82 |
public function block_long_urls() {
|
83 |
if ( strlen( $_SERVER['REQUEST_URI'] ) <= 255 ) {
|
84 |
return;
|
core/modules/wordpress-tweaks/class-itsec-wordpress-tweaks.php
CHANGED
@@ -91,7 +91,7 @@ final class ITSEC_WordPress_Tweaks {
|
|
91 |
if ( 2 == $this->settings['disable_xmlrpc'] ) {
|
92 |
add_filter( 'xmlrpc_enabled', '__return_null' );
|
93 |
add_filter( 'bloginfo_url', array( $this, 'remove_pingback_url' ), 10, 2 );
|
94 |
-
} else if ( 1 == $this->settings['disable_xmlrpc'] ) {
|
95 |
add_filter( 'xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
|
96 |
}
|
97 |
|
@@ -122,7 +122,17 @@ final class ITSEC_WordPress_Tweaks {
|
|
122 |
}
|
123 |
}
|
124 |
|
125 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
if ( in_array( $this->settings['rest_api'], array( 'enable', 'default-access' ) ) ) {
|
127 |
return $result;
|
128 |
}
|
@@ -242,6 +252,15 @@ final class ITSEC_WordPress_Tweaks {
|
|
242 |
wp_enqueue_script( 'itsec-wt-block-tabnapping', plugins_url( 'js/block-tabnapping.js', __FILE__ ), array( 'blankshield' ), ITSEC_Core::get_plugin_build(), true );
|
243 |
}
|
244 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
245 |
public function block_multiauth_attempts( $filter_val, $username, $password ) {
|
246 |
if ( empty( $this->first_xmlrpc_credentials ) ) {
|
247 |
$this->first_xmlrpc_credentials = array(
|
@@ -261,11 +280,16 @@ final class ITSEC_WordPress_Tweaks {
|
|
261 |
die( __( 'XML-RPC services are disabled on this site.' ) );
|
262 |
}
|
263 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
264 |
public function current_jquery() {
|
265 |
|
266 |
-
|
267 |
-
|
268 |
-
if ( ! is_admin() && ! $itsec_is_old_admin ) {
|
269 |
|
270 |
wp_deregister_script( 'jquery' );
|
271 |
wp_deregister_script( 'jquery-core' );
|
@@ -300,10 +324,16 @@ final class ITSEC_WordPress_Tweaks {
|
|
300 |
}
|
301 |
|
302 |
/**
|
303 |
-
* Requires a
|
|
|
|
|
304 |
*
|
305 |
* @since 4.0
|
306 |
*
|
|
|
|
|
|
|
|
|
307 |
* @return void
|
308 |
*/
|
309 |
public function force_unique_nicename( &$errors, $update, &$user ) {
|
91 |
if ( 2 == $this->settings['disable_xmlrpc'] ) {
|
92 |
add_filter( 'xmlrpc_enabled', '__return_null' );
|
93 |
add_filter( 'bloginfo_url', array( $this, 'remove_pingback_url' ), 10, 2 );
|
94 |
+
} else if ( 1 == $this->settings['disable_xmlrpc'] ) { // Disable pingbacks
|
95 |
add_filter( 'xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
|
96 |
}
|
97 |
|
122 |
}
|
123 |
}
|
124 |
|
125 |
+
/**
|
126 |
+
* Require capabilities for reading from WordPress object routes.
|
127 |
+
*
|
128 |
+
* @param null|WP_REST_Response|WP_Error $result
|
129 |
+
* @param WP_REST_Request $request
|
130 |
+
* @param string $route_regex
|
131 |
+
* @param array $handler
|
132 |
+
*
|
133 |
+
* @return WP_Error
|
134 |
+
*/
|
135 |
+
public function filter_rest_dispatch_request( $result, $request, $route_regex, $handler ) {
|
136 |
if ( in_array( $this->settings['rest_api'], array( 'enable', 'default-access' ) ) ) {
|
137 |
return $result;
|
138 |
}
|
252 |
wp_enqueue_script( 'itsec-wt-block-tabnapping', plugins_url( 'js/block-tabnapping.js', __FILE__ ), array( 'blankshield' ), ITSEC_Core::get_plugin_build(), true );
|
253 |
}
|
254 |
|
255 |
+
/**
|
256 |
+
* Prevent an attacker from trying multiple login credentials in a single XML-RPC request.
|
257 |
+
*
|
258 |
+
* @param WP_User|WP_Error|null $filter_val
|
259 |
+
* @param string $username
|
260 |
+
* @param string $password
|
261 |
+
*
|
262 |
+
* @return null|\WP_User|\WP_Error
|
263 |
+
*/
|
264 |
public function block_multiauth_attempts( $filter_val, $username, $password ) {
|
265 |
if ( empty( $this->first_xmlrpc_credentials ) ) {
|
266 |
$this->first_xmlrpc_credentials = array(
|
280 |
die( __( 'XML-RPC services are disabled on this site.' ) );
|
281 |
}
|
282 |
|
283 |
+
/**
|
284 |
+
* Attempt to force the core version of jQuery to be loaded.
|
285 |
+
*
|
286 |
+
* This will deregister the current version of jQuery and re-enqueue with the core version of the script.
|
287 |
+
*
|
288 |
+
* This could probably be refactored to use the 'script_loader_src' filter.
|
289 |
+
*/
|
290 |
public function current_jquery() {
|
291 |
|
292 |
+
if ( ! is_admin() ) {
|
|
|
|
|
293 |
|
294 |
wp_deregister_script( 'jquery' );
|
295 |
wp_deregister_script( 'jquery-core' );
|
324 |
}
|
325 |
|
326 |
/**
|
327 |
+
* Requires a user's nicename to be distinct from their username.
|
328 |
+
*
|
329 |
+
* This helps to prevent username leaking.
|
330 |
*
|
331 |
* @since 4.0
|
332 |
*
|
333 |
+
* @param \WP_Error $errors
|
334 |
+
* @param bool $update
|
335 |
+
* @param \WP_User $user
|
336 |
+
*
|
337 |
* @return void
|
338 |
*/
|
339 |
public function force_unique_nicename( &$errors, $update, &$user ) {
|
core/{class-itsec-notify.php → notify.php}
RENAMED
@@ -68,6 +68,8 @@ class ITSEC_Notify {
|
|
68 |
* @return
|
69 |
*/
|
70 |
public function send_daily_digest() {
|
|
|
|
|
71 |
global $itsec_lockout;
|
72 |
|
73 |
|
68 |
* @return
|
69 |
*/
|
70 |
public function send_daily_digest() {
|
71 |
+
|
72 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
73 |
global $itsec_lockout;
|
74 |
|
75 |
|
core/{class-itsec-response.php → response.php}
RENAMED
@@ -226,7 +226,7 @@ final class ITSEC_Response {
|
|
226 |
}
|
227 |
}
|
228 |
|
229 |
-
public static function
|
230 |
$self = self::get_instance();
|
231 |
|
232 |
self::maybe_regenerate_wp_config();
|
@@ -250,6 +250,12 @@ final class ITSEC_Response {
|
|
250 |
'closeModal' => $self->close_modal,
|
251 |
);
|
252 |
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
wp_send_json( $data );
|
254 |
}
|
255 |
|
226 |
}
|
227 |
}
|
228 |
|
229 |
+
public static function get_raw_data() {
|
230 |
$self = self::get_instance();
|
231 |
|
232 |
self::maybe_regenerate_wp_config();
|
250 |
'closeModal' => $self->close_modal,
|
251 |
);
|
252 |
|
253 |
+
return $data;
|
254 |
+
}
|
255 |
+
|
256 |
+
public static function send_json() {
|
257 |
+
$data = self::get_raw_data();
|
258 |
+
|
259 |
wp_send_json( $data );
|
260 |
}
|
261 |
|
core/{class-itsec-setup.php → setup.php}
RENAMED
@@ -76,7 +76,6 @@ final class ITSEC_Setup {
|
|
76 |
|
77 |
|
78 |
// Ensure that the database tables are present and updated to the current schema.
|
79 |
-
require_once( ITSEC_Core::get_core_dir() . '/class-itsec-lib.php' );
|
80 |
ITSEC_Lib::create_database_tables();
|
81 |
|
82 |
// Run activation routines for modules to ensure that they are properly set up.
|
@@ -144,7 +143,7 @@ final class ITSEC_Setup {
|
|
144 |
|
145 |
}
|
146 |
|
147 |
-
private function uninstall() {
|
148 |
|
149 |
global $wpdb;
|
150 |
|
76 |
|
77 |
|
78 |
// Ensure that the database tables are present and updated to the current schema.
|
|
|
79 |
ITSEC_Lib::create_database_tables();
|
80 |
|
81 |
// Run activation routines for modules to ensure that they are properly set up.
|
143 |
|
144 |
}
|
145 |
|
146 |
+
private static function uninstall() {
|
147 |
|
148 |
global $wpdb;
|
149 |
|
core/sidebar-widget-active-lockouts.php
CHANGED
@@ -10,6 +10,8 @@ class ITSEC_Settings_Page_Sidebar_Widget_Active_Lockouts extends ITSEC_Settings_
|
|
10 |
}
|
11 |
|
12 |
public function render( $form ) {
|
|
|
|
|
13 |
global $itsec_lockout;
|
14 |
|
15 |
$lockouts = $itsec_lockout->get_lockouts( 'all', true );
|
@@ -78,6 +80,8 @@ class ITSEC_Settings_Page_Sidebar_Widget_Active_Lockouts extends ITSEC_Settings_
|
|
78 |
}
|
79 |
|
80 |
protected function save( $data ) {
|
|
|
|
|
81 |
global $itsec_lockout;
|
82 |
|
83 |
$count = 0;
|
10 |
}
|
11 |
|
12 |
public function render( $form ) {
|
13 |
+
|
14 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
15 |
global $itsec_lockout;
|
16 |
|
17 |
$lockouts = $itsec_lockout->get_lockouts( 'all', true );
|
80 |
}
|
81 |
|
82 |
protected function save( $data ) {
|
83 |
+
|
84 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
85 |
global $itsec_lockout;
|
86 |
|
87 |
$count = 0;
|
core/sidebar-widget-temp-whitelist.php
CHANGED
@@ -9,6 +9,8 @@ class ITSEC_Settings_Page_Sidebar_Widget_Temp_Whitelist extends ITSEC_Settings_P
|
|
9 |
}
|
10 |
|
11 |
public function render( $form ) {
|
|
|
|
|
12 |
global $itsec_lockout;
|
13 |
|
14 |
$lockouts = $itsec_lockout->get_lockouts( 'all', true );
|
9 |
}
|
10 |
|
11 |
public function render( $form ) {
|
12 |
+
|
13 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
14 |
global $itsec_lockout;
|
15 |
|
16 |
$lockouts = $itsec_lockout->get_lockouts( 'all', true );
|
core/sync-verbs/itsec-get-temp-whitelist.php
CHANGED
@@ -8,6 +8,7 @@ class Ithemes_Sync_Verb_ITSEC_Get_Temp_Whitelist extends Ithemes_Sync_Verb {
|
|
8 |
|
9 |
|
10 |
public function run( $arguments ) {
|
|
|
11 |
global $itsec_lockout;
|
12 |
|
13 |
$response = array(
|
8 |
|
9 |
|
10 |
public function run( $arguments ) {
|
11 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
12 |
global $itsec_lockout;
|
13 |
|
14 |
$response = array(
|
core/sync-verbs/itsec-release-lockout.php
CHANGED
@@ -11,6 +11,7 @@ class Ithemes_Sync_Verb_ITSEC_Release_Lockout extends Ithemes_Sync_Verb {
|
|
11 |
|
12 |
public function run( $arguments ) {
|
13 |
|
|
|
14 |
global $itsec_lockout;
|
15 |
|
16 |
$id = intval( $arguments['id'] );
|
11 |
|
12 |
public function run( $arguments ) {
|
13 |
|
14 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
15 |
global $itsec_lockout;
|
16 |
|
17 |
$id = intval( $arguments['id'] );
|
core/sync-verbs/itsec-set-temp-whitelist.php
CHANGED
@@ -11,6 +11,7 @@ class Ithemes_Sync_Verb_ITSEC_Set_Temp_Whitelist extends Ithemes_Sync_Verb {
|
|
11 |
|
12 |
|
13 |
public function run( $arguments ) {
|
|
|
14 |
global $itsec_lockout;
|
15 |
|
16 |
|
11 |
|
12 |
|
13 |
public function run( $arguments ) {
|
14 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
15 |
global $itsec_lockout;
|
16 |
|
17 |
|
history.txt
CHANGED
@@ -627,3 +627,38 @@
|
|
627 |
Bug Fix: When a requesting IP address cannot be found, default to 127.0.0.1. This fixes issues with some alternate cron setups.
|
628 |
Bug Fix: Having more than one iThemes Security modification in a .htaccess, nginx.conf, or wp-config.php file will no longer result in having all the file content between each section removed when updating the file.
|
629 |
Bug Fix: Modifications to the wp-config.php file added by W3 Total Cache now have their Windows-style newlines preserved when iThemes Security updates the file.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
627 |
Bug Fix: When a requesting IP address cannot be found, default to 127.0.0.1. This fixes issues with some alternate cron setups.
|
628 |
Bug Fix: Having more than one iThemes Security modification in a .htaccess, nginx.conf, or wp-config.php file will no longer result in having all the file content between each section removed when updating the file.
|
629 |
Bug Fix: Modifications to the wp-config.php file added by W3 Total Cache now have their Windows-style newlines preserved when iThemes Security updates the file.
|
630 |
+
6.3.0 - 2017-07-06 - Chris Jean & Timothy Jacobs
|
631 |
+
Important: The way that Hide Backend functions changes in this release. Previously, if your Hide Backend Login Slug was wplogin, going to example.com/wplogin would result in the URL remaining example.com/wplogin. The new implementation of this feature results in a redirect to a URL that looks as follows: example.com/wp-login.php?itsec-hb-token=wplogin. While this may not be desireable for some users, this change was necessary to fix longstanding compatibility issues with other plugins. Once you access the login page using the Login Slug page, a cookie is set with an expiration time of one hour. As long as the cookie remains, you can access example.com/wp-login.php without having to access the Hide Backend Login Slug first. If you wish to confirm that Hide Backend is working properly on your site, opening up a private browsing window is a quick way to test without having to log out and clear cookies.
|
632 |
+
|
633 |
+
New Feature: Added support for iThemes Sync to run the Security Check feature from inside the Sync service.
|
634 |
+
New Feature: Added support for the ITSEC_DISABLE_MODULES define.
|
635 |
+
Bug Fix: Removed warning: "Non-static method ITSEC_Setup::uninstall() should not be called statically".
|
636 |
+
Bug Fix: Fixed the ability to manually enter a page number to navigate to on the Security > Logs page.
|
637 |
+
Bug Fix: Fixed source of warning that could appear when creating a backup while running a PHP version less than 5.4.
|
638 |
+
Bug Fix: Fixed source of notice that could appear when reseting a user's password when the Strong Passwords Enforcement feature is enabled.
|
639 |
+
Bug Fix: Fixed bugs that prevented reporting of specific error messages related to updating the wp-config.php file.
|
640 |
+
Bug Fix: Fixed an infinite loop that could occur when expiring a cookie and Hide Backend is enabled.
|
641 |
+
Bug Fix: Fixed compatibility issue with the Jetpack plugin when Hide Backend is enabled which could prevent Jetpack from redirecting users to the wordpress.com login page.
|
642 |
+
Bug Fix: Fixed issue where access to wp-admin/admin-post.php when Hide Backend is enabled.
|
643 |
+
Bug Fix: Fixed issue that could prevent "Register" and "Lost your password?" links from working properly on the login page when Hide Backend is enabled.
|
644 |
+
Bug Fix: Fix fatal error when updating a profile.
|
645 |
+
Bug Fix: Fix strong passwords not being recognized as strong on the profile page.
|
646 |
+
Bug Fix: Fix fatal error when registering a new user without specifying a role ( iThemes Exchange ).
|
647 |
+
Bug Fix: Compatability with JetPack SSO and Password Requirements.
|
648 |
+
Bug Fix: Ensure viewport meta is defined when loading the password requirements update password form.
|
649 |
+
Bug Fix: Hide Backend is now compatible with Jetpack Single Sign On.
|
650 |
+
Bug Fix: Hide Backend now hides registration pages on multisite sites.
|
651 |
+
Bug Fix: Fixed password-protected posts not properly handling the password when Hide Backend is enabled.
|
652 |
+
Enhancement: Removed AhrefsBot from the HackRepair blacklist as they are legitimate bot.
|
653 |
+
Enhancement: Improved efficiency of Hide Backend code, increasing site performance when the feature is enabled.
|
654 |
+
Enhancement: Enforce strong passwords during log-in. Can be disabled via the ITSEC_DISABLE_PASSWORD_REQUIREMENTS constant.
|
655 |
+
Enhancement: Use canonical roles library to determine if a new user or an updated role requires a strong password.
|
656 |
+
Enhancement: Introduce password requirements module to centralize handling of password updates.
|
657 |
+
Enhancement: The Hide Backend hidden login URL is no longer leaked by password-protected content.
|
658 |
+
Enhancement: Allow for searching through modules and settings.
|
659 |
+
Enhancement: Link to other module settings pages without forcing the page to refresh.
|
660 |
+
Enhancement: Fire an action, "itsec_change_admin_user_id", when the admin user id changes.
|
661 |
+
Enhancement: Changed default Hide Backend Register Slug from wp-register.php to wp-signup.php since WordPress switched from using wp-register.php to wp-signup.php for registrations. This will not affect existing sites.
|
662 |
+
Enhancement: Hide Backend functions purely in PHP code now rather than relying half on PHP code and half on .htaccess and nginx.conf modifications. This allows Hide Backend to function on web servers and server configurations that it was previously not compatible with.
|
663 |
+
Misc: Updated or added phpDoc to many functions.
|
664 |
+
Misc: Updated Disable File Locking description.
|
readme.txt
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
=== iThemes Security (formerly Better WP Security) ===
|
2 |
Contributors: ithemes, chrisjean, gerroald, mattdanner
|
3 |
Tags: security, security plugin, malware, hack, secure, block, SSL, admin, htaccess, lockdown, login, protect, protection, anti virus, attack, injection, login security, maintenance, permissions, prevention, authentication, administration, password, brute force, ban, permissions, bots, user agents, xml rpc, security log
|
4 |
-
Requires at least: 4.
|
5 |
-
Tested up to: 4.
|
6 |
-
Stable tag: 6.
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
@@ -188,6 +188,41 @@ Free support may be available with the help of the community in the <a href="htt
|
|
188 |
|
189 |
== Changelog ==
|
190 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
191 |
= 6.2.1 =
|
192 |
* Bug Fix: When a requesting IP address cannot be found, default to 127.0.0.1. This fixes issues with some alternate cron setups.
|
193 |
* Bug Fix: Having more than one iThemes Security modification in a .htaccess, nginx.conf, or wp-config.php file will no longer result in having all the file content between each section removed when updating the file.
|
@@ -1666,5 +1701,5 @@ This release is a complete rewrite from the ground up. Special thanks to Cory Mi
|
|
1666 |
|
1667 |
== Upgrade Notice ==
|
1668 |
|
1669 |
-
= 6.
|
1670 |
-
Version 6.
|
1 |
=== iThemes Security (formerly Better WP Security) ===
|
2 |
Contributors: ithemes, chrisjean, gerroald, mattdanner
|
3 |
Tags: security, security plugin, malware, hack, secure, block, SSL, admin, htaccess, lockdown, login, protect, protection, anti virus, attack, injection, login security, maintenance, permissions, prevention, authentication, administration, password, brute force, ban, permissions, bots, user agents, xml rpc, security log
|
4 |
+
Requires at least: 4.6
|
5 |
+
Tested up to: 4.8
|
6 |
+
Stable tag: 6.3.0
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
188 |
|
189 |
== Changelog ==
|
190 |
|
191 |
+
= 6.3.0 =
|
192 |
+
* Important: The way that Hide Backend functions changes in this release. Previously, if your Hide Backend Login Slug was wplogin, going to example.com/wplogin would result in the URL remaining example.com/wplogin. The new implementation of this feature results in a redirect to a URL that looks as follows: example.com/wp-login.php?itsec-hb-token=wplogin. While this may not be desireable for some users, this change was necessary to fix longstanding compatibility issues with other plugins. Once you access the login page using the Login Slug page, a cookie is set with an expiration time of one hour. As long as the cookie remains, you can access example.com/wp-login.php without having to access the Hide Backend Login Slug first. If you wish to confirm that Hide Backend is working properly on your site, opening up a private browsing window is a quick way to test without having to log out and clear cookies.
|
193 |
+
* New Feature: Added support for iThemes Sync to run the Security Check feature from inside the Sync service.
|
194 |
+
* New Feature: Added support for the ITSEC_DISABLE_MODULES define.
|
195 |
+
* Bug Fix: Removed warning: "Non-static method ITSEC_Setup::uninstall() should not be called statically".
|
196 |
+
* Bug Fix: Fixed the ability to manually enter a page number to navigate to on the Security > Logs page.
|
197 |
+
* Bug Fix: Fixed source of warning that could appear when creating a backup while running a PHP version less than 5.4.
|
198 |
+
* Bug Fix: Fixed source of notice that could appear when reseting a user's password when the Strong Passwords Enforcement feature is enabled.
|
199 |
+
* Bug Fix: Fixed bugs that prevented reporting of specific error messages related to updating the wp-config.php file.
|
200 |
+
* Bug Fix: Fixed an infinite loop that could occur when expiring a cookie and Hide Backend is enabled.
|
201 |
+
* Bug Fix: Fixed compatibility issue with the Jetpack plugin when Hide Backend is enabled which could prevent Jetpack from redirecting users to the wordpress.com login page.
|
202 |
+
* Bug Fix: Fixed issue where access to wp-admin/admin-post.php when Hide Backend is enabled.
|
203 |
+
* Bug Fix: Fixed issue that could prevent "Register" and "Lost your password?" links from working properly on the login page when Hide Backend is enabled.
|
204 |
+
* Bug Fix: Fix fatal error when updating a profile.
|
205 |
+
* Bug Fix: Fix strong passwords not being recognized as strong on the profile page.
|
206 |
+
* Bug Fix: Fix fatal error when registering a new user without specifying a role ( iThemes Exchange ).
|
207 |
+
* Bug Fix: Compatability with JetPack SSO and Password Requirements.
|
208 |
+
* Bug Fix: Ensure viewport meta is defined when loading the password requirements update password form.
|
209 |
+
* Bug Fix: Hide Backend is now compatible with Jetpack Single Sign On.
|
210 |
+
* Bug Fix: Hide Backend now hides registration pages on multisite sites.
|
211 |
+
* Bug Fix: Fixed password-protected posts not properly handling the password when Hide Backend is enabled.
|
212 |
+
* Enhancement: Removed AhrefsBot from the HackRepair blacklist as they are legitimate bot.
|
213 |
+
* Enhancement: Improved efficiency of Hide Backend code, increasing site performance when the feature is enabled.
|
214 |
+
* Enhancement: Enforce strong passwords during log-in. Can be disabled via the ITSEC_DISABLE_PASSWORD_REQUIREMENTS constant.
|
215 |
+
* Enhancement: Use canonical roles library to determine if a new user or an updated role requires a strong password.
|
216 |
+
* Enhancement: Introduce password requirements module to centralize handling of password updates.
|
217 |
+
* Enhancement: The Hide Backend hidden login URL is no longer leaked by password-protected content.
|
218 |
+
* Enhancement: Allow for searching through modules and settings.
|
219 |
+
* Enhancement: Link to other module settings pages without forcing the page to refresh.
|
220 |
+
* Enhancement: Fire an action, "itsec_change_admin_user_id", when the admin user id changes.
|
221 |
+
* Enhancement: Changed default Hide Backend Register Slug from wp-register.php to wp-signup.php since WordPress switched from using wp-register.php to wp-signup.php for registrations. This will not affect existing sites.
|
222 |
+
* Enhancement: Hide Backend functions purely in PHP code now rather than relying half on PHP code and half on .htaccess and nginx.conf modifications. This allows Hide Backend to function on web servers and server configurations that it was previously not compatible with.
|
223 |
+
* Misc: Updated or added phpDoc to many functions.
|
224 |
+
* Misc: Updated Disable File Locking description.
|
225 |
+
|
226 |
= 6.2.1 =
|
227 |
* Bug Fix: When a requesting IP address cannot be found, default to 127.0.0.1. This fixes issues with some alternate cron setups.
|
228 |
* Bug Fix: Having more than one iThemes Security modification in a .htaccess, nginx.conf, or wp-config.php file will no longer result in having all the file content between each section removed when updating the file.
|
1701 |
|
1702 |
== Upgrade Notice ==
|
1703 |
|
1704 |
+
= 6.3.0 =
|
1705 |
+
Version 6.3.0 contains important bug and compatibility fixes. It is recommended for all users.
|