Version Description
- New Feature: Introduces the Notification Center, a centralized place to manage and customize email notifications sent by iThemes Security.
- Enhancement: Updated queries and prepare statements to account for changes to the esc_sql() function in WordPress 4.8.3.
- Bug Fix: Corrected some Javascript and CSS links not generating correctly on Windows servers.
Download this release
Release Info
Developer | chrisjean |
Plugin | iThemes Security (formerly Better WP Security) |
Version | 6.7.0 |
Comparing to | |
See all releases |
Code changes from version 6.6.1 to 6.7.0
- better-wp-security.php +1 -1
- core/admin-pages/css/style.css +23 -0
- core/admin-pages/js/script.js +84 -11
- core/admin-pages/module-settings.php +8 -1
- core/admin-pages/page-settings.php +21 -3
- core/core.php +21 -1
- core/history.txt +19 -0
- core/lib.php +49 -236
- core/lib/class-itsec-mail.php +255 -34
- core/lib/mail-templates/close.html +8 -0
- core/lib/mail-templates/file-change-summary.html +40 -0
- core/lib/mail-templates/footer-user.html +27 -0
- core/lib/mail-templates/footer.html +156 -162
- core/lib/mail-templates/header.html +7 -6
- core/lib/mail-templates/large-code.html +23 -0
- core/lib/mail-templates/list.html +27 -0
- core/lib/mail-templates/lockouts-table.html +1 -1
- core/lib/mail-templates/table.html +13 -0
- core/lockout.php +115 -68
- core/logger.php +1 -3
- core/modules/404-detection/settings-page.php +4 -2
- core/modules/admin-user/validator.php +13 -11
- core/modules/backup/class-itsec-backup.php +49 -10
- core/modules/brute-force/settings-page.php +4 -1
- core/modules/core/setup.php +8 -0
- core/modules/database-prefix/utility.php +4 -6
- core/modules/file-change/class-itsec-file-change.php +34 -0
- core/modules/file-change/scanner.php +66 -97
- core/modules/file-change/settings-page.php +0 -8
- core/modules/file-change/settings.php +0 -1
- core/modules/file-change/validator.php +2 -2
- core/modules/global/settings-page.php +0 -31
- core/modules/global/settings.php +0 -8
- core/modules/global/validator.php +2 -10
- core/modules/hide-backend/class-itsec-hide-backend.php +45 -0
- core/modules/hide-backend/validator.php +20 -39
- core/modules/notification-center/active.php +7 -0
- core/modules/notification-center/class-notification-center.php +1079 -0
- core/modules/notification-center/css/index.php +1 -0
- core/modules/notification-center/css/settings-page.css +42 -0
- core/modules/notification-center/index.php +1 -0
- core/modules/notification-center/js/index.php +1 -0
- core/modules/notification-center/js/settings-page.js +44 -0
- core/modules/notification-center/settings-page.php +320 -0
- core/modules/notification-center/settings.php +148 -0
- core/modules/notification-center/setup.php +123 -0
- core/modules/notification-center/validator.php +313 -0
- core/modules/strong-passwords/class-itsec-strong-passwords.php +1 -3
- core/notify.php +217 -158
- core/response.php +51 -9
- core/setup.php +4 -4
- core/sidebar-widget-active-lockouts.php +1 -1
- core/sidebar-widget-temp-whitelist.php +3 -1
- core/sync-verbs/itsec-get-lockouts.php +2 -1
- history.txt +4 -0
- readme.txt +9 -4
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
|
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.7.0
|
10 |
* Text Domain: better-wp-security
|
11 |
* Network: True
|
12 |
* License: GPLv2
|
core/admin-pages/css/style.css
CHANGED
@@ -384,6 +384,10 @@ body.itsec-modal-open {
|
|
384 |
border-left-color: #00a0d2;
|
385 |
box-shadow: 1px 1px 0px rgba(0,0,0,.1);
|
386 |
}
|
|
|
|
|
|
|
|
|
387 |
.itsec-module-card-content .module-actions {
|
388 |
float: none;
|
389 |
margin: 1em 0 0 0;
|
@@ -597,6 +601,25 @@ body.itsec-modal-open {
|
|
597 |
background: #fff9ec;
|
598 |
}
|
599 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
600 |
/*
|
601 |
* Security Check
|
602 |
*/
|
384 |
border-left-color: #00a0d2;
|
385 |
box-shadow: 1px 1px 0px rgba(0,0,0,.1);
|
386 |
}
|
387 |
+
.itsec-module-type-enabled.itsec-module-status--warning .itsec-module-card-content {
|
388 |
+
background: #fff8e5;
|
389 |
+
border-left-color: #ffb900;
|
390 |
+
}
|
391 |
.itsec-module-card-content .module-actions {
|
392 |
float: none;
|
393 |
margin: 1em 0 0 0;
|
601 |
background: #fff9ec;
|
602 |
}
|
603 |
|
604 |
+
.notice.itsec-is-dismissible {
|
605 |
+
padding-right: 38px;
|
606 |
+
position: relative;
|
607 |
+
}
|
608 |
+
|
609 |
+
.itsec-notification-center-link {
|
610 |
+
float: right;
|
611 |
+
text-decoration: none;
|
612 |
+
font-style: italic;
|
613 |
+
font-weight: normal;
|
614 |
+
font-size: .8rem;
|
615 |
+
}
|
616 |
+
|
617 |
+
.itsec-notification-center-link::after {
|
618 |
+
content: "\f345";
|
619 |
+
font-family: Dashicons;
|
620 |
+
font-size: .8rem;
|
621 |
+
vertical-align: sub;
|
622 |
+
}
|
623 |
/*
|
624 |
* Security Check
|
625 |
*/
|
core/admin-pages/js/script.js
CHANGED
@@ -14,6 +14,7 @@ var itsecSettingsPage = {
|
|
14 |
|
15 |
this.initFilters();
|
16 |
this.initCurrentModule();
|
|
|
17 |
},
|
18 |
|
19 |
initFilters: function() {
|
@@ -236,6 +237,7 @@ var itsecSettingsPage = {
|
|
236 |
itsecSettingsPage.showErrors( results.errors, results.module, 'open' );
|
237 |
itsecSettingsPage.showErrors( results.warnings, results.module, 'open', 'warning' );
|
238 |
itsecSettingsPage.showMessages( results.messages, results.module, 'open' );
|
|
|
239 |
|
240 |
if ( 'grid' === view ) {
|
241 |
$container.find( '.itsec-module-settings-content-container:visible' ).animate( {'scrollTop': 0}, 'fast' );
|
@@ -246,6 +248,7 @@ var itsecSettingsPage = {
|
|
246 |
}
|
247 |
} else {
|
248 |
itsecSettingsPage.showMessages( results.messages, results.module, 'closed' );
|
|
|
249 |
|
250 |
if ( 'grid' === view ) {
|
251 |
$container.find( '.itsec-module-settings-content-container:visible' ).scrollTop( 0 );
|
@@ -303,13 +306,16 @@ var itsecSettingsPage = {
|
|
303 |
container.append( $notice ).addClass( 'visible' );
|
304 |
},
|
305 |
|
306 |
-
showMessages: function( messages, module, containerStatus ) {
|
307 |
jQuery.each( messages, function( index, message ) {
|
308 |
-
itsecSettingsPage.showMessage( message, module, containerStatus );
|
309 |
} );
|
310 |
},
|
311 |
|
312 |
-
showMessage: function( message, module, containerStatus ) {
|
|
|
|
|
|
|
313 |
if ( jQuery( '.itsec-module-cards-container' ).hasClass( 'grid' ) ) {
|
314 |
var view = 'grid';
|
315 |
} else {
|
@@ -328,17 +334,25 @@ var itsecSettingsPage = {
|
|
328 |
if ( 'closed' === containerStatus || '' === module ) {
|
329 |
var container = jQuery( '#itsec-settings-messages-container' );
|
330 |
|
331 |
-
|
|
|
|
|
|
|
|
|
|
|
332 |
container.removeClass( 'visible' );
|
333 |
-
setTimeout( function() {
|
334 |
container.find( 'div' ).remove();
|
335 |
}, 500 );
|
336 |
-
}
|
|
|
|
|
337 |
} else {
|
338 |
var container = jQuery( '#itsec-module-card-' + module + ' .itsec-module-messages-container' );
|
339 |
}
|
340 |
|
341 |
-
var $notice = jQuery( '<div class="notice
|
|
|
342 |
|
343 |
if ( containerStatus === 'open' || module.length ) {
|
344 |
$notice.addClass( 'notice-alt' );
|
@@ -434,7 +448,7 @@ var itsecSettingsPage = {
|
|
434 |
var $listClassElement = $module.parents( '.itsec-module-cards-container' ),
|
435 |
$toggleButton = $module.find( '.itsec-toggle-settings' );
|
436 |
|
437 |
-
if ( highlight.length ) {
|
438 |
jQuery( 'label[for="' + highlight + '"]', $module ).parents( 'tr' ).addClass( 'itsec-highlighted-setting' );
|
439 |
}
|
440 |
|
@@ -447,6 +461,14 @@ var itsecSettingsPage = {
|
|
447 |
var type = $module.hasClass( 'itsec-module-type-advanced' ) ? 'advanced' : 'recommended';
|
448 |
|
449 |
window.history.pushState( {module: module}, module, '?page=itsec&module=' + module + '&module_type=' + type );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
450 |
},
|
451 |
|
452 |
toggleSettings: function( e ) {
|
@@ -698,6 +720,11 @@ var itsecSettingsPage = {
|
|
698 |
|
699 |
jQuery( '#itsec-module-filter-enabled .count' ).html( '(' + enabledCount + ')' );
|
700 |
jQuery( '#itsec-module-filter-disabled .count' ).html( '(' + disabledCount + ')' );
|
|
|
|
|
|
|
|
|
|
|
701 |
},
|
702 |
|
703 |
isModuleActive: function( module ) {
|
@@ -733,13 +760,25 @@ var itsecSettingsPage = {
|
|
733 |
|
734 |
itsecSettingsPage.sendAJAXRequest( module, method, data, function( results ) {
|
735 |
if ( results.success && results.response ) {
|
736 |
-
jQuery( '#itsec-module-card-' + module
|
737 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
738 |
} else if ( results.errors && results.errors.length > 0 ) {
|
739 |
itsecSettingsPage.showErrors( results.errors, results.module, 'open' );
|
740 |
} else if ( results.warnings && results.warnings.length > 0 ) {
|
741 |
itsecSettingsPage.showErrors( results.warnings, results.module, 'open', 'warning' );
|
742 |
}
|
|
|
|
|
|
|
|
|
743 |
} );
|
744 |
},
|
745 |
|
@@ -779,10 +818,12 @@ var itsecSettingsPage = {
|
|
779 |
|
780 |
if ( initialResponse ) {
|
781 |
itsecSettingsPage.showMessages( initialResponse.messages, initialResponse.module, $open ? 'open' : 'closed' );
|
|
|
782 |
itsecSettingsPage.showErrors( initialResponse.errors, initialResponse.module, $open ? 'open' : 'closed' );
|
783 |
itsecSettingsPage.showErrors( initialResponse.warnings, initialResponse.module, $open ? 'open' : 'closed', 'warning' );
|
784 |
}
|
785 |
|
|
|
786 |
itsecSettingsPage.events.trigger( 'modulesReloaded', initialResponse );
|
787 |
} );
|
788 |
},
|
@@ -828,6 +869,7 @@ var itsecSettingsPage = {
|
|
828 |
'errors': [],
|
829 |
'warnings': [],
|
830 |
'messages': [],
|
|
|
831 |
'functionCalls': [],
|
832 |
'redirect': false,
|
833 |
'closeModal': true
|
@@ -842,6 +884,7 @@ var itsecSettingsPage = {
|
|
842 |
results.errors = a.errors;
|
843 |
results.warnings = a.warnings;
|
844 |
results.messages = a.messages;
|
|
|
845 |
results.functionCalls = a.functionCalls;
|
846 |
results.redirect = a.redirect;
|
847 |
results.closeModal = a.closeModal;
|
@@ -934,7 +977,37 @@ var itsecSettingsPage = {
|
|
934 |
}
|
935 |
// If the requested parameter doesn't exist, return false
|
936 |
return false;
|
937 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
938 |
};
|
939 |
|
940 |
jQuery(document).ready(function( $ ) {
|
14 |
|
15 |
this.initFilters();
|
16 |
this.initCurrentModule();
|
17 |
+
this.makeNoticesDismissible();
|
18 |
},
|
19 |
|
20 |
initFilters: function() {
|
237 |
itsecSettingsPage.showErrors( results.errors, results.module, 'open' );
|
238 |
itsecSettingsPage.showErrors( results.warnings, results.module, 'open', 'warning' );
|
239 |
itsecSettingsPage.showMessages( results.messages, results.module, 'open' );
|
240 |
+
itsecSettingsPage.showMessages( results.infos, results.module, 'open', 'info' );
|
241 |
|
242 |
if ( 'grid' === view ) {
|
243 |
$container.find( '.itsec-module-settings-content-container:visible' ).animate( {'scrollTop': 0}, 'fast' );
|
248 |
}
|
249 |
} else {
|
250 |
itsecSettingsPage.showMessages( results.messages, results.module, 'closed' );
|
251 |
+
itsecSettingsPage.showMessages( results.infos, results.module, 'closed', 'info' );
|
252 |
|
253 |
if ( 'grid' === view ) {
|
254 |
$container.find( '.itsec-module-settings-content-container:visible' ).scrollTop( 0 );
|
306 |
container.append( $notice ).addClass( 'visible' );
|
307 |
},
|
308 |
|
309 |
+
showMessages: function( messages, module, containerStatus, type ) {
|
310 |
jQuery.each( messages, function( index, message ) {
|
311 |
+
itsecSettingsPage.showMessage( message, module, containerStatus, type );
|
312 |
} );
|
313 |
},
|
314 |
|
315 |
+
showMessage: function( message, module, containerStatus, type ) {
|
316 |
+
|
317 |
+
type = type || 'success';
|
318 |
+
|
319 |
if ( jQuery( '.itsec-module-cards-container' ).hasClass( 'grid' ) ) {
|
320 |
var view = 'grid';
|
321 |
} else {
|
334 |
if ( 'closed' === containerStatus || '' === module ) {
|
335 |
var container = jQuery( '#itsec-settings-messages-container' );
|
336 |
|
337 |
+
var dismiss = function () {
|
338 |
+
|
339 |
+
if ( container.is( ':hover' ) ) {
|
340 |
+
return setTimeout( dismiss, 2000 );
|
341 |
+
}
|
342 |
+
|
343 |
container.removeClass( 'visible' );
|
344 |
+
setTimeout( function () {
|
345 |
container.find( 'div' ).remove();
|
346 |
}, 500 );
|
347 |
+
};
|
348 |
+
|
349 |
+
setTimeout( dismiss, 4000 );
|
350 |
} else {
|
351 |
var container = jQuery( '#itsec-module-card-' + module + ' .itsec-module-messages-container' );
|
352 |
}
|
353 |
|
354 |
+
var $notice = jQuery( '<div class="notice fade"><p><strong>' + message + '</strong></p></div>' );
|
355 |
+
$notice.addClass( 'notice-' + type );
|
356 |
|
357 |
if ( containerStatus === 'open' || module.length ) {
|
358 |
$notice.addClass( 'notice-alt' );
|
448 |
var $listClassElement = $module.parents( '.itsec-module-cards-container' ),
|
449 |
$toggleButton = $module.find( '.itsec-toggle-settings' );
|
450 |
|
451 |
+
if ( highlight && highlight.length ) {
|
452 |
jQuery( 'label[for="' + highlight + '"]', $module ).parents( 'tr' ).addClass( 'itsec-highlighted-setting' );
|
453 |
}
|
454 |
|
461 |
var type = $module.hasClass( 'itsec-module-type-advanced' ) ? 'advanced' : 'recommended';
|
462 |
|
463 |
window.history.pushState( {module: module}, module, '?page=itsec&module=' + module + '&module_type=' + type );
|
464 |
+
|
465 |
+
var href = $link.attr( 'href' );
|
466 |
+
|
467 |
+
if ( href && href.length > 1 && href.charAt( 0 ) === '#' ) {
|
468 |
+
setTimeout( function () {
|
469 |
+
jQuery( '.itsec-module-settings-content-container', '#itsec-module-card-notification-center' ).scrollTo( jQuery( href ), 'swing', { offset: -30 } );
|
470 |
+
}, 350 );
|
471 |
+
}
|
472 |
},
|
473 |
|
474 |
toggleSettings: function( e ) {
|
720 |
|
721 |
jQuery( '#itsec-module-filter-enabled .count' ).html( '(' + enabledCount + ')' );
|
722 |
jQuery( '#itsec-module-filter-disabled .count' ).html( '(' + disabledCount + ')' );
|
723 |
+
|
724 |
+
|
725 |
+
itsecSettingsPage.showErrors( results.warnings, results.module, 'closed', 'warning' );
|
726 |
+
itsecSettingsPage.showMessages( results.messages, results.module, 'closed' );
|
727 |
+
itsecSettingsPage.showMessages( results.infos, results.module, 'closed', 'info' );
|
728 |
},
|
729 |
|
730 |
isModuleActive: function( module ) {
|
760 |
|
761 |
itsecSettingsPage.sendAJAXRequest( module, method, data, function( results ) {
|
762 |
if ( results.success && results.response ) {
|
763 |
+
var $card = jQuery( '#itsec-module-card-' + module );
|
764 |
+
var isHidden = $card.is( ':hidden' );
|
765 |
+
|
766 |
+
jQuery( '.itsec-module-settings-content-main', $card ).html( results.response );
|
767 |
+
|
768 |
+
if ( isHidden ) {
|
769 |
+
$card.hide();
|
770 |
+
} else {
|
771 |
+
jQuery( '.itsec-settings-toggle' ).trigger( 'change' );
|
772 |
+
}
|
773 |
} else if ( results.errors && results.errors.length > 0 ) {
|
774 |
itsecSettingsPage.showErrors( results.errors, results.module, 'open' );
|
775 |
} else if ( results.warnings && results.warnings.length > 0 ) {
|
776 |
itsecSettingsPage.showErrors( results.warnings, results.module, 'open', 'warning' );
|
777 |
}
|
778 |
+
|
779 |
+
itsecSettingsPage.events.trigger( 'moduleReloaded', module );
|
780 |
+
|
781 |
+
itsecSettingsPage.makeNoticesDismissible();
|
782 |
} );
|
783 |
},
|
784 |
|
818 |
|
819 |
if ( initialResponse ) {
|
820 |
itsecSettingsPage.showMessages( initialResponse.messages, initialResponse.module, $open ? 'open' : 'closed' );
|
821 |
+
itsecSettingsPage.showMessages( initialResponse.infos, initialResponse.module, $open ? 'open' : 'closed', 'info' );
|
822 |
itsecSettingsPage.showErrors( initialResponse.errors, initialResponse.module, $open ? 'open' : 'closed' );
|
823 |
itsecSettingsPage.showErrors( initialResponse.warnings, initialResponse.module, $open ? 'open' : 'closed', 'warning' );
|
824 |
}
|
825 |
|
826 |
+
itsecSettingsPage.makeNoticesDismissible();
|
827 |
itsecSettingsPage.events.trigger( 'modulesReloaded', initialResponse );
|
828 |
} );
|
829 |
},
|
869 |
'errors': [],
|
870 |
'warnings': [],
|
871 |
'messages': [],
|
872 |
+
'infos': [],
|
873 |
'functionCalls': [],
|
874 |
'redirect': false,
|
875 |
'closeModal': true
|
884 |
results.errors = a.errors;
|
885 |
results.warnings = a.warnings;
|
886 |
results.messages = a.messages;
|
887 |
+
results.infos = a.infos;
|
888 |
results.functionCalls = a.functionCalls;
|
889 |
results.redirect = a.redirect;
|
890 |
results.closeModal = a.closeModal;
|
977 |
}
|
978 |
// If the requested parameter doesn't exist, return false
|
979 |
return false;
|
980 |
+
},
|
981 |
+
|
982 |
+
// Make notices dismissible
|
983 |
+
makeNoticesDismissible: function(){
|
984 |
+
jQuery( '.notice.itsec-is-dismissible' ).each( function() {
|
985 |
+
var $el = jQuery( this ),
|
986 |
+
$button = jQuery( '<button type="button" class="notice-dismiss"><span class="screen-reader-text"></span></button>' ),
|
987 |
+
btnText = itsec_page.translations.dismiss || '';
|
988 |
+
|
989 |
+
// Don't rebind twice
|
990 |
+
if ( jQuery( '.notice-dismiss', $el ).length ) {
|
991 |
+
return;
|
992 |
+
}
|
993 |
+
|
994 |
+
// Ensure plain text
|
995 |
+
$button.find( '.screen-reader-text' ).text( btnText );
|
996 |
+
$button.on( 'click.wp-dismiss-notice', function( event ) {
|
997 |
+
event.preventDefault();
|
998 |
+
|
999 |
+
$el.trigger( 'itsec-dismiss-notice' );
|
1000 |
+
|
1001 |
+
$el.fadeTo( 100, 0, function() {
|
1002 |
+
$el.slideUp( 100, function() {
|
1003 |
+
$el.remove();
|
1004 |
+
});
|
1005 |
+
});
|
1006 |
+
});
|
1007 |
+
|
1008 |
+
$el.append( $button );
|
1009 |
+
});
|
1010 |
+
}
|
1011 |
};
|
1012 |
|
1013 |
jQuery(document).ready(function( $ ) {
|
core/admin-pages/module-settings.php
CHANGED
@@ -94,6 +94,13 @@ class ITSEC_Module_Settings_Page {
|
|
94 |
*/
|
95 |
protected $information_only = false;
|
96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
|
98 |
/**
|
99 |
* Constructor.
|
@@ -120,7 +127,7 @@ class ITSEC_Module_Settings_Page {
|
|
120 |
* @return mixed Property.
|
121 |
*/
|
122 |
public function __get( $name ) {
|
123 |
-
if ( in_array( $name, array( 'id', 'title', 'description', 'type', 'pro', 'can_save', 'redraw_on_save', 'upsell', 'upsell_url', 'information_only' ) ) ) {
|
124 |
return $this->$name;
|
125 |
}
|
126 |
|
94 |
*/
|
95 |
protected $information_only = false;
|
96 |
|
97 |
+
/**
|
98 |
+
* Set the module status to 'warning' to signal to the user it needs attention.
|
99 |
+
*
|
100 |
+
* @var string
|
101 |
+
*/
|
102 |
+
protected $status = '';
|
103 |
+
|
104 |
|
105 |
/**
|
106 |
* Constructor.
|
127 |
* @return mixed Property.
|
128 |
*/
|
129 |
public function __get( $name ) {
|
130 |
+
if ( in_array( $name, array( 'id', 'title', 'description', 'type', 'pro', 'can_save', 'redraw_on_save', 'upsell', 'upsell_url', 'information_only', 'status' ) ) ) {
|
131 |
return $this->$name;
|
132 |
}
|
133 |
|
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 static $instance;
|
8 |
|
@@ -114,6 +114,7 @@ final class ITSEC_Settings_Page {
|
|
114 |
'activate' => __( 'Enable', 'better-wp-security' ),
|
115 |
'deactivate' => __( 'Disable', 'better-wp-security' ),
|
116 |
'error' => __( 'Error', 'better-wp-security' ),
|
|
|
117 |
'copied' => __( 'Copied!', 'better-wp-security' ),
|
118 |
'copy_instruction' => __( 'Please press Ctrl/Cmd+C to copy.', 'better-wp-security' ),
|
119 |
|
@@ -167,12 +168,21 @@ final class ITSEC_Settings_Page {
|
|
167 |
ITSEC_Response::add_error( new WP_Error( 'itsec-settings-page-missing-method', __( 'The server did not receive a valid request. The required "method" argument is missing. Please try again.', 'better-wp-security' ) ) );
|
168 |
} else if ( 'save' === $method ) {
|
169 |
$this->handle_post();
|
|
|
170 |
} else if ( empty( $module ) ) {
|
171 |
ITSEC_Response::add_error( new WP_Error( 'itsec-settings-page-missing-module', __( 'The server did not receive a valid request. The required "module" argument is missing. Please try again.', 'better-wp-security' ) ) );
|
172 |
} else if ( 'activate' === $method ) {
|
173 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
} else if ( 'deactivate' === $method ) {
|
175 |
ITSEC_Response::set_response( ITSEC_Modules::deactivate( $module ) );
|
|
|
176 |
} else if ( 'is_active' === $method ) {
|
177 |
ITSEC_Response::set_response( ITSEC_Modules::is_active( $module ) );
|
178 |
} else if ( 'get_refreshed_module_settings' === $method ) {
|
@@ -310,6 +320,7 @@ final class ITSEC_Settings_Page {
|
|
310 |
return;
|
311 |
}
|
312 |
|
|
|
313 |
ITSEC_Response::maybe_regenerate_wp_config();
|
314 |
ITSEC_Response::maybe_regenerate_server_config();
|
315 |
ITSEC_Response::maybe_do_force_logout();
|
@@ -543,6 +554,10 @@ final class ITSEC_Settings_Page {
|
|
543 |
if ( $module->pro ) {
|
544 |
$classes[] = 'itsec-module-type-pro';
|
545 |
}
|
|
|
|
|
|
|
|
|
546 |
?>
|
547 |
<li id="itsec-module-card-<?php echo $id; ?>" class="itsec-module-card <?php echo implode( ' ', $classes ); ?>" data-module-id="<?php echo $id; ?>">
|
548 |
<div class="itsec-module-card-content">
|
@@ -579,7 +594,10 @@ final class ITSEC_Settings_Page {
|
|
579 |
</div>
|
580 |
<div class="itsec-module-settings-content-container">
|
581 |
<div class="itsec-module-settings-content">
|
582 |
-
<h3 class="itsec-modal-header"
|
|
|
|
|
|
|
583 |
<div class="itsec-module-messages-container"></div>
|
584 |
<div class="itsec-module-settings-content-main">
|
585 |
<?php $this->get_module_settings( $id, $form, true ); ?>
|
2 |
|
3 |
|
4 |
final class ITSEC_Settings_Page {
|
5 |
+
private $version = 1.9;
|
6 |
|
7 |
private static $instance;
|
8 |
|
114 |
'activate' => __( 'Enable', 'better-wp-security' ),
|
115 |
'deactivate' => __( 'Disable', 'better-wp-security' ),
|
116 |
'error' => __( 'Error', 'better-wp-security' ),
|
117 |
+
'dismiss' => __( 'Dismiss Notice', 'better-wp-security' ), // Screen reader text for dismissible notices
|
118 |
'copied' => __( 'Copied!', 'better-wp-security' ),
|
119 |
'copy_instruction' => __( 'Please press Ctrl/Cmd+C to copy.', 'better-wp-security' ),
|
120 |
|
168 |
ITSEC_Response::add_error( new WP_Error( 'itsec-settings-page-missing-method', __( 'The server did not receive a valid request. The required "method" argument is missing. Please try again.', 'better-wp-security' ) ) );
|
169 |
} else if ( 'save' === $method ) {
|
170 |
$this->handle_post();
|
171 |
+
ITSEC_Response::maybe_flag_new_notifications_available();
|
172 |
} else if ( empty( $module ) ) {
|
173 |
ITSEC_Response::add_error( new WP_Error( 'itsec-settings-page-missing-module', __( 'The server did not receive a valid request. The required "module" argument is missing. Please try again.', 'better-wp-security' ) ) );
|
174 |
} else if ( 'activate' === $method ) {
|
175 |
+
$was_active = ITSEC_Modules::activate( $module );
|
176 |
+
ITSEC_Response::set_response( $was_active );
|
177 |
+
|
178 |
+
if ( ! $was_active ) {
|
179 |
+
ITSEC_Modules::load_module_file( 'active.php', $module );
|
180 |
+
}
|
181 |
+
|
182 |
+
ITSEC_Response::maybe_flag_new_notifications_available();
|
183 |
} else if ( 'deactivate' === $method ) {
|
184 |
ITSEC_Response::set_response( ITSEC_Modules::deactivate( $module ) );
|
185 |
+
ITSEC_Response::maybe_flag_new_notifications_available();
|
186 |
} else if ( 'is_active' === $method ) {
|
187 |
ITSEC_Response::set_response( ITSEC_Modules::is_active( $module ) );
|
188 |
} else if ( 'get_refreshed_module_settings' === $method ) {
|
320 |
return;
|
321 |
}
|
322 |
|
323 |
+
ITSEC_Response::maybe_flag_new_notifications_available();
|
324 |
ITSEC_Response::maybe_regenerate_wp_config();
|
325 |
ITSEC_Response::maybe_regenerate_server_config();
|
326 |
ITSEC_Response::maybe_do_force_logout();
|
554 |
if ( $module->pro ) {
|
555 |
$classes[] = 'itsec-module-type-pro';
|
556 |
}
|
557 |
+
|
558 |
+
if ( 'warning' === $module->status ) {
|
559 |
+
$classes[] = 'itsec-module-status--warning';
|
560 |
+
}
|
561 |
?>
|
562 |
<li id="itsec-module-card-<?php echo $id; ?>" class="itsec-module-card <?php echo implode( ' ', $classes ); ?>" data-module-id="<?php echo $id; ?>">
|
563 |
<div class="itsec-module-card-content">
|
594 |
</div>
|
595 |
<div class="itsec-module-settings-content-container">
|
596 |
<div class="itsec-module-settings-content">
|
597 |
+
<h3 class="itsec-modal-header">
|
598 |
+
<?php echo esc_html( $module->title ); ?>
|
599 |
+
<?php do_action( 'itsec_module_settings_after_title', $id ); ?>
|
600 |
+
</h3>
|
601 |
<div class="itsec-module-messages-container"></div>
|
602 |
<div class="itsec-module-settings-content-main">
|
603 |
<?php $this->get_module_settings( $id, $form, true ); ?>
|
core/core.php
CHANGED
@@ -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
|
@@ -41,6 +41,7 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
41 |
private
|
42 |
$itsec_files,
|
43 |
$itsec_notify,
|
|
|
44 |
$sync_api,
|
45 |
$plugin_file,
|
46 |
$plugin_dir,
|
@@ -190,6 +191,24 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
190 |
return $self->itsec_notify;
|
191 |
}
|
192 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
/**
|
194 |
* Retrieve the global instance of the Sync API.
|
195 |
*
|
@@ -222,6 +241,7 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
222 |
|
223 |
ITSEC_Modules::register_module( 'security-check', "$path/modules/security-check", 'always-active' );
|
224 |
ITSEC_Modules::register_module( 'global', "$path/modules/global", 'always-active' );
|
|
|
225 |
ITSEC_Modules::register_module( '404-detection', "$path/modules/404-detection" );
|
226 |
ITSEC_Modules::register_module( 'admin-user', "$path/modules/admin-user", 'always-active' );
|
227 |
ITSEC_Modules::register_module( 'away-mode', "$path/modules/away-mode" );
|
25 |
*
|
26 |
* @access private
|
27 |
*/
|
28 |
+
private $plugin_build = 4078;
|
29 |
|
30 |
/**
|
31 |
* Used to distinguish between a user modifying settings and the API modifying settings (such as from Sync
|
41 |
private
|
42 |
$itsec_files,
|
43 |
$itsec_notify,
|
44 |
+
$notifications,
|
45 |
$sync_api,
|
46 |
$plugin_file,
|
47 |
$plugin_dir,
|
191 |
return $self->itsec_notify;
|
192 |
}
|
193 |
|
194 |
+
/**
|
195 |
+
* Set the notification center instance.
|
196 |
+
*
|
197 |
+
* @param ITSEC_Notification_Center $center
|
198 |
+
*/
|
199 |
+
public static function set_notification_center( ITSEC_Notification_Center $center ) {
|
200 |
+
self::get_instance()->notifications = $center;
|
201 |
+
}
|
202 |
+
|
203 |
+
/**
|
204 |
+
* Get the notification center instance.
|
205 |
+
*
|
206 |
+
* @return ITSEC_Notification_Center
|
207 |
+
*/
|
208 |
+
public static function get_notification_center() {
|
209 |
+
return self::get_instance()->notifications;
|
210 |
+
}
|
211 |
+
|
212 |
/**
|
213 |
* Retrieve the global instance of the Sync API.
|
214 |
*
|
241 |
|
242 |
ITSEC_Modules::register_module( 'security-check', "$path/modules/security-check", 'always-active' );
|
243 |
ITSEC_Modules::register_module( 'global', "$path/modules/global", 'always-active' );
|
244 |
+
ITSEC_Modules::register_module( 'notification-center', "$path/modules/notification-center", 'always-active' );
|
245 |
ITSEC_Modules::register_module( '404-detection', "$path/modules/404-detection" );
|
246 |
ITSEC_Modules::register_module( 'admin-user', "$path/modules/admin-user", 'always-active' );
|
247 |
ITSEC_Modules::register_module( 'away-mode', "$path/modules/away-mode" );
|
core/history.txt
CHANGED
@@ -579,3 +579,22 @@
|
|
579 |
Bug Fix: Fixed SQL query bug that resulted in the "Minutes to Remember Bad Login (check period)" setting being ignored.
|
580 |
Bug Fix: Fixed bug that prevents wp-admin/install.php blocking from working properly on nginx servers.
|
581 |
Bug Fix: Don't attempt to do an SSL redirect when WP CLI is running.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
579 |
Bug Fix: Fixed SQL query bug that resulted in the "Minutes to Remember Bad Login (check period)" setting being ignored.
|
580 |
Bug Fix: Fixed bug that prevents wp-admin/install.php blocking from working properly on nginx servers.
|
581 |
Bug Fix: Don't attempt to do an SSL redirect when WP CLI is running.
|
582 |
+
3.9.0 - 2017-10-25 - Chris Jean, Timothy Jacobs and Saylor Bullington
|
583 |
+
New Feature: Introduces the Notification Center, a centralized place to manage and customize email notifications sent by iThemes Security.
|
584 |
+
Bug Fix: Corrected some Javascript and CSS links not generating correctly on Windows servers.
|
585 |
+
3.9.1 - 2017-10-26 - Chris Jean & Timothy Jacobs
|
586 |
+
Bug Fix: Only enable the Lockout email notification is the Daily Digest was previously disabled.
|
587 |
+
Bug Fix: Fix JavaScript error when loading the Notification Center on some systems.
|
588 |
+
Bug Fix: Don't store WP Error objects for mail errors preventing a fatal error for rare PHPMailer errors.
|
589 |
+
Bug Fix: Prevent error on upgrade warning the subject line was empty.
|
590 |
+
Bug Fix: Ensure file change notification is properly enabled/disabled on upgrade.
|
591 |
+
Bug Fix: Fallback to correct default subject lines.
|
592 |
+
Bug Fix: Don't enable all administrators as the recipients for emails where all custom email addresses did not have corresponding users.
|
593 |
+
Upgrade Routine: Properly enable lockout and file change notifications, uncheck all administrators as recipients when necessary.
|
594 |
+
3.9.2 - 2017-11-01 - Chris Jean & Timothy Jacobs
|
595 |
+
Enhancement: Updated queries and prepare statements to account for changes to the esc_sql() function in WordPress 4.8.3.
|
596 |
+
Bug Fix: Fixed the File Change module being incorrectly enabled when upgrading.
|
597 |
+
3.9.3 - 2017-11-02 - Chris Jean & Timothy Jacobs
|
598 |
+
Bug Fix: Fixed source of the following warning: "mysql_real_escape_string() expects parameter 1 to be string, object given".
|
599 |
+
3.9.4 - 2017-11-06 - Chris Jean & Timothy Jacobs
|
600 |
+
Bug Fix: Don't display file change admin notifications if the Notify Admin setting is not enabled.
|
core/lib.php
CHANGED
@@ -147,42 +147,6 @@ final class ITSEC_Lib {
|
|
147 |
return ITSEC_Lib_Config_File::get_wp_config_file_path();
|
148 |
}
|
149 |
|
150 |
-
/**
|
151 |
-
* Gets current url
|
152 |
-
*
|
153 |
-
* Finds and returns current url.
|
154 |
-
*
|
155 |
-
* @since 4.3.0
|
156 |
-
*
|
157 |
-
* @return string current url
|
158 |
-
* */
|
159 |
-
public static function get_current_url() {
|
160 |
-
|
161 |
-
$page_url = 'http';
|
162 |
-
|
163 |
-
if ( isset( $_SERVER["HTTPS"] ) ) {
|
164 |
-
|
165 |
-
if ( 'on' == $_SERVER["HTTPS"] ) {
|
166 |
-
$page_url .= "s";
|
167 |
-
}
|
168 |
-
|
169 |
-
}
|
170 |
-
|
171 |
-
$page_url .= "://";
|
172 |
-
|
173 |
-
if ( '80' != $_SERVER["SERVER_PORT"] ) {
|
174 |
-
|
175 |
-
$page_url .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
|
176 |
-
|
177 |
-
} else {
|
178 |
-
|
179 |
-
$page_url .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
|
180 |
-
|
181 |
-
}
|
182 |
-
|
183 |
-
return esc_url( $page_url );
|
184 |
-
}
|
185 |
-
|
186 |
/**
|
187 |
* Return primary domain from given url.
|
188 |
*
|
@@ -392,43 +356,6 @@ final class ITSEC_Lib {
|
|
392 |
return $GLOBALS['__itsec_remote_ip'];
|
393 |
}
|
394 |
|
395 |
-
/**
|
396 |
-
* Gets PHP Memory Limit.
|
397 |
-
*
|
398 |
-
* Attempts to get the maximum amount of memory allowed for the application by the server.
|
399 |
-
*
|
400 |
-
* @since 4.0.0
|
401 |
-
*
|
402 |
-
* @return int php memory limit in megabytes
|
403 |
-
*/
|
404 |
-
public static function get_memory_limit() {
|
405 |
-
|
406 |
-
return (int) ini_get( 'memory_limit' );
|
407 |
-
|
408 |
-
}
|
409 |
-
|
410 |
-
/**
|
411 |
-
* Returns the URL of the current module.
|
412 |
-
*
|
413 |
-
* Get's the full URL of the current module.
|
414 |
-
*
|
415 |
-
* @since 4.0.0
|
416 |
-
*
|
417 |
-
* @param string $file the module file from which to derive the path
|
418 |
-
*
|
419 |
-
* @return string the path of the current module
|
420 |
-
*/
|
421 |
-
public static function get_module_path( $file ) {
|
422 |
-
|
423 |
-
$path = str_replace( ITSEC_Core::get_plugin_dir(), '', dirname( $file ) );
|
424 |
-
$path = ltrim( str_replace( '\\', '/', $path ), '/' );
|
425 |
-
|
426 |
-
$url_base = trailingslashit( plugin_dir_url( ITSEC_Core::get_plugin_file() ) );
|
427 |
-
|
428 |
-
return trailingslashit( $url_base . $path );
|
429 |
-
|
430 |
-
}
|
431 |
-
|
432 |
/**
|
433 |
* Returns the server type of the plugin user.
|
434 |
*
|
@@ -444,63 +371,6 @@ final class ITSEC_Lib {
|
|
444 |
return ITSEC_Lib_Utility::get_web_server();
|
445 |
}
|
446 |
|
447 |
-
/**
|
448 |
-
* Determine whether the server supports SSL (shared cert not supported.
|
449 |
-
*
|
450 |
-
* Attempts to retrieve an HTML version of the homepage in an effort to determine if SSL is available.
|
451 |
-
*
|
452 |
-
* @since 4.0.0
|
453 |
-
*
|
454 |
-
* @return bool true if ssl is supported or false
|
455 |
-
*/
|
456 |
-
public static function get_ssl() {
|
457 |
-
|
458 |
-
$url = str_ireplace( 'http://', 'https://', get_bloginfo( 'url' ) );
|
459 |
-
|
460 |
-
if ( function_exists( 'wp_http_supports' ) && wp_http_supports( array( 'ssl' ), $url ) ) {
|
461 |
-
|
462 |
-
return true;
|
463 |
-
|
464 |
-
} elseif ( function_exists( 'curl_init' ) ) {
|
465 |
-
|
466 |
-
//use a manual CURL request to better account for self-signed certificates
|
467 |
-
$timeout = 5; //timeout for the request
|
468 |
-
$site_title = trim( get_bloginfo() );
|
469 |
-
|
470 |
-
$request = curl_init();
|
471 |
-
|
472 |
-
curl_setopt( $request, CURLOPT_RETURNTRANSFER, true );
|
473 |
-
curl_setopt( $request, CURLOPT_VERBOSE, false );
|
474 |
-
curl_setopt( $request, CURLOPT_SSL_VERIFYPEER, false );
|
475 |
-
curl_setopt( $request, CURLOPT_HEADER, true );
|
476 |
-
curl_setopt( $request, CURLOPT_URL, $url );
|
477 |
-
curl_setopt( $request, CURLOPT_RETURNTRANSFER, true );
|
478 |
-
curl_setopt( $request, CURLOPT_CONNECTTIMEOUT, $timeout );
|
479 |
-
|
480 |
-
$data = curl_exec( $request );
|
481 |
-
|
482 |
-
$header_size = curl_getinfo( $request, CURLINFO_HEADER_SIZE );
|
483 |
-
$http_code = intval( curl_getinfo( $request, CURLINFO_HTTP_CODE ) );
|
484 |
-
$body = substr( $data, $header_size );
|
485 |
-
|
486 |
-
preg_match( '/<title>(.+)<\/title>/', $body, $matches );
|
487 |
-
|
488 |
-
if ( 200 == $http_code && isset( $matches[1] ) && false !== strpos( $matches[1], $site_title ) ) {
|
489 |
-
|
490 |
-
return true;
|
491 |
-
|
492 |
-
} else {
|
493 |
-
|
494 |
-
return false;
|
495 |
-
|
496 |
-
}
|
497 |
-
|
498 |
-
}
|
499 |
-
|
500 |
-
return false;
|
501 |
-
|
502 |
-
}
|
503 |
-
|
504 |
public static function get_whitelisted_ips() {
|
505 |
return apply_filters( 'itsec_white_ips', array() );
|
506 |
}
|
@@ -591,21 +461,6 @@ final class ITSEC_Lib {
|
|
591 |
return false;
|
592 |
}
|
593 |
|
594 |
-
/**
|
595 |
-
* Determine whether we're on the login page or not.
|
596 |
-
*
|
597 |
-
* Attempts to determine whether or not the user is on the WordPress dashboard login page.
|
598 |
-
*
|
599 |
-
* @since 4.0.0
|
600 |
-
*
|
601 |
-
* @return bool true if is login page else false
|
602 |
-
*/
|
603 |
-
public static function is_login_page() {
|
604 |
-
|
605 |
-
return in_array( $GLOBALS['pagenow'], array( 'wp-login.php', 'wp-register.php' ) );
|
606 |
-
|
607 |
-
}
|
608 |
-
|
609 |
/**
|
610 |
* Set a 404 error.
|
611 |
*
|
@@ -724,7 +579,7 @@ final class ITSEC_Lib {
|
|
724 |
}
|
725 |
|
726 |
//queary the user table to see if the user is there
|
727 |
-
$saved_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM `" . $wpdb->users . "` WHERE ID=
|
728 |
|
729 |
if ( $saved_id == $user_id ) {
|
730 |
|
@@ -738,96 +593,6 @@ final class ITSEC_Lib {
|
|
738 |
|
739 |
}
|
740 |
|
741 |
-
/**
|
742 |
-
* Validates a file path
|
743 |
-
*
|
744 |
-
* Adapted from http://stackoverflow.com/questions/4049856/replace-phps-realpath/4050444#4050444 as a replacement for PHP's realpath
|
745 |
-
*
|
746 |
-
* @since 4.0.0
|
747 |
-
*
|
748 |
-
* @param string $path The original path, can be relative etc.
|
749 |
-
*
|
750 |
-
* @return bool true if the path is valid and writeable else false
|
751 |
-
*/
|
752 |
-
public static function validate_path( $path ) {
|
753 |
-
|
754 |
-
// whether $path is unix or not
|
755 |
-
$unipath = strlen( $path ) == 0 || $path{0} != '/';
|
756 |
-
|
757 |
-
// attempts to detect if path is relative in which case, add cwd
|
758 |
-
if ( false === strpos( $path, ':' ) && $unipath ) {
|
759 |
-
$path = getcwd() . DIRECTORY_SEPARATOR . $path;
|
760 |
-
}
|
761 |
-
|
762 |
-
// resolve path parts (single dot, double dot and double delimiters)
|
763 |
-
$path = str_replace( array( '/', '\\' ), DIRECTORY_SEPARATOR, $path );
|
764 |
-
$parts = array_filter( explode( DIRECTORY_SEPARATOR, $path ), 'strlen' );
|
765 |
-
$absolutes = array();
|
766 |
-
|
767 |
-
foreach ( $parts as $part ) {
|
768 |
-
|
769 |
-
if ( '.' == $part ) {
|
770 |
-
continue;
|
771 |
-
}
|
772 |
-
|
773 |
-
if ( '..' == $part ) {
|
774 |
-
|
775 |
-
array_pop( $absolutes );
|
776 |
-
|
777 |
-
} else {
|
778 |
-
|
779 |
-
$absolutes[] = $part;
|
780 |
-
|
781 |
-
}
|
782 |
-
|
783 |
-
}
|
784 |
-
|
785 |
-
$path = implode( DIRECTORY_SEPARATOR, $absolutes );
|
786 |
-
|
787 |
-
// resolve any symlinks
|
788 |
-
if ( function_exists( 'linkinfo' ) ) { //linkinfo not available on Windows with PHP < 5.3.0
|
789 |
-
|
790 |
-
if ( file_exists( $path ) && 0 < linkinfo( $path ) ) {
|
791 |
-
$path = @readlink( $path );
|
792 |
-
}
|
793 |
-
|
794 |
-
} else {
|
795 |
-
|
796 |
-
if ( file_exists( $path ) && 0 < linkinfo( $path ) ) {
|
797 |
-
$path = @readlink( $path );
|
798 |
-
}
|
799 |
-
|
800 |
-
}
|
801 |
-
|
802 |
-
// put initial separator that could have been lost
|
803 |
-
$path = ! $unipath ? '/' . $path : $path;
|
804 |
-
|
805 |
-
$test = @touch( $path . '/test.txt' );
|
806 |
-
@unlink( $path . '/test.txt' );
|
807 |
-
|
808 |
-
return $test;
|
809 |
-
|
810 |
-
}
|
811 |
-
|
812 |
-
/**
|
813 |
-
* Validates a URL
|
814 |
-
*
|
815 |
-
* Ensures the provided URL is a valid URL.
|
816 |
-
*
|
817 |
-
* @since 4.3.0
|
818 |
-
*
|
819 |
-
* @param string $url the url to validate
|
820 |
-
*
|
821 |
-
* @return bool true if valid url else false
|
822 |
-
*/
|
823 |
-
public static function validate_url( $url ) {
|
824 |
-
|
825 |
-
$pattern = "/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i";
|
826 |
-
|
827 |
-
return (bool) preg_match( $pattern, $url );
|
828 |
-
|
829 |
-
}
|
830 |
-
|
831 |
public static function show_status_message( $message ) {
|
832 |
echo "<div class=\"updated fade\"><p><strong>$message</strong></p></div>\n";
|
833 |
}
|
@@ -1239,4 +1004,52 @@ final class ITSEC_Lib {
|
|
1239 |
|
1240 |
return apply_filters( 'itsec-ssl-support-probability', $probability );
|
1241 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1242 |
}
|
147 |
return ITSEC_Lib_Config_File::get_wp_config_file_path();
|
148 |
}
|
149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
/**
|
151 |
* Return primary domain from given url.
|
152 |
*
|
356 |
return $GLOBALS['__itsec_remote_ip'];
|
357 |
}
|
358 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
359 |
/**
|
360 |
* Returns the server type of the plugin user.
|
361 |
*
|
371 |
return ITSEC_Lib_Utility::get_web_server();
|
372 |
}
|
373 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
374 |
public static function get_whitelisted_ips() {
|
375 |
return apply_filters( 'itsec_white_ips', array() );
|
376 |
}
|
461 |
return false;
|
462 |
}
|
463 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
464 |
/**
|
465 |
* Set a 404 error.
|
466 |
*
|
579 |
}
|
580 |
|
581 |
//queary the user table to see if the user is there
|
582 |
+
$saved_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM `" . $wpdb->users . "` WHERE ID= %d;", $user_id ) );
|
583 |
|
584 |
if ( $saved_id == $user_id ) {
|
585 |
|
593 |
|
594 |
}
|
595 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
596 |
public static function show_status_message( $message ) {
|
597 |
echo "<div class=\"updated fade\"><p><strong>$message</strong></p></div>\n";
|
598 |
}
|
1004 |
|
1005 |
return apply_filters( 'itsec-ssl-support-probability', $probability );
|
1006 |
}
|
1007 |
+
|
1008 |
+
/**
|
1009 |
+
* Format a date using date_i18n and convert the time from GMT to local.
|
1010 |
+
*
|
1011 |
+
* @author Modified from ticket #25331
|
1012 |
+
*
|
1013 |
+
* @param int $timestamp
|
1014 |
+
* @param string $format Specify the format. If blank, will default to the date and time format settings.
|
1015 |
+
*
|
1016 |
+
* @return string
|
1017 |
+
*/
|
1018 |
+
public static function date_format_i18n_and_local_timezone( $timestamp, $format = '' ) {
|
1019 |
+
|
1020 |
+
if ( ! $format ) {
|
1021 |
+
$format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
|
1022 |
+
}
|
1023 |
+
|
1024 |
+
return date_i18n( $format, strtotime( get_date_from_gmt( date( 'Y-m-d H:i:s', $timestamp ) ) ) );
|
1025 |
+
}
|
1026 |
+
|
1027 |
+
public static function array_get( $array, $key, $default = null ) {
|
1028 |
+
|
1029 |
+
if ( ! is_array( $array ) ) {
|
1030 |
+
return $default;
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
if ( null === $key ) {
|
1034 |
+
return $array;
|
1035 |
+
}
|
1036 |
+
|
1037 |
+
if ( isset( $array[ $key ] ) ) {
|
1038 |
+
return $array[ $key ];
|
1039 |
+
}
|
1040 |
+
|
1041 |
+
if ( strpos( $key, '.' ) === false ) {
|
1042 |
+
return isset( $array[ $key ] ) ? $array[ $key ] : $default;
|
1043 |
+
}
|
1044 |
+
|
1045 |
+
foreach ( explode( '.', $key ) as $segment ) {
|
1046 |
+
if ( is_array( $array ) && isset( $array[ $segment ] ) ) {
|
1047 |
+
$array = $array[ $segment ];
|
1048 |
+
} else {
|
1049 |
+
return $default;
|
1050 |
+
}
|
1051 |
+
}
|
1052 |
+
|
1053 |
+
return $array;
|
1054 |
+
}
|
1055 |
}
|
core/lib/class-itsec-mail.php
CHANGED
@@ -11,45 +11,29 @@ final class ITSEC_Mail {
|
|
11 |
$this->template_path = dirname( __FILE__ ) . '/mail-templates/';
|
12 |
}
|
13 |
|
14 |
-
public function add_header( $title, $banner_title ) {
|
15 |
$header = $this->get_template( 'header.html' );
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
$replacements = array(
|
18 |
'lang' => esc_attr( get_bloginfo( 'language' ) ),
|
19 |
'charset' => esc_attr( get_bloginfo( 'charset' ) ),
|
20 |
'title_tag' => $title,
|
21 |
'banner_title' => $banner_title,
|
22 |
-
'logo' =>
|
23 |
'title' => $title,
|
24 |
);
|
25 |
|
26 |
$this->content .= $this->replace_all( $header, $replacements );
|
27 |
}
|
28 |
|
29 |
-
private function replace( $content, $variable, $value ) {
|
30 |
-
return preg_replace( '/{{ \$' . preg_quote( $variable, '/' ) . ' }}/', $value, $content );
|
31 |
-
}
|
32 |
-
|
33 |
-
private function replace_all( $content, $replacements ) {
|
34 |
-
foreach ( $replacements as $variable => $value ) {
|
35 |
-
$content = preg_replace( '/{{ \$' . preg_quote( $variable, '/' ) . ' }}/', $value, $content );
|
36 |
-
}
|
37 |
-
|
38 |
-
return $content;
|
39 |
-
}
|
40 |
-
|
41 |
-
private function replace_images( $content ) {
|
42 |
-
return preg_replace_callback( '/{! \$([a-zA-Z_][\w]*) }}/', array( $this, 'replace_image_callback' ), $content );
|
43 |
-
}
|
44 |
-
|
45 |
-
private function replace_image_callback( $matches ) {
|
46 |
-
if ( empty( $matches ) || empty( $matches[1] ) ) {
|
47 |
-
return '';
|
48 |
-
}
|
49 |
-
|
50 |
-
return esc_url( $this->get_image_url( $matches[1] ) );
|
51 |
-
}
|
52 |
-
|
53 |
public function add_footer() {
|
54 |
$footer = '';
|
55 |
|
@@ -69,6 +53,8 @@ final class ITSEC_Mail {
|
|
69 |
|
70 |
$footer .= $this->get_template( 'footer.html' );
|
71 |
|
|
|
|
|
72 |
$replacements = array(
|
73 |
'security_resources' => esc_html__( 'Security Resources', 'better-wp-security' ),
|
74 |
'articles' => esc_html__( 'Articles', 'better-wp-security' ),
|
@@ -81,15 +67,35 @@ final class ITSEC_Mail {
|
|
81 |
'support' => esc_html__( 'Support', 'better-wp-security' ),
|
82 |
'pro' => esc_html__( 'Pro', 'better-wp-security' ),
|
83 |
'support_content' => sprintf( wp_kses( __( 'Pro customers can contact <a href="%s">iThemes Helpdesk</a> for help. Our support team answers questions Monday – Friday, 8am – 5pm (CST).', 'better-wp-security' ), array( 'a' => array( 'href' => array() ) ) ), esc_url( 'https://members.ithemes.com/panel/helpdesk.php' ) ),
|
84 |
-
'security_settings_link' =>
|
85 |
-
'unsubscribe_link_text' => esc_html__( 'This email was generated by the iThemes Security plugin.', 'better-wp-security' ) . '<br>' . esc_html__( 'To unsubscribe from these updates, visit the
|
86 |
'security_guide' => esc_html__( 'Free WordPress Security Guide', 'better-wp-security' ),
|
87 |
'security_guide_content' => sprintf( wp_kses( __( 'Learn simple WordPress security tips — including 3 kinds of security your site needs and 4 best security practices for keeping your WordPress site safe with our <a href="%s">free guide</a>.', 'better-wp-security' ), array( 'a' => array( 'href' => array() ) ) ), esc_url( 'https://ithemes.com/publishing/wordpress-security/' ) ),
|
88 |
|
89 |
);
|
90 |
|
91 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
|
|
|
93 |
$this->content .= $footer;
|
94 |
}
|
95 |
|
@@ -112,7 +118,7 @@ final class ITSEC_Mail {
|
|
112 |
}
|
113 |
|
114 |
public function add_info_box( $content, $icon_type = 'info' ) {
|
115 |
-
$icon_url = $this->get_image_url( "{$icon_type}_icon" );
|
116 |
|
117 |
$module = $this->get_template( 'info-box.html' );
|
118 |
$module = $this->replace_all( $module, compact( 'content', 'icon_url' ) );
|
@@ -127,6 +133,13 @@ final class ITSEC_Mail {
|
|
127 |
$this->content .= $module;
|
128 |
}
|
129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
public function add_section_heading( $content, $icon_type = false ) {
|
131 |
if ( empty( $icon_type ) ) {
|
132 |
$heading = $this->get_template( 'section-heading.html' );
|
@@ -156,10 +169,27 @@ final class ITSEC_Mail {
|
|
156 |
$this->content .= $lockouts;
|
157 |
}
|
158 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
public function add_button( $link_text, $href ) {
|
160 |
$module = $this->get_template( 'module-button.html' );
|
161 |
-
$module =
|
162 |
-
$module =
|
163 |
|
164 |
$this->content .= $module;
|
165 |
}
|
@@ -194,19 +224,165 @@ final class ITSEC_Mail {
|
|
194 |
$this->content .= $table;
|
195 |
}
|
196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
public function get_content() {
|
198 |
return $this->content;
|
199 |
}
|
200 |
|
201 |
public function set_subject( $subject, $add_site_url = true ) {
|
202 |
if ( $add_site_url ) {
|
203 |
-
|
204 |
-
$subject = sprintf( __( '[%1$s] %2$s', 'better-wp-security' ), get_option( 'siteurl' ), $subject );
|
205 |
}
|
206 |
|
207 |
$this->subject = esc_html( $subject );
|
208 |
}
|
209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
210 |
public function set_recipients( $recipients ) {
|
211 |
$this->recipients = array();
|
212 |
|
@@ -224,6 +400,10 @@ final class ITSEC_Mail {
|
|
224 |
$this->set_recipients( $recipients );
|
225 |
}
|
226 |
|
|
|
|
|
|
|
|
|
227 |
public function set_attachments( $attachments ) {
|
228 |
$this->attachments = $attachments;
|
229 |
}
|
@@ -244,10 +424,51 @@ final class ITSEC_Mail {
|
|
244 |
return wp_mail( $this->recipients, $this->subject, $this->content, array( 'Content-Type: text/html; charset=UTF-8' ), $this->attachments );
|
245 |
}
|
246 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
247 |
private function get_template( $template ) {
|
248 |
return $this->replace_images( file_get_contents( $this->template_path . $template ) );
|
249 |
}
|
250 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
251 |
private function get_image_url( $name ) {
|
252 |
return plugin_dir_url( ITSEC_Core::get_core_dir() . 'img/mail/index.php' ) . "{$name}.png";
|
253 |
}
|
11 |
$this->template_path = dirname( __FILE__ ) . '/mail-templates/';
|
12 |
}
|
13 |
|
14 |
+
public function add_header( $title, $banner_title, $use_site_logo = false ) {
|
15 |
$header = $this->get_template( 'header.html' );
|
16 |
|
17 |
+
if ( $use_site_logo ) {
|
18 |
+
$logo = $this->get_site_logo_url();
|
19 |
+
} elseif ( ITSEC_Core::is_pro() ) {
|
20 |
+
$logo = $this->get_image_url( 'pro_logo' );
|
21 |
+
} else {
|
22 |
+
$logo = $this->get_image_url( 'logo' );
|
23 |
+
}
|
24 |
+
|
25 |
$replacements = array(
|
26 |
'lang' => esc_attr( get_bloginfo( 'language' ) ),
|
27 |
'charset' => esc_attr( get_bloginfo( 'charset' ) ),
|
28 |
'title_tag' => $title,
|
29 |
'banner_title' => $banner_title,
|
30 |
+
'logo' => $logo,
|
31 |
'title' => $title,
|
32 |
);
|
33 |
|
34 |
$this->content .= $this->replace_all( $header, $replacements );
|
35 |
}
|
36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
public function add_footer() {
|
38 |
$footer = '';
|
39 |
|
53 |
|
54 |
$footer .= $this->get_template( 'footer.html' );
|
55 |
|
56 |
+
$settings = esc_url( self::filter_admin_page_url( ITSEC_Core::get_settings_page_url() ) );
|
57 |
+
|
58 |
$replacements = array(
|
59 |
'security_resources' => esc_html__( 'Security Resources', 'better-wp-security' ),
|
60 |
'articles' => esc_html__( 'Articles', 'better-wp-security' ),
|
67 |
'support' => esc_html__( 'Support', 'better-wp-security' ),
|
68 |
'pro' => esc_html__( 'Pro', 'better-wp-security' ),
|
69 |
'support_content' => sprintf( wp_kses( __( 'Pro customers can contact <a href="%s">iThemes Helpdesk</a> for help. Our support team answers questions Monday – Friday, 8am – 5pm (CST).', 'better-wp-security' ), array( 'a' => array( 'href' => array() ) ) ), esc_url( 'https://members.ithemes.com/panel/helpdesk.php' ) ),
|
70 |
+
'security_settings_link' => $settings,
|
71 |
+
'unsubscribe_link_text' => esc_html__( 'This email was generated by the iThemes Security plugin.', 'better-wp-security' ) . '<br>' . sprintf( esc_html__( 'To unsubscribe from these updates, visit the %1$sSettings page%2$s in the iThemes Security plugin menu.', 'better-wp-security' ), "<a href=\"{$settings}\" style=\"color: #0084CB\">", '</a>' ),
|
72 |
'security_guide' => esc_html__( 'Free WordPress Security Guide', 'better-wp-security' ),
|
73 |
'security_guide_content' => sprintf( wp_kses( __( 'Learn simple WordPress security tips — including 3 kinds of security your site needs and 4 best security practices for keeping your WordPress site safe with our <a href="%s">free guide</a>.', 'better-wp-security' ), array( 'a' => array( 'href' => array() ) ) ), esc_url( 'https://ithemes.com/publishing/wordpress-security/' ) ),
|
74 |
|
75 |
);
|
76 |
|
77 |
+
$this->content .= $this->replace_all( $footer, $replacements );
|
78 |
+
|
79 |
+
if ( defined( 'ITSEC_DEBUG' ) && ITSEC_DEBUG ) {
|
80 |
+
$this->include_debug_info();
|
81 |
+
}
|
82 |
+
|
83 |
+
$this->content .= $this->get_template( 'close.html' );
|
84 |
+
}
|
85 |
+
|
86 |
+
public function add_user_footer() {
|
87 |
+
|
88 |
+
$link_text = sprintf( esc_html__( 'This email was generated by the iThemes Security plugin on behalf of %s.', 'better-wp-security' ), get_bloginfo( 'name', 'display' ) ) . '<br>';
|
89 |
+
$link_text .= sprintf(
|
90 |
+
esc_html__( 'To unsubscribe from these notifications, please %1$scontact the site administrator%2$s.', 'better-wp-security' ),
|
91 |
+
'<a href="' . esc_url( site_url() ) . '" style="color: #0084CB">', '</a>'
|
92 |
+
);
|
93 |
+
|
94 |
+
$footer = $this->replace_all( $this->replace_images( $this->get_template( 'footer-user.html' ) ), array(
|
95 |
+
'unsubscribe_link_text' => $link_text,
|
96 |
+
) );
|
97 |
|
98 |
+
$footer .= $this->get_template( 'close.html' );
|
99 |
$this->content .= $footer;
|
100 |
}
|
101 |
|
118 |
}
|
119 |
|
120 |
public function add_info_box( $content, $icon_type = 'info' ) {
|
121 |
+
$icon_url = $this->get_image_url( $icon_type === 'warning' ? 'warning_icon_yellow' : "{$icon_type}_icon" );
|
122 |
|
123 |
$module = $this->get_template( 'info-box.html' );
|
124 |
$module = $this->replace_all( $module, compact( 'content', 'icon_url' ) );
|
133 |
$this->content .= $module;
|
134 |
}
|
135 |
|
136 |
+
public function add_large_code( $content ) {
|
137 |
+
$module = $this->get_template( 'large-code.html' );
|
138 |
+
$module = $this->replace( $module, 'content', $content );
|
139 |
+
|
140 |
+
$this->content .= $module;
|
141 |
+
}
|
142 |
+
|
143 |
public function add_section_heading( $content, $icon_type = false ) {
|
144 |
if ( empty( $icon_type ) ) {
|
145 |
$heading = $this->get_template( 'section-heading.html' );
|
169 |
$this->content .= $lockouts;
|
170 |
}
|
171 |
|
172 |
+
public function add_file_change_summary( $added, $removed, $modified ) {
|
173 |
+
$lockouts = $this->get_template( 'file-change-summary.html' );
|
174 |
+
|
175 |
+
$replacements = array(
|
176 |
+
'added_text' => esc_html_x( 'Added', 'Files added', 'better-wp-security' ),
|
177 |
+
'removed_text' => esc_html_x( 'Removed', 'Files removed', 'better-wp-security' ),
|
178 |
+
'modified_text' => esc_html_x( 'Modified', 'Files modified', 'better-wp-security' ),
|
179 |
+
'added_count' => $added,
|
180 |
+
'removed_count' => $removed,
|
181 |
+
'modified_count' => $modified,
|
182 |
+
);
|
183 |
+
|
184 |
+
$lockouts = $this->replace_all( $lockouts, $replacements );
|
185 |
+
|
186 |
+
$this->content .= $lockouts;
|
187 |
+
}
|
188 |
+
|
189 |
public function add_button( $link_text, $href ) {
|
190 |
$module = $this->get_template( 'module-button.html' );
|
191 |
+
$module = $this->replace( $module, 'href', $href );
|
192 |
+
$module = $this->replace( $module, 'link_text', $link_text );
|
193 |
|
194 |
$this->content .= $module;
|
195 |
}
|
224 |
$this->content .= $table;
|
225 |
}
|
226 |
|
227 |
+
/**
|
228 |
+
* Add a generic table.
|
229 |
+
*
|
230 |
+
* @param string[] $headers
|
231 |
+
* @param array[] $entries
|
232 |
+
*/
|
233 |
+
public function add_table( $headers, $entries ) {
|
234 |
+
|
235 |
+
$template = $this->get_template( 'table.html' );
|
236 |
+
$html = $this->build_table_header( $headers );
|
237 |
+
|
238 |
+
foreach ( $entries as $entry ) {
|
239 |
+
$html .= $this->build_table_row( $entry, count( $headers ) );
|
240 |
+
}
|
241 |
+
|
242 |
+
$this->content .= $this->replace( $template, 'html', $html );
|
243 |
+
}
|
244 |
+
|
245 |
+
/**
|
246 |
+
* Build the table header.
|
247 |
+
*
|
248 |
+
* @param array $headers
|
249 |
+
*
|
250 |
+
* @return string
|
251 |
+
*/
|
252 |
+
private function build_table_header( $headers ) {
|
253 |
+
|
254 |
+
$html = '<tr>';
|
255 |
+
|
256 |
+
foreach ( $headers as $header ) {
|
257 |
+
$html .= '<th style="text-align: left;font-weight: bold;padding:5px 10px;border:1px solid #cdcece;color: #666f72;">';
|
258 |
+
$html .= $header;
|
259 |
+
$html .= '</th>';
|
260 |
+
}
|
261 |
+
|
262 |
+
$html .= '</tr>';
|
263 |
+
|
264 |
+
return $html;
|
265 |
+
}
|
266 |
+
|
267 |
+
/**
|
268 |
+
* Build a table row.
|
269 |
+
*
|
270 |
+
* @param array|string $columns
|
271 |
+
* @param int $count
|
272 |
+
*
|
273 |
+
* @return string
|
274 |
+
*/
|
275 |
+
private function build_table_row( $columns, $count ) {
|
276 |
+
$html = '<tr>';
|
277 |
+
|
278 |
+
if ( is_array( $columns ) ) {
|
279 |
+
foreach ( $columns as $i => $column ) {
|
280 |
+
$style = 'border:1px solid #cdcece;padding:10px;';
|
281 |
+
|
282 |
+
if ( 0 === $i ) {
|
283 |
+
$style .= 'font-style:italic;';
|
284 |
+
$el = 'th';
|
285 |
+
} else {
|
286 |
+
$el = 'td';
|
287 |
+
}
|
288 |
+
|
289 |
+
$html .= "<{$el} style=\"{$style}\">";
|
290 |
+
$html .= $column;
|
291 |
+
$html .= "</{$el}>";
|
292 |
+
}
|
293 |
+
} else {
|
294 |
+
$html .= "<td style=\"border:1px solid #cdcece;padding:10px;\" colspan=\"{$count}\">{$columns}</td>";
|
295 |
+
}
|
296 |
+
|
297 |
+
$html .= '</tr>';
|
298 |
+
|
299 |
+
return $html;
|
300 |
+
}
|
301 |
+
|
302 |
+
/**
|
303 |
+
* Add an HTML list to an email.
|
304 |
+
*
|
305 |
+
* @param string[] $items
|
306 |
+
* @param bool $bold_first Whether to emphasize the first item of the list.
|
307 |
+
*/
|
308 |
+
public function add_list( $items, $bold_first = false ) {
|
309 |
+
|
310 |
+
$template = $this->get_template( 'list.html' );
|
311 |
+
$html = '';
|
312 |
+
|
313 |
+
foreach ( $items as $i => $item ) {
|
314 |
+
$html .= $this->build_list_item( $item, $bold_first && 0 === $i );
|
315 |
+
}
|
316 |
+
|
317 |
+
$this->content .= $this->replace( $template, 'html', $html );
|
318 |
+
}
|
319 |
+
|
320 |
+
private function build_list_item( $item, $bold = false ) {
|
321 |
+
$bold_tag = $bold ? 'font-weight: bold;' : '';
|
322 |
+
|
323 |
+
return "<li style=\"margin: 0; padding: 5px 10px;{$bold_tag}\">{$item}</li>";
|
324 |
+
}
|
325 |
+
|
326 |
+
/**
|
327 |
+
* Include debug info in the email.
|
328 |
+
*
|
329 |
+
* This is automatically included in non-user emails if ITSEC_DEBUG is turned on.
|
330 |
+
*/
|
331 |
+
public function include_debug_info() {
|
332 |
+
$this->add_text( sprintf( esc_html__( 'Debug info (source page): %s', 'better-wp-security' ), esc_url( $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) ) );
|
333 |
+
}
|
334 |
+
|
335 |
+
/**
|
336 |
+
* Get the site URL formatted for display in emails.
|
337 |
+
*
|
338 |
+
* This strips out the URL scheme, but keeps the path in case of multisite.
|
339 |
+
*
|
340 |
+
* @return string
|
341 |
+
*/
|
342 |
+
public function get_display_url() {
|
343 |
+
|
344 |
+
$url = network_site_url();
|
345 |
+
$parsed = parse_url( $url );
|
346 |
+
|
347 |
+
$display = $parsed['host'];
|
348 |
+
|
349 |
+
if ( ! empty( $parsed['path'] ) ) {
|
350 |
+
$display .= $parsed['path'];
|
351 |
+
}
|
352 |
+
|
353 |
+
// Escape URL will force a scheme.
|
354 |
+
return esc_html( $display );
|
355 |
+
}
|
356 |
+
|
357 |
+
public function set_content( $content ) {
|
358 |
+
$this->content = $content;
|
359 |
+
}
|
360 |
+
|
361 |
public function get_content() {
|
362 |
return $this->content;
|
363 |
}
|
364 |
|
365 |
public function set_subject( $subject, $add_site_url = true ) {
|
366 |
if ( $add_site_url ) {
|
367 |
+
$subject = $this->prepend_site_url_to_subject( $subject );
|
|
|
368 |
}
|
369 |
|
370 |
$this->subject = esc_html( $subject );
|
371 |
}
|
372 |
|
373 |
+
public function prepend_site_url_to_subject( $subject ) {
|
374 |
+
/* translators: 1: site URL, 2: email subject */
|
375 |
+
return sprintf( __( '[%1$s] %2$s', 'better-wp-security' ), $this->get_display_url(), $subject );
|
376 |
+
}
|
377 |
+
|
378 |
+
public function set_default_subject() {
|
379 |
+
return __( 'New Notification from iThemes Security', 'better-wp-security' );
|
380 |
+
}
|
381 |
+
|
382 |
+
public function get_subject() {
|
383 |
+
return $this->subject;
|
384 |
+
}
|
385 |
+
|
386 |
public function set_recipients( $recipients ) {
|
387 |
$this->recipients = array();
|
388 |
|
400 |
$this->set_recipients( $recipients );
|
401 |
}
|
402 |
|
403 |
+
public function get_recipients() {
|
404 |
+
return $this->recipients;
|
405 |
+
}
|
406 |
+
|
407 |
public function set_attachments( $attachments ) {
|
408 |
$this->attachments = $attachments;
|
409 |
}
|
424 |
return wp_mail( $this->recipients, $this->subject, $this->content, array( 'Content-Type: text/html; charset=UTF-8' ), $this->attachments );
|
425 |
}
|
426 |
|
427 |
+
/**
|
428 |
+
* Get the URL to the site logo.
|
429 |
+
*
|
430 |
+
* @return string
|
431 |
+
*/
|
432 |
+
private function get_site_logo_url() {
|
433 |
+
$custom_logo_id = get_theme_mod( 'custom_logo' );
|
434 |
+
|
435 |
+
if ( ! $custom_logo_id ) {
|
436 |
+
return '';
|
437 |
+
}
|
438 |
+
|
439 |
+
$image = wp_get_attachment_image_src( $custom_logo_id, array( 300, 127 ) );
|
440 |
+
|
441 |
+
if ( ! $image || empty( $image[0] ) ) {
|
442 |
+
return '';
|
443 |
+
}
|
444 |
+
|
445 |
+
return $image[0];
|
446 |
+
}
|
447 |
+
|
448 |
private function get_template( $template ) {
|
449 |
return $this->replace_images( file_get_contents( $this->template_path . $template ) );
|
450 |
}
|
451 |
|
452 |
+
private function replace( $content, $variable, $value ) {
|
453 |
+
return ITSEC_Lib::replace_tag( $content, $variable, $value );
|
454 |
+
}
|
455 |
+
|
456 |
+
private function replace_all( $content, $replacements ) {
|
457 |
+
return ITSEC_Lib::replace_tags( $content, $replacements );
|
458 |
+
}
|
459 |
+
|
460 |
+
private function replace_images( $content ) {
|
461 |
+
return preg_replace_callback( '/{! \$([a-zA-Z_][\w]*) }}/', array( $this, 'replace_image_callback' ), $content );
|
462 |
+
}
|
463 |
+
|
464 |
+
private function replace_image_callback( $matches ) {
|
465 |
+
if ( empty( $matches ) || empty( $matches[1] ) ) {
|
466 |
+
return '';
|
467 |
+
}
|
468 |
+
|
469 |
+
return esc_url( $this->get_image_url( $matches[1] ) );
|
470 |
+
}
|
471 |
+
|
472 |
private function get_image_url( $name ) {
|
473 |
return plugin_dir_url( ITSEC_Core::get_core_dir() . 'img/mail/index.php' ) . "{$name}.png";
|
474 |
}
|
core/lib/mail-templates/close.html
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
</table>
|
2 |
+
</td>
|
3 |
+
</tr>
|
4 |
+
</table>
|
5 |
+
</center>
|
6 |
+
</body>
|
7 |
+
|
8 |
+
</html>
|
core/lib/mail-templates/file-change-summary.html
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<tr>
|
2 |
+
<td class="file-change-summary" align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
3 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
4 |
+
<tr>
|
5 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
6 |
+
<table class="container" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
7 |
+
<tr>
|
8 |
+
<td class="section-padding" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
9 |
+
<table class="container left-column" align="left" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;margin-right: 60px;">
|
10 |
+
<tr>
|
11 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
12 |
+
<h4 style="color: #ACAAAA;font-family: Helvetica;font-size: 16px;font-weight: normal;line-height: 150%;margin: 0;padding: 0;text-align: center;">{{ $added_text }}</h4>
|
13 |
+
<p style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;font-family: Helvetica;font-size: 30px;line-height: 150%;margin-top: 10px;margin-right: 0;margin-bottom: 10px;margin-left: 0;padding: 0;text-align: center;color: #505050;font-weight: bold;">{{ $added_count }}</p>
|
14 |
+
</td>
|
15 |
+
</tr>
|
16 |
+
</table>
|
17 |
+
<table class="container center-column" align="left" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;margin-right: 60px;">
|
18 |
+
<tr>
|
19 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
20 |
+
<h4 style="color: #ACAAAA;font-family: Helvetica;font-size: 16px;font-weight: normal;line-height: 150%;margin: 0;padding: 0;text-align: center;">{{ $removed_text }}</h4>
|
21 |
+
<p style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;font-family: Helvetica;font-size: 30px;line-height: 150%;margin-top: 10px;margin-right: 0;margin-bottom: 10px;margin-left: 0;padding: 0;text-align: center;color: #505050;font-weight: bold;">{{ $removed_count }}</p>
|
22 |
+
</td>
|
23 |
+
</tr>
|
24 |
+
</table>
|
25 |
+
<table class="container right-column" align="right" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
26 |
+
<tr>
|
27 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
28 |
+
<h4 style="color: #ACAAAA;font-family: Helvetica;font-size: 16px;font-weight: normal;line-height: 150%;margin: 0;padding: 0;text-align: center;">{{ $modified_text }}</h4>
|
29 |
+
<p style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;font-family: Helvetica;font-size: 30px;line-height: 150%;margin-top: 10px;margin-right: 0;margin-bottom: 10px;margin-left: 0;padding: 0;text-align: center;color: #505050;font-weight: bold;">{{ $modified_count }}</p>
|
30 |
+
</td>
|
31 |
+
</tr>
|
32 |
+
</table>
|
33 |
+
</td>
|
34 |
+
</tr>
|
35 |
+
</table>
|
36 |
+
</td>
|
37 |
+
</tr>
|
38 |
+
</table>
|
39 |
+
</td>
|
40 |
+
</tr>
|
core/lib/mail-templates/footer-user.html
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<tr>
|
2 |
+
<td id="footer-source-details" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
3 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
4 |
+
<tr>
|
5 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
6 |
+
<table class="container" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
7 |
+
<tr>
|
8 |
+
<td class="section-padding" align="center" valign="top" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
9 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
10 |
+
<tr>
|
11 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 200%;text-align: center;padding-bottom: 0;padding-top: 60px;">
|
12 |
+
<img class="preserve-ratio" src="{! $footer_logo }}" style="max-width: 50px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;" width="50" alt="" align="center"><br>
|
13 |
+
<br>
|
14 |
+
<span style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #666f72;font-family: Helvetica;font-size: 11px;line-height: 200%;text-align: center;text-decoration: none;font-weight: bold;">
|
15 |
+
{{ $unsubscribe_link_text }}
|
16 |
+
</span>
|
17 |
+
</td>
|
18 |
+
</tr>
|
19 |
+
</table>
|
20 |
+
</td>
|
21 |
+
</tr>
|
22 |
+
</table>
|
23 |
+
</td>
|
24 |
+
</tr>
|
25 |
+
</table>
|
26 |
+
</td>
|
27 |
+
</tr>
|
core/lib/mail-templates/footer.html
CHANGED
@@ -1,208 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<tr>
|
2 |
-
<td class="
|
3 |
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
4 |
<tr>
|
5 |
-
<td
|
6 |
-
<
|
7 |
-
<tr>
|
8 |
-
<td class="section-padding" align="center" valign="top" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
9 |
-
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
10 |
-
<tr>
|
11 |
-
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
12 |
-
<h2 style="color: #002030;font-family: Helvetica;font-size: 26px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: center;">{{ $security_resources }}</h2>
|
13 |
-
</td>
|
14 |
-
</tr>
|
15 |
-
</table>
|
16 |
-
</td>
|
17 |
-
</tr>
|
18 |
-
</table>
|
19 |
</td>
|
20 |
</tr>
|
21 |
</table>
|
22 |
</td>
|
23 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
<tr>
|
25 |
-
<td
|
26 |
-
<table border="0" cellpadding="0" cellspacing="0" width="
|
27 |
<tr>
|
28 |
-
<td
|
29 |
-
<
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
<br>
|
50 |
-
<h4 style="color: #202020;font-family: Helvetica;font-size: 20px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: center;">
|
51 |
-
<a href="https://ithemes.com/tutorial/category/ithemes-security/" target="_blank" style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #0084CB;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;text-decoration: none;">{{ $tutorials }}</a>
|
52 |
-
</h4>
|
53 |
-
<br>
|
54 |
-
<p style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;font-family: Helvetica;font-size: 16px;line-height: 150%;margin-top: 10px;margin-right: 0;margin-bottom: 10px;margin-left: 0;padding: 0;text-align: center;">{{ $tutorials_content }}</p>
|
55 |
-
</td>
|
56 |
-
</tr>
|
57 |
-
</table>
|
58 |
-
</td>
|
59 |
-
</tr>
|
60 |
-
</table>
|
61 |
</td>
|
62 |
</tr>
|
63 |
</table>
|
64 |
</td>
|
65 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
<tr>
|
67 |
-
<td class="
|
68 |
-
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
69 |
<tr>
|
70 |
-
<td
|
71 |
-
|
72 |
-
<tr>
|
73 |
-
<td class="section-padding" align="center" valign="top" width="450" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
74 |
-
<table class="divider-border" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;border-top-width: 1px;border-top-style: solid;border-top-color: #E8E8E8;">
|
75 |
-
<tr>
|
76 |
-
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 1px;text-align: center;padding-bottom: 20px;width: 450px;">
|
77 |
-
|
78 |
-
</td>
|
79 |
-
</tr>
|
80 |
-
</table>
|
81 |
-
</td>
|
82 |
-
</tr>
|
83 |
-
</table>
|
84 |
</td>
|
85 |
</tr>
|
86 |
</table>
|
87 |
</td>
|
88 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
<tr>
|
90 |
-
<td class="
|
91 |
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
92 |
<tr>
|
93 |
-
<td
|
94 |
-
<
|
95 |
-
<tr>
|
96 |
-
<td class="section-padding" align="center" valign="top" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
97 |
-
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
98 |
-
<tr>
|
99 |
-
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
100 |
-
<h2 style="color: #002030;font-family: Helvetica;font-size: 26px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: center;">{{ $help_and_support }}</h2>
|
101 |
-
</td>
|
102 |
-
</tr>
|
103 |
-
</table>
|
104 |
-
</td>
|
105 |
-
</tr>
|
106 |
-
</table>
|
107 |
</td>
|
108 |
</tr>
|
109 |
</table>
|
110 |
</td>
|
111 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
<tr>
|
113 |
-
<td
|
114 |
-
<table border="0" cellpadding="0" cellspacing="0" width="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
<tr>
|
116 |
-
<td
|
117 |
-
<
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
<h4 style="color: #202020;font-family: Helvetica;font-size: 20px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: center;">
|
126 |
-
<a href="http://ithemes.com/codex/page/IThemes_Security" target="_blank" style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #0084CB;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;text-decoration: none;">{{ $documentation }}</a>
|
127 |
-
</h4>
|
128 |
-
<br>
|
129 |
-
<p style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;font-family: Helvetica;font-size: 16px;line-height: 150%;margin-top: 10px;margin-right: 0;margin-bottom: 10px;margin-left: 0;padding: 0;text-align: center;">{{ $documentation_content }}</p>
|
130 |
-
</td>
|
131 |
-
</tr>
|
132 |
-
</table>
|
133 |
-
<table class="container" align="right" border="0" cellpadding="0" cellspacing="0" width="260" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
134 |
-
<tr>
|
135 |
-
<td class="container-cell container-cell-bottom" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
136 |
-
<img class="preserve-ratio" src="{! $support_icon }}" style="max-width: 62px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;" width="62" alt="" align="center">
|
137 |
-
<br>
|
138 |
-
<h4 style="color: #202020;font-family: Helvetica;font-size: 20px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: center;">
|
139 |
-
<a href="https://members.ithemes.com/panel/helpdesk.php" target="_blank" style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #0084CB;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;text-decoration: none;">{{ $support }}</a>
|
140 |
-
<span class="pro-flag" style="background-color: #FFCC00;color: #000000;font-size: 10px;display: inline-block;padding: 3px;line-height: 1;position: relative;bottom: 10px;text-transform: uppercase;">{{ $pro }}</span>
|
141 |
-
</h4>
|
142 |
-
<br>
|
143 |
-
<p style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;font-family: Helvetica;font-size: 16px;line-height: 150%;margin-top: 10px;margin-right: 0;margin-bottom: 10px;margin-left: 0;padding: 0;text-align: center;">{{ $support_content }}</p>
|
144 |
-
</td>
|
145 |
-
</tr>
|
146 |
-
</table>
|
147 |
-
</td>
|
148 |
-
</tr>
|
149 |
-
</table>
|
150 |
</td>
|
151 |
</tr>
|
152 |
</table>
|
153 |
</td>
|
154 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
<tr>
|
156 |
-
<td
|
157 |
-
<table border="0" cellpadding="0" cellspacing="0" width="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
<tr>
|
159 |
-
<td
|
160 |
-
<
|
161 |
-
|
162 |
-
<td class="section-padding" valign="top" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
163 |
-
<table class="container" align="left" border="0" cellpadding="0" cellspacing="0" width="104" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
164 |
-
<tr>
|
165 |
-
<td class="section-padding-bottom" align="left" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-bottom: 20px;">
|
166 |
-
<img class="preserve-ratio" src="{! $wp_security_book }}" style="max-width: 84px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;" width="84" alt="" align="center">
|
167 |
-
</td>
|
168 |
-
</tr>
|
169 |
-
</table>
|
170 |
-
<table class="container" align="right" border="0" cellpadding="0" cellspacing="0" width="454" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
171 |
-
<tr>
|
172 |
-
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #6C6C6C;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: left;padding-bottom: 20px;">
|
173 |
-
<h4 style="color: #6C6C6C;font-family: Helvetica;font-size: 18px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: left;padding-bottom: 10px;">{{ $security_guide }}</h4>
|
174 |
-
{{ $security_guide_content }}
|
175 |
-
</td>
|
176 |
-
</tr>
|
177 |
-
</table>
|
178 |
-
</td>
|
179 |
-
</tr>
|
180 |
-
</table>
|
181 |
</td>
|
182 |
</tr>
|
183 |
</table>
|
184 |
</td>
|
185 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
<tr>
|
187 |
-
<td
|
188 |
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
189 |
<tr>
|
190 |
-
<td
|
191 |
-
<
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 200%;text-align: center;padding-bottom: 0;padding-top: 60px;">
|
197 |
-
<img class="preserve-ratio" src="{! $footer_logo }}" style="max-width: 50px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;" width="50" alt="" align="center"><br>
|
198 |
-
<br>
|
199 |
-
<a href="{{ $security_settings_link }}" style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #0084CB;font-family: Helvetica;font-size: 11px;line-height: 200%;text-align: center;text-decoration: none;font-weight: bold;">{{ $unsubscribe_link_text }}</a>
|
200 |
-
</td>
|
201 |
-
</tr>
|
202 |
-
</table>
|
203 |
-
</td>
|
204 |
-
</tr>
|
205 |
-
</table>
|
206 |
</td>
|
207 |
</tr>
|
208 |
</table>
|
@@ -212,7 +208,5 @@
|
|
212 |
</td>
|
213 |
</tr>
|
214 |
</table>
|
215 |
-
</
|
216 |
-
</
|
217 |
-
|
218 |
-
</html>
|
1 |
+
<tr>
|
2 |
+
<td class="footer-heading" align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
3 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
4 |
+
<tr>
|
5 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
6 |
+
<table class="container" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
7 |
<tr>
|
8 |
+
<td class="section-padding" align="center" valign="top" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
9 |
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
10 |
<tr>
|
11 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
12 |
+
<h2 style="color: #002030;font-family: Helvetica;font-size: 26px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: center;">{{ $security_resources }}</h2>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
</td>
|
14 |
</tr>
|
15 |
</table>
|
16 |
</td>
|
17 |
</tr>
|
18 |
+
</table>
|
19 |
+
</td>
|
20 |
+
</tr>
|
21 |
+
</table>
|
22 |
+
</td>
|
23 |
+
</tr>
|
24 |
+
<tr>
|
25 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
26 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
27 |
+
<tr>
|
28 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
29 |
+
<table class="container" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
30 |
<tr>
|
31 |
+
<td class="section-padding" valign="top" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
32 |
+
<table class="container" align="left" border="0" cellpadding="0" cellspacing="0" width="260" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
33 |
<tr>
|
34 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
35 |
+
<img class="preserve-ratio" src="{! $article_icon }}" style="max-width: 61px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;" width="61" alt="" align="center">
|
36 |
+
<br>
|
37 |
+
<h4 style="color: #202020;font-family: Helvetica;font-size: 20px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: center;">
|
38 |
+
<a href="https://ithemes.com/category/wordpress-security/" target="_blank" style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #0084CB;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;text-decoration: none;">{{ $articles }}</a>
|
39 |
+
</h4>
|
40 |
+
<br>
|
41 |
+
<p style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;font-family: Helvetica;font-size: 16px;line-height: 150%;margin-top: 10px;margin-right: 0;margin-bottom: 10px;margin-left: 0;padding: 0;text-align: center;">{{ $articles_content }}</p>
|
42 |
+
</td>
|
43 |
+
</tr>
|
44 |
+
</table>
|
45 |
+
<table class="container" align="right" border="0" cellpadding="0" cellspacing="0" width="260" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
46 |
+
<tr>
|
47 |
+
<td class="container-cell container-cell-bottom" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
48 |
+
<img class="preserve-ratio" src="{! $video_icon }}" style="max-width: 61px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;" width="61" alt="" align="center">
|
49 |
+
<br>
|
50 |
+
<h4 style="color: #202020;font-family: Helvetica;font-size: 20px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: center;">
|
51 |
+
<a href="https://ithemes.com/tutorial/category/ithemes-security/" target="_blank" style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #0084CB;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;text-decoration: none;">{{ $tutorials }}</a>
|
52 |
+
</h4>
|
53 |
+
<br>
|
54 |
+
<p style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;font-family: Helvetica;font-size: 16px;line-height: 150%;margin-top: 10px;margin-right: 0;margin-bottom: 10px;margin-left: 0;padding: 0;text-align: center;">{{ $tutorials_content }}</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
</td>
|
56 |
</tr>
|
57 |
</table>
|
58 |
</td>
|
59 |
</tr>
|
60 |
+
</table>
|
61 |
+
</td>
|
62 |
+
</tr>
|
63 |
+
</table>
|
64 |
+
</td>
|
65 |
+
</tr>
|
66 |
+
<tr>
|
67 |
+
<td class="divider" align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
68 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
69 |
+
<tr>
|
70 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
71 |
+
<table class="container" border="0" cellpadding="0" cellspacing="0" width="450" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
72 |
<tr>
|
73 |
+
<td class="section-padding" align="center" valign="top" width="450" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
74 |
+
<table class="divider-border" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;border-top-width: 1px;border-top-style: solid;border-top-color: #E8E8E8;">
|
75 |
<tr>
|
76 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 1px;text-align: center;padding-bottom: 20px;width: 450px;">
|
77 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
</td>
|
79 |
</tr>
|
80 |
</table>
|
81 |
</td>
|
82 |
</tr>
|
83 |
+
</table>
|
84 |
+
</td>
|
85 |
+
</tr>
|
86 |
+
</table>
|
87 |
+
</td>
|
88 |
+
</tr>
|
89 |
+
<tr>
|
90 |
+
<td class="footer-heading" align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
91 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
92 |
+
<tr>
|
93 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
94 |
+
<table class="container" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
95 |
<tr>
|
96 |
+
<td class="section-padding" align="center" valign="top" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
97 |
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
98 |
<tr>
|
99 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
100 |
+
<h2 style="color: #002030;font-family: Helvetica;font-size: 26px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: center;">{{ $help_and_support }}</h2>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
</td>
|
102 |
</tr>
|
103 |
</table>
|
104 |
</td>
|
105 |
</tr>
|
106 |
+
</table>
|
107 |
+
</td>
|
108 |
+
</tr>
|
109 |
+
</table>
|
110 |
+
</td>
|
111 |
+
</tr>
|
112 |
+
<tr>
|
113 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
114 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
115 |
+
<tr>
|
116 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
117 |
+
<table class="container" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
118 |
<tr>
|
119 |
+
<td class="section-padding" valign="top" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
120 |
+
<table class="container" align="left" border="0" cellpadding="0" cellspacing="0" width="260" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
121 |
+
<tr>
|
122 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
123 |
+
<img class="preserve-ratio" src="{! $documentation_icon }}" style="max-width: 62px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;" width="62" alt="" align="center">
|
124 |
+
<br>
|
125 |
+
<h4 style="color: #202020;font-family: Helvetica;font-size: 20px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: center;">
|
126 |
+
<a href="http://ithemes.com/codex/page/IThemes_Security" target="_blank" style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #0084CB;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;text-decoration: none;">{{ $documentation }}</a>
|
127 |
+
</h4>
|
128 |
+
<br>
|
129 |
+
<p style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;font-family: Helvetica;font-size: 16px;line-height: 150%;margin-top: 10px;margin-right: 0;margin-bottom: 10px;margin-left: 0;padding: 0;text-align: center;">{{ $documentation_content }}</p>
|
130 |
+
</td>
|
131 |
+
</tr>
|
132 |
+
</table>
|
133 |
+
<table class="container" align="right" border="0" cellpadding="0" cellspacing="0" width="260" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
134 |
<tr>
|
135 |
+
<td class="container-cell container-cell-bottom" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
136 |
+
<img class="preserve-ratio" src="{! $support_icon }}" style="max-width: 62px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;" width="62" alt="" align="center">
|
137 |
+
<br>
|
138 |
+
<h4 style="color: #202020;font-family: Helvetica;font-size: 20px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: center;">
|
139 |
+
<a href="https://members.ithemes.com/panel/helpdesk.php" target="_blank" style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #0084CB;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;text-decoration: none;">{{ $support }}</a>
|
140 |
+
<span class="pro-flag" style="background-color: #FFCC00;color: #000000;font-size: 10px;display: inline-block;padding: 3px;line-height: 1;position: relative;bottom: 10px;text-transform: uppercase;">{{ $pro }}</span>
|
141 |
+
</h4>
|
142 |
+
<br>
|
143 |
+
<p style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;font-family: Helvetica;font-size: 16px;line-height: 150%;margin-top: 10px;margin-right: 0;margin-bottom: 10px;margin-left: 0;padding: 0;text-align: center;">{{ $support_content }}</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
</td>
|
145 |
</tr>
|
146 |
</table>
|
147 |
</td>
|
148 |
</tr>
|
149 |
+
</table>
|
150 |
+
</td>
|
151 |
+
</tr>
|
152 |
+
</table>
|
153 |
+
</td>
|
154 |
+
</tr>
|
155 |
+
<tr>
|
156 |
+
<td id="security-guide" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
157 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
158 |
+
<tr>
|
159 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
160 |
+
<table id="security-guide-container" class="container" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;border: 1px solid #CDCECE;background-color: #D3E8E9;">
|
161 |
<tr>
|
162 |
+
<td class="section-padding" valign="top" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
163 |
+
<table class="container" align="left" border="0" cellpadding="0" cellspacing="0" width="104" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
164 |
+
<tr>
|
165 |
+
<td class="section-padding-bottom" align="left" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-bottom: 20px;">
|
166 |
+
<img class="preserve-ratio" src="{! $wp_security_book }}" style="max-width: 84px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;" width="84" alt="" align="center">
|
167 |
+
</td>
|
168 |
+
</tr>
|
169 |
+
</table>
|
170 |
+
<table class="container" align="right" border="0" cellpadding="0" cellspacing="0" width="454" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
171 |
<tr>
|
172 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #6C6C6C;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: left;padding-bottom: 20px;">
|
173 |
+
<h4 style="color: #6C6C6C;font-family: Helvetica;font-size: 18px;font-weight: bold;line-height: 150%;margin: 0;padding: 0;text-align: left;padding-bottom: 10px;">{{ $security_guide }}</h4>
|
174 |
+
{{ $security_guide_content }}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
</td>
|
176 |
</tr>
|
177 |
</table>
|
178 |
</td>
|
179 |
</tr>
|
180 |
+
</table>
|
181 |
+
</td>
|
182 |
+
</tr>
|
183 |
+
</table>
|
184 |
+
</td>
|
185 |
+
</tr>
|
186 |
+
<tr>
|
187 |
+
<td id="footer-source-details" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
188 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
189 |
+
<tr>
|
190 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
191 |
+
<table class="container" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
192 |
<tr>
|
193 |
+
<td class="section-padding" align="center" valign="top" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
194 |
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
195 |
<tr>
|
196 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 200%;text-align: center;padding-bottom: 0;padding-top: 60px;">
|
197 |
+
<img class="preserve-ratio" src="{! $footer_logo }}" style="max-width: 50px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;" width="50" alt="" align="center"><br>
|
198 |
+
<br>
|
199 |
+
<span style="-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #666f72;font-family: Helvetica;font-size: 11px;line-height: 200%;text-align: center;text-decoration: none;font-weight: bold;">
|
200 |
+
{{ $unsubscribe_link_text }}
|
201 |
+
</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
202 |
</td>
|
203 |
</tr>
|
204 |
</table>
|
208 |
</td>
|
209 |
</tr>
|
210 |
</table>
|
211 |
+
</td>
|
212 |
+
</tr>
|
|
|
|
core/lib/mail-templates/header.html
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2 |
<html xmlns="http://www.w3.org/1999/xhtml" lang="{{ $lang }}">
|
3 |
|
@@ -49,11 +50,11 @@
|
|
49 |
.lockouts-summary .container.left-column{margin-right:60px;}
|
50 |
.lockouts-summary h4{color:#ACAAAA;font-size:16px;font-weight:normal;}
|
51 |
.lockouts-summary p{color:#505050;font-size:30px;font-weight:bold;}
|
52 |
-
.
|
53 |
-
.
|
54 |
-
.
|
55 |
-
.
|
56 |
-
.
|
57 |
.large-text h4{color:#505050;margin-bottom:10px;}
|
58 |
.details-box-container{padding-top:20px;padding-bottom:20px;}
|
59 |
.details-box{background-color:#E4EEF7;border:1px solid #CDCECE;}
|
@@ -132,7 +133,7 @@
|
|
132 |
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
133 |
<tr>
|
134 |
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;padding-top: 20px;">
|
135 |
-
<img class="preserve-ratio" src="{{ $logo }}" style="max-width: 300px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;"
|
136 |
</td>
|
137 |
</tr>
|
138 |
</table>
|
1 |
+
|
2 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3 |
<html xmlns="http://www.w3.org/1999/xhtml" lang="{{ $lang }}">
|
4 |
|
50 |
.lockouts-summary .container.left-column{margin-right:60px;}
|
51 |
.lockouts-summary h4{color:#ACAAAA;font-size:16px;font-weight:normal;}
|
52 |
.lockouts-summary p{color:#505050;font-size:30px;font-weight:bold;}
|
53 |
+
.table{border:1px solid #cdcece;color: #404040;font-family:Helvetica;font-size:14px;}
|
54 |
+
.table th,.table td{border:1px solid #cdcece;padding:10px;}
|
55 |
+
.table th{text-align:left;font-weight:bold;padding:5px 10px;}
|
56 |
+
.table .row-label{font-style:italic;}
|
57 |
+
.table a,.table b{font-size:14px;}
|
58 |
.large-text h4{color:#505050;margin-bottom:10px;}
|
59 |
.details-box-container{padding-top:20px;padding-bottom:20px;}
|
60 |
.details-box{background-color:#E4EEF7;border:1px solid #CDCECE;}
|
133 |
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
134 |
<tr>
|
135 |
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;padding-top: 20px;">
|
136 |
+
<img class="preserve-ratio" src="{{ $logo }}" style="max-width: 300px;border: 0;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;height: auto;" alt="" align="center">
|
137 |
</td>
|
138 |
</tr>
|
139 |
</table>
|
core/lib/mail-templates/large-code.html
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<tr>
|
2 |
+
<td class="details-box-container" align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-bottom: 20px;">
|
3 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
4 |
+
<tr>
|
5 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
6 |
+
<table class="details-box container" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;background-color: #CEEAF5;border: 1px solid #BFE7FF;">
|
7 |
+
<tr>
|
8 |
+
<td class="section-padding" align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 40px;padding-left: 40px;">
|
9 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
10 |
+
<tr>
|
11 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #0b70b9;font-family: monospace;font-size: 32px;font-weight:bold;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
12 |
+
{{ $content }}
|
13 |
+
</td>
|
14 |
+
</tr>
|
15 |
+
</table>
|
16 |
+
</td>
|
17 |
+
</tr>
|
18 |
+
</table>
|
19 |
+
</td>
|
20 |
+
</tr>
|
21 |
+
</table>
|
22 |
+
</td>
|
23 |
+
</tr>
|
core/lib/mail-templates/list.html
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<tr>
|
2 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
3 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
4 |
+
<tr>
|
5 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
6 |
+
<table class="container" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
7 |
+
<tr>
|
8 |
+
<td class="section-padding" align="center" valign="top" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;padding-top: 20px;padding-right: 20px;padding-left: 20px;">
|
9 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
10 |
+
<tr>
|
11 |
+
<td class="container-cell" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #404040;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: center;padding-bottom: 20px;">
|
12 |
+
<div style="text-align: left;">
|
13 |
+
<ul style="font-size: 15px; line-height: 1.2; text-align: left; margin: 20px 0 20px 20px; padding: 0;">
|
14 |
+
{{ $html }}
|
15 |
+
</ul>
|
16 |
+
</div>
|
17 |
+
</td>
|
18 |
+
</tr>
|
19 |
+
</table>
|
20 |
+
</td>
|
21 |
+
</tr>
|
22 |
+
</table>
|
23 |
+
</td>
|
24 |
+
</tr>
|
25 |
+
</table>
|
26 |
+
</td>
|
27 |
+
</tr>
|
core/lib/mail-templates/lockouts-table.html
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
4 |
<tr>
|
5 |
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
6 |
-
<table class="
|
7 |
<tr>
|
8 |
<th style="text-align: left;font-weight: bold;padding:5px 10px;border:1px solid #cdcece;">{{ $heading_types }}</th>
|
9 |
<th style="text-align: left;font-weight: bold;padding:5px 10px;border:1px solid #cdcece;">{{ $heading_until }}</th>
|
3 |
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
4 |
<tr>
|
5 |
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
6 |
+
<table class="table" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;border:1px solid #CDCECE; font-family: Helvetica;">
|
7 |
<tr>
|
8 |
<th style="text-align: left;font-weight: bold;padding:5px 10px;border:1px solid #cdcece;">{{ $heading_types }}</th>
|
9 |
<th style="text-align: left;font-weight: bold;padding:5px 10px;border:1px solid #cdcece;">{{ $heading_until }}</th>
|
core/lib/mail-templates/table.html
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<tr>
|
2 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
3 |
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
4 |
+
<tr>
|
5 |
+
<td align="center" valign="top" style="border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
|
6 |
+
<table class="table" border="0" cellpadding="0" cellspacing="0" style="width: auto;max-width: 850px;border-collapse: collapse;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;border:1px solid #CDCECE; color: #404040;font-family: Helvetica;">
|
7 |
+
{{ $html }}
|
8 |
+
</table>
|
9 |
+
</td>
|
10 |
+
</tr>
|
11 |
+
</table>
|
12 |
+
</td>
|
13 |
+
</tr>
|
core/lockout.php
CHANGED
@@ -104,6 +104,9 @@ final class ITSEC_Lockout {
|
|
104 |
|
105 |
add_action( 'itsec-settings-page-init', array( $this, 'init_settings_page' ) );
|
106 |
add_action( 'itsec-logs-page-init', array( $this, 'init_settings_page' ) );
|
|
|
|
|
|
|
107 |
}
|
108 |
|
109 |
public function init_settings_page() {
|
@@ -183,17 +186,25 @@ final class ITSEC_Lockout {
|
|
183 |
$user_id = $user->ID;
|
184 |
|
185 |
if ( $username !== false && $username != '' ) {
|
186 |
-
$username_check = $wpdb->get_results(
|
|
|
|
|
|
|
187 |
}
|
188 |
|
189 |
-
$host_check = $wpdb->get_results(
|
|
|
|
|
|
|
190 |
|
191 |
}
|
192 |
|
193 |
if ( $user_id !== 0 && $user_id !== null ) {
|
194 |
|
195 |
-
$user_check = $wpdb->get_results(
|
196 |
-
|
|
|
|
|
197 |
}
|
198 |
|
199 |
$error = $wpdb->last_error;
|
@@ -306,8 +317,8 @@ final class ITSEC_Lockout {
|
|
306 |
|
307 |
$host_count = $wpdb->get_var(
|
308 |
$wpdb->prepare(
|
309 |
-
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` >
|
310 |
-
date( 'Y-m-d H:i:s',
|
311 |
$host
|
312 |
)
|
313 |
);
|
@@ -339,8 +350,8 @@ final class ITSEC_Lockout {
|
|
339 |
|
340 |
$user_count = $wpdb->get_var(
|
341 |
$wpdb->prepare(
|
342 |
-
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` > '%s' AND (`temp_username`=
|
343 |
-
date( 'Y-m-d H:i:s',
|
344 |
sanitize_text_field( $username ),
|
345 |
intval( $user_id )
|
346 |
)
|
@@ -368,8 +379,8 @@ final class ITSEC_Lockout {
|
|
368 |
|
369 |
$user_count = $wpdb->get_var(
|
370 |
$wpdb->prepare(
|
371 |
-
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` >
|
372 |
-
date( 'Y-m-d H:i:s',
|
373 |
$username
|
374 |
)
|
375 |
);
|
@@ -539,66 +550,80 @@ final class ITSEC_Lockout {
|
|
539 |
* @since 4.0
|
540 |
*
|
541 |
* @param string $type 'all', 'host', or 'user'
|
542 |
-
* @param
|
543 |
-
* @param int $limit the maximum number of locks to return
|
544 |
*
|
545 |
* @return array all lockouts in the system
|
546 |
*/
|
547 |
-
public function get_lockouts( $type = 'all', $
|
548 |
|
549 |
-
global $wpdb
|
550 |
|
551 |
-
if (
|
552 |
-
$
|
553 |
-
} else {
|
554 |
-
$where = '';
|
555 |
}
|
556 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
557 |
switch ( $type ) {
|
558 |
|
559 |
case 'host':
|
560 |
-
$
|
561 |
break;
|
562 |
case 'user':
|
563 |
-
$
|
564 |
break;
|
565 |
case 'username':
|
566 |
-
$
|
567 |
-
break;
|
568 |
-
default:
|
569 |
-
$type_statement = '';
|
570 |
break;
|
571 |
-
|
572 |
}
|
573 |
|
574 |
-
if ( $current
|
575 |
-
|
576 |
-
|
577 |
-
$and = ' AND ';
|
578 |
-
} else {
|
579 |
-
$and = '';
|
580 |
-
}
|
581 |
-
|
582 |
-
$active = $and . " `lockout_active`=1 AND `lockout_expire_gmt` > '" . date( 'Y-m-d H:i:s', $itsec_globals['current_time_gmt'] ) . "'";
|
583 |
-
|
584 |
-
} else {
|
585 |
|
586 |
-
|
|
|
|
|
587 |
|
|
|
588 |
}
|
589 |
|
590 |
-
if (
|
|
|
|
|
591 |
|
592 |
-
|
|
|
|
|
593 |
|
|
|
|
|
|
|
594 |
} else {
|
|
|
|
|
|
|
595 |
|
596 |
-
|
597 |
|
|
|
|
|
598 |
}
|
599 |
|
600 |
-
return $
|
601 |
-
|
602 |
}
|
603 |
|
604 |
/**
|
@@ -774,8 +799,8 @@ final class ITSEC_Lockout {
|
|
774 |
|
775 |
$host_count = 1 + $wpdb->get_var(
|
776 |
$wpdb->prepare(
|
777 |
-
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_lockouts` WHERE `lockout_expire_gmt` >
|
778 |
-
date( 'Y-m-d H:i:s',
|
779 |
$host
|
780 |
)
|
781 |
);
|
@@ -892,9 +917,7 @@ final class ITSEC_Lockout {
|
|
892 |
|
893 |
if ( $whitelisted === false ) {
|
894 |
|
895 |
-
|
896 |
-
$this->send_lockout_email( $good_host, $good_user, $good_username, $host_expiration, $user_expiration, $reason );
|
897 |
-
}
|
898 |
|
899 |
$lock_context = array(
|
900 |
'type' => $type,
|
@@ -966,10 +989,10 @@ final class ITSEC_Lockout {
|
|
966 |
*/
|
967 |
public function purge_lockouts() {
|
968 |
|
969 |
-
global $wpdb
|
970 |
|
971 |
-
$wpdb->query( "DELETE FROM `" . $wpdb->base_prefix . "itsec_lockouts` WHERE `lockout_expire_gmt` < '" . date( 'Y-m-d H:i:s',
|
972 |
-
$wpdb->query( "DELETE FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` < '" . date( 'Y-m-d H:i:s',
|
973 |
|
974 |
}
|
975 |
|
@@ -1057,9 +1080,7 @@ final class ITSEC_Lockout {
|
|
1057 |
|
1058 |
if ( $id !== null && trim( $id ) !== '' ) {
|
1059 |
|
1060 |
-
$
|
1061 |
-
|
1062 |
-
$lockout = $wpdb->get_results( "SELECT * FROM `" . $wpdb->base_prefix . "itsec_lockouts` WHERE lockout_id = " . $sanitized_id . ";", ARRAY_A );
|
1063 |
|
1064 |
if ( is_array( $lockout ) && sizeof( $lockout ) >= 1 ) {
|
1065 |
|
@@ -1069,7 +1090,7 @@ final class ITSEC_Lockout {
|
|
1069 |
'lockout_active' => 0,
|
1070 |
),
|
1071 |
array(
|
1072 |
-
'lockout_id' => $
|
1073 |
)
|
1074 |
);
|
1075 |
|
@@ -1100,7 +1121,7 @@ final class ITSEC_Lockout {
|
|
1100 |
'lockout_active' => 0,
|
1101 |
),
|
1102 |
array(
|
1103 |
-
'lockout_id' =>
|
1104 |
)
|
1105 |
);
|
1106 |
|
@@ -1128,6 +1149,37 @@ final class ITSEC_Lockout {
|
|
1128 |
|
1129 |
}
|
1130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1131 |
/**
|
1132 |
* Sends an email to notify site admins of lockouts
|
1133 |
*
|
@@ -1143,17 +1195,13 @@ final class ITSEC_Lockout {
|
|
1143 |
* @return void
|
1144 |
*/
|
1145 |
private function send_lockout_email( $host, $user_id, $username, $host_expiration, $user_expiration, $reason ) {
|
1146 |
-
if ( ITSEC_Modules::get_setting( 'global', 'digest_email' ) ) {
|
1147 |
-
// The daily digest will show the relevant lockout details.
|
1148 |
-
return;
|
1149 |
-
}
|
1150 |
|
1151 |
-
|
1152 |
-
|
|
|
1153 |
return;
|
1154 |
}
|
1155 |
|
1156 |
-
|
1157 |
$lockouts = array();
|
1158 |
$show_remove_ip_ban_message = false;
|
1159 |
$show_remove_lockout_message = false;
|
@@ -1191,30 +1239,29 @@ final class ITSEC_Lockout {
|
|
1191 |
}
|
1192 |
|
1193 |
|
1194 |
-
|
1195 |
-
$mail = new ITSEC_Mail();
|
1196 |
|
1197 |
$mail->add_header( esc_html__( 'Site Lockout Notification', 'better-wp-security' ), esc_html__( 'Site Lockout Notification', 'better-wp-security' ) );
|
1198 |
$mail->add_lockouts_table( $lockouts );
|
1199 |
|
1200 |
if ( $show_remove_lockout_message ) {
|
1201 |
$mail->add_text( __( 'Release lockouts from the Active Lockouts section of the settings page.', 'better-wp-security' ) );
|
1202 |
-
$mail->add_button( __( 'Visit Settings Page', 'better-wp-security' ),
|
1203 |
}
|
1204 |
|
1205 |
if ( $show_remove_ip_ban_message ) {
|
1206 |
$mail->add_text( __( 'Release the permanent host ban from Ban Hosts list in the Banned Users section of the settings page.', 'better-wp-security' ) );
|
1207 |
-
$mail->add_button( __( 'Visit Banned Users Settings', 'better-wp-security' ),
|
1208 |
}
|
1209 |
|
1210 |
$mail->add_footer();
|
1211 |
|
1212 |
|
1213 |
-
$subject =
|
1214 |
$subject = apply_filters( 'itsec_lockout_email_subject', $subject );
|
1215 |
$mail->set_subject( $subject, false );
|
1216 |
|
1217 |
-
$
|
1218 |
}
|
1219 |
|
1220 |
/**
|
104 |
|
105 |
add_action( 'itsec-settings-page-init', array( $this, 'init_settings_page' ) );
|
106 |
add_action( 'itsec-logs-page-init', array( $this, 'init_settings_page' ) );
|
107 |
+
|
108 |
+
add_filter( 'itsec_notifications', array( $this, 'register_notification' ) );
|
109 |
+
add_filter( 'itsec_lockout_notification_strings', array( $this, 'notification_strings' ) );
|
110 |
}
|
111 |
|
112 |
public function init_settings_page() {
|
186 |
$user_id = $user->ID;
|
187 |
|
188 |
if ( $username !== false && $username != '' ) {
|
189 |
+
$username_check = $wpdb->get_results( $wpdb->prepare(
|
190 |
+
"SELECT `lockout_username`, `lockout_type` FROM `{$wpdb->base_prefix}itsec_lockouts` WHERE `lockout_active`=1 AND `lockout_expire_gmt` > %s AND `lockout_username`= %s;",
|
191 |
+
date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() ), $username
|
192 |
+
) );
|
193 |
}
|
194 |
|
195 |
+
$host_check = $wpdb->get_results( $wpdb->prepare(
|
196 |
+
"SELECT `lockout_host`, `lockout_type` FROM `{$wpdb->base_prefix}itsec_lockouts` WHERE `lockout_active`=1 AND `lockout_expire_gmt` > %s AND `lockout_host`= %s;",
|
197 |
+
date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() ), $host
|
198 |
+
) );
|
199 |
|
200 |
}
|
201 |
|
202 |
if ( $user_id !== 0 && $user_id !== null ) {
|
203 |
|
204 |
+
$user_check = $wpdb->get_results( $wpdb->prepare(
|
205 |
+
"SELECT `lockout_user`, `lockout_type` FROM `{$wpdb->base_prefix}itsec_lockouts` WHERE `lockout_active`=1 AND `lockout_expire_gmt` > %s AND `lockout_user`= %d;",
|
206 |
+
date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() ), $user_id
|
207 |
+
) );
|
208 |
}
|
209 |
|
210 |
$error = $wpdb->last_error;
|
317 |
|
318 |
$host_count = $wpdb->get_var(
|
319 |
$wpdb->prepare(
|
320 |
+
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` > %s AND `temp_host`= %s;",
|
321 |
+
date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() - ( $options['period'] * 60 ) ),
|
322 |
$host
|
323 |
)
|
324 |
);
|
350 |
|
351 |
$user_count = $wpdb->get_var(
|
352 |
$wpdb->prepare(
|
353 |
+
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` > '%s' AND (`temp_username`= %s OR `temp_user`= %d);",
|
354 |
+
date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() - ( $options['period'] * 60 ) ),
|
355 |
sanitize_text_field( $username ),
|
356 |
intval( $user_id )
|
357 |
)
|
379 |
|
380 |
$user_count = $wpdb->get_var(
|
381 |
$wpdb->prepare(
|
382 |
+
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` > %s AND `temp_username`= %s;",
|
383 |
+
date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() - ( $options['period'] * 60 ) ),
|
384 |
$username
|
385 |
)
|
386 |
);
|
550 |
* @since 4.0
|
551 |
*
|
552 |
* @param string $type 'all', 'host', or 'user'
|
553 |
+
* @param array $args Additional arguments.
|
|
|
554 |
*
|
555 |
* @return array all lockouts in the system
|
556 |
*/
|
557 |
+
public function get_lockouts( $type = 'all', $args = array() ) {
|
558 |
|
559 |
+
global $wpdb;
|
560 |
|
561 |
+
if ( is_bool( $args ) ) {
|
562 |
+
$args = array( 'current' => $args );
|
|
|
|
|
563 |
}
|
564 |
|
565 |
+
if ( func_num_args() === 3 ) {
|
566 |
+
$third = func_get_arg( 2 );
|
567 |
+
|
568 |
+
if ( $third && is_numeric( $third ) ) {
|
569 |
+
$args['limit'] = $third;
|
570 |
+
}
|
571 |
+
}
|
572 |
+
|
573 |
+
$args = wp_parse_args( $args, array(
|
574 |
+
'current' => true,
|
575 |
+
) );
|
576 |
+
|
577 |
+
$where = $limit = '';
|
578 |
+
$wheres = array();
|
579 |
+
|
580 |
switch ( $type ) {
|
581 |
|
582 |
case 'host':
|
583 |
+
$wheres[] = "`lockout_host` IS NOT NULL AND `lockout_host` != ''";
|
584 |
break;
|
585 |
case 'user':
|
586 |
+
$wheres[] = '`lockout_user` != 0';
|
587 |
break;
|
588 |
case 'username':
|
589 |
+
$wheres[] = "`lockout_username` IS NOT NULL AND `lockout_username` != ''";
|
|
|
|
|
|
|
590 |
break;
|
|
|
591 |
}
|
592 |
|
593 |
+
if ( $args['current'] ) {
|
594 |
+
$wheres[] = "`lockout_active` = 1 AND `lockout_expire_gmt` > '" . date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() ) . "'";
|
595 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
596 |
|
597 |
+
if ( isset( $args['after'] ) ) {
|
598 |
+
$after = is_int( $args['after'] ) ? $args['after'] : strtotime( $args['after'] );
|
599 |
+
$after = date( 'Y-m-d H:i:s', $after );
|
600 |
|
601 |
+
$wheres[] = "`lockout_start_gmt` > '{$after}'";
|
602 |
}
|
603 |
|
604 |
+
if ( $wheres ) {
|
605 |
+
$where = ' WHERE ' . implode( ' AND ', $wheres );
|
606 |
+
}
|
607 |
|
608 |
+
if ( ! empty( $args['limit'] ) ) {
|
609 |
+
$limit = ' LIMIT ' . absint( $args['limit'] );
|
610 |
+
}
|
611 |
|
612 |
+
if ( isset( $args['return'] ) && 'count' === $args['return'] ) {
|
613 |
+
$select = 'SELECT COUNT(1) as COUNT';
|
614 |
+
$is_count = true;
|
615 |
} else {
|
616 |
+
$select = 'SELECT *';
|
617 |
+
$is_count = false;
|
618 |
+
}
|
619 |
|
620 |
+
$results = $wpdb->get_results( "{$select} FROM `" . $wpdb->base_prefix . "itsec_lockouts`" . $where . $limit . ';', ARRAY_A );
|
621 |
|
622 |
+
if ( $is_count && $results ) {
|
623 |
+
return $results[0]['COUNT'];
|
624 |
}
|
625 |
|
626 |
+
return $results;
|
|
|
627 |
}
|
628 |
|
629 |
/**
|
799 |
|
800 |
$host_count = 1 + $wpdb->get_var(
|
801 |
$wpdb->prepare(
|
802 |
+
"SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_lockouts` WHERE `lockout_expire_gmt` > %s AND `lockout_host`= %s;",
|
803 |
+
date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() - $blacklist_seconds ),
|
804 |
$host
|
805 |
)
|
806 |
);
|
917 |
|
918 |
if ( $whitelisted === false ) {
|
919 |
|
920 |
+
$this->send_lockout_email( $good_host, $good_user, $good_username, $host_expiration, $user_expiration, $reason );
|
|
|
|
|
921 |
|
922 |
$lock_context = array(
|
923 |
'type' => $type,
|
989 |
*/
|
990 |
public function purge_lockouts() {
|
991 |
|
992 |
+
global $wpdb;
|
993 |
|
994 |
+
$wpdb->query( "DELETE FROM `" . $wpdb->base_prefix . "itsec_lockouts` WHERE `lockout_expire_gmt` < '" . date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() - ( ( ITSEC_Modules::get_setting( 'global', 'blacklist_period' ) + 1 ) * DAY_IN_SECONDS ) ) . "';" );
|
995 |
+
$wpdb->query( "DELETE FROM `" . $wpdb->base_prefix . "itsec_temp` WHERE `temp_date_gmt` < '" . date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() - DAY_IN_SECONDS ) . "';" );
|
996 |
|
997 |
}
|
998 |
|
1080 |
|
1081 |
if ( $id !== null && trim( $id ) !== '' ) {
|
1082 |
|
1083 |
+
$lockout = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$wpdb->base_prefix}itsec_lockouts` WHERE lockout_id = %d;", $id ), ARRAY_A );
|
|
|
|
|
1084 |
|
1085 |
if ( is_array( $lockout ) && sizeof( $lockout ) >= 1 ) {
|
1086 |
|
1090 |
'lockout_active' => 0,
|
1091 |
),
|
1092 |
array(
|
1093 |
+
'lockout_id' => (int) $id,
|
1094 |
)
|
1095 |
);
|
1096 |
|
1121 |
'lockout_active' => 0,
|
1122 |
),
|
1123 |
array(
|
1124 |
+
'lockout_id' => (int) $value,
|
1125 |
)
|
1126 |
);
|
1127 |
|
1149 |
|
1150 |
}
|
1151 |
|
1152 |
+
/**
|
1153 |
+
* Register the lockout notification.
|
1154 |
+
*
|
1155 |
+
* @param array $notifications
|
1156 |
+
*
|
1157 |
+
* @return array
|
1158 |
+
*/
|
1159 |
+
public function register_notification( $notifications ) {
|
1160 |
+
$notifications['lockout'] = array(
|
1161 |
+
'subject_editable' => true,
|
1162 |
+
'recipient' => ITSEC_Notification_Center::R_USER_LIST_ADMIN_UPGRADE,
|
1163 |
+
'schedule' => ITSEC_Notification_Center::S_NONE,
|
1164 |
+
'optional' => true,
|
1165 |
+
);
|
1166 |
+
|
1167 |
+
return $notifications;
|
1168 |
+
}
|
1169 |
+
|
1170 |
+
/**
|
1171 |
+
* Get the strings for the lockout notification.
|
1172 |
+
*
|
1173 |
+
* @return array
|
1174 |
+
*/
|
1175 |
+
public function notification_strings() {
|
1176 |
+
return array(
|
1177 |
+
'label' => esc_html__( 'Site Lockouts', 'better-wp-security' ),
|
1178 |
+
'description' => esc_html__( 'Various modules send emails to notify you when a user or host is locked out of your website.', 'better-wp-security' ),
|
1179 |
+
'subject' => esc_html__( 'Site Lockout Notification', 'better-wp-security' ),
|
1180 |
+
);
|
1181 |
+
}
|
1182 |
+
|
1183 |
/**
|
1184 |
* Sends an email to notify site admins of lockouts
|
1185 |
*
|
1195 |
* @return void
|
1196 |
*/
|
1197 |
private function send_lockout_email( $host, $user_id, $username, $host_expiration, $user_expiration, $reason ) {
|
|
|
|
|
|
|
|
|
1198 |
|
1199 |
+
$nc = ITSEC_Core::get_notification_center();
|
1200 |
+
|
1201 |
+
if ( ! $nc->is_notification_enabled( 'lockout' ) ) {
|
1202 |
return;
|
1203 |
}
|
1204 |
|
|
|
1205 |
$lockouts = array();
|
1206 |
$show_remove_ip_ban_message = false;
|
1207 |
$show_remove_lockout_message = false;
|
1239 |
}
|
1240 |
|
1241 |
|
1242 |
+
$mail = $nc->mail();
|
|
|
1243 |
|
1244 |
$mail->add_header( esc_html__( 'Site Lockout Notification', 'better-wp-security' ), esc_html__( 'Site Lockout Notification', 'better-wp-security' ) );
|
1245 |
$mail->add_lockouts_table( $lockouts );
|
1246 |
|
1247 |
if ( $show_remove_lockout_message ) {
|
1248 |
$mail->add_text( __( 'Release lockouts from the Active Lockouts section of the settings page.', 'better-wp-security' ) );
|
1249 |
+
$mail->add_button( __( 'Visit Settings Page', 'better-wp-security' ), ITSEC_Mail::filter_admin_page_url( ITSEC_Core::get_settings_page_url() ) );
|
1250 |
}
|
1251 |
|
1252 |
if ( $show_remove_ip_ban_message ) {
|
1253 |
$mail->add_text( __( 'Release the permanent host ban from Ban Hosts list in the Banned Users section of the settings page.', 'better-wp-security' ) );
|
1254 |
+
$mail->add_button( __( 'Visit Banned Users Settings', 'better-wp-security' ), ITSEC_Mail::filter_admin_page_url( ITSEC_Core::get_settings_module_url( 'ban-users' ) ) );
|
1255 |
}
|
1256 |
|
1257 |
$mail->add_footer();
|
1258 |
|
1259 |
|
1260 |
+
$subject = $mail->prepend_site_url_to_subject( $nc->get_subject( 'lockout' ) );
|
1261 |
$subject = apply_filters( 'itsec_lockout_email_subject', $subject );
|
1262 |
$mail->set_subject( $subject, false );
|
1263 |
|
1264 |
+
$nc->send( 'lockout', $mail );
|
1265 |
}
|
1266 |
|
1267 |
/**
|
core/logger.php
CHANGED
@@ -11,8 +11,7 @@ final class ITSEC_Logger {
|
|
11 |
private
|
12 |
$log_file,
|
13 |
$logger_displays,
|
14 |
-
$logger_modules
|
15 |
-
$module_path;
|
16 |
|
17 |
/**
|
18 |
* @access private
|
@@ -25,7 +24,6 @@ final class ITSEC_Logger {
|
|
25 |
|
26 |
$this->logger_modules = array(); //array to hold information on modules using this feature
|
27 |
$this->logger_displays = array(); //array to hold metabox information
|
28 |
-
$this->module_path = ITSEC_Lib::get_module_path( __FILE__ );
|
29 |
|
30 |
add_action( 'plugins_loaded', array( $this, 'register_modules' ) );
|
31 |
add_action( 'plugins_loaded', array( $this, 'write_pending_events_to_file' ) );
|
11 |
private
|
12 |
$log_file,
|
13 |
$logger_displays,
|
14 |
+
$logger_modules;
|
|
|
15 |
|
16 |
/**
|
17 |
* @access private
|
24 |
|
25 |
$this->logger_modules = array(); //array to hold information on modules using this feature
|
26 |
$this->logger_displays = array(); //array to hold metabox information
|
|
|
27 |
|
28 |
add_action( 'plugins_loaded', array( $this, 'register_modules' ) );
|
29 |
add_action( 'plugins_loaded', array( $this, 'write_pending_events_to_file' ) );
|
core/modules/404-detection/settings-page.php
CHANGED
@@ -19,9 +19,11 @@ final class ITSEC_404_Detection_Settings_Page extends ITSEC_Module_Settings_Page
|
|
19 |
}
|
20 |
|
21 |
protected function render_settings( $form ) {
|
22 |
-
|
|
|
|
|
23 |
?>
|
24 |
-
<?php echo $
|
25 |
<table class="form-table">
|
26 |
<tr>
|
27 |
<th scope="row"><label for="itsec-404-detection-check_period"><?php _e( 'Minutes to Remember 404 Error (Check Period)', 'better-wp-security' ); ?></label></th>
|
19 |
}
|
20 |
|
21 |
protected function render_settings( $form ) {
|
22 |
+
|
23 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
24 |
+
global $itsec_lockout;
|
25 |
?>
|
26 |
+
<?php echo $itsec_lockout->get_lockout_description(); ?>
|
27 |
<table class="form-table">
|
28 |
<tr>
|
29 |
<th scope="row"><label for="itsec-404-detection-check_period"><?php _e( 'Minutes to Remember 404 Error (Check Period)', 'better-wp-security' ); ?></label></th>
|
core/modules/admin-user/validator.php
CHANGED
@@ -83,13 +83,14 @@ final class ITSEC_Admin_User_Validator extends ITSEC_Validator {
|
|
83 |
} else { // we're only changing the username
|
84 |
|
85 |
//query main user table
|
86 |
-
$wpdb->query( "UPDATE `
|
87 |
|
88 |
if ( is_multisite() ) { //process sitemeta if we're in a multi-site situation
|
89 |
|
90 |
-
$
|
91 |
-
|
92 |
-
$
|
|
|
93 |
|
94 |
}
|
95 |
|
@@ -124,18 +125,19 @@ final class ITSEC_Admin_User_Validator extends ITSEC_Validator {
|
|
124 |
|
125 |
if ( is_multisite() && $username !== null && validate_username( $new_user ) ) { //process sitemeta if we're in a multi-site situation
|
126 |
|
127 |
-
$
|
128 |
-
|
129 |
-
$
|
|
|
130 |
|
131 |
}
|
132 |
|
133 |
$new_user = $wpdb->insert_id;
|
134 |
|
135 |
-
$wpdb->query( "UPDATE
|
136 |
-
$wpdb->query( "UPDATE
|
137 |
-
$wpdb->query( "UPDATE
|
138 |
-
$wpdb->query( "UPDATE
|
139 |
|
140 |
/**
|
141 |
* Fires when the admin user with id of #1 has been changed.
|
83 |
} else { // we're only changing the username
|
84 |
|
85 |
//query main user table
|
86 |
+
$wpdb->query( $wpdb->prepare( "UPDATE `{$wpdb->users}` SET user_login = %s WHERE user_login = %s", $new_user, 'admin' ) );
|
87 |
|
88 |
if ( is_multisite() ) { //process sitemeta if we're in a multi-site situation
|
89 |
|
90 |
+
$old_admins = $wpdb->get_var( "SELECT meta_value FROM `" . $wpdb->sitemeta . "` WHERE meta_key = 'site_admins'" );
|
91 |
+
// No need to escape the new username. It is already safe via validate_userame() which will check for quotes
|
92 |
+
$new_admins = str_replace( '5:"admin"', strlen( $new_user ) . ':"' . $new_user . '"', $old_admins );
|
93 |
+
$wpdb->query( $wpdb->prepare( "UPDATE `{$wpdb->sitemeta}` SET meta_value = %s WHERE meta_key = 'site_admins'", $new_admins ) );
|
94 |
|
95 |
}
|
96 |
|
125 |
|
126 |
if ( is_multisite() && $username !== null && validate_username( $new_user ) ) { //process sitemeta if we're in a multi-site situation
|
127 |
|
128 |
+
$old_admins = $wpdb->get_var( "SELECT meta_value FROM `{$wpdb->sitemeta}` WHERE meta_key = 'site_admins'" );
|
129 |
+
// No need to escape the new username. It is already safe via validate_userame() which will check for quotes
|
130 |
+
$new_admins = str_replace( '5:"admin"', strlen( $new_user ) . ':"' . $new_user . '"', $old_admins );
|
131 |
+
$wpdb->query( $wpdb->prepare( "UPDATE `{$wpdb->sitemeta}` SET meta_value = %s WHERE meta_key = 'site_admins'", $new_admins ) );
|
132 |
|
133 |
}
|
134 |
|
135 |
$new_user = $wpdb->insert_id;
|
136 |
|
137 |
+
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_author = %d WHERE post_author = 1", $new_user ) );
|
138 |
+
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->usermeta} SET user_id = %d WHERE user_id = 1", $new_user ) );
|
139 |
+
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->comments} SET user_id = %d WHERE user_id = 1", $new_user ) );
|
140 |
+
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->links} SET link_owner = %d WHERE link_owner = 1", $new_user ) );
|
141 |
|
142 |
/**
|
143 |
* Fires when the admin user with id of #1 has been changed.
|
core/modules/backup/class-itsec-backup.php
CHANGED
@@ -37,6 +37,9 @@ class ITSEC_Backup {
|
|
37 |
add_action( 'itsec_execute_backup_cron', array( $this, 'do_backup' ) );
|
38 |
add_filter( 'itsec_logger_modules', array( $this, 'register_logger' ) );
|
39 |
|
|
|
|
|
|
|
40 |
if ( defined( 'ITSEC_BACKUP_CRON' ) && true === ITSEC_BACKUP_CRON ) {
|
41 |
if ( ! wp_next_scheduled( 'itsec_execute_backup_cron' ) ) {
|
42 |
wp_schedule_event( time(), 'daily', 'itsec_execute_backup_cron' );
|
@@ -145,7 +148,7 @@ class ITSEC_Backup {
|
|
145 |
if ( $this->settings['all_sites'] ) {
|
146 |
$tables = $wpdb->get_col( 'SHOW TABLES' );
|
147 |
} else {
|
148 |
-
$tables = $wpdb->get_col( 'SHOW TABLES LIKE
|
149 |
}
|
150 |
|
151 |
$max_rows_per_query = 1000;
|
@@ -168,7 +171,7 @@ class ITSEC_Backup {
|
|
168 |
$has_more_rows = true;
|
169 |
|
170 |
while ( $has_more_rows ) {
|
171 |
-
$rows = $wpdb->get_results( "SELECT * FROM `$table` LIMIT $offset, $max_rows_per_query
|
172 |
|
173 |
foreach ( $rows as $row ) {
|
174 |
$sql = "INSERT INTO `$table` VALUES (";
|
@@ -276,15 +279,16 @@ class ITSEC_Backup {
|
|
276 |
}
|
277 |
|
278 |
private function send_mail( $file ) {
|
279 |
-
require_once( ITSEC_Core::get_core_dir() . 'lib/class-itsec-mail.php' );
|
280 |
|
281 |
-
$
|
282 |
-
$mail
|
|
|
|
|
283 |
$mail->add_info_box( esc_html__( 'Attached is the database backup file for your site.', 'better-wp-security' ), 'attachment' );
|
284 |
|
285 |
|
286 |
$mail->add_section_heading( esc_html__( 'Website', 'better-wp-security' ) );
|
287 |
-
$mail->add_text(
|
288 |
|
289 |
$mail->add_section_heading( esc_html__( 'Date', 'better-wp-security' ) );
|
290 |
$mail->add_text( esc_html( date_i18n( get_option( 'date_format' ) ) ) );
|
@@ -292,16 +296,15 @@ class ITSEC_Backup {
|
|
292 |
$mail->add_footer();
|
293 |
|
294 |
|
295 |
-
$
|
296 |
-
$mail->set_recipients( $recipients );
|
297 |
|
298 |
-
$subject =
|
299 |
$subject = apply_filters( 'itsec_backup_email_subject', $subject );
|
300 |
$mail->set_subject( $subject, false );
|
301 |
|
302 |
$mail->add_attachment( $file );
|
303 |
|
304 |
-
return $
|
305 |
}
|
306 |
|
307 |
/**
|
@@ -326,4 +329,40 @@ class ITSEC_Backup {
|
|
326 |
|
327 |
}
|
328 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
329 |
}
|
37 |
add_action( 'itsec_execute_backup_cron', array( $this, 'do_backup' ) );
|
38 |
add_filter( 'itsec_logger_modules', array( $this, 'register_logger' ) );
|
39 |
|
40 |
+
add_filter( 'itsec_notifications', array( $this, 'register_notification' ) );
|
41 |
+
add_filter( 'itsec_backup_notification_strings', array( $this, 'notification_strings' ) );
|
42 |
+
|
43 |
if ( defined( 'ITSEC_BACKUP_CRON' ) && true === ITSEC_BACKUP_CRON ) {
|
44 |
if ( ! wp_next_scheduled( 'itsec_execute_backup_cron' ) ) {
|
45 |
wp_schedule_event( time(), 'daily', 'itsec_execute_backup_cron' );
|
148 |
if ( $this->settings['all_sites'] ) {
|
149 |
$tables = $wpdb->get_col( 'SHOW TABLES' );
|
150 |
} else {
|
151 |
+
$tables = $wpdb->get_col( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->base_prefix . '%' ) );
|
152 |
}
|
153 |
|
154 |
$max_rows_per_query = 1000;
|
171 |
$has_more_rows = true;
|
172 |
|
173 |
while ( $has_more_rows ) {
|
174 |
+
$rows = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `$table` LIMIT %d, %d", $offset, $max_rows_per_query ), ARRAY_N );
|
175 |
|
176 |
foreach ( $rows as $row ) {
|
177 |
$sql = "INSERT INTO `$table` VALUES (";
|
279 |
}
|
280 |
|
281 |
private function send_mail( $file ) {
|
|
|
282 |
|
283 |
+
$nc = ITSEC_Core::get_notification_center();
|
284 |
+
$mail = $nc->mail();
|
285 |
+
|
286 |
+
$mail->add_header( esc_html__( 'Database Backup', 'better-wp-security' ), sprintf( esc_html__( 'Site Database Backup for %s', 'better-wp-security' ), '<b>' . date_i18n( get_option( 'date_format' ) ) . '</b>' ) );
|
287 |
$mail->add_info_box( esc_html__( 'Attached is the database backup file for your site.', 'better-wp-security' ), 'attachment' );
|
288 |
|
289 |
|
290 |
$mail->add_section_heading( esc_html__( 'Website', 'better-wp-security' ) );
|
291 |
+
$mail->add_text( $mail->get_display_url() );
|
292 |
|
293 |
$mail->add_section_heading( esc_html__( 'Date', 'better-wp-security' ) );
|
294 |
$mail->add_text( esc_html( date_i18n( get_option( 'date_format' ) ) ) );
|
296 |
$mail->add_footer();
|
297 |
|
298 |
|
299 |
+
$mail->set_recipients( $nc->get_recipients( 'backup' ) );
|
|
|
300 |
|
301 |
+
$subject = $mail->prepend_site_url_to_subject( $nc->get_subject( 'backup' ) );
|
302 |
$subject = apply_filters( 'itsec_backup_email_subject', $subject );
|
303 |
$mail->set_subject( $subject, false );
|
304 |
|
305 |
$mail->add_attachment( $file );
|
306 |
|
307 |
+
return $nc->send( 'backup', $mail );
|
308 |
}
|
309 |
|
310 |
/**
|
329 |
|
330 |
}
|
331 |
|
332 |
+
/**
|
333 |
+
* Register the Backup notification email.
|
334 |
+
*
|
335 |
+
* @param array $notifications
|
336 |
+
*
|
337 |
+
* @return array
|
338 |
+
*/
|
339 |
+
public function register_notification( $notifications ) {
|
340 |
+
|
341 |
+
$method = ITSEC_Modules::get_setting( 'backup', 'method' );
|
342 |
+
|
343 |
+
if ( 0 === $method || 1 === $method ) {
|
344 |
+
$notifications['backup'] = array(
|
345 |
+
'subject_editable' => true,
|
346 |
+
'recipient' => ITSEC_Notification_Center::R_EMAIL_LIST,
|
347 |
+
'schedule' => ITSEC_Notification_Center::S_NONE,
|
348 |
+
'module' => 'backup',
|
349 |
+
);
|
350 |
+
}
|
351 |
+
|
352 |
+
return $notifications;
|
353 |
+
}
|
354 |
+
|
355 |
+
/**
|
356 |
+
* Register the strings for the Backup email.
|
357 |
+
*
|
358 |
+
* @return array
|
359 |
+
*/
|
360 |
+
public function notification_strings() {
|
361 |
+
return array(
|
362 |
+
'label' => esc_html__( 'Database Backup', 'better-wp-security' ),
|
363 |
+
'description' => sprintf( esc_html__( 'The %1$sDatabase Backup%2$s module will send a copy of any backups to the email addresses listed below.', 'better-wp-security' ), '<a href="#" data-module-link="backup">', '</a>' ),
|
364 |
+
'subject' => esc_html__( 'Database Backup', 'better-wp-security' ),
|
365 |
+
);
|
366 |
+
}
|
367 |
+
|
368 |
}
|
core/modules/brute-force/settings-page.php
CHANGED
@@ -19,9 +19,12 @@ final class ITSEC_Brute_Force_Settings_Page extends ITSEC_Module_Settings_Page {
|
|
19 |
}
|
20 |
|
21 |
protected function render_settings( $form ) {
|
|
|
|
|
|
|
22 |
|
23 |
?>
|
24 |
-
<?php echo $
|
25 |
<table class="form-table" id="brute_force-settings">
|
26 |
<tr>
|
27 |
<th scope="row"><label for="itsec-brute-force-max_attempts_host"><?php _e( 'Max Login Attempts Per Host', 'better-wp-security' ); ?></label></th>
|
19 |
}
|
20 |
|
21 |
protected function render_settings( $form ) {
|
22 |
+
|
23 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
24 |
+
global $itsec_lockout;
|
25 |
|
26 |
?>
|
27 |
+
<?php echo $itsec_lockout->get_lockout_description(); ?>
|
28 |
<table class="form-table" id="brute_force-settings">
|
29 |
<tr>
|
30 |
<th scope="row"><label for="itsec-brute-force-max_attempts_host"><?php _e( 'Max Login Attempts Per Host', 'better-wp-security' ); ?></label></th>
|
core/modules/core/setup.php
CHANGED
@@ -53,6 +53,14 @@ if ( ! class_exists( 'ITSEC_Core_Setup' ) ) {
|
|
53 |
if ( $build < 4069 ) {
|
54 |
delete_site_option( 'itsec_free_just_activated' );
|
55 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
}
|
57 |
|
58 |
}
|
53 |
if ( $build < 4069 ) {
|
54 |
delete_site_option( 'itsec_free_just_activated' );
|
55 |
}
|
56 |
+
|
57 |
+
if ( $build < 4076 ) {
|
58 |
+
$digest = wp_next_scheduled( 'itsec_digest_email' );
|
59 |
+
|
60 |
+
if ( $digest ) {
|
61 |
+
wp_unschedule_event( $digest, 'itsec_digest_email' );
|
62 |
+
}
|
63 |
+
}
|
64 |
}
|
65 |
|
66 |
}
|
core/modules/database-prefix/utility.php
CHANGED
@@ -39,9 +39,7 @@ final class ITSEC_Database_Prefix_Utility {
|
|
39 |
//complete with underscore
|
40 |
$new_prefix .= '_';
|
41 |
|
42 |
-
$
|
43 |
-
|
44 |
-
$check_prefix = $wpdb->get_results( 'SHOW TABLES LIKE "' . $new_prefix . '%";', ARRAY_N ); //if there are no tables with that prefix in the database set checkPrefix to false
|
45 |
|
46 |
}
|
47 |
|
@@ -72,7 +70,7 @@ final class ITSEC_Database_Prefix_Utility {
|
|
72 |
|
73 |
|
74 |
|
75 |
-
$tables = $wpdb->get_results( 'SHOW TABLES LIKE
|
76 |
|
77 |
//Rename each table
|
78 |
foreach ( $tables as $table ) {
|
@@ -113,7 +111,7 @@ final class ITSEC_Database_Prefix_Utility {
|
|
113 |
|
114 |
}
|
115 |
|
116 |
-
$rows = $wpdb->get_results(
|
117 |
|
118 |
//update all prefixes in usermeta
|
119 |
foreach ( $rows as $row ) {
|
@@ -122,7 +120,7 @@ final class ITSEC_Database_Prefix_Utility {
|
|
122 |
|
123 |
$pos = $new_prefix . substr( $row->meta_key, strlen( $wpdb->base_prefix ), strlen( $row->meta_key ) );
|
124 |
|
125 |
-
$result = $wpdb->query(
|
126 |
|
127 |
if ( $result == false ) {
|
128 |
|
39 |
//complete with underscore
|
40 |
$new_prefix .= '_';
|
41 |
|
42 |
+
$check_prefix = $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s;', $new_prefix . '%' ), ARRAY_N ); //if there are no tables with that prefix in the database set checkPrefix to false
|
|
|
|
|
43 |
|
44 |
}
|
45 |
|
70 |
|
71 |
|
72 |
|
73 |
+
$tables = $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->base_prefix . '%' ), ARRAY_N ); //retrieve a list of all tables in the DB
|
74 |
|
75 |
//Rename each table
|
76 |
foreach ( $tables as $table ) {
|
111 |
|
112 |
}
|
113 |
|
114 |
+
$rows = $wpdb->get_results( "SELECT * FROM `{$new_prefix}usermeta`" ); //get all rows in usermeta
|
115 |
|
116 |
//update all prefixes in usermeta
|
117 |
foreach ( $rows as $row ) {
|
120 |
|
121 |
$pos = $new_prefix . substr( $row->meta_key, strlen( $wpdb->base_prefix ), strlen( $row->meta_key ) );
|
122 |
|
123 |
+
$result = $wpdb->query( $wpdb->prepare( "UPDATE `{$new_prefix}usermeta` SET meta_key = %s WHERE meta_key = %s LIMIT 1", $pos, $row->meta_key ) );
|
124 |
|
125 |
if ( $result == false ) {
|
126 |
|
core/modules/file-change/class-itsec-file-change.php
CHANGED
@@ -37,6 +37,8 @@ class ITSEC_File_Change {
|
|
37 |
add_filter( 'itsec_logger_displays', array( $this, 'itsec_logger_displays' ) ); //adds logs metaboxes
|
38 |
add_filter( 'itsec_logger_modules', array( $this, 'itsec_logger_modules' ) );
|
39 |
add_action( 'ithemes_sync_register_verbs', array( $this, 'register_sync_verbs' ) );
|
|
|
|
|
40 |
|
41 |
|
42 |
if (
|
@@ -169,4 +171,36 @@ class ITSEC_File_Change {
|
|
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' );
|
171 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
172 |
}
|
37 |
add_filter( 'itsec_logger_displays', array( $this, 'itsec_logger_displays' ) ); //adds logs metaboxes
|
38 |
add_filter( 'itsec_logger_modules', array( $this, 'itsec_logger_modules' ) );
|
39 |
add_action( 'ithemes_sync_register_verbs', array( $this, 'register_sync_verbs' ) );
|
40 |
+
add_filter( 'itsec_notifications', array( $this, 'register_notification' ) );
|
41 |
+
add_filter( 'itsec_file-change_notification_strings', array( $this, 'register_notification_strings' ) );
|
42 |
|
43 |
|
44 |
if (
|
171 |
public function register_sync_verbs( $api ) {
|
172 |
$api->register( 'itsec-perform-file-scan', 'Ithemes_Sync_Verb_ITSEC_Perform_File_Scan', dirname( __FILE__ ) . '/sync-verbs/itsec-perform-file-scan.php' );
|
173 |
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Register the file change notification.
|
177 |
+
*
|
178 |
+
* @param array $notifications
|
179 |
+
*
|
180 |
+
* @return array
|
181 |
+
*/
|
182 |
+
public function register_notification( $notifications ) {
|
183 |
+
$notifications['file-change'] = array(
|
184 |
+
'recipient' => ITSEC_Notification_Center::R_USER_LIST_ADMIN_UPGRADE,
|
185 |
+
'schedule' => ITSEC_Notification_Center::S_NONE,
|
186 |
+
'subject_editable' => true,
|
187 |
+
'optional' => true,
|
188 |
+
'module' => 'file-change',
|
189 |
+
);
|
190 |
+
|
191 |
+
return $notifications;
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* Register the file change notification strings.
|
196 |
+
*
|
197 |
+
* @return array
|
198 |
+
*/
|
199 |
+
public function register_notification_strings() {
|
200 |
+
return array(
|
201 |
+
'label' => esc_html__( 'File Change', 'better-wp-security' ),
|
202 |
+
'description' => sprintf( esc_html__( 'The %1$sFile Change Detection%2$s module will email a file scan report after changes have been detected.', 'better-wp-security' ), '<a href="#" data-module-link="file-change">', '</a>' ),
|
203 |
+
'subject' => esc_html__( 'File Change Warning', 'better-wp-security' ),
|
204 |
+
);
|
205 |
+
}
|
206 |
}
|
core/modules/file-change/scanner.php
CHANGED
@@ -245,8 +245,6 @@ final class ITSEC_File_Change_Scanner {
|
|
245 |
if (
|
246 |
true === $send_email &&
|
247 |
false !== $scheduled_call &&
|
248 |
-
isset( $this->settings['email'] ) &&
|
249 |
-
true === $this->settings['email'] &&
|
250 |
(
|
251 |
0 < $files_added_count ||
|
252 |
0 < $files_changed_count ||
|
@@ -270,8 +268,7 @@ final class ITSEC_File_Change_Scanner {
|
|
270 |
! isset( get_current_screen()->id ) ||
|
271 |
false === strpos( get_current_screen()->id, 'security_page_toplevel_page_itsec_logs' )
|
272 |
) &&
|
273 |
-
|
274 |
-
true === $this->settings['notify_admin']
|
275 |
) {
|
276 |
ITSEC_Modules::set_setting( 'file-change', 'show_warning', true );
|
277 |
}
|
@@ -325,74 +322,9 @@ final class ITSEC_File_Change_Scanner {
|
|
325 |
* @return string report details
|
326 |
*/
|
327 |
public function get_email_report( $email_details ) {
|
|
|
328 |
|
329 |
-
|
330 |
-
$added = $email_details[3]['added'];
|
331 |
-
$removed = $email_details[3]['removed'];
|
332 |
-
$changed = $email_details[3]['changed'];
|
333 |
-
$report = '<strong>' . __( 'Scan Time:', 'better-wp-security' ) . '</strong> ' . date( 'l, F jS g:i a e', ITSEC_Core::get_current_time() ) . "<br />" . PHP_EOL;
|
334 |
-
$report .= '<strong>' . __( 'Files Added:', 'better-wp-security' ) . '</strong> ' . $email_details[0] . "<br />" . PHP_EOL;
|
335 |
-
$report .= '<strong>' . __( 'Files Deleted:', 'better-wp-security' ) . '</strong> ' . $email_details[1] . "<br />" . PHP_EOL;
|
336 |
-
$report .= '<strong>' . __( 'Files Modified:', 'better-wp-security' ) . '</strong> ' . $email_details[2] . "<br />" . PHP_EOL;
|
337 |
-
$report .= '<strong>' . __( 'Memory Used:', 'better-wp-security' ) . '</strong> ' . $email_details[3]['memory'] . " MB<br />" . PHP_EOL;
|
338 |
-
|
339 |
-
$report .= $this->build_table_section( __( 'Added', 'better-wp-security' ), $added );
|
340 |
-
$report .= $this->build_table_section( __( 'Deleted', 'better-wp-security' ), $removed );
|
341 |
-
$report .= $this->build_table_section( __( 'Modified', 'better-wp-security' ), $changed );
|
342 |
-
|
343 |
-
return $report;
|
344 |
-
|
345 |
-
}
|
346 |
-
|
347 |
-
/**
|
348 |
-
* Builds table section for file report
|
349 |
-
*
|
350 |
-
* Builds the individual table areas for files added, changed and deleted that goes in the file
|
351 |
-
* change notification emails.
|
352 |
-
*
|
353 |
-
* @since 4.6.0
|
354 |
-
*
|
355 |
-
* @access private
|
356 |
-
*
|
357 |
-
* @param string $title User readable title to display
|
358 |
-
* @param array $files array of files to build the report on
|
359 |
-
*
|
360 |
-
* @return string the markup with the given files to be added to the report
|
361 |
-
*/
|
362 |
-
private function build_table_section( $title, $files ) {
|
363 |
-
|
364 |
-
$section = '<h4>' . __( 'Files', 'better-wp-security' ) . ' ' . $title . '</h4>';
|
365 |
-
$section .= '<table border="1" style="width: 100%; text-align: center;">' . PHP_EOL;
|
366 |
-
$section .= '<tr>' . PHP_EOL;
|
367 |
-
$section .= '<th>' . __( 'File', 'better-wp-security' ) . '</th>' . PHP_EOL;
|
368 |
-
$section .= '<th>' . __( 'Modified', 'better-wp-security' ) . '</th>' . PHP_EOL;
|
369 |
-
$section .= '<th>' . __( 'File Hash', 'better-wp-security' ) . '</th>' . PHP_EOL;
|
370 |
-
$section .= '</tr>' . PHP_EOL;
|
371 |
-
|
372 |
-
if ( isset( $files ) && is_array( $files ) && 0 < sizeof( $files ) ) {
|
373 |
-
|
374 |
-
foreach ( $files as $item => $attr ) {
|
375 |
-
|
376 |
-
$section .= '<tr>' . PHP_EOL;
|
377 |
-
$section .= '<td>' . $item . '</td>' . PHP_EOL;
|
378 |
-
$section .= '<td>' . date( 'l F jS, Y \a\t g:i a e', ( isset( $attr['mod_date'] ) ? $attr['mod_date'] : $attr['d'] ) ) . '</td>' . PHP_EOL;
|
379 |
-
$section .= '<td>' . ( isset( $attr['hash'] ) ? $attr['hash'] : $attr['h'] ) . '</td>' . PHP_EOL;
|
380 |
-
$section .= '</tr>' . PHP_EOL;
|
381 |
-
|
382 |
-
}
|
383 |
-
|
384 |
-
} else {
|
385 |
-
|
386 |
-
$section .= '<tr>' . PHP_EOL;
|
387 |
-
$section .= '<td colspan="3">' . __( 'No files were changed.', 'better-wp-security' ) . '</td>' . PHP_EOL;
|
388 |
-
$section .= '</tr>' . PHP_EOL;
|
389 |
-
|
390 |
-
}
|
391 |
-
|
392 |
-
$section .= '</table>' . PHP_EOL;
|
393 |
-
|
394 |
-
return $section;
|
395 |
-
|
396 |
}
|
397 |
|
398 |
/**
|
@@ -577,50 +509,87 @@ final class ITSEC_File_Change_Scanner {
|
|
577 |
*/
|
578 |
private function send_notification_email( $email_details ) {
|
579 |
|
580 |
-
$
|
581 |
|
582 |
-
if (
|
|
|
|
|
583 |
|
584 |
-
|
585 |
-
$subject = '[' . get_option( 'siteurl' ) . '] ' . __( 'WordPress File Change Warning', 'better-wp-security' ) . ' ' . date( 'l, F jS, Y \a\\t g:i a e', ITSEC_Core::get_current_time() );
|
586 |
|
587 |
-
|
588 |
-
$
|
|
|
589 |
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
|
596 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
597 |
|
598 |
-
|
|
|
|
|
|
|
|
|
599 |
|
600 |
-
|
|
|
601 |
|
602 |
-
|
603 |
-
$itsec_notify->register_file_change();
|
604 |
-
}
|
605 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
606 |
}
|
607 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
608 |
}
|
609 |
|
610 |
/**
|
611 |
-
*
|
612 |
*
|
613 |
-
*
|
614 |
-
* HTML in order to send the tables and related data included in file change reporting.
|
615 |
*
|
616 |
-
* @
|
617 |
-
*
|
618 |
-
* @return string html content type
|
619 |
*/
|
620 |
-
|
|
|
621 |
|
622 |
-
|
|
|
623 |
|
624 |
-
|
|
|
|
|
|
|
|
|
|
|
625 |
|
|
|
|
|
626 |
}
|
245 |
if (
|
246 |
true === $send_email &&
|
247 |
false !== $scheduled_call &&
|
|
|
|
|
248 |
(
|
249 |
0 < $files_added_count ||
|
250 |
0 < $files_changed_count ||
|
268 |
! isset( get_current_screen()->id ) ||
|
269 |
false === strpos( get_current_screen()->id, 'security_page_toplevel_page_itsec_logs' )
|
270 |
) &&
|
271 |
+
! empty( $this->settings['notify_admin'] )
|
|
|
272 |
) {
|
273 |
ITSEC_Modules::set_setting( 'file-change', 'show_warning', true );
|
274 |
}
|
322 |
* @return string report details
|
323 |
*/
|
324 |
public function get_email_report( $email_details ) {
|
325 |
+
_deprecated_function( __METHOD__, '3.9.0' );
|
326 |
|
327 |
+
return $this->generate_notification_email( $email_details )->get_content();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
}
|
329 |
|
330 |
/**
|
509 |
*/
|
510 |
private function send_notification_email( $email_details ) {
|
511 |
|
512 |
+
$changed = $email_details[0] + $email_details[1] + $email_details[2];
|
513 |
|
514 |
+
if ( $changed <= 0 ) {
|
515 |
+
return;
|
516 |
+
}
|
517 |
|
518 |
+
$nc = ITSEC_Core::get_notification_center();
|
|
|
519 |
|
520 |
+
if ( $nc->is_notification_enabled( 'digest' ) ) {
|
521 |
+
$nc->enqueue_data( 'digest', array( 'type' => 'file-change' ) );
|
522 |
+
}
|
523 |
|
524 |
+
if ( $nc->is_notification_enabled( 'file-change' ) ) {
|
525 |
+
$mail = $this->generate_notification_email( $email_details );
|
526 |
+
$nc->send( 'file-change', $mail );
|
527 |
+
}
|
528 |
+
}
|
529 |
|
530 |
+
/**
|
531 |
+
* Generate the notification email.
|
532 |
+
*
|
533 |
+
* @param array $email_details
|
534 |
+
*
|
535 |
+
* @return ITSEC_Mail
|
536 |
+
*/
|
537 |
+
private function generate_notification_email( $email_details ) {
|
538 |
+
$mail = ITSEC_Core::get_notification_center()->mail();
|
539 |
|
540 |
+
$mail->add_header(
|
541 |
+
esc_html__( 'File Change Warning', 'better-wp-security' ),
|
542 |
+
sprintf( esc_html__( 'File Scan Report for %s', 'better-wp-security' ), '<b>' . date_i18n( get_option( 'date_format' ) ) . '</b>' )
|
543 |
+
);
|
544 |
+
$mail->add_text( esc_html__( 'A file (or files) on your site have been changed. Please review the report below to verify changes are not the result of a compromise.', 'better-wp-security' ) );
|
545 |
|
546 |
+
$mail->add_section_heading( esc_html__( 'Scan Summary', 'better-wp-security' ) );
|
547 |
+
$mail->add_file_change_summary( $email_details[0], $email_details[1], $email_details[2] );
|
548 |
|
549 |
+
$mail->add_section_heading( esc_html__( 'Scan Details', 'better-wp-security' ) );
|
|
|
|
|
550 |
|
551 |
+
$headers = array( esc_html__( 'File', 'better-wp-security' ), esc_html__( 'Modified', 'better-wp-security' ), esc_html__( 'File Hash', 'better-wp-security' ) );
|
552 |
+
|
553 |
+
if ( $email_details[0] ) {
|
554 |
+
$mail->add_large_text( esc_html__( 'Added Files', 'better-wp-security' ) );
|
555 |
+
$mail->add_table( $headers, $this->generate_email_rows( $email_details[3]['added'] ) );
|
556 |
+
}
|
557 |
+
|
558 |
+
if ( $email_details[1] ) {
|
559 |
+
$mail->add_large_text( esc_html__( 'Removed Files', 'better-wp-security' ) );
|
560 |
+
$mail->add_table( $headers, $this->generate_email_rows( $email_details[3]['removed'] ) );
|
561 |
}
|
562 |
|
563 |
+
if ( $email_details[2] ) {
|
564 |
+
$mail->add_large_text( esc_html__( 'Changed Files', 'better-wp-security' ) );
|
565 |
+
$mail->add_table( $headers, $this->generate_email_rows( $email_details[3]['changed'] ) );
|
566 |
+
}
|
567 |
+
|
568 |
+
$mail->add_footer();
|
569 |
+
|
570 |
+
return $mail;
|
571 |
}
|
572 |
|
573 |
/**
|
574 |
+
* Generate email report rows for a series of files.
|
575 |
*
|
576 |
+
* @param array $files
|
|
|
577 |
*
|
578 |
+
* @return array
|
|
|
|
|
579 |
*/
|
580 |
+
private function generate_email_rows( $files ) {
|
581 |
+
$rows = array();
|
582 |
|
583 |
+
foreach ( $files as $item => $attr ) {
|
584 |
+
$time = isset( $attr['mod_date'] ) ? $attr['mod_date'] : $attr['d'];
|
585 |
|
586 |
+
$rows[] = array(
|
587 |
+
$item,
|
588 |
+
ITSEC_Lib::date_format_i18n_and_local_timezone( $time ),
|
589 |
+
isset( $attr['hash'] ) ? $attr['hash'] : $attr['h']
|
590 |
+
);
|
591 |
+
}
|
592 |
|
593 |
+
return $rows;
|
594 |
+
}
|
595 |
}
|
core/modules/file-change/settings-page.php
CHANGED
@@ -125,14 +125,6 @@ final class ITSEC_File_Change_Settings_Page extends ITSEC_Module_Settings_Page {
|
|
125 |
<label for="itsec-file-change-types"><?php _e( 'File types listed here will not be checked for changes. While it is possible to change files such as images it is quite rare and nearly all known WordPress attacks exploit php, js and other text files.', 'better-wp-security' ); ?></label>
|
126 |
</td>
|
127 |
</tr>
|
128 |
-
<tr>
|
129 |
-
<th scope="row"><label for="itsec-file-change-email"><?php _e( 'Email File Change Notifications', 'better-wp-security' ); ?></label></th>
|
130 |
-
<td>
|
131 |
-
<?php $form->add_checkbox( 'email' ); ?>
|
132 |
-
<label for="itsec-file-change-email"><?php _e( 'Email file change notifications', 'better-wp-security' ); ?></label>
|
133 |
-
<p class="description"><?php _e( 'Notifications will be sent to all emails set to receive notifications on the global settings page.', 'better-wp-security' ); ?></p>
|
134 |
-
</td>
|
135 |
-
</tr>
|
136 |
<tr>
|
137 |
<th scope="row"><label for="itsec-file-change-notify_admin"><?php _e( 'Display File Change Admin Warning', 'better-wp-security' ); ?></label></th>
|
138 |
<td>
|
125 |
<label for="itsec-file-change-types"><?php _e( 'File types listed here will not be checked for changes. While it is possible to change files such as images it is quite rare and nearly all known WordPress attacks exploit php, js and other text files.', 'better-wp-security' ); ?></label>
|
126 |
</td>
|
127 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
<tr>
|
129 |
<th scope="row"><label for="itsec-file-change-notify_admin"><?php _e( 'Display File Change Admin Warning', 'better-wp-security' ); ?></label></th>
|
130 |
<td>
|
core/modules/file-change/settings.php
CHANGED
@@ -18,7 +18,6 @@ final class ITSEC_File_Change_Settings extends ITSEC_Settings {
|
|
18 |
'.mo',
|
19 |
'.po'
|
20 |
),
|
21 |
-
'email' => true,
|
22 |
'notify_admin' => true,
|
23 |
'last_run' => 0,
|
24 |
'last_chunk' => false,
|
18 |
'.mo',
|
19 |
'.po'
|
20 |
),
|
|
|
21 |
'notify_admin' => true,
|
22 |
'last_run' => 0,
|
23 |
'last_chunk' => false,
|
core/modules/file-change/validator.php
CHANGED
@@ -18,14 +18,14 @@ class ITSEC_File_Change_Validator extends ITSEC_Validator {
|
|
18 |
$this->settings['show_warning'] = $previous_settings['show_warning'];
|
19 |
}
|
20 |
|
21 |
-
$this->set_previous_if_empty( array( 'latest_changes' ) );
|
22 |
$this->vars_to_skip_validate_matching_types[] = 'last_chunk';
|
|
|
23 |
|
24 |
$this->sanitize_setting( 'bool', 'split', __( 'Split File Scanning', 'better-wp-security' ) );
|
25 |
$this->sanitize_setting( array( 'exclude', 'include' ), 'method', __( 'Include/Exclude Files and Folders', 'better-wp-security' ) );
|
26 |
$this->sanitize_setting( 'newline-separated-array', 'file_list', __( 'Files and Folders List', 'better-wp-security' ) );
|
27 |
$this->sanitize_setting( 'newline-separated-extensions', 'types', __( 'Ignore File Types', 'better-wp-security' ) );
|
28 |
-
$this->sanitize_setting( 'bool', 'email', __( 'Email File Change Notifications', 'better-wp-security' ) );
|
29 |
$this->sanitize_setting( 'bool', 'notify_admin', __( 'Display File Change Admin Warning', 'better-wp-security' ) );
|
30 |
$this->sanitize_setting( 'positive-int', 'last_run', __( 'Last Run', 'better-wp-security' ), false );
|
31 |
|
18 |
$this->settings['show_warning'] = $previous_settings['show_warning'];
|
19 |
}
|
20 |
|
21 |
+
$this->set_previous_if_empty( array( 'latest_changes', 'email' ) );
|
22 |
$this->vars_to_skip_validate_matching_types[] = 'last_chunk';
|
23 |
+
$this->vars_to_skip_validate_matching_fields[] = 'email';
|
24 |
|
25 |
$this->sanitize_setting( 'bool', 'split', __( 'Split File Scanning', 'better-wp-security' ) );
|
26 |
$this->sanitize_setting( array( 'exclude', 'include' ), 'method', __( 'Include/Exclude Files and Folders', 'better-wp-security' ) );
|
27 |
$this->sanitize_setting( 'newline-separated-array', 'file_list', __( 'Files and Folders List', 'better-wp-security' ) );
|
28 |
$this->sanitize_setting( 'newline-separated-extensions', 'types', __( 'Ignore File Types', 'better-wp-security' ) );
|
|
|
29 |
$this->sanitize_setting( 'bool', 'notify_admin', __( 'Display File Change Admin Warning', 'better-wp-security' ) );
|
30 |
$this->sanitize_setting( 'positive-int', 'last_run', __( 'Last Run', 'better-wp-security' ), false );
|
31 |
|
core/modules/global/settings-page.php
CHANGED
@@ -83,29 +83,6 @@ final class ITSEC_Global_Settings_Page extends ITSEC_Module_Settings_Page {
|
|
83 |
<p class="description"><?php _e( 'Whether or not iThemes Security should be allowed to write to wp-config.php and .htaccess automatically. If disabled you will need to manually place configuration options in those files.', 'better-wp-security' ); ?></p>
|
84 |
</td>
|
85 |
</tr>
|
86 |
-
<tr>
|
87 |
-
<th scope="row"><label for="itsec-global-notification_email"><?php _e( 'Notification Email', 'better-wp-security' ); ?></label></th>
|
88 |
-
<td>
|
89 |
-
<?php $form->add_textarea( 'notification_email', array( 'class' => 'textarea-small' ) ); ?>
|
90 |
-
<p class="description"><?php _e( 'The email address(es) all security notifications will be sent to. One address per line.', 'better-wp-security' ); ?></p>
|
91 |
-
</td>
|
92 |
-
</tr>
|
93 |
-
<tr>
|
94 |
-
<th scope="row"><label for="itsec-global-digest_email"><?php _e( 'Send Digest Email', 'better-wp-security' ); ?></label></th>
|
95 |
-
<td>
|
96 |
-
<?php $form->add_checkbox( 'digest_email' ); ?>
|
97 |
-
<label for="itsec-global-digest_email"><?php _e( 'Send digest email', 'better-wp-security' ); ?></label>
|
98 |
-
<p class="description"><?php _e( 'During periods of heavy attack or other times a security plugin can generate a LOT of email just telling you that it is doing its job. Turning this on will reduce the emails from this plugin to no more than one per day for any notification.', 'better-wp-security' ); ?></p>
|
99 |
-
</td>
|
100 |
-
</tr>
|
101 |
-
<tr>
|
102 |
-
<th scope="row"><label for="itsec-global-backup_email"><?php _e( 'Backup Delivery Email', 'better-wp-security' ); ?></label></th>
|
103 |
-
<td>
|
104 |
-
<?php $form->add_textarea( 'backup_email', array( 'class' => 'textarea-small' ) ); ?>
|
105 |
-
<br />
|
106 |
-
<p class="description"><?php _e( 'The email address(es) all database backups will be sent to. One address per line.', 'better-wp-security' ); ?></p>
|
107 |
-
</td>
|
108 |
-
</tr>
|
109 |
<tr>
|
110 |
<th scope="row"><label for="itsec-global-lockout_message"><?php _e( 'Host Lockout Message', 'better-wp-security' ); ?></label></th>
|
111 |
<td>
|
@@ -183,14 +160,6 @@ final class ITSEC_Global_Settings_Page extends ITSEC_Module_Settings_Page {
|
|
183 |
<p class="description"><strong><?php _e( 'This white list will prevent any IP listed from triggering an automatic lockout. You can still block the IP address manually in the banned users settings.', 'better-wp-security' ); ?></strong></p>
|
184 |
</td>
|
185 |
</tr>
|
186 |
-
<tr>
|
187 |
-
<th scope="row"><label for="itsec-global-email_notifications"><?php _e( 'Email Lockout Notifications', 'better-wp-security' ); ?></label></th>
|
188 |
-
<td>
|
189 |
-
<?php $form->add_checkbox( 'email_notifications' ); ?>
|
190 |
-
<label for="itsec-global-email_notifications"><?php _e( 'Enable Email Lockout Notifications', 'better-wp-security' ); ?></label>
|
191 |
-
<p class="description"><?php _e( 'This feature will trigger an email to be sent to the email addresses listed in the Notification Email setting whenever a host or user is locked out of the system.', 'better-wp-security' ); ?></p>
|
192 |
-
</td>
|
193 |
-
</tr>
|
194 |
<tr>
|
195 |
<th scope="row"><label for="itsec-global-log_type"><?php _e( 'Log Type', 'better-wp-security' ); ?></label></th>
|
196 |
<td>
|
83 |
<p class="description"><?php _e( 'Whether or not iThemes Security should be allowed to write to wp-config.php and .htaccess automatically. If disabled you will need to manually place configuration options in those files.', 'better-wp-security' ); ?></p>
|
84 |
</td>
|
85 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
<tr>
|
87 |
<th scope="row"><label for="itsec-global-lockout_message"><?php _e( 'Host Lockout Message', 'better-wp-security' ); ?></label></th>
|
88 |
<td>
|
160 |
<p class="description"><strong><?php _e( 'This white list will prevent any IP listed from triggering an automatic lockout. You can still block the IP address manually in the banned users settings.', 'better-wp-security' ); ?></strong></p>
|
161 |
</td>
|
162 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
<tr>
|
164 |
<th scope="row"><label for="itsec-global-log_type"><?php _e( 'Log Type', 'better-wp-security' ); ?></label></th>
|
165 |
<td>
|
core/modules/global/settings.php
CHANGED
@@ -6,18 +6,13 @@ final class ITSEC_Global_Settings_New extends ITSEC_Settings {
|
|
6 |
}
|
7 |
|
8 |
public function get_defaults() {
|
9 |
-
$email = get_option( 'admin_email' );
|
10 |
-
|
11 |
return array(
|
12 |
-
'notification_email' => array( $email ),
|
13 |
-
'backup_email' => array( $email ),
|
14 |
'lockout_message' => __( 'error', 'better-wp-security' ),
|
15 |
'user_lockout_message' => __( 'You have been locked out due to too many invalid login attempts.', 'better-wp-security' ),
|
16 |
'community_lockout_message' => __( 'Your IP address has been flagged as a threat by the iThemes Security network.', 'better-wp-security' ),
|
17 |
'blacklist' => true,
|
18 |
'blacklist_count' => 3,
|
19 |
'blacklist_period' => 7,
|
20 |
-
'email_notifications' => true,
|
21 |
'lockout_period' => 15,
|
22 |
'lockout_white_list' => array(),
|
23 |
'log_rotation' => 14,
|
@@ -30,14 +25,11 @@ final class ITSEC_Global_Settings_New extends ITSEC_Settings {
|
|
30 |
'infinitewp_compatibility' => false,
|
31 |
'did_upgrade' => false,
|
32 |
'lock_file' => false,
|
33 |
-
'digest_email' => false,
|
34 |
'proxy_override' => false,
|
35 |
'hide_admin_bar' => false,
|
36 |
'show_error_codes' => false,
|
37 |
'show_new_dashboard_notice' => true,
|
38 |
'show_security_check' => true,
|
39 |
-
'digest_last_sent' => 0,
|
40 |
-
'digest_messages' => array(),
|
41 |
'build' => 0,
|
42 |
'activation_timestamp' => 0,
|
43 |
);
|
6 |
}
|
7 |
|
8 |
public function get_defaults() {
|
|
|
|
|
9 |
return array(
|
|
|
|
|
10 |
'lockout_message' => __( 'error', 'better-wp-security' ),
|
11 |
'user_lockout_message' => __( 'You have been locked out due to too many invalid login attempts.', 'better-wp-security' ),
|
12 |
'community_lockout_message' => __( 'Your IP address has been flagged as a threat by the iThemes Security network.', 'better-wp-security' ),
|
13 |
'blacklist' => true,
|
14 |
'blacklist_count' => 3,
|
15 |
'blacklist_period' => 7,
|
|
|
16 |
'lockout_period' => 15,
|
17 |
'lockout_white_list' => array(),
|
18 |
'log_rotation' => 14,
|
25 |
'infinitewp_compatibility' => false,
|
26 |
'did_upgrade' => false,
|
27 |
'lock_file' => false,
|
|
|
28 |
'proxy_override' => false,
|
29 |
'hide_admin_bar' => false,
|
30 |
'show_error_codes' => false,
|
31 |
'show_new_dashboard_notice' => true,
|
32 |
'show_security_check' => true,
|
|
|
|
|
33 |
'build' => 0,
|
34 |
'activation_timestamp' => 0,
|
35 |
);
|
core/modules/global/validator.php
CHANGED
@@ -19,14 +19,13 @@ class ITSEC_Global_Validator extends ITSEC_Validator {
|
|
19 |
}
|
20 |
|
21 |
|
22 |
-
$this->
|
|
|
23 |
$this->set_default_if_empty( array( 'log_location', 'nginx_file' ) );
|
24 |
|
25 |
|
26 |
$this->sanitize_setting( 'bool', 'write_files', __( 'Write to Files', 'better-wp-security' ) );
|
27 |
-
$this->sanitize_setting( 'bool', 'digest_email', __( 'Send Digest Email', 'better-wp-security' ) );
|
28 |
$this->sanitize_setting( 'bool', 'blacklist', __( 'Blacklist Repeat Offender', 'better-wp-security' ) );
|
29 |
-
$this->sanitize_setting( 'bool', 'email_notifications', __( 'Email Lockout Notifications', 'better-wp-security' ) );
|
30 |
$this->sanitize_setting( 'bool', 'allow_tracking', __( 'Allow Data Tracking', 'better-wp-security' ) );
|
31 |
$this->sanitize_setting( 'bool', 'proxy_override', __( 'Override Proxy Detection', 'better-wp-security' ) );
|
32 |
$this->sanitize_setting( 'bool', 'hide_admin_bar', __( 'Hide Security Menu in Admin Bar', 'better-wp-security' ) );
|
@@ -48,19 +47,12 @@ class ITSEC_Global_Validator extends ITSEC_Validator {
|
|
48 |
|
49 |
$this->sanitize_setting( 'newline-separated-ips', 'lockout_white_list', __( 'Lockout White List', 'better-wp-security' ) );
|
50 |
|
51 |
-
$this->sanitize_setting( 'newline-separated-emails', 'notification_email', __( 'Notification Email', 'better-wp-security' ) );
|
52 |
-
$this->sanitize_setting( 'newline-separated-emails', 'backup_email', __( 'Backup Delivery Email', 'better-wp-security' ) );
|
53 |
-
|
54 |
|
55 |
$allowed_tags = $this->get_allowed_tags();
|
56 |
|
57 |
$this->settings['lockout_message'] = trim( wp_kses( $this->settings['lockout_message'], $allowed_tags ) );
|
58 |
$this->settings['user_lockout_message'] = trim( wp_kses( $this->settings['user_lockout_message'], $allowed_tags ) );
|
59 |
$this->settings['community_lockout_message'] = trim( wp_kses( $this->settings['community_lockout_message'], $allowed_tags ) );
|
60 |
-
|
61 |
-
if ( $this->settings['digest_last_sent'] <= 0 ) {
|
62 |
-
$this->settings['digest_last_sent'] = ITSEC_Core::get_current_time_gmt();
|
63 |
-
}
|
64 |
}
|
65 |
|
66 |
public function get_valid_log_types() {
|
19 |
}
|
20 |
|
21 |
|
22 |
+
$this->vars_to_skip_validate_matching_fields = array( 'digest_last_sent', 'digest_messages', 'digest_email', 'email_notifications', 'notification_email', 'backup_email' );
|
23 |
+
$this->set_previous_if_empty( array( 'did_upgrade', 'log_info', 'show_new_dashboard_notice', 'show_security_check', 'digest_last_sent', 'digest_messages', 'build', 'activation_timestamp', 'lock_file', 'digest_email', 'email_notifications', 'notification_email', 'backup_email' ) );
|
24 |
$this->set_default_if_empty( array( 'log_location', 'nginx_file' ) );
|
25 |
|
26 |
|
27 |
$this->sanitize_setting( 'bool', 'write_files', __( 'Write to Files', 'better-wp-security' ) );
|
|
|
28 |
$this->sanitize_setting( 'bool', 'blacklist', __( 'Blacklist Repeat Offender', 'better-wp-security' ) );
|
|
|
29 |
$this->sanitize_setting( 'bool', 'allow_tracking', __( 'Allow Data Tracking', 'better-wp-security' ) );
|
30 |
$this->sanitize_setting( 'bool', 'proxy_override', __( 'Override Proxy Detection', 'better-wp-security' ) );
|
31 |
$this->sanitize_setting( 'bool', 'hide_admin_bar', __( 'Hide Security Menu in Admin Bar', 'better-wp-security' ) );
|
47 |
|
48 |
$this->sanitize_setting( 'newline-separated-ips', 'lockout_white_list', __( 'Lockout White List', 'better-wp-security' ) );
|
49 |
|
|
|
|
|
|
|
50 |
|
51 |
$allowed_tags = $this->get_allowed_tags();
|
52 |
|
53 |
$this->settings['lockout_message'] = trim( wp_kses( $this->settings['lockout_message'], $allowed_tags ) );
|
54 |
$this->settings['user_lockout_message'] = trim( wp_kses( $this->settings['user_lockout_message'], $allowed_tags ) );
|
55 |
$this->settings['community_lockout_message'] = trim( wp_kses( $this->settings['community_lockout_message'], $allowed_tags ) );
|
|
|
|
|
|
|
|
|
56 |
}
|
57 |
|
58 |
public function get_valid_log_types() {
|
core/modules/hide-backend/class-itsec-hide-backend.php
CHANGED
@@ -14,6 +14,9 @@ class ITSEC_Hide_Backend {
|
|
14 |
public function run() {
|
15 |
$this->settings = ITSEC_Modules::get_settings( 'hide-backend' );
|
16 |
|
|
|
|
|
|
|
17 |
if ( ! $this->settings['enabled'] ) {
|
18 |
return;
|
19 |
}
|
@@ -317,6 +320,48 @@ class ITSEC_Hide_Backend {
|
|
317 |
}
|
318 |
}
|
319 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
320 |
/**
|
321 |
* Creates a cookie to validate future requests.
|
322 |
*
|
14 |
public function run() {
|
15 |
$this->settings = ITSEC_Modules::get_settings( 'hide-backend' );
|
16 |
|
17 |
+
add_filter( 'itsec_notifications', array( $this, 'register_notification' ) );
|
18 |
+
add_filter( 'itsec_hide-backend_notification_strings', array( $this, 'notification_strings' ) );
|
19 |
+
|
20 |
if ( ! $this->settings['enabled'] ) {
|
21 |
return;
|
22 |
}
|
320 |
}
|
321 |
}
|
322 |
|
323 |
+
/**
|
324 |
+
* Register the New Login URL notification.
|
325 |
+
*
|
326 |
+
* @param array $notifications
|
327 |
+
*
|
328 |
+
* @return array
|
329 |
+
*/
|
330 |
+
public function register_notification( $notifications ) {
|
331 |
+
|
332 |
+
if ( ITSEC_Modules::get_setting( 'hide-backend', 'enabled' ) ) {
|
333 |
+
$notifications['hide-backend'] = array(
|
334 |
+
'subject_editable' => true,
|
335 |
+
'message_editable' => true,
|
336 |
+
'schedule' => ITSEC_Notification_Center::S_NONE,
|
337 |
+
'recipient' => ITSEC_Notification_Center::R_USER_LIST,
|
338 |
+
'tags' => array( 'login_url', 'site_title', 'site_url' ),
|
339 |
+
'module' => 'hide-backend',
|
340 |
+
);
|
341 |
+
}
|
342 |
+
|
343 |
+
return $notifications;
|
344 |
+
}
|
345 |
+
|
346 |
+
/**
|
347 |
+
* Register the strings for the Hide Backend change notification.
|
348 |
+
*
|
349 |
+
* @return array
|
350 |
+
*/
|
351 |
+
public function notification_strings() {
|
352 |
+
return array(
|
353 |
+
'label' => esc_html__( 'Hide Backend – New Login URL', 'better-wp-security' ),
|
354 |
+
'description' => sprintf( esc_html__( '%1$sHide Backend%2$s will notify the chosen recipients whenever the login URL is changed.', 'better-wp-security' ), '<a href="#" data-module-link="hide-backend">', '</a>' ),
|
355 |
+
'subject' => esc_html__( 'WordPress Login Address Changed', 'better-wp-security' ),
|
356 |
+
'message' => esc_html__( 'The login address for {{ $site_title }} has changed. The new login address is {{ $login_url }}. You will be unable to use the old login address.', 'better-wp-security' ),
|
357 |
+
'tags' => array(
|
358 |
+
'login_url' => esc_html__( 'The new login link.', 'better-wp-security' ),
|
359 |
+
'site_title' => esc_html__( 'The WordPress Site Title. Can be changed under Settings -> General -> Site Title', 'better-wp-security' ),
|
360 |
+
'site_url' => esc_html__( 'The URL to your website.', 'better-wp-security' ),
|
361 |
+
),
|
362 |
+
);
|
363 |
+
}
|
364 |
+
|
365 |
/**
|
366 |
* Creates a cookie to validate future requests.
|
367 |
*
|
core/modules/hide-backend/validator.php
CHANGED
@@ -48,13 +48,14 @@ final class ITSEC_Hide_Backend_Validator extends ITSEC_Validator {
|
|
48 |
|
49 |
if ( $this->settings['enabled'] && $this->settings['slug'] !== $this->previous_settings['slug'] ) {
|
50 |
$url = get_site_url() . '/' . $this->settings['slug'];
|
51 |
-
ITSEC_Response::add_message( sprintf( __( 'The Hide Backend feature is now active. Your new login URL is <strong><code>%1$s</code></strong>. Please note this may be different than what you sent as the URL was sanitized to meet various requirements. A reminder has also been sent to the notification email addresses set in iThemes Security\'s
|
52 |
} else if ( $this->settings['enabled'] && ! $this->previous_settings['enabled'] ) {
|
|
|
53 |
$url = get_site_url() . '/' . $this->settings['slug'];
|
54 |
-
ITSEC_Response::add_message( sprintf( __( 'The Hide Backend feature is now active. Your new login URL is <strong><code>%1$s</code></strong>. A reminder has also been sent to the notification email addresses set in iThemes Security\'s
|
55 |
} else if ( ! $this->settings['enabled'] && $this->previous_settings['enabled'] ) {
|
56 |
$url = get_site_url() . '/wp-login.php';
|
57 |
-
ITSEC_Response::add_message( sprintf( __( 'The Hide Backend feature is now disabled. Your new login URL is <strong><code>%1$s</code></strong>. A reminder has also been sent to the notification email addresses set in iThemes Security\'s
|
58 |
}
|
59 |
|
60 |
if ( isset( $url ) ) {
|
@@ -73,42 +74,22 @@ final class ITSEC_Hide_Backend_Validator extends ITSEC_Validator {
|
|
73 |
return;
|
74 |
}
|
75 |
|
76 |
-
$
|
77 |
-
|
78 |
-
|
79 |
-
$
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
$
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
$
|
90 |
-
$
|
91 |
-
$
|
92 |
-
$headers = 'From: ' . get_bloginfo( 'name' ) . ' <' . get_option( 'admin_email' ) . '>' . "\r\n";
|
93 |
-
|
94 |
-
//Use HTML Content type
|
95 |
-
add_filter( 'wp_mail_content_type', array( $this, 'get_html_content_type' ) );
|
96 |
-
|
97 |
-
//Send emails to all recipients
|
98 |
-
foreach ( $recipients as $recipient ) {
|
99 |
-
$recipient = trim( $recipient );
|
100 |
-
|
101 |
-
if ( is_email( $recipient ) ) {
|
102 |
-
|
103 |
-
wp_mail( $recipient, $subject, $message, $headers );
|
104 |
-
|
105 |
-
}
|
106 |
-
|
107 |
-
}
|
108 |
-
|
109 |
-
//Remove HTML Content type
|
110 |
-
remove_filter( 'wp_mail_content_type', array( $this, 'get_html_content_type' ) );
|
111 |
-
|
112 |
}
|
113 |
|
114 |
/**
|
48 |
|
49 |
if ( $this->settings['enabled'] && $this->settings['slug'] !== $this->previous_settings['slug'] ) {
|
50 |
$url = get_site_url() . '/' . $this->settings['slug'];
|
51 |
+
ITSEC_Response::add_message( sprintf( __( 'The Hide Backend feature is now active. Your new login URL is <strong><code>%1$s</code></strong>. Please note this may be different than what you sent as the URL was sanitized to meet various requirements. A reminder has also been sent to the notification email addresses set in iThemes Security\'s Notification Center.', 'better-wp-security' ), esc_url( $url ) ) );
|
52 |
} else if ( $this->settings['enabled'] && ! $this->previous_settings['enabled'] ) {
|
53 |
+
ITSEC_Core::get_notification_center()->clear_notifications_cache();
|
54 |
$url = get_site_url() . '/' . $this->settings['slug'];
|
55 |
+
ITSEC_Response::add_message( sprintf( __( 'The Hide Backend feature is now active. Your new login URL is <strong><code>%1$s</code></strong>. A reminder has also been sent to the notification email addresses set in iThemes Security\'s Notification Center.', 'better-wp-security' ), esc_url( $url ) ) );
|
56 |
} else if ( ! $this->settings['enabled'] && $this->previous_settings['enabled'] ) {
|
57 |
$url = get_site_url() . '/wp-login.php';
|
58 |
+
ITSEC_Response::add_message( sprintf( __( 'The Hide Backend feature is now disabled. Your new login URL is <strong><code>%1$s</code></strong>. A reminder has also been sent to the notification email addresses set in iThemes Security\'s Notification Center.', 'better-wp-security' ), esc_url( $url ) ) );
|
59 |
}
|
60 |
|
61 |
if ( isset( $url ) ) {
|
74 |
return;
|
75 |
}
|
76 |
|
77 |
+
$nc = ITSEC_Core::get_notification_center();
|
78 |
+
$mail = $nc->mail();
|
79 |
+
|
80 |
+
$mail->add_header( esc_html__( 'New Login URL', 'better-wp-security' ), esc_html__( 'New Login URL', 'better-wp-security' ) );
|
81 |
+
$mail->add_text( ITSEC_Lib::replace_tags( $nc->get_message( 'hide-backend' ), array(
|
82 |
+
'login_url' => '<code>' . esc_url( $url ) . '</code>',
|
83 |
+
'site_title' => get_bloginfo( 'name', 'display' ),
|
84 |
+
'site_url' => $mail->get_display_url(),
|
85 |
+
) ) );
|
86 |
+
$mail->add_button( esc_html__( 'Login Now', 'better-wp-security' ), $url );
|
87 |
+
$mail->add_footer();
|
88 |
+
|
89 |
+
$subject = $mail->prepend_site_url_to_subject( $nc->get_subject( 'hide-backend' ) );
|
90 |
+
$subject = apply_filters( 'itsec_hide_backend_email_subject', $subject );
|
91 |
+
$mail->set_subject( $subject, false );
|
92 |
+
$nc->send( 'hide-backend', $mail );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
}
|
94 |
|
95 |
/**
|
core/modules/notification-center/active.php
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once( dirname( __FILE__ ) . '/class-notification-center.php' );
|
4 |
+
|
5 |
+
$center = new ITSEC_Notification_Center();
|
6 |
+
$center->run();
|
7 |
+
ITSEC_Core::set_notification_center( $center );
|
core/modules/notification-center/class-notification-center.php
ADDED
@@ -0,0 +1,1079 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class ITSEC_Notification_Center
|
5 |
+
*/
|
6 |
+
final class ITSEC_Notification_Center {
|
7 |
+
|
8 |
+
const R_USER = 'user'; // Goes to an end user. Two Factor or Magic Links.
|
9 |
+
const R_ADMIN = 'admin'; // Emails currently listed in Global Settings -> Notification Email
|
10 |
+
const R_USER_LIST = 'user-list'; // Can select users who should receive the email. For example Malware Scheduling.
|
11 |
+
const R_EMAIL_LIST = 'email-list'; // List of email addresses.
|
12 |
+
const R_PER_USE = 'per-use'; // Email address is selected before performing the action. For example Import/Export.
|
13 |
+
const R_USER_LIST_ADMIN_UPGRADE = 'user-list-admin-upgrade'; // Can select users/roles, but was previously the admin email list. Contains upgrade functionality
|
14 |
+
|
15 |
+
const S_NONE = 'none';
|
16 |
+
const S_DAILY = 'daily';
|
17 |
+
const S_WEEKLY = 'weekly';
|
18 |
+
const S_MONTHLY = 'monthly';
|
19 |
+
const S_CONFIGURABLE = 'configurable';
|
20 |
+
|
21 |
+
// If this is updated, make sure to update setup.php as well
|
22 |
+
const CRON_ACTION = 'itsec-send-scheduled-notifications';
|
23 |
+
|
24 |
+
/** @var bool */
|
25 |
+
private $use_cron;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Array of notification configs, keyed by notification slug.
|
29 |
+
*
|
30 |
+
* Lazily computed, see ::get_notifications().
|
31 |
+
*
|
32 |
+
* @var array
|
33 |
+
*/
|
34 |
+
private $notifications;
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Array of notification strings, keyed by notification slug.
|
38 |
+
* Separated from regular configuration due to gettext perforamnce.
|
39 |
+
*
|
40 |
+
* Lazily computed, see ::get_notification_strings().
|
41 |
+
*
|
42 |
+
* @var array
|
43 |
+
*/
|
44 |
+
private $strings = array();
|
45 |
+
|
46 |
+
/**
|
47 |
+
* The current notification being sent by ::send().
|
48 |
+
*
|
49 |
+
* Used for providing additional information when capturing mail errors.
|
50 |
+
*
|
51 |
+
* This could be replaced with closure scope if migrated to PHP 5.3.
|
52 |
+
*
|
53 |
+
* @var string
|
54 |
+
*/
|
55 |
+
private $_sending_notification = '';
|
56 |
+
|
57 |
+
/**
|
58 |
+
* ITSEC_Notification_Center constructor.
|
59 |
+
*/
|
60 |
+
public function __construct() {
|
61 |
+
$this->use_cron = defined( 'ITSEC_NOTIFY_USE_CRON' ) && ITSEC_NOTIFY_USE_CRON;
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Get registered notifications.
|
66 |
+
*
|
67 |
+
* This value is cached.
|
68 |
+
*
|
69 |
+
* @return array
|
70 |
+
*/
|
71 |
+
public function get_notifications() {
|
72 |
+
|
73 |
+
if ( null === $this->notifications ) {
|
74 |
+
/**
|
75 |
+
* Filter the registered notifications.
|
76 |
+
*
|
77 |
+
* Do not conditionally register the filter, instead perform any conditional registration in the callback,
|
78 |
+
* so the cache can be properly cleared on settings changes.
|
79 |
+
*
|
80 |
+
* @param array $notifications
|
81 |
+
* @param ITSEC_Notification_Center $this
|
82 |
+
*/
|
83 |
+
$notifications = apply_filters( 'itsec_notifications', array(), $this );
|
84 |
+
|
85 |
+
foreach ( $notifications as $slug => $notification ) {
|
86 |
+
$notification = $this->notification_defaults( $notification );
|
87 |
+
$notification['slug'] = $slug;
|
88 |
+
$this->notifications[ $slug ] = $notification;
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
return $this->notifications;
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Clear the notifications cache.
|
97 |
+
*
|
98 |
+
* This shouldn't be necessary in the vast majority of cases.
|
99 |
+
*/
|
100 |
+
public function clear_notifications_cache() {
|
101 |
+
$this->notifications = null;
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Get enabled notifications.
|
106 |
+
*
|
107 |
+
* @return array
|
108 |
+
*/
|
109 |
+
public function get_enabled_notifications() {
|
110 |
+
$notifications = $this->get_notifications();
|
111 |
+
$enabled = array();
|
112 |
+
|
113 |
+
foreach ( $notifications as $slug => $notification ) {
|
114 |
+
if ( $this->is_notification_enabled( $slug ) ) {
|
115 |
+
$enabled[ $slug ] = $notification;
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
return $enabled;
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Check if a notification is enabled.
|
124 |
+
*
|
125 |
+
* @param string $notification
|
126 |
+
*
|
127 |
+
* @return bool
|
128 |
+
*/
|
129 |
+
public function is_notification_enabled( $notification ) {
|
130 |
+
|
131 |
+
$config = $this->get_notification( $notification );
|
132 |
+
|
133 |
+
if ( ! $config ) {
|
134 |
+
return false;
|
135 |
+
}
|
136 |
+
|
137 |
+
if ( empty( $config['optional'] ) ) {
|
138 |
+
return true;
|
139 |
+
}
|
140 |
+
|
141 |
+
$settings = $this->get_notification_settings( $notification );
|
142 |
+
|
143 |
+
return ! empty( $settings['enabled'] );
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Parse notification defaults.
|
148 |
+
*
|
149 |
+
* @param array $args
|
150 |
+
*
|
151 |
+
* @return array
|
152 |
+
*/
|
153 |
+
private function notification_defaults( $args ) {
|
154 |
+
$args = wp_parse_args( $args, array(
|
155 |
+
'recipient' => self::R_ADMIN,
|
156 |
+
'schedule' => self::S_NONE,
|
157 |
+
'subject_editable' => false,
|
158 |
+
'message_editable' => false,
|
159 |
+
'optional' => false,
|
160 |
+
'tags' => array(),
|
161 |
+
'module' => '',
|
162 |
+
) );
|
163 |
+
|
164 |
+
$schedules = self::get_schedule_order();
|
165 |
+
$schedule = array(
|
166 |
+
'min' => $schedules[0],
|
167 |
+
'max' => $schedules[ count( $schedules ) - 1 ],
|
168 |
+
'default' => self::S_DAILY,
|
169 |
+
);
|
170 |
+
|
171 |
+
if ( $args['schedule'] === self::S_CONFIGURABLE ) {
|
172 |
+
$args['schedule'] = $schedule;
|
173 |
+
} elseif ( is_array( $args['schedule'] ) ) {
|
174 |
+
$args['schedule'] = wp_parse_args( $args['schedule'], $schedule );
|
175 |
+
}
|
176 |
+
|
177 |
+
return $args;
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Get the notification config.
|
182 |
+
*
|
183 |
+
* @param string $slug
|
184 |
+
*
|
185 |
+
* @return array|null
|
186 |
+
*/
|
187 |
+
public function get_notification( $slug ) {
|
188 |
+
$notifications = $this->get_notifications();
|
189 |
+
|
190 |
+
return isset( $notifications[ $slug ] ) ? $notifications[ $slug ] : null;
|
191 |
+
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Get strings for a notification.
|
195 |
+
*
|
196 |
+
* @param string $slug
|
197 |
+
*
|
198 |
+
* @return array
|
199 |
+
*/
|
200 |
+
public function get_notification_strings( $slug ) {
|
201 |
+
|
202 |
+
if ( ! isset( $this->strings[ $slug ] ) ) {
|
203 |
+
$this->strings[ $slug ] = apply_filters( "itsec_{$slug}_notification_strings", array() );
|
204 |
+
}
|
205 |
+
|
206 |
+
return $this->strings[ $slug ];
|
207 |
+
}
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Get the configured subject for a notification.
|
211 |
+
*
|
212 |
+
* @param string $notification
|
213 |
+
*
|
214 |
+
* @return string
|
215 |
+
*/
|
216 |
+
public function get_subject( $notification ) {
|
217 |
+
|
218 |
+
$config = $this->get_notification( $notification );
|
219 |
+
|
220 |
+
if ( ! $config ) {
|
221 |
+
return '';
|
222 |
+
}
|
223 |
+
|
224 |
+
$settings = $this->get_notification_settings( $notification );
|
225 |
+
|
226 |
+
if ( ! empty( $config['subject_editable'] ) && ! empty( $settings['subject'] ) ) {
|
227 |
+
return $settings['subject'];
|
228 |
+
}
|
229 |
+
|
230 |
+
$strings = $this->get_notification_strings( $notification );
|
231 |
+
|
232 |
+
return isset( $strings['subject'] ) ? $strings['subject'] : '';
|
233 |
+
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Get the configured main message for a notification.
|
237 |
+
*
|
238 |
+
* @param string $notification
|
239 |
+
* @param string $format Either 'raw' or 'display'. If 'display', the message will have wpautop. Defaults to 'display'.
|
240 |
+
*
|
241 |
+
* @return string
|
242 |
+
*/
|
243 |
+
public function get_message( $notification, $format = 'display' ) {
|
244 |
+
|
245 |
+
$config = $this->get_notification( $notification );
|
246 |
+
|
247 |
+
if ( ! $config ) {
|
248 |
+
return '';
|
249 |
+
}
|
250 |
+
|
251 |
+
$settings = $this->get_notification_settings( $notification );
|
252 |
+
|
253 |
+
if ( ! empty( $config['message_editable'] ) && ! empty( $settings['message'] ) ) {
|
254 |
+
return 'display' === $format ? wpautop( $settings['message'] ) : $settings['message'];
|
255 |
+
}
|
256 |
+
|
257 |
+
$strings = $this->get_notification_strings( $notification );
|
258 |
+
|
259 |
+
if ( isset( $strings['message'] ) ) {
|
260 |
+
return 'display' === $format ? wpautop( $strings['message'] ) : $strings['message'];
|
261 |
+
}
|
262 |
+
|
263 |
+
return '';
|
264 |
+
}
|
265 |
+
|
266 |
+
/**
|
267 |
+
* Get the selected schedule for a notification.
|
268 |
+
*
|
269 |
+
* @param string $notification
|
270 |
+
*
|
271 |
+
* @return string
|
272 |
+
*/
|
273 |
+
public function get_schedule( $notification ) {
|
274 |
+
|
275 |
+
$config = $this->get_notification( $notification );
|
276 |
+
|
277 |
+
if ( ! $config ) {
|
278 |
+
return self::S_NONE;
|
279 |
+
}
|
280 |
+
|
281 |
+
if ( self::S_CONFIGURABLE !== $config['schedule'] && ! is_array( $config['schedule'] ) ) {
|
282 |
+
return $config['schedule'];
|
283 |
+
}
|
284 |
+
|
285 |
+
$settings = $this->get_notification_settings( $notification );
|
286 |
+
|
287 |
+
if ( ! empty( $settings['schedule'] ) ) {
|
288 |
+
return $settings['schedule'];
|
289 |
+
}
|
290 |
+
|
291 |
+
return $config['schedule']['min'];
|
292 |
+
}
|
293 |
+
|
294 |
+
/**
|
295 |
+
* Get the email addresses a notification should be sent to.
|
296 |
+
*
|
297 |
+
* @param string $notification
|
298 |
+
*
|
299 |
+
* @return string[]
|
300 |
+
*/
|
301 |
+
public function get_recipients( $notification ) {
|
302 |
+
|
303 |
+
$config = $this->get_notification( $notification );
|
304 |
+
|
305 |
+
if ( self::R_ADMIN === $config['recipient'] ) {
|
306 |
+
return array( get_option( 'admin_email' ) );
|
307 |
+
}
|
308 |
+
|
309 |
+
if ( self::R_EMAIL_LIST === $config['recipient'] ) {
|
310 |
+
$settings = $this->get_notification_settings( $notification );
|
311 |
+
|
312 |
+
return ! empty( $settings['email_list'] ) ? $settings['email_list'] : array();
|
313 |
+
}
|
314 |
+
|
315 |
+
if ( self::R_USER_LIST !== $config['recipient'] && self::R_USER_LIST_ADMIN_UPGRADE !== $config['recipient'] ) {
|
316 |
+
return array();
|
317 |
+
}
|
318 |
+
|
319 |
+
$settings = $this->get_notification_settings( $notification );
|
320 |
+
$contacts = $settings['user_list'];
|
321 |
+
|
322 |
+
$addresses = array();
|
323 |
+
|
324 |
+
foreach ( $contacts as $contact ) {
|
325 |
+
if ( (string) $contact === (string) intval( $contact ) ) {
|
326 |
+
$users = array( get_userdata( $contact ) );
|
327 |
+
} else {
|
328 |
+
list( $prefix, $role ) = explode( ':', $contact, 2 );
|
329 |
+
|
330 |
+
if ( empty( $role ) ) {
|
331 |
+
continue;
|
332 |
+
}
|
333 |
+
|
334 |
+
$users = get_users( array( 'role' => $role ) );
|
335 |
+
}
|
336 |
+
|
337 |
+
foreach ( $users as $user ) {
|
338 |
+
if ( is_object( $user ) && ! empty( $user->user_email ) ) {
|
339 |
+
$addresses[] = $user->user_email;
|
340 |
+
}
|
341 |
+
}
|
342 |
+
}
|
343 |
+
|
344 |
+
if ( self::R_USER_LIST_ADMIN_UPGRADE === $config['recipient'] && ! empty( $settings['previous_emails'] ) ) {
|
345 |
+
$addresses = array_merge( $addresses, $settings['previous_emails'] );
|
346 |
+
}
|
347 |
+
|
348 |
+
return array_unique( $addresses );
|
349 |
+
}
|
350 |
+
|
351 |
+
/**
|
352 |
+
* Get the time the notification was last sent.
|
353 |
+
*
|
354 |
+
* @param string $notification
|
355 |
+
*
|
356 |
+
* @return int
|
357 |
+
*/
|
358 |
+
public function get_last_sent( $notification ) {
|
359 |
+
$last_sent = $this->get_all_last_sent();
|
360 |
+
|
361 |
+
return isset( $last_sent[ $notification ] ) ? $last_sent[ $notification ] : 0;
|
362 |
+
}
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Get the time that the notification should next be sent.
|
366 |
+
*
|
367 |
+
* @param string $notification The notification slug.
|
368 |
+
*
|
369 |
+
* @return int|false False if invalid notification or invalid notification schedule. Unix time otherwise.
|
370 |
+
*/
|
371 |
+
public function get_next_send_time( $notification ) {
|
372 |
+
return $this->calculate_next_send_time( $notification, $this->get_last_sent( $notification ) );
|
373 |
+
}
|
374 |
+
|
375 |
+
/**
|
376 |
+
* Enqueue some data a scheduled notification should have access to when sending.
|
377 |
+
*
|
378 |
+
* @param string $notification
|
379 |
+
* @param mixed $data
|
380 |
+
* @param bool $enforce_unique Whether to enforce all the data for that notification is unique. Only set to false if you are sure data is already unique.
|
381 |
+
*/
|
382 |
+
public function enqueue_data( $notification, $data, $enforce_unique = true ) {
|
383 |
+
$all_data = ITSEC_Modules::get_setting( 'notification-center', 'data' );
|
384 |
+
|
385 |
+
$notification_data = isset( $all_data[ $notification ] ) ? $all_data[ $notification ] : array();
|
386 |
+
$notification_data[] = $data;
|
387 |
+
|
388 |
+
if ( $enforce_unique ) {
|
389 |
+
$notification_data = array_unique( $notification_data );
|
390 |
+
}
|
391 |
+
|
392 |
+
$all_data[ $notification ] = $notification_data;
|
393 |
+
|
394 |
+
ITSEC_Modules::set_setting( 'notification-center', 'data', $all_data );
|
395 |
+
}
|
396 |
+
|
397 |
+
/**
|
398 |
+
* Get the data for a notification.
|
399 |
+
*
|
400 |
+
* @param string $notification
|
401 |
+
*
|
402 |
+
* @return array
|
403 |
+
*/
|
404 |
+
public function get_data( $notification ) {
|
405 |
+
|
406 |
+
$all_data = ITSEC_Modules::get_setting( 'notification-center', 'data' );
|
407 |
+
|
408 |
+
return isset( $all_data[ $notification ] ) ? $all_data[ $notification ] : array();
|
409 |
+
}
|
410 |
+
|
411 |
+
/**
|
412 |
+
* Initialize a Mail instance.
|
413 |
+
*
|
414 |
+
* @return ITSEC_Mail
|
415 |
+
*/
|
416 |
+
public function mail() {
|
417 |
+
require_once( ITSEC_Core::get_core_dir() . 'lib/class-itsec-mail.php' );
|
418 |
+
|
419 |
+
return new ITSEC_Mail();
|
420 |
+
}
|
421 |
+
|
422 |
+
/**
|
423 |
+
* Send an email.
|
424 |
+
*
|
425 |
+
* This will set the subject and recipients configured for the notification if they have not been set.
|
426 |
+
*
|
427 |
+
* Additionally, will log any errors encountered while sending.
|
428 |
+
*
|
429 |
+
* @param string $notification
|
430 |
+
* @param ITSEC_Mail $mail
|
431 |
+
*
|
432 |
+
* @return bool
|
433 |
+
*/
|
434 |
+
public function send( $notification, $mail ) {
|
435 |
+
|
436 |
+
if ( ! $mail->get_subject() ) {
|
437 |
+
$mail->set_subject( $this->get_subject( $notification ) );
|
438 |
+
}
|
439 |
+
|
440 |
+
if ( ! $mail->get_recipients() ) {
|
441 |
+
$mail->set_recipients( $this->get_recipients( $notification ) );
|
442 |
+
}
|
443 |
+
|
444 |
+
add_action( 'wp_mail_failed', array( $this, 'capture_mail_fail' ) );
|
445 |
+
|
446 |
+
$this->_sending_notification = $notification;
|
447 |
+
$result = $mail->send();
|
448 |
+
$this->_sending_notification = '';
|
449 |
+
|
450 |
+
remove_action( 'wp_mail_failed', array( $this, 'capture_mail_fail' ) );
|
451 |
+
|
452 |
+
return $result;
|
453 |
+
}
|
454 |
+
|
455 |
+
/**
|
456 |
+
* Dismiss an error encountered while sending a notification with wp_mail().
|
457 |
+
*
|
458 |
+
* @param string $error_id
|
459 |
+
*/
|
460 |
+
public function dismiss_mail_error( $error_id ) {
|
461 |
+
$errors = ITSEC_Modules::get_setting( 'notification-center', 'mail_errors', array() );
|
462 |
+
unset( $errors[ $error_id ] );
|
463 |
+
ITSEC_Modules::set_setting( 'notification-center', 'mail_errors', $errors );
|
464 |
+
}
|
465 |
+
|
466 |
+
/**
|
467 |
+
* Get the loggged mail errors keyed by id.
|
468 |
+
*
|
469 |
+
* @return array
|
470 |
+
*/
|
471 |
+
public function get_mail_errors() {
|
472 |
+
return ITSEC_Modules::get_setting( 'notification-center', 'mail_errors', array() );
|
473 |
+
}
|
474 |
+
|
475 |
+
/**
|
476 |
+
* Initialize the module.
|
477 |
+
*/
|
478 |
+
public function run() {
|
479 |
+
add_action( 'itsec_change_admin_user_id', array( $this, 'update_notification_user_id_on_admin_change' ) );
|
480 |
+
add_action( 'itsec_module_settings_after_title', array( $this, 'display_notification_center_link_for_module' ) );
|
481 |
+
$this->setup_scheduling();
|
482 |
+
}
|
483 |
+
|
484 |
+
/**
|
485 |
+
* Capture whenever an error occurs in wp_mail() while sending a notification so it can be displayed later in the Notification Center.
|
486 |
+
*
|
487 |
+
* @param WP_Error $error
|
488 |
+
*/
|
489 |
+
public function capture_mail_fail( $error ) {
|
490 |
+
|
491 |
+
$errors = ITSEC_Modules::get_setting( 'notification-center', 'mail_errors', array() );
|
492 |
+
|
493 |
+
$errors[ uniqid() ] = array(
|
494 |
+
'error' => array( 'message' => $error->get_error_message(), 'code' => $error->get_error_code() ),
|
495 |
+
'time' => ITSEC_Core::get_current_time_gmt(),
|
496 |
+
'notification' => $this->_sending_notification,
|
497 |
+
);
|
498 |
+
|
499 |
+
ITSEC_Modules::set_setting( 'notification-center', 'mail_errors', $errors );
|
500 |
+
|
501 |
+
if ( ITSEC_Core::is_interactive() ) {
|
502 |
+
ITSEC_Response::reload_module( 'notification-center' );
|
503 |
+
}
|
504 |
+
}
|
505 |
+
|
506 |
+
/**
|
507 |
+
* Update the notification settings when the admin user id changes.
|
508 |
+
*
|
509 |
+
* @since 4.1.0
|
510 |
+
*
|
511 |
+
* @param int $new_user_id
|
512 |
+
*/
|
513 |
+
public function update_notification_user_id_on_admin_change( $new_user_id ) {
|
514 |
+
|
515 |
+
$settings = ITSEC_Modules::get_settings_obj( 'notification-center' );
|
516 |
+
$notifications = $settings->get( 'notifications' );
|
517 |
+
|
518 |
+
if ( empty( $notifications ) ) {
|
519 |
+
return;
|
520 |
+
}
|
521 |
+
|
522 |
+
$changed = false;
|
523 |
+
|
524 |
+
foreach ( $notifications as $slug => $notification ) {
|
525 |
+
|
526 |
+
if ( empty( $notification['user_list'] ) ) {
|
527 |
+
continue;
|
528 |
+
}
|
529 |
+
|
530 |
+
$user_list = $notification['user_list'];
|
531 |
+
|
532 |
+
foreach ( $user_list as $i => $contact ) {
|
533 |
+
if ( is_numeric( $contact ) && 1 === (int) $contact ) {
|
534 |
+
$notifications[ $slug ]['user_list'][ $i ] = $new_user_id;
|
535 |
+
|
536 |
+
$changed = true;
|
537 |
+
break;
|
538 |
+
}
|
539 |
+
}
|
540 |
+
}
|
541 |
+
|
542 |
+
if ( $changed ) {
|
543 |
+
$settings->set( 'notifications', $notifications );
|
544 |
+
}
|
545 |
+
}
|
546 |
+
|
547 |
+
/**
|
548 |
+
* Display a link to the notification center for any modules that have an associated notification.
|
549 |
+
*
|
550 |
+
* @param string $module_slug
|
551 |
+
*/
|
552 |
+
public function display_notification_center_link_for_module( $module_slug ) {
|
553 |
+
|
554 |
+
$display = false;
|
555 |
+
|
556 |
+
foreach ( $this->get_notifications() as $slug => $notification ) {
|
557 |
+
if ( $module_slug === $notification['module'] ) {
|
558 |
+
$display = $slug;
|
559 |
+
break;
|
560 |
+
}
|
561 |
+
}
|
562 |
+
|
563 |
+
if ( $display ) {
|
564 |
+
$href = esc_attr( "#itsec-notification-center-notification-settings--{$display}" );
|
565 |
+
echo '<a href="' . $href .'" class="itsec-notification-center-link" data-module-link="notification-center">' . esc_html__( 'Notification Center', 'better-wp-security' ) . '</a>';
|
566 |
+
}
|
567 |
+
}
|
568 |
+
|
569 |
+
/**
|
570 |
+
* Setup scheduling actions.
|
571 |
+
*/
|
572 |
+
private function setup_scheduling() {
|
573 |
+
if ( $this->use_cron ) {
|
574 |
+
if ( ! wp_next_scheduled( self::CRON_ACTION ) ) {
|
575 |
+
wp_schedule_event( time(), 'daily', self::CRON_ACTION );
|
576 |
+
}
|
577 |
+
|
578 |
+
// We can afford the more expensive check when running cron.
|
579 |
+
add_action( self::CRON_ACTION, array( $this, 'check_notification_schedule_accurate' ) );
|
580 |
+
} else {
|
581 |
+
add_action( 'init', array( $this, 'check_notification_schedule_fast' ), 20 );
|
582 |
+
}
|
583 |
+
}
|
584 |
+
|
585 |
+
/**
|
586 |
+
* This runs on every page load, so we only use the cached last sent options and don't get a lock unless we think some notifications
|
587 |
+
* need to be run.
|
588 |
+
*
|
589 |
+
* @return array|WP_Error
|
590 |
+
*/
|
591 |
+
public function check_notification_schedule_fast() {
|
592 |
+
|
593 |
+
$last_sent = $this->get_all_last_sent();
|
594 |
+
$resend_at = $this->get_all_resend_at();
|
595 |
+
$to_send = array();
|
596 |
+
|
597 |
+
foreach ( $this->get_enabled_notifications() as $slug => $notification ) {
|
598 |
+
|
599 |
+
$time = $resend_at[ $slug ] > $last_sent[ $slug ] ? $resend_at[ $slug ] : $last_sent[ $slug ];
|
600 |
+
|
601 |
+
if ( $this->is_time_to_send_notification( $slug, $time ) ) {
|
602 |
+
$to_send[ $slug ] = $notification;
|
603 |
+
}
|
604 |
+
}
|
605 |
+
|
606 |
+
if ( $to_send ) {
|
607 |
+
return $this->check_notification_schedule_accurate( $to_send );
|
608 |
+
}
|
609 |
+
|
610 |
+
return array();
|
611 |
+
}
|
612 |
+
|
613 |
+
/**
|
614 |
+
* This checks against the uncached last sent times.
|
615 |
+
*
|
616 |
+
* @param array[] $notifications Notifications to check. Leave empty to check against all.
|
617 |
+
*
|
618 |
+
* @return array|WP_Error
|
619 |
+
*/
|
620 |
+
public function check_notification_schedule_accurate( $notifications = array() ) {
|
621 |
+
|
622 |
+
$notifications = $notifications && is_array( $notifications ) ? $notifications : $this->get_enabled_notifications();
|
623 |
+
|
624 |
+
if ( ! ITSEC_Lib::get_lock( 'notification-center', 120 ) ) {
|
625 |
+
return new WP_Error( 'itsec-notification-center-cannot-get-lock', esc_html__( 'Cannot get lock.', 'better-wp-security' ) );
|
626 |
+
}
|
627 |
+
|
628 |
+
$last_sent = $this->get_all_last_sent_uncached();
|
629 |
+
$resend_at = $this->get_all_resend_at_uncached();
|
630 |
+
$to_send = array();
|
631 |
+
|
632 |
+
foreach ( $notifications as $slug => $notification ) {
|
633 |
+
$time = $resend_at[ $slug ] > $last_sent[ $slug ] ? $resend_at[ $slug ] : $last_sent[ $slug ];
|
634 |
+
|
635 |
+
if ( $this->is_time_to_send_notification( $slug, $time ) ) {
|
636 |
+
$to_send[] = $slug;
|
637 |
+
}
|
638 |
+
}
|
639 |
+
|
640 |
+
$ret = array();
|
641 |
+
|
642 |
+
if ( $to_send ) {
|
643 |
+
$ret = $this->send_scheduled_notifications( $to_send );
|
644 |
+
}
|
645 |
+
|
646 |
+
ITSEC_Lib::release_lock( 'notification-center' );
|
647 |
+
|
648 |
+
return $ret;
|
649 |
+
}
|
650 |
+
|
651 |
+
/**
|
652 |
+
* Send scheduled notifications.
|
653 |
+
*
|
654 |
+
* @param string[] $notification_slugs The notification slugs to send.
|
655 |
+
* @param bool $silent If true, will not update last sent times or destroy data. Defaults to false.
|
656 |
+
*
|
657 |
+
* @return array Notification slugs keyed to send success.
|
658 |
+
*/
|
659 |
+
public function send_scheduled_notifications( $notification_slugs, $silent = false ) {
|
660 |
+
|
661 |
+
@set_time_limit( 120 );
|
662 |
+
$sent = array();
|
663 |
+
|
664 |
+
foreach ( $notification_slugs as $notification_slug ) {
|
665 |
+
$sent[ $notification_slug ] = $this->send_scheduled_notification( $notification_slug );
|
666 |
+
}
|
667 |
+
|
668 |
+
if ( $silent ) {
|
669 |
+
return $sent;
|
670 |
+
}
|
671 |
+
|
672 |
+
$settings = ITSEC_Modules::get_settings( 'notification-center' );
|
673 |
+
|
674 |
+
foreach ( $notification_slugs as $slug ) {
|
675 |
+
|
676 |
+
// Only clear queued data if the notification was actually able to be sent.
|
677 |
+
if ( ! empty( $sent[ $slug ] ) ) {
|
678 |
+
$settings['data'][ $slug ] = array();
|
679 |
+
$settings['last_sent'][ $slug ] = ITSEC_Core::get_current_time_gmt();
|
680 |
+
} else {
|
681 |
+
// Retry sending the notification in 6 hours.
|
682 |
+
$settings['resend_at'][ $slug ] = ITSEC_Core::get_current_time_gmt() + 6 * HOUR_IN_SECONDS;
|
683 |
+
}
|
684 |
+
}
|
685 |
+
|
686 |
+
ITSEC_Modules::set_settings( 'notification-center', $settings );
|
687 |
+
ITSEC_Storage::save();
|
688 |
+
|
689 |
+
return $sent;
|
690 |
+
}
|
691 |
+
|
692 |
+
/**
|
693 |
+
* Send a scheduled notification.
|
694 |
+
*
|
695 |
+
* @param string $slug
|
696 |
+
*
|
697 |
+
* @return bool
|
698 |
+
*/
|
699 |
+
private function send_scheduled_notification( $slug ) {
|
700 |
+
|
701 |
+
$last_sent = $this->get_last_sent( $slug );
|
702 |
+
$data = $this->get_data( $slug );
|
703 |
+
|
704 |
+
if ( ! has_filter( "itsec_send_notification_{$slug}" ) ) {
|
705 |
+
return $this->default_send( $slug, $last_sent, $data );
|
706 |
+
}
|
707 |
+
|
708 |
+
/**
|
709 |
+
* Fire an action to send the requested notification.
|
710 |
+
*
|
711 |
+
* @param bool $sent Whether the notification has been successfully sent.
|
712 |
+
* @param int $last_sent The time this notification was last sent to the user.
|
713 |
+
* @param array $data Queued data.
|
714 |
+
*/
|
715 |
+
return apply_filters( "itsec_send_notification_{$slug}", false, $last_sent, $data );
|
716 |
+
}
|
717 |
+
|
718 |
+
/**
|
719 |
+
* Default schedule notification handler.
|
720 |
+
*
|
721 |
+
* @param string $notification
|
722 |
+
* @param int $last_sent
|
723 |
+
* @param array $data
|
724 |
+
*
|
725 |
+
* @return bool
|
726 |
+
*/
|
727 |
+
private function default_send( $notification, $last_sent, $data ) {
|
728 |
+
|
729 |
+
$config = $this->get_notification( $notification );
|
730 |
+
|
731 |
+
$mail = $this->mail();
|
732 |
+
|
733 |
+
if ( ! isset( $config['template'] ) ) {
|
734 |
+
$mail->add_header( $this->get_subject( $notification ), '' );
|
735 |
+
$mail->add_text( $this->get_message( $notification ) );
|
736 |
+
$mail->add_footer();
|
737 |
+
} elseif ( $data ) {
|
738 |
+
foreach ( $config['template'] as $part ) {
|
739 |
+
$this->render_template_part( $mail, $data, $part );
|
740 |
+
}
|
741 |
+
} else {
|
742 |
+
return true;
|
743 |
+
}
|
744 |
+
|
745 |
+
$this->replace_computed_tags( $mail, $last_sent, $config );
|
746 |
+
|
747 |
+
return $this->send( $notification, $mail );
|
748 |
+
}
|
749 |
+
|
750 |
+
/**
|
751 |
+
* Render a template part.
|
752 |
+
*
|
753 |
+
* @param ITSEC_Mail $mail
|
754 |
+
* @param array[] $data
|
755 |
+
* @param array $part
|
756 |
+
*/
|
757 |
+
private function render_template_part( $mail, $data, $part ) {
|
758 |
+
|
759 |
+
if ( empty( $part ) || ! is_array( $part ) || empty( $part[0] ) ) {
|
760 |
+
return;
|
761 |
+
}
|
762 |
+
|
763 |
+
switch ( $part[0] ) {
|
764 |
+
case 'header':
|
765 |
+
$func = 'add_header';
|
766 |
+
break;
|
767 |
+
case 'footer':
|
768 |
+
$func = 'add_footer';
|
769 |
+
break;
|
770 |
+
case 'table':
|
771 |
+
|
772 |
+
if ( ! isset( $part[1], $part[2] ) ) {
|
773 |
+
return;
|
774 |
+
}
|
775 |
+
|
776 |
+
$paths = $part[2];
|
777 |
+
$columns = array();
|
778 |
+
|
779 |
+
foreach ( $paths as $path ) {
|
780 |
+
$resolved = $this->resolve_data_path( $data, $path );
|
781 |
+
|
782 |
+
if ( $resolved === false ) {
|
783 |
+
$columns[] = array_fill( 0, count( $data ), $path );
|
784 |
+
} else {
|
785 |
+
$columns[] = $resolved;
|
786 |
+
}
|
787 |
+
}
|
788 |
+
|
789 |
+
$rows = self::flip_2d_array( $columns );
|
790 |
+
$mail->add_table( $part[1], $rows );
|
791 |
+
|
792 |
+
return;
|
793 |
+
default:
|
794 |
+
return;
|
795 |
+
|
796 |
+
}
|
797 |
+
|
798 |
+
$args = array_slice( $part, 1 );
|
799 |
+
call_user_func_array( array( $mail, $func ), $args );
|
800 |
+
}
|
801 |
+
|
802 |
+
/**
|
803 |
+
* Replace the computed tags.
|
804 |
+
*
|
805 |
+
* @param ITSEC_Mail $mail
|
806 |
+
* @param int $last_sent
|
807 |
+
* @param array $config
|
808 |
+
*/
|
809 |
+
private function replace_computed_tags( $mail, $last_sent, $config ) {
|
810 |
+
|
811 |
+
$df = get_option( 'date_format' );
|
812 |
+
|
813 |
+
if ( self::S_DAILY === $config['schedule'] ) {
|
814 |
+
$_period = ITSEC_Lib::date_format_i18n_and_local_timezone( ITSEC_Core::get_current_time_gmt(), $df );
|
815 |
+
} else {
|
816 |
+
$_period = sprintf(
|
817 |
+
'%s - %s',
|
818 |
+
ITSEC_Lib::date_format_i18n_and_local_timezone( $last_sent, $df ),
|
819 |
+
ITSEC_Lib::date_format_i18n_and_local_timezone( ITSEC_Core::get_current_time_gmt(), $df )
|
820 |
+
);
|
821 |
+
}
|
822 |
+
|
823 |
+
$tags = compact( '_period' );
|
824 |
+
|
825 |
+
$mail->set_content( ITSEC_Lib::replace_tags( $mail->get_content(), $tags ) );
|
826 |
+
}
|
827 |
+
|
828 |
+
/**
|
829 |
+
* Resolve a data path from stored data.
|
830 |
+
*
|
831 |
+
* @param array $data
|
832 |
+
* @param string $path
|
833 |
+
*
|
834 |
+
* @return array|false
|
835 |
+
*/
|
836 |
+
private function resolve_data_path( $data, $path ) {
|
837 |
+
|
838 |
+
if ( strpos( $path, ':data' ) !== 0 ) {
|
839 |
+
return false;
|
840 |
+
}
|
841 |
+
|
842 |
+
$path = substr( $path, 6 );
|
843 |
+
$values = array();
|
844 |
+
|
845 |
+
foreach ( $data as $entry ) {
|
846 |
+
$values[] = ITSEC_Lib::array_get( $entry, $path );
|
847 |
+
}
|
848 |
+
|
849 |
+
return $values;
|
850 |
+
}
|
851 |
+
|
852 |
+
/**
|
853 |
+
* Check if enough time has elapsed for a scheduled notification to be sent.
|
854 |
+
*
|
855 |
+
* @param string $notification Notification slug.
|
856 |
+
* @param int $last_sent
|
857 |
+
*
|
858 |
+
* @return bool False if not time, the notification isn't scheduled, or it has an unknown period.
|
859 |
+
*/
|
860 |
+
private function is_time_to_send_notification( $notification, $last_sent ) {
|
861 |
+
|
862 |
+
$next = $this->calculate_next_send_time( $notification, $last_sent );
|
863 |
+
|
864 |
+
return $next && $next < ITSEC_Core::get_current_time_gmt();
|
865 |
+
}
|
866 |
+
|
867 |
+
/**
|
868 |
+
* Calculate the next time a notification should be sent.
|
869 |
+
*
|
870 |
+
* @param string $notification The notification slug.
|
871 |
+
* @param int $last_sent Time to calculate from.
|
872 |
+
*
|
873 |
+
* @return int|false
|
874 |
+
*/
|
875 |
+
private function calculate_next_send_time( $notification, $last_sent ) {
|
876 |
+
$schedule = $this->get_schedule( $notification );
|
877 |
+
|
878 |
+
if ( self::S_NONE === $schedule ) {
|
879 |
+
return false; // This is an on-demand
|
880 |
+
}
|
881 |
+
|
882 |
+
switch ( $schedule ) {
|
883 |
+
case self::S_DAILY:
|
884 |
+
$period = DAY_IN_SECONDS;
|
885 |
+
break;
|
886 |
+
case self::S_WEEKLY:
|
887 |
+
$period = WEEK_IN_SECONDS;
|
888 |
+
break;
|
889 |
+
case self::S_MONTHLY:
|
890 |
+
$period = MONTH_IN_SECONDS;
|
891 |
+
break;
|
892 |
+
default:
|
893 |
+
return false;
|
894 |
+
}
|
895 |
+
|
896 |
+
return $last_sent + $period;
|
897 |
+
}
|
898 |
+
|
899 |
+
/**
|
900 |
+
* Get the settings for a notification.
|
901 |
+
*
|
902 |
+
* @param string $notification
|
903 |
+
*
|
904 |
+
* @return array|null
|
905 |
+
*/
|
906 |
+
private function get_notification_settings( $notification ) {
|
907 |
+
$settings = ITSEC_Modules::get_setting( 'notification-center', 'notifications' );
|
908 |
+
|
909 |
+
return isset( $settings[ $notification ] ) ? $settings[ $notification ] : null;
|
910 |
+
}
|
911 |
+
|
912 |
+
/**
|
913 |
+
* Get the cached value that all notifications have last been sent.
|
914 |
+
*
|
915 |
+
* @return int[]
|
916 |
+
*/
|
917 |
+
private function get_all_last_sent() {
|
918 |
+
|
919 |
+
$last_sent = ITSEC_Modules::get_setting( 'notification-center', 'last_sent' );
|
920 |
+
|
921 |
+
if ( ! is_array( $last_sent ) || empty( $last_sent ) ) {
|
922 |
+
return $this->fill_last_sent();
|
923 |
+
}
|
924 |
+
|
925 |
+
return $this->fill_last_sent( $last_sent );
|
926 |
+
}
|
927 |
+
|
928 |
+
/**
|
929 |
+
* Get the time scheduled notifications were last sent directly from the database.
|
930 |
+
*
|
931 |
+
* @return int[]
|
932 |
+
*/
|
933 |
+
private function get_all_last_sent_uncached() {
|
934 |
+
|
935 |
+
$storage = $this->get_uncached_options();
|
936 |
+
|
937 |
+
if ( isset( $storage['last_sent'] ) ) {
|
938 |
+
$last_sent = $storage['last_sent'];
|
939 |
+
|
940 |
+
if ( count( $last_sent ) === count( $this->get_notifications() ) ) {
|
941 |
+
return $last_sent;
|
942 |
+
}
|
943 |
+
|
944 |
+
return $this->fill_last_sent( $last_sent );
|
945 |
+
}
|
946 |
+
|
947 |
+
return $this->fill_last_sent();
|
948 |
+
}
|
949 |
+
|
950 |
+
/**
|
951 |
+
* Fill the last sent array with the time the plugin was activated for notifications that haven't been sent yet.
|
952 |
+
*
|
953 |
+
* @param array $last_sent
|
954 |
+
*
|
955 |
+
* @return array
|
956 |
+
*/
|
957 |
+
private function fill_last_sent( $last_sent = array() ) {
|
958 |
+
$activated = ITSEC_Modules::get_setting( 'global', 'activation_timestamp' );
|
959 |
+
|
960 |
+
if ( $last_sent ) {
|
961 |
+
return array_merge( array_fill_keys( array_keys( $this->get_notifications() ), $activated ), $last_sent );
|
962 |
+
}
|
963 |
+
|
964 |
+
return array_fill_keys( array_keys( $this->get_notifications() ), $activated );
|
965 |
+
}
|
966 |
+
|
967 |
+
/**
|
968 |
+
* Get the cached value that all notification should be resent at.
|
969 |
+
*
|
970 |
+
* @return int[]
|
971 |
+
*/
|
972 |
+
private function get_all_resend_at() {
|
973 |
+
|
974 |
+
$resend_at = ITSEC_Modules::get_setting( 'notification-center', 'resend_at' );
|
975 |
+
|
976 |
+
if ( ! is_array( $resend_at ) || empty( $resend_at ) ) {
|
977 |
+
$resend_at = array();
|
978 |
+
}
|
979 |
+
|
980 |
+
return array_merge( array_fill_keys( array_keys( $this->get_notifications() ), 0 ), $resend_at );
|
981 |
+
}
|
982 |
+
|
983 |
+
/**
|
984 |
+
* Get the time scheduled notifications are scheduled to be resent at.
|
985 |
+
*
|
986 |
+
* @return int[]
|
987 |
+
*/
|
988 |
+
private function get_all_resend_at_uncached() {
|
989 |
+
|
990 |
+
$storage = $this->get_uncached_options();
|
991 |
+
|
992 |
+
if ( isset( $storage['resend_at'] ) ) {
|
993 |
+
$resend_at = $storage['resend_at'];
|
994 |
+
|
995 |
+
if ( count( $resend_at ) === count( $this->get_notifications() ) ) {
|
996 |
+
return $resend_at;
|
997 |
+
}
|
998 |
+
|
999 |
+
return array_merge( array_fill_keys( array_keys( $this->get_notifications() ), 0 ), $resend_at );
|
1000 |
+
}
|
1001 |
+
|
1002 |
+
return array_fill_keys( array_keys( $this->get_notifications() ), 0 );
|
1003 |
+
}
|
1004 |
+
|
1005 |
+
/**
|
1006 |
+
* Get the uncached options storage.
|
1007 |
+
*
|
1008 |
+
* @return array
|
1009 |
+
*/
|
1010 |
+
private function get_uncached_options() {
|
1011 |
+
/** @var $wpdb \wpdb */
|
1012 |
+
global $wpdb;
|
1013 |
+
|
1014 |
+
$option = 'itsec-storage';
|
1015 |
+
$storage = array();
|
1016 |
+
|
1017 |
+
if ( is_multisite() ) {
|
1018 |
+
$network_id = get_current_site()->id;
|
1019 |
+
$row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
|
1020 |
+
|
1021 |
+
if ( is_object( $row ) ) {
|
1022 |
+
$storage = maybe_unserialize( $row->meta_value );
|
1023 |
+
}
|
1024 |
+
} else {
|
1025 |
+
$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
|
1026 |
+
|
1027 |
+
if ( is_object( $row ) ) {
|
1028 |
+
$storage = maybe_unserialize( $row->option_value );
|
1029 |
+
}
|
1030 |
+
}
|
1031 |
+
|
1032 |
+
if ( ! isset( $storage['notification-center'] ) ) {
|
1033 |
+
return array();
|
1034 |
+
}
|
1035 |
+
|
1036 |
+
return $storage['notification-center'];
|
1037 |
+
}
|
1038 |
+
|
1039 |
+
/**
|
1040 |
+
* Get labels for the different schedule options.
|
1041 |
+
*
|
1042 |
+
* @return array
|
1043 |
+
*/
|
1044 |
+
public static function get_schedule_labels() {
|
1045 |
+
return array(
|
1046 |
+
self::S_DAILY => esc_html__( 'Daily', 'better-wp-security' ),
|
1047 |
+
self::S_WEEKLY => esc_html__( 'Weekly', 'better-wp-security' ),
|
1048 |
+
self::S_MONTHLY => esc_html__( 'Monthly', 'better-wp-security' ),
|
1049 |
+
);
|
1050 |
+
}
|
1051 |
+
|
1052 |
+
/**
|
1053 |
+
* Get the order of schedules from smallest to largest.
|
1054 |
+
*
|
1055 |
+
* @return array
|
1056 |
+
*/
|
1057 |
+
public static function get_schedule_order() {
|
1058 |
+
return array( self::S_DAILY, self::S_WEEKLY, self::S_MONTHLY );
|
1059 |
+
}
|
1060 |
+
|
1061 |
+
/**
|
1062 |
+
* Flip a 2-dimensional array.
|
1063 |
+
*
|
1064 |
+
* @param array $array
|
1065 |
+
*
|
1066 |
+
* @return array
|
1067 |
+
*/
|
1068 |
+
private static function flip_2d_array( $array ) {
|
1069 |
+
$out = array();
|
1070 |
+
|
1071 |
+
foreach ( $array as $row => $columns ) {
|
1072 |
+
foreach ( $columns as $new_row => $new_column ) {
|
1073 |
+
$out[ $new_row ][ $row ] = $new_column;
|
1074 |
+
}
|
1075 |
+
}
|
1076 |
+
|
1077 |
+
return $out;
|
1078 |
+
}
|
1079 |
+
}
|
core/modules/notification-center/css/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden.
|
core/modules/notification-center/css/settings-page.css
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.itsec-email-contacts-setting ul {
|
2 |
+
margin: 1em 0;
|
3 |
+
padding-left: 0;
|
4 |
+
}
|
5 |
+
|
6 |
+
.itsec-email-contacts-setting ul + ul,
|
7 |
+
.itsec-notification-center--deprecated-recipients {
|
8 |
+
padding-top: 1em;
|
9 |
+
border-top: 1px solid #ddd;
|
10 |
+
}
|
11 |
+
|
12 |
+
.itsec-email-contacts-setting ul li {
|
13 |
+
list-style: none;
|
14 |
+
}
|
15 |
+
|
16 |
+
.itsec-email-contacts-setting ul li input[type="checkbox"] {
|
17 |
+
margin-top: 0;
|
18 |
+
}
|
19 |
+
|
20 |
+
#itsec-module-card-notification-center h4 {
|
21 |
+
margin: .25em 0;
|
22 |
+
}
|
23 |
+
|
24 |
+
.itsec-notification-center-notification-settings .itsec-settings-section {
|
25 |
+
border: none;
|
26 |
+
padding: 0;
|
27 |
+
margin: 0;
|
28 |
+
}
|
29 |
+
|
30 |
+
.itsec-notification-center-notification-settings {
|
31 |
+
border-top: 1px solid #ddd;
|
32 |
+
margin-top: 20px;
|
33 |
+
padding-top: 20px;
|
34 |
+
}
|
35 |
+
|
36 |
+
.itsec-notification-center-notification-settings input[type="text"] {
|
37 |
+
width: 25em;
|
38 |
+
}
|
39 |
+
|
40 |
+
.itsec-notification-center-tags dt {
|
41 |
+
font-family: monospace;
|
42 |
+
}
|
core/modules/notification-center/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden.
|
core/modules/notification-center/js/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden.
|
core/modules/notification-center/js/settings-page.js
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery( function ( $ ) {
|
2 |
+
|
3 |
+
$( document ).on( 'click', '.itsec-notification-center-enable-notification input[type="checkbox"]', function () {
|
4 |
+
toggleSettings( $( this ) );
|
5 |
+
} );
|
6 |
+
|
7 |
+
$( document ).on( 'itsec-dismiss-notice', '.itsec-notification-center-mail-errors-container .notice.itsec-is-dismissible', function () {
|
8 |
+
var errorId = $( this ).data( 'id' );
|
9 |
+
|
10 |
+
itsecSettingsPage.sendModuleAJAXRequest( 'notification-center', { method: 'dismiss-mail-error', mail_error: errorId }, function ( r ) {
|
11 |
+
if ( r.response && r.response.status === 'all-cleared' ) {
|
12 |
+
jQuery( '#itsec-module-card-notification-center' ).removeClass( 'itsec-module-status--warning' );
|
13 |
+
}
|
14 |
+
} )
|
15 |
+
} );
|
16 |
+
|
17 |
+
function initializeHiding() {
|
18 |
+
|
19 |
+
$( '.itsec-notification-center-enable-notification input[type="checkbox"]' ).each( function () {
|
20 |
+
toggleSettings( $( this ) );
|
21 |
+
} );
|
22 |
+
}
|
23 |
+
|
24 |
+
initializeHiding();
|
25 |
+
|
26 |
+
function toggleSettings( $input ) {
|
27 |
+
var isEnabled = $input.is( ':checked' ), slug = $input.data( 'slug' );
|
28 |
+
|
29 |
+
var $other = $( 'tr:not(.itsec-notification-center-enable-notification)', '#itsec-notification-center-notification-' + slug );
|
30 |
+
|
31 |
+
if ( isEnabled ) {
|
32 |
+
$other.show();
|
33 |
+
} else {
|
34 |
+
$other.hide();
|
35 |
+
}
|
36 |
+
}
|
37 |
+
|
38 |
+
itsecSettingsPage.events.on( 'modulesReloaded', initializeHiding );
|
39 |
+
itsecSettingsPage.events.on( 'moduleReloaded', function ( _, module ) {
|
40 |
+
if ( 'notification-center' === module ) {
|
41 |
+
initializeHiding();
|
42 |
+
}
|
43 |
+
} );
|
44 |
+
} );
|
core/modules/notification-center/settings-page.php
ADDED
@@ -0,0 +1,320 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ITSEC_Notification_Center_Settings_Page extends ITSEC_Module_Settings_Page {
|
4 |
+
|
5 |
+
private $version = 1;
|
6 |
+
|
7 |
+
/** @var ITSEC_Notification_Center_Validator */
|
8 |
+
private $validator;
|
9 |
+
|
10 |
+
/** @var array */
|
11 |
+
private $last_sent = array();
|
12 |
+
|
13 |
+
public function __construct() {
|
14 |
+
$this->id = 'notification-center';
|
15 |
+
$this->title = __( 'Notification Center', 'better-wp-security' );
|
16 |
+
$this->description = __( 'Manage and configure email notifications sent by iThemes Security related to various settings modules.', 'better-wp-security' );
|
17 |
+
$this->type = 'recommended';
|
18 |
+
$this->can_save = true;
|
19 |
+
|
20 |
+
$this->validator = ITSEC_Modules::get_validator( 'notification-center' );
|
21 |
+
|
22 |
+
if ( ITSEC_Core::get_notification_center()->get_mail_errors() ) {
|
23 |
+
$this->status = 'warning';
|
24 |
+
}
|
25 |
+
|
26 |
+
parent::__construct();
|
27 |
+
}
|
28 |
+
|
29 |
+
public function enqueue_scripts_and_styles() {
|
30 |
+
wp_enqueue_style( 'itsec-notification-center-admin', plugins_url( 'css/settings-page.css', __FILE__ ), array(), $this->version );
|
31 |
+
wp_enqueue_script( 'itsec-notification-center-admin', plugins_url( 'js/settings-page.js', __FILE__ ), array( 'jquery', 'itsec-settings-page-script' ), $this->version );
|
32 |
+
}
|
33 |
+
|
34 |
+
public function handle_ajax_request( $data ) {
|
35 |
+
|
36 |
+
if ( empty( $data['method'] ) ) {
|
37 |
+
return;
|
38 |
+
}
|
39 |
+
|
40 |
+
switch ( $data['method'] ) {
|
41 |
+
case 'dismiss-mail-error':
|
42 |
+
|
43 |
+
if ( ! empty( $data['mail_error'] ) ) {
|
44 |
+
ITSEC_Core::get_notification_center()->dismiss_mail_error( $data['mail_error'] );
|
45 |
+
|
46 |
+
if ( ! ITSEC_Core::get_notification_center()->get_mail_errors() ) {
|
47 |
+
ITSEC_Response::set_response( array( 'status' => 'all-cleared' ) );
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
break;
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
protected function render_description( $form ) {
|
56 |
+
|
57 |
+
?>
|
58 |
+
<p><?php esc_html_e( 'Manage and configure email notifications sent by iThemes Security related to various settings modules. If errors are encountered while sending notification emails, they will be reported here..', 'better-wp-security' ); ?></p>
|
59 |
+
<?php
|
60 |
+
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* @param ITSEC_Form $form
|
65 |
+
*/
|
66 |
+
protected function render_settings( $form ) {
|
67 |
+
|
68 |
+
$this->last_sent = ITSEC_Modules::get_setting( 'notification-center', 'last_sent' );
|
69 |
+
|
70 |
+
$this->render_mail_errors();
|
71 |
+
?>
|
72 |
+
|
73 |
+
<table class="form-table itsec-settings-section">
|
74 |
+
<tbody>
|
75 |
+
</tbody>
|
76 |
+
</table>
|
77 |
+
|
78 |
+
|
79 |
+
<?php
|
80 |
+
|
81 |
+
$notifications = ITSEC_Core::get_notification_center()->get_notifications();
|
82 |
+
usort( $notifications, array( $this, 'sort_notifications' ) );
|
83 |
+
|
84 |
+
$form->add_input_group( 'notifications' );
|
85 |
+
foreach ( $notifications as $notification ) {
|
86 |
+
$this->render_notification_setting( $form, $notification['slug'], $notification );
|
87 |
+
}
|
88 |
+
$form->remove_input_group();
|
89 |
+
}
|
90 |
+
|
91 |
+
protected function render_mail_errors() {
|
92 |
+
$errors = ITSEC_Core::get_notification_center()->get_mail_errors();
|
93 |
+
|
94 |
+
if ( ! $errors ) {
|
95 |
+
return;
|
96 |
+
}
|
97 |
+
|
98 |
+
?>
|
99 |
+
<div class="itsec-notification-center-mail-errors-container">
|
100 |
+
<?php foreach ( $errors as $id => $error ):
|
101 |
+
$strings = ITSEC_Core::get_notification_center()->get_notification_strings( $error['notification'] );
|
102 |
+
$error = $error['error'];
|
103 |
+
|
104 |
+
if ( is_wp_error( $error ) ) {
|
105 |
+
$message = $error->get_error_message();
|
106 |
+
} elseif ( is_array( $error ) && isset( $error['message'] ) && is_string( $error['message'] ) ) {
|
107 |
+
$message = $error['message'];
|
108 |
+
} else {
|
109 |
+
$message = __( 'Unknown error encountered while sending.', 'better-wp-security' );
|
110 |
+
}
|
111 |
+
?>
|
112 |
+
<div class="notice notice-alt notice-error below-h2 itsec-is-dismissible itsec-notification-center-mail-error" data-id="<?php echo esc_attr( $id ); ?>">
|
113 |
+
<p><?php printf( esc_html__( 'Error while sending %1$s notification at %2$s: %3$s', 'better-wp-security' ), '<b>' . $strings['label'] . '</b>', '<b>' . ITSEC_Lib::date_format_i18n_and_local_timezone( $error['time'] ) . '</b>', $message ); ?></p>
|
114 |
+
</div>
|
115 |
+
<?php endforeach; ?>
|
116 |
+
</div>
|
117 |
+
<?php
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* @param ITSEC_Form $form
|
122 |
+
* @param string $slug
|
123 |
+
* @param array $config
|
124 |
+
*/
|
125 |
+
protected function render_notification_setting( $form, $slug, $config ) {
|
126 |
+
$strings = ITSEC_Core::get_notification_center()->get_notification_strings( $slug );
|
127 |
+
|
128 |
+
$form->add_input_group( $slug );
|
129 |
+
?>
|
130 |
+
|
131 |
+
<div class="itsec-notification-center-notification-settings" id="itsec-notification-center-notification-settings--<?php echo esc_attr( $slug ); ?>">
|
132 |
+
<h4><?php echo $strings['label']; ?></h4>
|
133 |
+
<?php if ( ! empty( $strings['description'] ) ): ?>
|
134 |
+
<p class="description"><?php echo $strings['description']; ?></p>
|
135 |
+
<?php endif; ?>
|
136 |
+
|
137 |
+
<table class="form-table itsec-settings-section" id="itsec-notification-center-notification-<?php echo esc_attr( $slug ); ?>">
|
138 |
+
|
139 |
+
<?php if ( ! empty( $config['optional'] ) ): ?>
|
140 |
+
<tr class="itsec-notification-center-enable-notification">
|
141 |
+
<th><label for="itsec-notification-center-notifications-<?php echo esc_attr( $slug ); ?>-enabled"><?php esc_html_e( 'Enabled', 'better-wp-security' ); ?></label></th>
|
142 |
+
<td><?php $form->add_checkbox( 'enabled', array( 'data-slug' => $slug ) ); ?></td>
|
143 |
+
</tr>
|
144 |
+
<?php endif; ?>
|
145 |
+
|
146 |
+
<?php if ( ! empty( $config['subject_editable'] ) ) :
|
147 |
+
$form->get_option( 'subject' ) ? '' : $form->set_option( 'subject', $strings['subject'] ); ?>
|
148 |
+
<tr>
|
149 |
+
<th><label for="itsec-notification-center-notifications-<?php echo esc_attr( $slug ); ?>-subject"><?php esc_html_e( 'Subject', 'better-wp-security' ); ?></label></th>
|
150 |
+
<td><?php $form->add_text( 'subject' ); ?></td>
|
151 |
+
</tr>
|
152 |
+
<?php endif; ?>
|
153 |
+
|
154 |
+
<?php if ( ! empty( $config['message_editable'] ) ) :
|
155 |
+
$form->get_option( 'message' ) ? '' : $form->set_option( 'message', $strings['message'] ); ?>
|
156 |
+
<tr>
|
157 |
+
<th><label for="itsec-notification-center-notifications-<?php echo esc_attr( $slug ); ?>-message"><?php esc_html_e( 'Message', 'better-wp-security' ); ?></label></th>
|
158 |
+
<td>
|
159 |
+
<?php $form->add_textarea( 'message' ); ?>
|
160 |
+
|
161 |
+
<p class="description">
|
162 |
+
<?php echo wp_sprintf( esc_html__( 'You can use HTML in your message. Allowed HTML includes: %l.', 'better-wp-security' ), array_keys( $this->validator->get_allowed_html() ) ); ?>
|
163 |
+
|
164 |
+
<?php if ( ! empty( $config['tags'] ) ) : ?>
|
165 |
+
<?php printf( esc_html__( 'This notification supports email tags. Tags are formatted as follows %s.', 'better-wp-security' ), '<code>{{ $tag_name }}</code>' ); ?>
|
166 |
+
<?php endif; ?>
|
167 |
+
</p>
|
168 |
+
|
169 |
+
<?php if ( ! empty( $config['tags'] ) ) : ?>
|
170 |
+
<dl class="itsec-notification-center-tags">
|
171 |
+
<?php foreach( $strings['tags'] as $tag => $description ): ?>
|
172 |
+
<dt><?php echo esc_html( $tag ); ?></dt>
|
173 |
+
<dd><?php echo $description; // Already escaped. ?></dd>
|
174 |
+
<?php endforeach; ?>
|
175 |
+
</dl>
|
176 |
+
<?php endif; ?>
|
177 |
+
</td>
|
178 |
+
</tr>
|
179 |
+
<?php endif; ?>
|
180 |
+
|
181 |
+
<?php if ( is_array( $config['schedule'] ) ): ?>
|
182 |
+
<tr>
|
183 |
+
<th><label for="itsec-notification-center-notifications-<?php echo esc_attr( $slug ); ?>-schedule"><?php esc_html_e( 'Schedule', 'better-wp-security' ); ?></label></th>
|
184 |
+
<td>
|
185 |
+
<?php $form->add_select( 'schedule', $this->validator->get_schedule_options( $config['schedule'] ) ); ?>
|
186 |
+
<p class="description">
|
187 |
+
<?php if ( empty( $this->last_sent[ $slug ] ) ): ?>
|
188 |
+
<?php esc_html_e( 'Not yet sent.', 'better-wp-security' ); ?>
|
189 |
+
<?php else: ?>
|
190 |
+
<?php printf( esc_html__( 'Last sent on %s', 'better-wp-security' ), ITSEC_Lib::date_format_i18n_and_local_timezone( $this->last_sent[ $slug ] ) ); ?>
|
191 |
+
<?php endif; ?>
|
192 |
+
</p>
|
193 |
+
</td>
|
194 |
+
</tr>
|
195 |
+
<?php endif; ?>
|
196 |
+
|
197 |
+
<?php switch( $config['recipient'] ) :
|
198 |
+
case ITSEC_Notification_Center::R_USER: ?>
|
199 |
+
<tr>
|
200 |
+
<th><?php esc_html_e( 'Recipient', 'better-wp-security' ); ?></th>
|
201 |
+
<td><em><?php esc_html_e( 'Site Users', 'better-wp-security' ); ?></em></td>
|
202 |
+
</tr>
|
203 |
+
<?php break; ?>
|
204 |
+
|
205 |
+
<?php case ITSEC_Notification_Center::R_ADMIN: ?>
|
206 |
+
<tr>
|
207 |
+
<th><?php esc_html_e( 'Recipient', 'better-wp-security' ); ?></th>
|
208 |
+
<td><em><?php esc_html_e( 'Admin Emails', 'better-wp-security' ); ?></em></td>
|
209 |
+
</tr>
|
210 |
+
<?php break; ?>
|
211 |
+
|
212 |
+
<?php case ITSEC_Notification_Center::R_PER_USE: ?>
|
213 |
+
<tr>
|
214 |
+
<th><?php esc_html_e( 'Recipient', 'better-wp-security' ); ?></th>
|
215 |
+
<td><em><?php esc_html_e( 'Specified when sending', 'better-wp-security' ); ?></em></td>
|
216 |
+
</tr>
|
217 |
+
<?php break; ?>
|
218 |
+
|
219 |
+
<?php case ITSEC_Notification_Center::R_EMAIL_LIST: ?>
|
220 |
+
<tr>
|
221 |
+
<th><label for="itsec-notification-center-notifications-<?php echo esc_attr( $slug ); ?>-email_list"><?php esc_html_e( 'Recipient', 'better-wp-security' ); ?></label></th>
|
222 |
+
<td>
|
223 |
+
<?php $form->add_textarea( 'email_list', array( 'class' => 'textarea-small' ) ); ?>
|
224 |
+
<p class="description"><?php _e( 'The email address(es) this notification will be sent to. One address per line.', 'better-wp-security' ); ?></p>
|
225 |
+
</td>
|
226 |
+
</tr>
|
227 |
+
<?php break; ?>
|
228 |
+
|
229 |
+
<?php case ITSEC_Notification_Center::R_USER_LIST: case ITSEC_Notification_Center::R_USER_LIST_ADMIN_UPGRADE: ?>
|
230 |
+
<?php $this->render_user_list( $slug, $form, $config['recipient'] ); ?>
|
231 |
+
<?php break; ?>
|
232 |
+
|
233 |
+
<?php endswitch; ?>
|
234 |
+
</table>
|
235 |
+
</div>
|
236 |
+
<?php
|
237 |
+
$form->remove_input_group();
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
* Render the User List form.
|
242 |
+
*
|
243 |
+
* @param string $slug Notification slug.
|
244 |
+
* @param ITSEC_Form $form
|
245 |
+
* @param string $type
|
246 |
+
*/
|
247 |
+
protected function render_user_list( $slug, $form, $type ) {
|
248 |
+
|
249 |
+
$users_and_roles = $this->validator->get_available_admin_users_and_roles();
|
250 |
+
|
251 |
+
$users = $users_and_roles['users'];
|
252 |
+
$roles = $users_and_roles['roles'];
|
253 |
+
|
254 |
+
natcasesort( $users );
|
255 |
+
?>
|
256 |
+
|
257 |
+
<tr class="itsec-email-contacts-setting">
|
258 |
+
<th><?php esc_html_e( 'Recipient', 'better-wp-security' ); ?></th>
|
259 |
+
<td>
|
260 |
+
<fieldset>
|
261 |
+
<legend class="screen-reader-text"><?php esc_html_e( 'Recipients for this email.', 'better-wp-security' ); ?></legend>
|
262 |
+
<p><?php esc_html_e( 'Select which users should be emailed.', 'better-wp-security' ); ?></p>
|
263 |
+
|
264 |
+
<ul>
|
265 |
+
<?php foreach ( $roles as $role => $name ) : ?>
|
266 |
+
<li>
|
267 |
+
<label>
|
268 |
+
<?php $form->add_multi_checkbox( 'user_list', $role ); ?>
|
269 |
+
<?php echo esc_html( sprintf( _x( 'All %s users', 'role', 'better-wp-security' ), $name ) ); ?>
|
270 |
+
</label>
|
271 |
+
</li>
|
272 |
+
<?php endforeach; ?>
|
273 |
+
</ul>
|
274 |
+
|
275 |
+
<ul>
|
276 |
+
<?php foreach ( $users as $id => $name ) : ?>
|
277 |
+
<li>
|
278 |
+
<label>
|
279 |
+
<?php $form->add_multi_checkbox( 'user_list', $id ); ?>
|
280 |
+
<?php echo esc_html( $name ); ?>
|
281 |
+
</label>
|
282 |
+
</li>
|
283 |
+
<?php endforeach; ?>
|
284 |
+
</ul>
|
285 |
+
|
286 |
+
<?php if ( ITSEC_Notification_Center::R_USER_LIST_ADMIN_UPGRADE === $type && $form->get_option( 'previous_emails' ) ): ?>
|
287 |
+
|
288 |
+
<div class="itsec-notification-center--deprecated-recipients">
|
289 |
+
<span><?php esc_html_e( 'Deprecated Recipients', 'better-wp-security' ); ?></span>
|
290 |
+
<p class="description">
|
291 |
+
<?php esc_html_e( 'The following email recipients are deprecated. Please create new users for these email addresses or remove them.', 'better-wp-security' ); ?>
|
292 |
+
</p>
|
293 |
+
<ul>
|
294 |
+
<?php foreach ( $form->get_option( 'previous_emails' ) as $email ): ?>
|
295 |
+
<li>
|
296 |
+
<label>
|
297 |
+
<?php $form->add_multi_checkbox( 'previous_emails', $email ); ?>
|
298 |
+
<?php echo esc_html( $email ); ?>
|
299 |
+
</label>
|
300 |
+
</li>
|
301 |
+
<?php endforeach; ?>
|
302 |
+
</ul>
|
303 |
+
</div>
|
304 |
+
<?php endif; ?>
|
305 |
+
</fieldset>
|
306 |
+
</td>
|
307 |
+
</tr>
|
308 |
+
<?php
|
309 |
+
}
|
310 |
+
|
311 |
+
private function sort_notifications( $a, $b ) {
|
312 |
+
|
313 |
+
$a_s = ITSEC_Core::get_notification_center()->get_notification_strings( $a['slug'] );
|
314 |
+
$b_s = ITSEC_Core::get_notification_center()->get_notification_strings( $b['slug'] );
|
315 |
+
|
316 |
+
return strcmp( $a_s['label'], $b_s['label'] );
|
317 |
+
}
|
318 |
+
}
|
319 |
+
|
320 |
+
new ITSEC_Notification_Center_Settings_Page();
|
core/modules/notification-center/settings.php
ADDED
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ITSEC_Notification_Center_Settings extends ITSEC_Settings {
|
4 |
+
|
5 |
+
/**
|
6 |
+
* ITSEC_Notification_Center_Settings constructor.
|
7 |
+
*/
|
8 |
+
public function __construct() {
|
9 |
+
parent::__construct();
|
10 |
+
|
11 |
+
add_action( 'itsec_notification_center_continue_upgrade', array( $this, 'continue_upgrade' ) );
|
12 |
+
}
|
13 |
+
|
14 |
+
|
15 |
+
public function get_id() {
|
16 |
+
return 'notification-center';
|
17 |
+
}
|
18 |
+
|
19 |
+
public function get_defaults() {
|
20 |
+
return array(
|
21 |
+
'last_sent' => array(),
|
22 |
+
'resend_at' => array(),
|
23 |
+
'data' => array(),
|
24 |
+
'mail_errors' => array(),
|
25 |
+
'notifications' => array(),
|
26 |
+
'admin_emails' => array(),
|
27 |
+
);
|
28 |
+
}
|
29 |
+
|
30 |
+
public function load() {
|
31 |
+
$this->settings = ITSEC_Storage::get( $this->get_id() );
|
32 |
+
$defaults = $this->get_defaults();
|
33 |
+
|
34 |
+
if ( ! is_array( $this->settings ) ) {
|
35 |
+
$this->settings = array();
|
36 |
+
}
|
37 |
+
|
38 |
+
$this->settings = array_merge( $defaults, $this->settings );
|
39 |
+
|
40 |
+
$notifications = ITSEC_Core::get_notification_center()->get_notifications();
|
41 |
+
|
42 |
+
foreach ( $notifications as $slug => $notification ) {
|
43 |
+
if ( ! isset( $this->settings['notifications'][ $slug ] ) ) {
|
44 |
+
$value = $this->get_notification_defaults( $notification, true );
|
45 |
+
} else {
|
46 |
+
$value = wp_parse_args( $this->settings['notifications'][ $slug ], $this->get_notification_defaults( $notification ) );
|
47 |
+
}
|
48 |
+
|
49 |
+
$this->settings['notifications'][ $slug ] = $value;
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
public function refresh_notification_settings( $save = true ) {
|
54 |
+
|
55 |
+
$nc = ITSEC_Core::get_notification_center();
|
56 |
+
|
57 |
+
foreach ( $this->settings['notifications'] as $slug => $notification ) {
|
58 |
+
$this->settings['notifications'][ $slug ] = array_merge( $this->get_notification_defaults( $nc->get_notification( $slug ), true ), $notification );
|
59 |
+
}
|
60 |
+
|
61 |
+
if ( $save ) {
|
62 |
+
$this->set_all( $this->settings );
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
public function continue_upgrade() {
|
67 |
+
$nc = ITSEC_Core::get_notification_center();
|
68 |
+
|
69 |
+
$nc->clear_notifications_cache();
|
70 |
+
$this->refresh_notification_settings( false );
|
71 |
+
|
72 |
+
$admin_users = array();
|
73 |
+
$admin_emails = array();
|
74 |
+
|
75 |
+
foreach ( $this->settings['admin_emails'] as $admin_email ) {
|
76 |
+
$user = get_user_by( 'email', $admin_email );
|
77 |
+
|
78 |
+
if ( $user && $user->has_cap( 'manage_options' ) ) {
|
79 |
+
$admin_users[] = $user->ID;
|
80 |
+
} else {
|
81 |
+
$admin_emails[] = $admin_email;
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
foreach ( $nc->get_notifications() as $slug => $notification ) {
|
86 |
+
|
87 |
+
if ( ITSEC_Notification_Center::R_USER_LIST_ADMIN_UPGRADE === $notification['recipient'] ) {
|
88 |
+
if ( $admin_users ) {
|
89 |
+
$this->settings['notifications'][ $slug ]['user_list'] = $admin_users;
|
90 |
+
} elseif ( $admin_emails ) {
|
91 |
+
$this->settings['notifications'][ $slug ]['user_list'] = array();
|
92 |
+
}
|
93 |
+
|
94 |
+
$this->settings['notifications'][ $slug ]['previous_emails'] = $admin_emails;
|
95 |
+
}
|
96 |
+
}
|
97 |
+
|
98 |
+
$this->set_all( $this->settings );
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Get the defaults for a notification.
|
103 |
+
*
|
104 |
+
* @param array $notification
|
105 |
+
* @param bool $include_strings Whether to include translated strings. Used for default subject and message.
|
106 |
+
* Defaults to false for performance reasons.
|
107 |
+
*
|
108 |
+
* @return array
|
109 |
+
*/
|
110 |
+
private function get_notification_defaults( $notification, $include_strings = false ) {
|
111 |
+
|
112 |
+
$strings = $include_strings ? ITSEC_Core::get_notification_center()->get_notification_strings( $notification['slug'] ) : array();
|
113 |
+
$defaults = array();
|
114 |
+
|
115 |
+
if ( is_array( $notification['schedule'] ) ) {
|
116 |
+
$defaults['schedule'] = $notification['schedule']['default'];
|
117 |
+
}
|
118 |
+
|
119 |
+
if ( ! empty( $strings['subject'] ) ) {
|
120 |
+
$defaults['subject'] = $strings['subject'];
|
121 |
+
}
|
122 |
+
|
123 |
+
if ( ! empty( $strings['message'] ) ) {
|
124 |
+
$defaults['message'] = $strings['message'];
|
125 |
+
}
|
126 |
+
|
127 |
+
if ( ! empty( $notification['optional'] ) ) {
|
128 |
+
$defaults['enabled'] = true;
|
129 |
+
}
|
130 |
+
|
131 |
+
if ( ITSEC_Notification_Center::R_USER_LIST === $notification['recipient'] ) {
|
132 |
+
$defaults['user_list'] = array( 'role:administrator' );
|
133 |
+
}
|
134 |
+
|
135 |
+
if ( ITSEC_Notification_Center::R_USER_LIST_ADMIN_UPGRADE === $notification['recipient'] ) {
|
136 |
+
$defaults['user_list'] = array( 'role:administrator' );
|
137 |
+
$defaults['previous_emails'] = array();
|
138 |
+
}
|
139 |
+
|
140 |
+
if ( ITSEC_Notification_Center::R_EMAIL_LIST === $notification['recipient'] ) {
|
141 |
+
$defaults['email_list'] = array( get_option( 'admin_email' ) );
|
142 |
+
}
|
143 |
+
|
144 |
+
return $defaults;
|
145 |
+
}
|
146 |
+
}
|
147 |
+
|
148 |
+
ITSEC_Modules::register_settings( new ITSEC_Notification_Center_Settings() );
|
core/modules/notification-center/setup.php
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ITSEC_Notification_Center_Setup {
|
4 |
+
|
5 |
+
public function __construct() {
|
6 |
+
add_action( 'itsec_modules_do_plugin_uninstall', array( $this, 'execute_uninstall' ) );
|
7 |
+
add_action( 'itsec_modules_do_plugin_upgrade', array( $this, 'execute_upgrade' ) );
|
8 |
+
}
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Execute module uninstall
|
12 |
+
*
|
13 |
+
* @return void
|
14 |
+
*/
|
15 |
+
public function execute_uninstall() {
|
16 |
+
$scheduled = wp_next_scheduled( 'itsec-send-scheduled-notifications' );
|
17 |
+
|
18 |
+
if ( $scheduled ) {
|
19 |
+
wp_unschedule_event( $scheduled, 'itsec-send-scheduled-notifications' );
|
20 |
+
}
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Execute module upgrade
|
25 |
+
*
|
26 |
+
* @param int $itsec_old_version
|
27 |
+
*/
|
28 |
+
public function execute_upgrade( $itsec_old_version ) {
|
29 |
+
if ( $itsec_old_version < 4076 ) {
|
30 |
+
|
31 |
+
ITSEC_Modules::load_module_file( 'active.php', 'notification-center' );
|
32 |
+
|
33 |
+
$settings = ITSEC_Modules::get_settings( 'notification-center' );
|
34 |
+
|
35 |
+
$global = ITSEC_Modules::get_settings( 'global' );
|
36 |
+
|
37 |
+
$settings['admin_emails'] = $global['notification_email'];
|
38 |
+
|
39 |
+
$settings['notifications']['digest']['enabled'] = $global['digest_email'];
|
40 |
+
$settings['notifications']['backup']['email_list'] = $global['backup_email'];
|
41 |
+
$settings['notifications']['lockout']['enabled'] = $global['email_notifications'] && ! $global['digest_email'];
|
42 |
+
|
43 |
+
$settings['last_sent']['digest'] = $global['digest_last_sent'];
|
44 |
+
|
45 |
+
if ( $global['digest_messages'] ) {
|
46 |
+
$settings['data']['digest'] = array();
|
47 |
+
|
48 |
+
foreach ( $global['digest_messages'] as $message ) {
|
49 |
+
if ( 'file-change' === $message ) {
|
50 |
+
$settings['data']['digest'][] = array( 'type' => 'file-change' );
|
51 |
+
} else {
|
52 |
+
$settings['data']['digest'][] = array( 'type' => 'general', 'message' => $message );
|
53 |
+
}
|
54 |
+
}
|
55 |
+
}
|
56 |
+
|
57 |
+
if ( $malware = ITSEC_Modules::get_settings( 'malware-scheduling' ) ) {
|
58 |
+
$settings['notifications']['malware-scheduling']['enabled'] = ! empty( $malware['email_notifications'] );
|
59 |
+
$settings['notifications']['malware-scheduling']['user_list'] = ! empty( $malware['email_contacts'] ) ? $malware['email_contacts'] : array( 'role:administrator' );
|
60 |
+
}
|
61 |
+
|
62 |
+
if ( $vm = ITSEC_Modules::get_settings( 'version-management' ) ) {
|
63 |
+
$settings['notifications']['automatic-updates-debug']['enabled'] = ! empty( $vm['automatic_update_emails'] );
|
64 |
+
$settings['notifications']['automatic-updates-debug']['user_list'] = ! empty( $vm['email_contacts'] ) ? $vm['email_contacts'] : array( 'role:administrator' );
|
65 |
+
$settings['notifications']['old-site-scan']['user_list'] = ! empty( $vm['email_contacts'] ) ? $vm['email_contacts'] : array( 'role:administrator' );
|
66 |
+
}
|
67 |
+
|
68 |
+
if ( $file_change = ITSEC_Modules::get_settings( 'file-change' ) ) {
|
69 |
+
$settings['notifications']['file-change']['enabled'] = ! empty( $file_change['email'] ) && ! $global['digest_email'];
|
70 |
+
}
|
71 |
+
|
72 |
+
ITSEC_Modules::set_settings( 'notification-center', $settings );
|
73 |
+
|
74 |
+
add_action( 'itsec_initialized', array( $this, 'fire_continue_upgrade' ) );
|
75 |
+
} elseif ( $itsec_old_version < 4077 ) { // Only run this if user is updating from 4076 -> 4077
|
76 |
+
ITSEC_Modules::load_module_file( 'active.php', 'notification-center' );
|
77 |
+
|
78 |
+
$settings = ITSEC_Modules::get_settings( 'notification-center' );
|
79 |
+
$global = ITSEC_Modules::get_settings( 'global' );
|
80 |
+
|
81 |
+
$settings['notifications']['lockout']['enabled'] = $global['email_notifications'] && ! $global['digest_email'];
|
82 |
+
|
83 |
+
if ( $file_change = ITSEC_Modules::get_settings( 'file-change' ) ) {
|
84 |
+
$settings['notifications']['file-change']['enabled'] = ! empty( $file_change['email'] ) && ! $global['digest_email'];
|
85 |
+
}
|
86 |
+
|
87 |
+
foreach ( $settings['notifications'] as $slug => $notification ) {
|
88 |
+
if ( empty( $notification['previous_emails'] ) ) {
|
89 |
+
continue;
|
90 |
+
}
|
91 |
+
|
92 |
+
if ( ! isset( $notification['user_list'] ) || $notification['user_list'] === array( 'role:administrator' ) ) {
|
93 |
+
$notification['user_list'] = array();
|
94 |
+
|
95 |
+
$settings['notifications'][ $slug ] = $notification;
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
ITSEC_Modules::set_settings( 'notification-center', $settings );
|
100 |
+
} elseif ( $itsec_old_version < 4078 ) { // Only run if user updating from 4077 -> 4078
|
101 |
+
ITSEC_Modules::load_module_file( 'active.php', 'notification-center' );
|
102 |
+
|
103 |
+
$settings = ITSEC_Modules::get_settings( 'notification-center' );
|
104 |
+
|
105 |
+
if ( ! isset( $settings['notifications']['file-change']['enabled'] ) || $settings['notifications']['file-change']['enabled'] ) {
|
106 |
+
|
107 |
+
$global = ITSEC_Modules::get_settings( 'global' );
|
108 |
+
|
109 |
+
if ( $file_change = ITSEC_Modules::get_settings( 'file-change' ) ) {
|
110 |
+
$settings['notifications']['file-change']['enabled'] = ! empty( $file_change['email'] ) && ! $global['digest_email'];
|
111 |
+
}
|
112 |
+
|
113 |
+
ITSEC_Modules::set_settings( 'notification-center', $settings );
|
114 |
+
}
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
public function fire_continue_upgrade() {
|
119 |
+
do_action( 'itsec_notification_center_continue_upgrade' );
|
120 |
+
}
|
121 |
+
}
|
122 |
+
|
123 |
+
new ITSEC_Notification_Center_Setup();
|
core/modules/notification-center/validator.php
ADDED
@@ -0,0 +1,313 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Notification Center Validator.
|
4 |
+
*/
|
5 |
+
|
6 |
+
class ITSEC_Notification_Center_Validator extends ITSEC_Validator {
|
7 |
+
|
8 |
+
private $current_tags = array();
|
9 |
+
private $tag_errors = array();
|
10 |
+
|
11 |
+
public function get_id() {
|
12 |
+
return 'notification-center';
|
13 |
+
}
|
14 |
+
|
15 |
+
protected function sanitize_settings() {
|
16 |
+
$this->vars_to_skip_validate_matching_fields = array( 'last_sent', 'data', 'resend_at', 'mail_errors', 'admin_emails' );
|
17 |
+
$this->set_previous_if_empty( array( 'last_sent', 'data', 'resend_at', 'admin_emails' ) );
|
18 |
+
|
19 |
+
if ( ! isset( $this->settings['mail_errors'] ) ) {
|
20 |
+
$this->settings['mail_errors'] = $this->previous_settings['mail_errors'];
|
21 |
+
}
|
22 |
+
|
23 |
+
if ( ! $this->sanitize_setting( 'array', 'notifications', esc_html__( 'Notifications', 'better-wp-security' ) ) ) {
|
24 |
+
return;
|
25 |
+
}
|
26 |
+
|
27 |
+
$notifications = $this->settings['notifications'];
|
28 |
+
|
29 |
+
foreach ( $notifications as $notification => $settings ) {
|
30 |
+
$config = ITSEC_Core::get_notification_center()->get_notification( $notification );
|
31 |
+
|
32 |
+
if ( ! $config ) {
|
33 |
+
$notifications[ $notification ] = array();
|
34 |
+
break;
|
35 |
+
}
|
36 |
+
|
37 |
+
$strings = ITSEC_Core::get_notification_center()->get_notification_strings( $notification );
|
38 |
+
|
39 |
+
if ( ITSEC_Notification_Center::R_USER_LIST !== $config['recipient'] && ITSEC_Notification_Center::R_USER_LIST_ADMIN_UPGRADE !== $config['recipient'] ) {
|
40 |
+
unset( $settings['user_list'] );
|
41 |
+
} else {
|
42 |
+
if ( ! is_array( $settings['user_list'] ) ) {
|
43 |
+
$settings['user_list'] = array();
|
44 |
+
}
|
45 |
+
|
46 |
+
$users_and_roles = $this->get_available_admin_users_and_roles();
|
47 |
+
$valid_contacts = $users_and_roles['users'] + $users_and_roles['roles'];
|
48 |
+
|
49 |
+
$contact_errors = array();
|
50 |
+
|
51 |
+
foreach ( $settings['user_list'] as $contact ) {
|
52 |
+
if ( ! isset( $valid_contacts[ $contact ] ) ) {
|
53 |
+
$contact_errors[] = $contact;
|
54 |
+
}
|
55 |
+
}
|
56 |
+
|
57 |
+
if ( ITSEC_Notification_Center::R_USER_LIST_ADMIN_UPGRADE === $config['recipient'] && isset( $settings['previous_emails'] ) ) {
|
58 |
+
foreach ( $settings['previous_emails'] as $previous_email ) {
|
59 |
+
if ( ! in_array( $previous_email, $this->settings['admin_emails'], true ) ) {
|
60 |
+
$contact_errors[] = $previous_email;
|
61 |
+
}
|
62 |
+
}
|
63 |
+
}
|
64 |
+
|
65 |
+
if ( $contact_errors ) {
|
66 |
+
$this->add_error( new WP_Error(
|
67 |
+
'itsec-validator-notification-center-invalid-type-notifications[user_list]-invalid-contacts',
|
68 |
+
wp_sprintf( esc_html__( 'Unknown contacts for %1$s, %2$l.', 'better-wp-security' ), $strings['label'], $contact_errors )
|
69 |
+
) );
|
70 |
+
|
71 |
+
if ( ITSEC_Core::is_interactive() ) {
|
72 |
+
$this->set_can_save( false );
|
73 |
+
}
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
if ( ITSEC_Notification_Center::R_EMAIL_LIST !== $config['recipient'] ) {
|
78 |
+
unset( $settings['email_list'] );
|
79 |
+
} else {
|
80 |
+
|
81 |
+
if ( ! isset( $settings['email_list'] ) ) {
|
82 |
+
$settings['email_list'] = '';
|
83 |
+
}
|
84 |
+
|
85 |
+
$settings['email_list'] = $this->convert_string_to_array( $settings['email_list'] );
|
86 |
+
|
87 |
+
$email_list_error = null; // Safety
|
88 |
+
|
89 |
+
if ( ! is_array( $settings['email_list'] ) ) {
|
90 |
+
$email_list_error = sprintf( __( 'The %1$s email list must be a string with each entry separated by a new line.', 'better-wp-security' ), $strings['label'] );
|
91 |
+
} else {
|
92 |
+
$invalid_emails = array();
|
93 |
+
|
94 |
+
foreach ( $settings['email_list'] as $index => $email ) {
|
95 |
+
$email = sanitize_text_field( trim( $email ) );
|
96 |
+
$settings['email_list'][ $index ] = $email;
|
97 |
+
|
98 |
+
if ( empty( $email ) ) {
|
99 |
+
unset( $settings['email_list'][ $index ] );
|
100 |
+
} elseif ( ! is_email( $email ) ) {
|
101 |
+
$invalid_emails[] = $email;
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
$settings['email_list'] = array_unique( $settings['email_list'] );
|
106 |
+
|
107 |
+
if ( ! empty( $invalid_emails ) ) {
|
108 |
+
$email_list_error = wp_sprintf( _n( 'The following email in %1$s is invalid: %2$l', 'The following emails in %1$s are invalid: %2$l', count( $invalid_emails ), 'better-wp-security' ), $strings['label'], $invalid_emails );
|
109 |
+
}
|
110 |
+
}
|
111 |
+
|
112 |
+
if ( $email_list_error ) {
|
113 |
+
$this->add_error( new WP_Error(
|
114 |
+
'itsec-validator-notification-center-invalid-type-notifications[email_list]-invalid-emails',
|
115 |
+
$email_list_error
|
116 |
+
) );
|
117 |
+
|
118 |
+
if ( ITSEC_Core::is_interactive() ) {
|
119 |
+
$this->set_can_save( false );
|
120 |
+
}
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
if ( empty( $config['optional'] ) ) {
|
125 |
+
unset( $settings['enabled'] );
|
126 |
+
} else {
|
127 |
+
if ( 'false' === $settings['enabled'] ) {
|
128 |
+
$settings['enabled'] = false;
|
129 |
+
} elseif ( 'true' === $settings['enabled'] ) {
|
130 |
+
$settings['enabled'] = true;
|
131 |
+
} else {
|
132 |
+
$settings['enabled'] = (bool) $settings['enabled'];
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
if ( ! is_array( $config['schedule'] ) ) {
|
137 |
+
unset( $settings['schedule'] );
|
138 |
+
} else {
|
139 |
+
$options = $this->get_schedule_options( $config['schedule'] );
|
140 |
+
|
141 |
+
if ( ! isset( $options[ $settings['schedule'] ] ) ) {
|
142 |
+
$this->add_error( new WP_Error(
|
143 |
+
'itsec-validator-notification-center-invalid-type-notifications[schedule]-unknown-schedule',
|
144 |
+
sprintf( esc_html__( 'Unknown schedule for %1$s, %2$s.', 'better-wp-security' ), $strings['label'], $settings['schedule'] )
|
145 |
+
) );
|
146 |
+
|
147 |
+
if ( ITSEC_Core::is_interactive() ) {
|
148 |
+
$this->set_can_save( false );
|
149 |
+
}
|
150 |
+
}
|
151 |
+
}
|
152 |
+
|
153 |
+
if ( empty( $config['subject_editable'] ) ) {
|
154 |
+
unset( $settings['subject'] );
|
155 |
+
} elseif ( ! empty( $settings['subject'] ) ) {
|
156 |
+
$subject = trim( wp_strip_all_tags( $settings['subject'], true ) );
|
157 |
+
|
158 |
+
if ( $subject === $strings['subject'] ) {
|
159 |
+
$subject = null;
|
160 |
+
}
|
161 |
+
|
162 |
+
$settings['subject'] = $subject;
|
163 |
+
}
|
164 |
+
|
165 |
+
if ( empty( $config['message_editable'] ) ) {
|
166 |
+
unset( $settings['message'] );
|
167 |
+
} else {
|
168 |
+
$message = isset( $settings['message'] ) ? trim( wp_kses( $settings['message'], $this->get_allowed_html() ) ) : '';
|
169 |
+
|
170 |
+
if ( ! empty( $message ) ) {
|
171 |
+
$this->check_unknown_tags( $message, $config['tags'], $strings['label'] );
|
172 |
+
}
|
173 |
+
|
174 |
+
if ( $message === $strings['message'] ) {
|
175 |
+
$message = null;
|
176 |
+
}
|
177 |
+
|
178 |
+
$settings['message'] = $message;
|
179 |
+
}
|
180 |
+
|
181 |
+
$notifications[ $notification ] = $settings;
|
182 |
+
}
|
183 |
+
|
184 |
+
$this->settings['notifications'] = $notifications;
|
185 |
+
}
|
186 |
+
|
187 |
+
/**
|
188 |
+
* Check whether any unknown tags are being used in the content.
|
189 |
+
*
|
190 |
+
* @param string $content
|
191 |
+
* @param string[] $tags
|
192 |
+
* @param string $label
|
193 |
+
*/
|
194 |
+
private function check_unknown_tags( $content, $tags, $label ) {
|
195 |
+
$this->current_tags = $tags;
|
196 |
+
|
197 |
+
preg_replace_callback( '/{{ \$(\w+) }}/', array( $this, 'is_known_tag' ), $content );
|
198 |
+
|
199 |
+
if ( $this->tag_errors ) {
|
200 |
+
$this->add_error( new WP_Error(
|
201 |
+
'itsec-validator-notification-center-invalid-type-notifications[message]-unknown-tags',
|
202 |
+
/* translators: %1$s notification label, %2$l list of unknown tags. */
|
203 |
+
wp_sprintf( esc_html__( 'Unknown tags for %1$s, %2$l.', 'better-wp-security' ), $label, $this->tag_errors )
|
204 |
+
) );
|
205 |
+
|
206 |
+
if ( ITSEC_Core::is_interactive() ) {
|
207 |
+
$this->set_can_save( false );
|
208 |
+
}
|
209 |
+
}
|
210 |
+
|
211 |
+
$this->tag_errors = array();
|
212 |
+
$this->current_tags = array();
|
213 |
+
}
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Check if a tag is known.
|
217 |
+
*
|
218 |
+
* @param array $matches
|
219 |
+
*/
|
220 |
+
public function is_known_tag( $matches ) {
|
221 |
+
if ( empty( $matches[1] ) ) {
|
222 |
+
return; // Sanity check
|
223 |
+
}
|
224 |
+
|
225 |
+
if ( ! in_array( $matches[1], $this->current_tags, true ) ) {
|
226 |
+
$this->tag_errors[] = $matches[1];
|
227 |
+
}
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Get the list of available users and roles that can be selected as a notification email contact.
|
232 |
+
*
|
233 |
+
* @return array
|
234 |
+
*/
|
235 |
+
public function get_available_admin_users_and_roles() {
|
236 |
+
if ( is_callable( 'wp_roles' ) ) {
|
237 |
+
$roles = wp_roles();
|
238 |
+
} else {
|
239 |
+
$roles = new WP_Roles();
|
240 |
+
}
|
241 |
+
|
242 |
+
$available_roles = array();
|
243 |
+
$available_users = array();
|
244 |
+
|
245 |
+
foreach ( $roles->roles as $role => $details ) {
|
246 |
+
if ( isset( $details['capabilities']['manage_options'] ) && ( true === $details['capabilities']['manage_options'] ) ) {
|
247 |
+
$available_roles["role:$role"] = translate_user_role( $details['name'] );
|
248 |
+
|
249 |
+
$users = get_users( array( 'role' => $role ) );
|
250 |
+
|
251 |
+
foreach ( $users as $user ) {
|
252 |
+
/* translators: 1: user display name, 2: user login */
|
253 |
+
$available_users[ $user->ID ] = sprintf( __( '%1$s (%2$s)', 'better-wp-security' ), $user->display_name, $user->user_login );
|
254 |
+
}
|
255 |
+
}
|
256 |
+
}
|
257 |
+
|
258 |
+
natcasesort( $available_users );
|
259 |
+
|
260 |
+
return array(
|
261 |
+
'users' => $available_users,
|
262 |
+
'roles' => $available_roles,
|
263 |
+
);
|
264 |
+
}
|
265 |
+
|
266 |
+
/**
|
267 |
+
* Get the available schedule options.
|
268 |
+
*
|
269 |
+
* @param array $schedule_config
|
270 |
+
*
|
271 |
+
* @return array
|
272 |
+
*/
|
273 |
+
public function get_schedule_options( $schedule_config ) {
|
274 |
+
$labels = ITSEC_Notification_Center::get_schedule_labels();
|
275 |
+
$ordered = ITSEC_Notification_Center::get_schedule_order();
|
276 |
+
$min = array_search( $schedule_config['min'], $ordered, true );
|
277 |
+
$max = array_search( $schedule_config['max'], $ordered, true );
|
278 |
+
|
279 |
+
$options = array();
|
280 |
+
|
281 |
+
foreach ( $ordered as $i => $schedule ) {
|
282 |
+
if ( $min <= $i && $max >= $i ) {
|
283 |
+
$options[ $schedule ] = $labels[ $schedule ];
|
284 |
+
}
|
285 |
+
}
|
286 |
+
|
287 |
+
return $options;
|
288 |
+
}
|
289 |
+
|
290 |
+
/**
|
291 |
+
* Get the allowed HTML tags for messages.
|
292 |
+
*
|
293 |
+
* @return array
|
294 |
+
*/
|
295 |
+
public function get_allowed_html() {
|
296 |
+
return array(
|
297 |
+
'a' => array(
|
298 |
+
'href' => array(),
|
299 |
+
'title' => array(),
|
300 |
+
),
|
301 |
+
'i' => array(),
|
302 |
+
'b' => array(),
|
303 |
+
'h2' => array(),
|
304 |
+
'h3' => array(),
|
305 |
+
'h4' => array(),
|
306 |
+
'h5' => array(),
|
307 |
+
'h6' => array(),
|
308 |
+
'p' => array(),
|
309 |
+
);
|
310 |
+
}
|
311 |
+
}
|
312 |
+
|
313 |
+
ITSEC_Modules::register_validator( new ITSEC_Notification_Center_Validator() );
|
core/modules/strong-passwords/class-itsec-strong-passwords.php
CHANGED
@@ -17,9 +17,7 @@ final class ITSEC_Strong_Passwords {
|
|
17 |
* @return void
|
18 |
*/
|
19 |
public function add_scripts() {
|
20 |
-
|
21 |
-
|
22 |
-
wp_enqueue_script( 'itsec_strong_passwords', $module_path . 'js/script.js', array( 'jquery' ), ITSEC_Core::get_plugin_build() );
|
23 |
}
|
24 |
|
25 |
/**
|
17 |
* @return void
|
18 |
*/
|
19 |
public function add_scripts() {
|
20 |
+
wp_enqueue_script( 'itsec_strong_passwords', plugins_url( 'js/script.js', __FILE__ ), array( 'jquery' ), ITSEC_Core::get_plugin_build() );
|
|
|
|
|
21 |
}
|
22 |
|
23 |
/**
|
core/notify.php
CHANGED
@@ -9,108 +9,52 @@
|
|
9 |
class ITSEC_Notify {
|
10 |
|
11 |
public function __construct() {
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
}
|
16 |
-
|
17 |
-
if ( defined( 'ITSEC_NOTIFY_USE_CRON' ) && true === ITSEC_NOTIFY_USE_CRON ) {
|
18 |
-
|
19 |
-
add_action( 'itsec_digest_email', array( $this, 'init' ) ); //Action to execute during a cron run.
|
20 |
-
|
21 |
-
//schedule digest email
|
22 |
-
if ( false === wp_next_scheduled( 'itsec_digest_email' ) ) {
|
23 |
-
wp_schedule_event( time(), 'daily', 'itsec_digest_email' );
|
24 |
-
}
|
25 |
-
|
26 |
-
} else {
|
27 |
-
add_action( 'init', array( $this, 'init' ) );
|
28 |
-
}
|
29 |
-
|
30 |
}
|
31 |
|
32 |
/**
|
33 |
-
*
|
34 |
*
|
35 |
-
* @
|
36 |
*
|
37 |
-
* @return
|
38 |
*/
|
39 |
-
public function
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
}
|
51 |
-
|
52 |
-
// Check the cached digest_last_sent value. This will be fast but may be inaccurate.
|
53 |
-
if ( ! $use_cron ) {
|
54 |
-
$last_sent = ITSEC_Modules::get_setting( 'global', 'digest_last_sent' );
|
55 |
-
$yesterday = ITSEC_Core::get_current_time_gmt() - DAY_IN_SECONDS;
|
56 |
-
|
57 |
-
if ( $last_sent > $yesterday ) {
|
58 |
-
return false;
|
59 |
-
}
|
60 |
-
}
|
61 |
-
|
62 |
-
// Attempt to acquire a lock so only one process can send the daily digest at a time.
|
63 |
-
if ( ! ITSEC_Lib::get_lock( 'daily-digest' ) ) {
|
64 |
-
return false;
|
65 |
-
}
|
66 |
-
|
67 |
-
if ( ! $use_cron ) {
|
68 |
-
// This prevents errors where the last sent value is loaded in memory early in the request, before another process has finished sending the value.
|
69 |
-
$last_sent = $this->get_last_sent_uncached();
|
70 |
-
|
71 |
-
// Send digest if it has been 24 hours
|
72 |
-
if ( $last_sent > $yesterday ) {
|
73 |
-
|
74 |
-
return false;
|
75 |
-
}
|
76 |
-
}
|
77 |
-
|
78 |
-
$result = $this->send_daily_digest();
|
79 |
-
|
80 |
-
ITSEC_Lib::release_lock( 'daily-digest' );
|
81 |
|
82 |
-
return $
|
83 |
}
|
84 |
|
85 |
/**
|
86 |
-
* Get the
|
87 |
*
|
88 |
-
* @return
|
89 |
*/
|
90 |
-
|
|
|
91 |
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
$option = 'itsec-storage';
|
96 |
-
$storage = array();
|
97 |
-
|
98 |
-
if ( is_multisite() ) {
|
99 |
-
$network_id = get_current_site()->id;
|
100 |
-
$row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
|
101 |
-
|
102 |
-
if ( is_object( $row ) ) {
|
103 |
-
$storage = maybe_unserialize( $row->meta_value );
|
104 |
-
}
|
105 |
} else {
|
106 |
-
$
|
107 |
-
|
108 |
-
if ( is_object( $row ) ) {
|
109 |
-
$storage = maybe_unserialize( $row->option_value );
|
110 |
-
}
|
111 |
}
|
112 |
|
113 |
-
return
|
|
|
|
|
|
|
|
|
114 |
}
|
115 |
|
116 |
/**
|
@@ -118,27 +62,75 @@ class ITSEC_Notify {
|
|
118 |
*
|
119 |
* @since 2.6.0
|
120 |
*
|
|
|
|
|
|
|
|
|
121 |
* @return bool
|
122 |
*/
|
123 |
-
public function send_daily_digest() {
|
124 |
|
125 |
/** @var ITSEC_Lockout $itsec_lockout */
|
126 |
global $itsec_lockout;
|
127 |
|
128 |
-
|
129 |
$send_email = false;
|
130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
|
132 |
-
|
133 |
-
$mail = new ITSEC_Mail();
|
134 |
-
$mail->add_header( esc_html__( 'Daily Security Digest', 'better-wp-security' ), sprintf( wp_kses( __( 'Your Daily Security Digest for <b>%s</b>', 'better-wp-security' ), array( 'b' => array() ) ), date_i18n( get_option( 'date_format' ) ) ) );
|
135 |
-
$mail->add_info_box( sprintf( wp_kses( __( 'The following is a summary of security related activity on your site: <b>%s</b>', 'better-wp-security' ), array( 'b' => array() ) ), get_option( 'siteurl' ) ) );
|
136 |
|
|
|
|
|
137 |
|
138 |
$mail->add_section_heading( esc_html__( 'Lockouts', 'better-wp-security' ), 'lock' );
|
139 |
|
140 |
-
$user_count =
|
141 |
-
$host_count =
|
142 |
|
143 |
if ( $host_count > 0 || $user_count > 0 ) {
|
144 |
$mail->add_lockouts_summary( $user_count, $host_count );
|
@@ -147,22 +139,36 @@ class ITSEC_Notify {
|
|
147 |
$mail->add_text( esc_html__( 'No lockouts since the last email check.', 'better-wp-security' ) );
|
148 |
}
|
149 |
|
|
|
150 |
|
151 |
-
|
152 |
-
|
153 |
-
if ( in_array( 'file-change', $messages ) ) {
|
154 |
$mail->add_section_heading( esc_html__( 'File Changes', 'better-wp-security' ), 'folder' );
|
155 |
$mail->add_text( esc_html__( 'File changes detected on the site.', 'better-wp-security' ) );
|
156 |
$send_email = true;
|
|
|
157 |
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
}
|
164 |
|
165 |
-
|
|
|
|
|
166 |
$mail->add_section_heading( esc_html__( 'Messages', 'better-wp-security' ), 'message' );
|
167 |
|
168 |
foreach ( $messages as $message ) {
|
@@ -174,31 +180,50 @@ class ITSEC_Notify {
|
|
174 |
|
175 |
|
176 |
if ( ! $send_email ) {
|
177 |
-
return;
|
178 |
}
|
179 |
|
180 |
|
181 |
-
$mail->add_details_box( sprintf(
|
|
|
|
|
|
|
|
|
182 |
$mail->add_divider();
|
183 |
$mail->add_large_text( esc_html__( 'Is your site as secure as it could be?', 'better-wp-security' ) );
|
184 |
$mail->add_text( esc_html__( 'Ensure your site is using recommended settings and features with a security check.', 'better-wp-security' ) );
|
185 |
$mail->add_button( esc_html__( 'Run a Security Check ✓', 'better-wp-security' ), ITSEC_Mail::filter_admin_page_url( ITSEC_Core::get_security_check_page_url() ) );
|
186 |
|
187 |
-
if ( defined( 'ITSEC_DEBUG' ) && true === ITSEC_DEBUG ) {
|
188 |
-
$mail->add_text( sprintf( esc_html__( 'Debug info (source page): %s', 'better-wp-security' ), esc_url( $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] ) ) );
|
189 |
-
}
|
190 |
-
|
191 |
$mail->add_footer();
|
192 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
|
194 |
-
|
195 |
-
ITSEC_Modules::set_setting( 'global', 'digest_messages', array() );
|
196 |
-
ITSEC_Storage::save();
|
197 |
|
198 |
-
|
199 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
200 |
|
201 |
-
return $
|
202 |
}
|
203 |
|
204 |
/**
|
@@ -209,17 +234,8 @@ class ITSEC_Notify {
|
|
209 |
* @return null
|
210 |
*/
|
211 |
public function register_file_change() {
|
212 |
-
|
213 |
-
|
214 |
-
$messages = ITSEC_Modules::get_setting( 'global', 'digest_messages' );
|
215 |
-
|
216 |
-
if ( in_array( 'file-change', $messages ) ) {
|
217 |
-
return;
|
218 |
-
}
|
219 |
-
|
220 |
-
$messages[] = 'file-change';
|
221 |
-
|
222 |
-
ITSEC_Modules::set_setting( 'global', 'digest_messages', $messages );
|
223 |
}
|
224 |
|
225 |
/**
|
@@ -233,6 +249,12 @@ class ITSEC_Notify {
|
|
233 |
*/
|
234 |
public function notify( $body = null ) {
|
235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
$allowed_tags = array(
|
237 |
'a' => array(
|
238 |
'href' => array(),
|
@@ -253,43 +275,20 @@ class ITSEC_Notify {
|
|
253 |
'h4' => array(),
|
254 |
);
|
255 |
|
256 |
-
|
257 |
-
|
258 |
-
$messages = ITSEC_Modules::get_setting( 'global', 'digest_messages' );
|
259 |
-
|
260 |
-
if ( ! in_array( wp_kses( $body, $allowed_tags ), $messages ) ) {
|
261 |
|
262 |
-
|
263 |
|
264 |
-
|
265 |
|
266 |
-
|
267 |
-
|
268 |
-
return true;
|
269 |
-
|
270 |
-
} else if ( ITSEC_Modules::get_setting( 'global', 'email_notifications', true ) ) {
|
271 |
-
|
272 |
-
$subject = trim( sanitize_text_field( $body['subject'] ) );
|
273 |
-
$message = wp_kses( $body['message'], $allowed_tags );
|
274 |
-
|
275 |
-
if ( isset( $body['headers'] ) ) {
|
276 |
-
|
277 |
-
$headers = $body['headers'];
|
278 |
-
|
279 |
-
} else {
|
280 |
-
|
281 |
-
$headers = '';
|
282 |
-
|
283 |
-
}
|
284 |
-
|
285 |
-
$attachments = isset( $body['attachments'] ) && is_array( $body['attachments'] ) ? $body['attachments'] : array();
|
286 |
|
287 |
-
|
288 |
|
289 |
}
|
290 |
|
291 |
-
return
|
292 |
-
|
293 |
}
|
294 |
|
295 |
/**
|
@@ -300,11 +299,10 @@ class ITSEC_Notify {
|
|
300 |
* @param string $subject Email subject
|
301 |
* @param string $message Message contents
|
302 |
* @param string|array $headers Optional. Additional headers.
|
303 |
-
* @param string|array $attachments Optional. Files to attach.
|
304 |
*
|
305 |
* @return bool Whether the email contents were sent successfully.
|
306 |
*/
|
307 |
-
private function send_mail( $subject, $message, $headers = ''
|
308 |
|
309 |
$recipients = ITSEC_Modules::get_setting( 'global', 'notification_email' );
|
310 |
$all_success = true;
|
@@ -348,3 +346,64 @@ class ITSEC_Notify {
|
|
348 |
|
349 |
}
|
350 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
class ITSEC_Notify {
|
10 |
|
11 |
public function __construct() {
|
12 |
+
add_filter( 'itsec_notifications', array( $this, 'register_notification' ) );
|
13 |
+
add_filter( 'itsec_digest_notification_strings', array( $this, 'notification_strings' ) );
|
14 |
+
add_filter( 'itsec_send_notification_digest', array( $this, 'send_daily_digest' ), 10, 3 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
}
|
16 |
|
17 |
/**
|
18 |
+
* Register the digest notification.
|
19 |
*
|
20 |
+
* @param array $notifications
|
21 |
*
|
22 |
+
* @return array
|
23 |
*/
|
24 |
+
public function register_notification( $notifications ) {
|
25 |
+
$notifications['digest'] = array(
|
26 |
+
'slug' => 'digest',
|
27 |
+
'recipient' => ITSEC_Notification_Center::R_USER_LIST_ADMIN_UPGRADE,
|
28 |
+
'schedule' => array(
|
29 |
+
'min' => ITSEC_Notification_Center::S_DAILY,
|
30 |
+
'max' => ITSEC_Notification_Center::S_WEEKLY,
|
31 |
+
),
|
32 |
+
'subject_editable' => true,
|
33 |
+
'optional' => true,
|
34 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
+
return $notifications;
|
37 |
}
|
38 |
|
39 |
/**
|
40 |
+
* Get the digest notification strings.
|
41 |
*
|
42 |
+
* @return array
|
43 |
*/
|
44 |
+
public function notification_strings() {
|
45 |
+
$description = esc_html__( 'During periods of heavy attack, iThemes Security can generate a LOT of email.', 'better-wp-security' );
|
46 |
|
47 |
+
if ( ITSEC_Core::is_pro() ) {
|
48 |
+
$features = esc_html__( 'The Security Digest reduces the number of emails sent so you can receive a summary of lockouts, file change detection scans, and privilege escalations.' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
} else {
|
50 |
+
$features = esc_html__( 'The Security Digest reduces the number of emails sent so you can receive a summary of lockouts and file change detection scans.' );
|
|
|
|
|
|
|
|
|
51 |
}
|
52 |
|
53 |
+
return array(
|
54 |
+
'label' => esc_html__( 'Security Digest', 'better-wp-security' ),
|
55 |
+
'description' => $description . ' ' . $features,
|
56 |
+
'subject' => esc_html__( 'Daily Security Digest', 'better-wp-security' ), // Default schedule is Daily
|
57 |
+
);
|
58 |
}
|
59 |
|
60 |
/**
|
62 |
*
|
63 |
* @since 2.6.0
|
64 |
*
|
65 |
+
* @param bool $sent
|
66 |
+
* @param int $last_sent
|
67 |
+
* @param array $data
|
68 |
+
*
|
69 |
* @return bool
|
70 |
*/
|
71 |
+
public function send_daily_digest( $sent, $last_sent, $data ) {
|
72 |
|
73 |
/** @var ITSEC_Lockout $itsec_lockout */
|
74 |
global $itsec_lockout;
|
75 |
|
|
|
76 |
$send_email = false;
|
77 |
|
78 |
+
$df = get_option( 'date_format' );
|
79 |
+
$nc = ITSEC_Core::get_notification_center();
|
80 |
+
|
81 |
+
switch ( $nc->get_schedule( 'digest' ) ) {
|
82 |
+
case ITSEC_Notification_Center::S_DAILY:
|
83 |
+
$title = esc_html__( 'Daily Security Digest', 'better-wp-security' );
|
84 |
+
$banner_title = sprintf( esc_html__( 'Your Daily Security Digest for %s', 'better-wp-security' ), '<b>' . date_i18n( $df ) . '</b>' );
|
85 |
+
break;
|
86 |
+
case ITSEC_Notification_Center::S_WEEKLY:
|
87 |
+
$period = sprintf(
|
88 |
+
'%s - %s',
|
89 |
+
ITSEC_Lib::date_format_i18n_and_local_timezone( $last_sent, $df ),
|
90 |
+
ITSEC_Lib::date_format_i18n_and_local_timezone( ITSEC_Core::get_current_time_gmt(), $df )
|
91 |
+
);
|
92 |
+
|
93 |
+
$title = esc_html__( 'Weekly Security Digest', 'better-wp-security' );
|
94 |
+
$banner_title = sprintf( esc_html__( 'Your Weekly Security Digest for %s', 'better-wp-security' ), '<b>' . $period . '</b>' );
|
95 |
+
break;
|
96 |
+
case ITSEC_Notification_Center::S_MONTHLY:
|
97 |
+
|
98 |
+
$this_day = (int) date( 'j', ITSEC_Core::get_current_time_gmt() );
|
99 |
+
|
100 |
+
if ( $this_day <= 3 ) {
|
101 |
+
$period = date_i18n('F Y', $last_sent );
|
102 |
+
} else {
|
103 |
+
$period = sprintf(
|
104 |
+
'%s - %s',
|
105 |
+
ITSEC_Lib::date_format_i18n_and_local_timezone( $last_sent, $df ),
|
106 |
+
ITSEC_Lib::date_format_i18n_and_local_timezone( ITSEC_Core::get_current_time_gmt(), $df )
|
107 |
+
);
|
108 |
+
}
|
109 |
+
|
110 |
+
$title = esc_html__( 'Monthly Security Digest', 'better-wp-security' );
|
111 |
+
$banner_title = sprintf( esc_html__( 'Your Monthly Security Digest for %s', 'better-wp-security' ), '<b>' . $period . '</b>' );
|
112 |
+
break;
|
113 |
+
default:
|
114 |
+
$period = sprintf(
|
115 |
+
'%s - %s',
|
116 |
+
ITSEC_Lib::date_format_i18n_and_local_timezone( $last_sent, $df ),
|
117 |
+
ITSEC_Lib::date_format_i18n_and_local_timezone( ITSEC_Core::get_current_time_gmt(), $df )
|
118 |
+
);
|
119 |
+
|
120 |
+
$title = esc_html__( 'Security Digest', 'better-wp-security' );
|
121 |
+
$banner_title = sprintf( esc_html__( 'Your Security Digest for %s', 'better-wp-security' ), '<b>' . $period . '</b>' );
|
122 |
+
break;
|
123 |
+
}
|
124 |
|
125 |
+
$mail = $nc->mail();
|
|
|
|
|
|
|
126 |
|
127 |
+
$mail->add_header( $title, $banner_title );
|
128 |
+
$mail->add_info_box( sprintf( esc_html__( 'The following is a summary of security related activity on your site: %s', 'better-wp-security' ), '<b>' . $mail->get_display_url() . '</b>' ) );
|
129 |
|
130 |
$mail->add_section_heading( esc_html__( 'Lockouts', 'better-wp-security' ), 'lock' );
|
131 |
|
132 |
+
$user_count = $itsec_lockout->get_lockouts( 'user', array( 'after' => $last_sent, 'return' => 'count' ) );
|
133 |
+
$host_count = $itsec_lockout->get_lockouts( 'host', array( 'after' => $last_sent, 'return' => 'count' ) );
|
134 |
|
135 |
if ( $host_count > 0 || $user_count > 0 ) {
|
136 |
$mail->add_lockouts_summary( $user_count, $host_count );
|
139 |
$mail->add_text( esc_html__( 'No lockouts since the last email check.', 'better-wp-security' ) );
|
140 |
}
|
141 |
|
142 |
+
$data_proxy = new ITSEC_Notify_Data_Proxy( $data );
|
143 |
|
144 |
+
if ( $data_proxy->has_message( 'file-change' ) ) {
|
|
|
|
|
145 |
$mail->add_section_heading( esc_html__( 'File Changes', 'better-wp-security' ), 'folder' );
|
146 |
$mail->add_text( esc_html__( 'File changes detected on the site.', 'better-wp-security' ) );
|
147 |
$send_email = true;
|
148 |
+
}
|
149 |
|
150 |
+
if ( ! $send_email ) {
|
151 |
+
$content = $mail->get_content();
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Fires when additional info should be attached to the Security Digest.
|
156 |
+
*
|
157 |
+
* @since 3.9.0
|
158 |
+
*
|
159 |
+
* @param ITSEC_Mail $mail
|
160 |
+
* @param ITSEC_Notify_Data_Proxy $data_proxy
|
161 |
+
* @param int $last_sent
|
162 |
+
*/
|
163 |
+
do_action( 'itsec_security_digest_attach_additional_info', $mail, $data_proxy, $last_sent );
|
164 |
+
|
165 |
+
if ( ! $send_email && $content !== $mail->get_content() ) {
|
166 |
+
$send_email = true;
|
167 |
}
|
168 |
|
169 |
+
$messages = $this->get_general_messages( $data );
|
170 |
+
|
171 |
+
if ( $messages ) {
|
172 |
$mail->add_section_heading( esc_html__( 'Messages', 'better-wp-security' ), 'message' );
|
173 |
|
174 |
foreach ( $messages as $message ) {
|
180 |
|
181 |
|
182 |
if ( ! $send_email ) {
|
183 |
+
return true;
|
184 |
}
|
185 |
|
186 |
|
187 |
+
$mail->add_details_box( sprintf(
|
188 |
+
esc_html__( 'For more details, %1$svisit your security logs%2$s', 'better-wp-security' ),
|
189 |
+
'<a href="' . ITSEC_Mail::filter_admin_page_url( ITSEC_Core::get_logs_page_url() ) . '"><b>',
|
190 |
+
'</b></a>'
|
191 |
+
) );
|
192 |
$mail->add_divider();
|
193 |
$mail->add_large_text( esc_html__( 'Is your site as secure as it could be?', 'better-wp-security' ) );
|
194 |
$mail->add_text( esc_html__( 'Ensure your site is using recommended settings and features with a security check.', 'better-wp-security' ) );
|
195 |
$mail->add_button( esc_html__( 'Run a Security Check ✓', 'better-wp-security' ), ITSEC_Mail::filter_admin_page_url( ITSEC_Core::get_security_check_page_url() ) );
|
196 |
|
|
|
|
|
|
|
|
|
197 |
$mail->add_footer();
|
198 |
|
199 |
+
return $nc->send( 'digest', $mail );
|
200 |
+
}
|
201 |
+
|
202 |
+
/**
|
203 |
+
* Get general digest messages.
|
204 |
+
*
|
205 |
+
* @param array $data
|
206 |
+
*
|
207 |
+
* @return string[]
|
208 |
+
*/
|
209 |
+
private function get_general_messages( $data ) {
|
210 |
+
|
211 |
+
$messages = array();
|
212 |
|
213 |
+
foreach ( $data as $datum ) {
|
|
|
|
|
214 |
|
215 |
+
if ( ! is_array( $datum ) || ! isset( $datum['message'] ) ) {
|
216 |
+
continue;
|
217 |
+
}
|
218 |
+
|
219 |
+
if ( isset( $datum['type'] ) && 'general' !== $datum['type'] ) {
|
220 |
+
continue;
|
221 |
+
}
|
222 |
+
|
223 |
+
$messages[] = $datum['message'];
|
224 |
+
}
|
225 |
|
226 |
+
return $messages;
|
227 |
}
|
228 |
|
229 |
/**
|
234 |
* @return null
|
235 |
*/
|
236 |
public function register_file_change() {
|
237 |
+
_deprecated_function( __METHOD__, '3.9.0', 'ITSEC_Notification_Center::enqueue_data' );
|
238 |
+
ITSEC_Core::get_notification_center()->enqueue_data( 'digest', array( 'type' => 'file-change' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
239 |
}
|
240 |
|
241 |
/**
|
249 |
*/
|
250 |
public function notify( $body = null ) {
|
251 |
|
252 |
+
_deprecated_function( __METHOD__, '3.9.0', 'ITSEC_Notification_Center' );
|
253 |
+
|
254 |
+
if ( empty( $body ) || ! is_array( $body ) ) {
|
255 |
+
return true;
|
256 |
+
}
|
257 |
+
|
258 |
$allowed_tags = array(
|
259 |
'a' => array(
|
260 |
'href' => array(),
|
275 |
'h4' => array(),
|
276 |
);
|
277 |
|
278 |
+
$subject = trim( sanitize_text_field( $body['subject'] ) );
|
279 |
+
$message = wp_kses( $body['message'], $allowed_tags );
|
|
|
|
|
|
|
280 |
|
281 |
+
if ( isset( $body['headers'] ) ) {
|
282 |
|
283 |
+
$headers = $body['headers'];
|
284 |
|
285 |
+
} else {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
286 |
|
287 |
+
$headers = '';
|
288 |
|
289 |
}
|
290 |
|
291 |
+
return $this->send_mail( $subject, $message, $headers );
|
|
|
292 |
}
|
293 |
|
294 |
/**
|
299 |
* @param string $subject Email subject
|
300 |
* @param string $message Message contents
|
301 |
* @param string|array $headers Optional. Additional headers.
|
|
|
302 |
*
|
303 |
* @return bool Whether the email contents were sent successfully.
|
304 |
*/
|
305 |
+
private function send_mail( $subject, $message, $headers = '' ) {
|
306 |
|
307 |
$recipients = ITSEC_Modules::get_setting( 'global', 'notification_email' );
|
308 |
$all_success = true;
|
346 |
|
347 |
}
|
348 |
}
|
349 |
+
|
350 |
+
class ITSEC_Notify_Data_Proxy {
|
351 |
+
|
352 |
+
/** @var array */
|
353 |
+
private $data;
|
354 |
+
|
355 |
+
/**
|
356 |
+
* ITSEC_Notify_Data_Proxy constructor.
|
357 |
+
*
|
358 |
+
* @param array $data
|
359 |
+
*/
|
360 |
+
public function __construct( $data ) { $this->data = $data; }
|
361 |
+
|
362 |
+
/**
|
363 |
+
* Check for a queued message.
|
364 |
+
*
|
365 |
+
* @param string $type
|
366 |
+
*
|
367 |
+
* @return array|null
|
368 |
+
*/
|
369 |
+
public function has_message( $type ) {
|
370 |
+
|
371 |
+
foreach ( $this->data as $datum ) {
|
372 |
+
|
373 |
+
if ( ! is_array( $datum ) ) {
|
374 |
+
continue;
|
375 |
+
}
|
376 |
+
|
377 |
+
if ( isset( $datum['type'] ) && $type === $datum['type'] ) {
|
378 |
+
return $datum;
|
379 |
+
}
|
380 |
+
}
|
381 |
+
|
382 |
+
return null;
|
383 |
+
}
|
384 |
+
|
385 |
+
/**
|
386 |
+
* Get all messages of a given type.
|
387 |
+
*
|
388 |
+
* @param string $type
|
389 |
+
*
|
390 |
+
* @return array
|
391 |
+
*/
|
392 |
+
public function get_messages_of_type( $type ) {
|
393 |
+
|
394 |
+
$of_type = array();
|
395 |
+
|
396 |
+
foreach ( $this->data as $datum ) {
|
397 |
+
if ( ! is_array( $datum ) ) {
|
398 |
+
continue;
|
399 |
+
}
|
400 |
+
|
401 |
+
if ( isset( $datum['type'] ) && $type === $datum['type'] ) {
|
402 |
+
$of_type[] = $datum;
|
403 |
+
}
|
404 |
+
}
|
405 |
+
|
406 |
+
return $of_type;
|
407 |
+
}
|
408 |
+
|
409 |
+
}
|
core/response.php
CHANGED
@@ -7,6 +7,7 @@ final class ITSEC_Response {
|
|
7 |
private $errors;
|
8 |
private $warnings;
|
9 |
private $messages;
|
|
|
10 |
private $success;
|
11 |
private $js_function_calls;
|
12 |
private $show_default_success_message;
|
@@ -16,6 +17,7 @@ final class ITSEC_Response {
|
|
16 |
private $close_modal;
|
17 |
private $regenerate_wp_config;
|
18 |
private $regenerate_server_config;
|
|
|
19 |
|
20 |
private function __construct() {
|
21 |
$this->reset_to_defaults();
|
@@ -113,6 +115,24 @@ final class ITSEC_Response {
|
|
113 |
return $self->messages;
|
114 |
}
|
115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
public static function add_js_function_call( $js_function, $args = null ) {
|
117 |
$self = self::get_instance();
|
118 |
|
@@ -249,6 +269,26 @@ final class ITSEC_Response {
|
|
249 |
}
|
250 |
}
|
251 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
252 |
public static function get_raw_data() {
|
253 |
$self = self::get_instance();
|
254 |
|
@@ -263,15 +303,17 @@ final class ITSEC_Response {
|
|
263 |
|
264 |
|
265 |
$data = array(
|
266 |
-
'source'
|
267 |
-
'success'
|
268 |
-
'response'
|
269 |
-
'errors'
|
270 |
-
'warnings'
|
271 |
-
'messages'
|
272 |
-
'
|
273 |
-
'
|
274 |
-
'
|
|
|
|
|
275 |
);
|
276 |
|
277 |
return $data;
|
7 |
private $errors;
|
8 |
private $warnings;
|
9 |
private $messages;
|
10 |
+
private $infos;
|
11 |
private $success;
|
12 |
private $js_function_calls;
|
13 |
private $show_default_success_message;
|
17 |
private $close_modal;
|
18 |
private $regenerate_wp_config;
|
19 |
private $regenerate_server_config;
|
20 |
+
private $has_new_notifications = false;
|
21 |
|
22 |
private function __construct() {
|
23 |
$this->reset_to_defaults();
|
115 |
return $self->messages;
|
116 |
}
|
117 |
|
118 |
+
public static function add_infos( $messages ) {
|
119 |
+
foreach ( $messages as $message ) {
|
120 |
+
self::add_info( $message );
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
public static function add_info( $message ) {
|
125 |
+
$self = self::get_instance();
|
126 |
+
|
127 |
+
$self->infos[] = $message;
|
128 |
+
}
|
129 |
+
|
130 |
+
public static function get_infos() {
|
131 |
+
$self = self::get_instance();
|
132 |
+
|
133 |
+
return $self->infos;
|
134 |
+
}
|
135 |
+
|
136 |
public static function add_js_function_call( $js_function, $args = null ) {
|
137 |
$self = self::get_instance();
|
138 |
|
269 |
}
|
270 |
}
|
271 |
|
272 |
+
public static function maybe_flag_new_notifications_available() {
|
273 |
+
$nc = ITSEC_Core::get_notification_center();
|
274 |
+
|
275 |
+
$current = array_keys( $nc->get_notifications() );
|
276 |
+
$nc->clear_notifications_cache();
|
277 |
+
$new = array_keys( $nc->get_notifications() );
|
278 |
+
|
279 |
+
$added = array_diff( $new, $current );
|
280 |
+
|
281 |
+
if ( $added ) {
|
282 |
+
self::reload_module( 'notification-center' );
|
283 |
+
self::get_instance()->has_new_notifications = true;
|
284 |
+
self::get_instance()->add_info( sprintf(
|
285 |
+
esc_html__( 'New notifications available in the %1$sNotification Center%2$s.', 'better-wp-security' ),
|
286 |
+
'<a href="#" data-module-link="notification-center">',
|
287 |
+
'</a>'
|
288 |
+
) );
|
289 |
+
}
|
290 |
+
}
|
291 |
+
|
292 |
public static function get_raw_data() {
|
293 |
$self = self::get_instance();
|
294 |
|
303 |
|
304 |
|
305 |
$data = array(
|
306 |
+
'source' => 'ITSEC_Response',
|
307 |
+
'success' => $self->success,
|
308 |
+
'response' => $self->response,
|
309 |
+
'errors' => self::get_error_strings( $self->errors ),
|
310 |
+
'warnings' => self::get_error_strings( $self->warnings ),
|
311 |
+
'messages' => $self->messages,
|
312 |
+
'infos' => $self->infos,
|
313 |
+
'functionCalls' => self::parse_js_function_calls_for_module_reloads(),
|
314 |
+
'redirect' => $self->redirect,
|
315 |
+
'closeModal' => $self->close_modal,
|
316 |
+
'newNotifications' => $self->has_new_notifications,
|
317 |
);
|
318 |
|
319 |
return $data;
|
core/setup.php
CHANGED
@@ -57,10 +57,7 @@ final class ITSEC_Setup {
|
|
57 |
|
58 |
if ( is_array( $plugin_data ) && ! empty( $plugin_data['build'] ) ) {
|
59 |
$build = $plugin_data['build'];
|
60 |
-
|
61 |
-
if ( ! empty( $plugin_data['activation_timestamp'] ) ) {
|
62 |
-
ITSEC_Modules::set_setting( 'global', 'activation_timestamp', $plugin_data['activation_timestamp'] );
|
63 |
-
}
|
64 |
}
|
65 |
|
66 |
delete_site_option( 'itsec_data' );
|
@@ -82,6 +79,9 @@ final class ITSEC_Setup {
|
|
82 |
}
|
83 |
}
|
84 |
|
|
|
|
|
|
|
85 |
|
86 |
// Ensure that the database tables are present and updated to the current schema.
|
87 |
ITSEC_Lib::create_database_tables();
|
57 |
|
58 |
if ( is_array( $plugin_data ) && ! empty( $plugin_data['build'] ) ) {
|
59 |
$build = $plugin_data['build'];
|
60 |
+
ITSEC_Modules::set_setting( 'global', 'activation_timestamp', $plugin_data['activation_timestamp'] );
|
|
|
|
|
|
|
61 |
}
|
62 |
|
63 |
delete_site_option( 'itsec_data' );
|
79 |
}
|
80 |
}
|
81 |
|
82 |
+
if ( ! ITSEC_Modules::get_setting( 'global', 'activation_timestamp' ) ) {
|
83 |
+
ITSEC_Modules::set_setting( 'global', 'activation_timestamp', ITSEC_Core::get_current_time_gmt() );
|
84 |
+
}
|
85 |
|
86 |
// Ensure that the database tables are present and updated to the current schema.
|
87 |
ITSEC_Lib::create_database_tables();
|
core/sidebar-widget-active-lockouts.php
CHANGED
@@ -14,7 +14,7 @@ class ITSEC_Settings_Page_Sidebar_Widget_Active_Lockouts extends ITSEC_Settings_
|
|
14 |
/** @var ITSEC_Lockout $itsec_lockout */
|
15 |
global $itsec_lockout;
|
16 |
|
17 |
-
$lockouts = $itsec_lockout->get_lockouts(
|
18 |
$users = array();
|
19 |
$hosts = array();
|
20 |
|
14 |
/** @var ITSEC_Lockout $itsec_lockout */
|
15 |
global $itsec_lockout;
|
16 |
|
17 |
+
$lockouts = $itsec_lockout->get_lockouts();
|
18 |
$users = array();
|
19 |
$hosts = array();
|
20 |
|
core/sidebar-widget-temp-whitelist.php
CHANGED
@@ -13,7 +13,7 @@ class ITSEC_Settings_Page_Sidebar_Widget_Temp_Whitelist extends ITSEC_Settings_P
|
|
13 |
/** @var ITSEC_Lockout $itsec_lockout */
|
14 |
global $itsec_lockout;
|
15 |
|
16 |
-
$lockouts = $itsec_lockout->get_lockouts(
|
17 |
$users = array();
|
18 |
$hosts = array();
|
19 |
|
@@ -79,6 +79,8 @@ class ITSEC_Settings_Page_Sidebar_Widget_Temp_Whitelist extends ITSEC_Settings_P
|
|
79 |
}
|
80 |
|
81 |
protected function save( $data ) {
|
|
|
|
|
82 |
global $itsec_lockout;
|
83 |
|
84 |
$count = 0;
|
13 |
/** @var ITSEC_Lockout $itsec_lockout */
|
14 |
global $itsec_lockout;
|
15 |
|
16 |
+
$lockouts = $itsec_lockout->get_lockouts();
|
17 |
$users = array();
|
18 |
$hosts = array();
|
19 |
|
79 |
}
|
80 |
|
81 |
protected function save( $data ) {
|
82 |
+
|
83 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
84 |
global $itsec_lockout;
|
85 |
|
86 |
$count = 0;
|
core/sync-verbs/itsec-get-lockouts.php
CHANGED
@@ -9,9 +9,10 @@ class Ithemes_Sync_Verb_ITSEC_Get_Lockouts extends Ithemes_Sync_Verb {
|
|
9 |
|
10 |
public function run( $arguments ) {
|
11 |
|
|
|
12 |
global $itsec_lockout;
|
13 |
|
14 |
-
$lockouts = $itsec_lockout->get_lockouts(
|
15 |
|
16 |
//Send the user name or false
|
17 |
foreach ( $lockouts as $key => $lockout ) {
|
9 |
|
10 |
public function run( $arguments ) {
|
11 |
|
12 |
+
/** @var ITSEC_Lockout $itsec_lockout */
|
13 |
global $itsec_lockout;
|
14 |
|
15 |
+
$lockouts = $itsec_lockout->get_lockouts(); //Gets all lockouts, host and user
|
16 |
|
17 |
//Send the user name or false
|
18 |
foreach ( $lockouts as $key => $lockout ) {
|
history.txt
CHANGED
@@ -692,3 +692,7 @@
|
|
692 |
Bug Fix: Fixed SQL query bug that resulted in the "Minutes to Remember Bad Login (check period)" setting being ignored.
|
693 |
Bug Fix: Fixed bug that prevents wp-admin/install.php blocking from working properly on nginx servers.
|
694 |
Bug Fix: Don't attempt to do an SSL redirect when WP CLI is running.
|
|
|
|
|
|
|
|
692 |
Bug Fix: Fixed SQL query bug that resulted in the "Minutes to Remember Bad Login (check period)" setting being ignored.
|
693 |
Bug Fix: Fixed bug that prevents wp-admin/install.php blocking from working properly on nginx servers.
|
694 |
Bug Fix: Don't attempt to do an SSL redirect when WP CLI is running.
|
695 |
+
6.7.0 - 2017-11-07 - Chris Jean & Timothy Jacobs
|
696 |
+
New Feature: Introduces the Notification Center, a centralized place to manage and customize email notifications sent by iThemes Security.
|
697 |
+
Enhancement: Updated queries and prepare statements to account for changes to the esc_sql() function in WordPress 4.8.3.
|
698 |
+
Bug Fix: Corrected some Javascript and CSS links not generating correctly on Windows servers.
|
readme.txt
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
Contributors: ithemes, chrisjean, gerroald, mattdanner, timothyblynjacobs
|
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.
|
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,11 @@ Free support may be available with the help of the community in the <a href="htt
|
|
188 |
|
189 |
== Changelog ==
|
190 |
|
|
|
|
|
|
|
|
|
|
|
191 |
= 6.6.1 =
|
192 |
* Bug Fix: Fixed SQL query bug that resulted in the "Minutes to Remember Bad Login (check period)" setting being ignored.
|
193 |
* Bug Fix: Fixed bug that prevents wp-admin/install.php blocking from working properly on nginx servers.
|
@@ -372,5 +377,5 @@ Free support may be available with the help of the community in the <a href="htt
|
|
372 |
|
373 |
== Upgrade Notice ==
|
374 |
|
375 |
-
= 6.
|
376 |
-
Version 6.
|
2 |
Contributors: ithemes, chrisjean, gerroald, mattdanner, timothyblynjacobs
|
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.9
|
6 |
+
Stable tag: 6.7.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.7.0 =
|
192 |
+
* New Feature: Introduces the Notification Center, a centralized place to manage and customize email notifications sent by iThemes Security.
|
193 |
+
* Enhancement: Updated queries and prepare statements to account for changes to the esc_sql() function in WordPress 4.8.3.
|
194 |
+
* Bug Fix: Corrected some Javascript and CSS links not generating correctly on Windows servers.
|
195 |
+
|
196 |
= 6.6.1 =
|
197 |
* Bug Fix: Fixed SQL query bug that resulted in the "Minutes to Remember Bad Login (check period)" setting being ignored.
|
198 |
* Bug Fix: Fixed bug that prevents wp-admin/install.php blocking from working properly on nginx servers.
|
377 |
|
378 |
== Upgrade Notice ==
|
379 |
|
380 |
+
= 6.7.0 =
|
381 |
+
Version 6.7.0 contains important bug fixes. It is recommended for all users.
|