Version Description
- New Feature: Introduces a scheduling framework for handling events. Cron is now used by default, and will switch to using an alternate scheduling system if it detects an error. To disable this detection set ITSEC_DISABLE_CRON_TEST in your wp-config.php file.
- Important: The ITSEC_FILE_CHECK_CRON and ITSEC_BACKUP_CRON constants have been deprecated. Use ITSEC_USE_CRON instead.
- Enhancement: Preserve notification settings when the responsible module is deactivated.
- Bug Fix: Process 404 lockouts on the 'wp' hook to prevent a headers have already been sent warning message.
- Bug Fix: Ensure Hide Backend emails are properly sent when activating Hide Backend before saving the Notification Center for the first time.
- Bug Fix: Prevent warning from being issued on new installs by allowing previous settings to be preserved if they exist.
- Bug Fix: Better handle WP_Error objects in mail errors that occurred before updating to first patch release.
- Bug Fix: A non static method was being called statically.
- Bug Fix: Fix occasional duplicate backups and file scans.
- Bug Fix: Fixed issue where scheduled events could repeat on sites that do not properly support WordPress's cron system.
- Bug Fix: Reactivating Away Mode now replaces the active file if you had previously removed it.
- Bug Fix: Ensure lockouts take effect immediately, even on systems where changes to server configuration files do not take effect immediately.
Download this release
Release Info
Developer | chrisjean |
Plugin | iThemes Security (formerly Better WP Security) |
Version | 6.8.0 |
Comparing to | |
See all releases |
Code changes from version 6.7.0 to 6.8.0
- better-wp-security.php +1 -1
- core/core.php +61 -7
- core/history.txt +25 -1
- core/lib.php +74 -0
- core/lib/class-itsec-job.php +92 -0
- core/lib/class-itsec-lib-utility.php +23 -0
- core/lib/class-itsec-scheduler-cron.php +378 -0
- core/lib/class-itsec-scheduler-page-load.php +352 -0
- core/lib/class-itsec-scheduler.php +255 -0
- core/lib/validator.php +8 -0
- core/lockout.php +55 -32
- core/modules/404-detection/class-itsec-four-oh-four.php +1 -2
- core/modules/away-mode/activate.php +5 -0
- core/modules/backup/activate.php +7 -0
- core/modules/backup/class-itsec-backup.php +27 -22
- core/modules/backup/deactivate.php +2 -0
- core/modules/backup/settings-page.php +8 -10
- core/modules/backup/settings.php +11 -0
- core/modules/backup/setup.php +4 -0
- core/modules/file-change/activate.php +6 -0
- core/modules/file-change/class-itsec-file-change.php +16 -25
- core/modules/file-change/deactivate.php +2 -0
- core/modules/file-change/settings.php +10 -0
- core/modules/file-change/setup.php +4 -0
- core/modules/file-change/validator.php +2 -1
- core/modules/global/active.php +101 -0
- core/modules/global/settings.php +42 -1
- core/modules/global/validator.php +2 -1
- core/modules/hide-backend/settings.php +42 -0
- core/modules/hide-backend/validator.php +0 -27
- core/modules/notification-center/settings-page.php +5 -5
- core/modules/notification-center/validator.php +1 -2
- core/modules/salts/utilities.php +3 -3
- core/setup.php +34 -2
- history.txt +13 -0
- readme.txt +19 -5
better-wp-security.php
CHANGED
@@ -6,7 +6,7 @@
|
|
6 |
* Description: Take the guesswork out of WordPress security. iThemes Security offers 30+ ways to lock down WordPress in an easy-to-use WordPress security plugin.
|
7 |
* Author: iThemes
|
8 |
* Author URI: https://ithemes.com
|
9 |
-
* Version: 6.
|
10 |
* Text Domain: better-wp-security
|
11 |
* Network: True
|
12 |
* License: GPLv2
|
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.8.0
|
10 |
* Text Domain: better-wp-security
|
11 |
* Network: True
|
12 |
* License: GPLv2
|
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
|
@@ -42,6 +42,7 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
42 |
$itsec_files,
|
43 |
$itsec_notify,
|
44 |
$notifications,
|
|
|
45 |
$sync_api,
|
46 |
$plugin_file,
|
47 |
$plugin_dir,
|
@@ -119,10 +120,16 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
119 |
require( $this->plugin_dir . 'core/lib/class-itsec-lib-user-activity.php' );
|
120 |
require( $this->plugin_dir . 'core/lib/class-itsec-lib-password-requirements.php' );
|
121 |
|
|
|
|
|
|
|
|
|
|
|
122 |
$this->itsec_files = ITSEC_Files::get_instance();
|
123 |
$this->itsec_notify = new ITSEC_Notify();
|
124 |
$itsec_logger = new ITSEC_Logger();
|
125 |
-
$itsec_lockout = new ITSEC_Lockout(
|
|
|
126 |
|
127 |
// Handle upgrade if needed.
|
128 |
if ( ITSEC_Modules::get_setting( 'global', 'build' ) < $this->plugin_build ) {
|
@@ -143,11 +150,8 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
143 |
|
144 |
add_action( 'ithemes_sync_register_verbs', array( $this, 'register_sync_verbs' ) );
|
145 |
|
146 |
-
|
147 |
-
|
148 |
-
}
|
149 |
-
|
150 |
-
add_action( 'itsec_clear_locks', array( 'ITSEC_Lib', 'delete_expired_locks' ) );
|
151 |
}
|
152 |
|
153 |
/**
|
@@ -168,9 +172,32 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
168 |
$pass_requirements->run();
|
169 |
}
|
170 |
|
|
|
|
|
|
|
|
|
171 |
do_action( 'itsec_initialized' );
|
172 |
}
|
173 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
/**
|
175 |
* Retrieve the global instance of the files utility.
|
176 |
*
|
@@ -209,6 +236,24 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
209 |
return self::get_instance()->notifications;
|
210 |
}
|
211 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
/**
|
213 |
* Retrieve the global instance of the Sync API.
|
214 |
*
|
@@ -233,6 +278,15 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
|
|
233 |
$sync_api->register( 'itsec-get-everything', 'Ithemes_Sync_Verb_ITSEC_Get_Everything', dirname( __FILE__ ) . '/sync-verbs/itsec-get-everything.php' );
|
234 |
}
|
235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
/**
|
237 |
* Register core modules.
|
238 |
*/
|
25 |
*
|
26 |
* @access private
|
27 |
*/
|
28 |
+
private $plugin_build = 4080;
|
29 |
|
30 |
/**
|
31 |
* Used to distinguish between a user modifying settings and the API modifying settings (such as from Sync
|
42 |
$itsec_files,
|
43 |
$itsec_notify,
|
44 |
$notifications,
|
45 |
+
$scheduler,
|
46 |
$sync_api,
|
47 |
$plugin_file,
|
48 |
$plugin_dir,
|
120 |
require( $this->plugin_dir . 'core/lib/class-itsec-lib-user-activity.php' );
|
121 |
require( $this->plugin_dir . 'core/lib/class-itsec-lib-password-requirements.php' );
|
122 |
|
123 |
+
require( $this->plugin_dir . 'core/lib/class-itsec-scheduler.php' );
|
124 |
+
require( $this->plugin_dir . 'core/lib/class-itsec-job.php' );
|
125 |
+
|
126 |
+
$this->setup_scheduler();
|
127 |
+
|
128 |
$this->itsec_files = ITSEC_Files::get_instance();
|
129 |
$this->itsec_notify = new ITSEC_Notify();
|
130 |
$itsec_logger = new ITSEC_Logger();
|
131 |
+
$itsec_lockout = new ITSEC_Lockout();
|
132 |
+
$itsec_lockout->run();
|
133 |
|
134 |
// Handle upgrade if needed.
|
135 |
if ( ITSEC_Modules::get_setting( 'global', 'build' ) < $this->plugin_build ) {
|
150 |
|
151 |
add_action( 'ithemes_sync_register_verbs', array( $this, 'register_sync_verbs' ) );
|
152 |
|
153 |
+
add_action( 'itsec_scheduler_register_events', array( $this, 'register_events' ) );
|
154 |
+
add_action( 'itsec_scheduled_clear-locks', array( 'ITSEC_Lib', 'delete_expired_locks' ) );
|
|
|
|
|
|
|
155 |
}
|
156 |
|
157 |
/**
|
172 |
$pass_requirements->run();
|
173 |
}
|
174 |
|
175 |
+
if ( defined( 'ITSEC_USE_CRON' ) && ITSEC_USE_CRON !== ITSEC_Lib::use_cron() ) {
|
176 |
+
ITSEC_Modules::set_setting( 'global', 'use_cron', ITSEC_USE_CRON );
|
177 |
+
}
|
178 |
+
|
179 |
do_action( 'itsec_initialized' );
|
180 |
}
|
181 |
|
182 |
+
private function setup_scheduler() {
|
183 |
+
|
184 |
+
$choices = array(
|
185 |
+
'ITSEC_Scheduler_Cron' => $this->plugin_dir . 'core/lib/class-itsec-scheduler-cron.php',
|
186 |
+
'ITSEC_Scheduler_Page_Load' => $this->plugin_dir . 'core/lib/class-itsec-scheduler-page-load.php',
|
187 |
+
);
|
188 |
+
|
189 |
+
if ( ITSEC_Lib::use_cron() ) {
|
190 |
+
$class = 'ITSEC_Scheduler_Cron';
|
191 |
+
} else {
|
192 |
+
$class = 'ITSEC_Scheduler_Page_Load';
|
193 |
+
}
|
194 |
+
|
195 |
+
require_once( $choices[ $class ] );
|
196 |
+
|
197 |
+
$this->scheduler = new $class();
|
198 |
+
self::get_scheduler()->run();
|
199 |
+
}
|
200 |
+
|
201 |
/**
|
202 |
* Retrieve the global instance of the files utility.
|
203 |
*
|
236 |
return self::get_instance()->notifications;
|
237 |
}
|
238 |
|
239 |
+
/**
|
240 |
+
* Set the scheduler to use.
|
241 |
+
*
|
242 |
+
* @param ITSEC_Scheduler $scheduler
|
243 |
+
*/
|
244 |
+
public static function set_scheduler( ITSEC_Scheduler $scheduler ) {
|
245 |
+
self::get_instance()->scheduler = $scheduler;
|
246 |
+
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
* Get the scheduler.
|
250 |
+
*
|
251 |
+
* @return ITSEC_Scheduler
|
252 |
+
*/
|
253 |
+
public static function get_scheduler() {
|
254 |
+
return self::get_instance()->scheduler;
|
255 |
+
}
|
256 |
+
|
257 |
/**
|
258 |
* Retrieve the global instance of the Sync API.
|
259 |
*
|
278 |
$sync_api->register( 'itsec-get-everything', 'Ithemes_Sync_Verb_ITSEC_Get_Everything', dirname( __FILE__ ) . '/sync-verbs/itsec-get-everything.php' );
|
279 |
}
|
280 |
|
281 |
+
/**
|
282 |
+
* Register events.
|
283 |
+
*
|
284 |
+
* @param ITSEC_Scheduler $scheduler
|
285 |
+
*/
|
286 |
+
public function register_events( $scheduler ) {
|
287 |
+
$scheduler->schedule( ITSEC_Scheduler::S_DAILY, 'clear-locks' );
|
288 |
+
}
|
289 |
+
|
290 |
/**
|
291 |
* Register core modules.
|
292 |
*/
|
core/history.txt
CHANGED
@@ -597,4 +597,28 @@
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
601 |
+
3.9.5 - 2017-11-27 - Chris Jean & Timothy Jacobs
|
602 |
+
Enhancement: Preserve notification settings when the responsible module is deactivated.
|
603 |
+
Bug Fix: Process 404 lockouts on the 'wp' hook to prevent a headers have already been sent warning message.
|
604 |
+
Bug Fix: Ensure Hide Backend emails are properly sent when activating Hide Backend before saving the Notification Center for the first time.
|
605 |
+
Bug Fix: Prevent warning from being issued on new installs by allowing previous settings to be preserved if they exist.
|
606 |
+
Bug Fix: Better handle WP_Error objects in mail errors that occurred before updating to first patch release.
|
607 |
+
Bug Fix: A non static method was being called statically.
|
608 |
+
4.0.0 - 2017-12-07 - Chris Jean & Timothy Jacobs
|
609 |
+
New Feature: Introduces a scheduling framework for handling events. Cron is now used by default, and will switch to using an alternate scheduling system if it detects an error. To disable this detection set ITSEC_DISABLE_CRON_TEST in your wp-config.php file.
|
610 |
+
Important: The ITSEC_FILE_CHECK_CRON and ITSEC_BACKUP_CRON constants have been deprecated. Use ITSEC_USE_CRON instead.
|
611 |
+
Bug Fix: Fix occasional duplicate backups and file scans.
|
612 |
+
4.0.1 - 2017-12-11 - Chris Jean & Timothy Jacobs
|
613 |
+
Bug Fix: Fixed issue where scheduled events could repeat on sites that do not properly support WordPress's cron system.
|
614 |
+
4.0.2 - 2017-12-28 - Chris Jean & Timothy Jacobs
|
615 |
+
Bug Fix: Make Cron scheduler available in more circumstances.
|
616 |
+
Bug Fix: Events with the Twice Daily schedule would not be carried over when switching scheduler strategies.
|
617 |
+
Bug Fix: Backup schedules respect the interval chosen.
|
618 |
+
Bug Fix: Prevent multiple cron tests from being scheduled at once.
|
619 |
+
Bug Fix: Cron test being stuck in a loop preventing a site from switching back to the cron scheduler.
|
620 |
+
Bug Fix: Prevent warnings when a single and recurring event were scheduled at the same time.
|
621 |
+
4.0.3 - 2017-01-04 - Chris Jean & Timothy Jacobs
|
622 |
+
Bug Fix: Fix scheduling retries for Malware Scans on sites that don't fully support WordPress's cron system.
|
623 |
+
Bug Fix: Reactivating Away Mode now replaces the active file if you had previously removed it.
|
624 |
+
Bug Fix: Ensure lockouts take effect immediately, even on systems where changes to server configuration files do not take effect immediately.
|
core/lib.php
CHANGED
@@ -1024,6 +1024,37 @@ final class ITSEC_Lib {
|
|
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 ) ) {
|
@@ -1052,4 +1083,47 @@ final class ITSEC_Lib {
|
|
1052 |
|
1053 |
return $array;
|
1054 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1055 |
}
|
1024 |
return date_i18n( $format, strtotime( get_date_from_gmt( date( 'Y-m-d H:i:s', $timestamp ) ) ) );
|
1025 |
}
|
1026 |
|
1027 |
+
/**
|
1028 |
+
* Get the value of an option directly from the database, bypassing any caching.
|
1029 |
+
*
|
1030 |
+
* @param string $option
|
1031 |
+
*
|
1032 |
+
* @return array|mixed
|
1033 |
+
*/
|
1034 |
+
public static function get_uncached_option( $option ) {
|
1035 |
+
/** @var $wpdb \wpdb */
|
1036 |
+
global $wpdb;
|
1037 |
+
|
1038 |
+
$storage = array();
|
1039 |
+
|
1040 |
+
if ( is_multisite() ) {
|
1041 |
+
$network_id = get_current_site()->id;
|
1042 |
+
$row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
|
1043 |
+
|
1044 |
+
if ( is_object( $row ) ) {
|
1045 |
+
$storage = maybe_unserialize( $row->meta_value );
|
1046 |
+
}
|
1047 |
+
} else {
|
1048 |
+
$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
|
1049 |
+
|
1050 |
+
if ( is_object( $row ) ) {
|
1051 |
+
$storage = maybe_unserialize( $row->option_value );
|
1052 |
+
}
|
1053 |
+
}
|
1054 |
+
|
1055 |
+
return $storage;
|
1056 |
+
}
|
1057 |
+
|
1058 |
public static function array_get( $array, $key, $default = null ) {
|
1059 |
|
1060 |
if ( ! is_array( $array ) ) {
|
1083 |
|
1084 |
return $array;
|
1085 |
}
|
1086 |
+
|
1087 |
+
/**
|
1088 |
+
* Check if WP Cron appears to be running properly.
|
1089 |
+
*
|
1090 |
+
* @return bool
|
1091 |
+
*/
|
1092 |
+
public static function is_cron_working() {
|
1093 |
+
$working = ITSEC_Modules::get_setting( 'global', 'cron_status' );
|
1094 |
+
|
1095 |
+
return $working === 1;
|
1096 |
+
}
|
1097 |
+
|
1098 |
+
/**
|
1099 |
+
* Should we be using Cron.
|
1100 |
+
*
|
1101 |
+
* @return bool
|
1102 |
+
*/
|
1103 |
+
public static function use_cron() {
|
1104 |
+
return ITSEC_Modules::get_setting( 'global', 'use_cron' );
|
1105 |
+
}
|
1106 |
+
|
1107 |
+
/**
|
1108 |
+
* Schedule a test to see if a user should be suggested to enable the Cron scheduler.
|
1109 |
+
*/
|
1110 |
+
public static function schedule_cron_test() {
|
1111 |
+
|
1112 |
+
if ( defined( 'ITSEC_DISABLE_CRON_TEST' ) && ITSEC_DISABLE_CRON_TEST ) {
|
1113 |
+
return;
|
1114 |
+
}
|
1115 |
+
|
1116 |
+
$crons = _get_cron_array();
|
1117 |
+
|
1118 |
+
foreach ( $crons as $timestamp => $cron ) {
|
1119 |
+
if ( isset( $cron['itsec_cron_test'] ) ) {
|
1120 |
+
return;
|
1121 |
+
}
|
1122 |
+
}
|
1123 |
+
|
1124 |
+
// Get a random time in the next 6-18 hours on a random minute.
|
1125 |
+
$time = ITSEC_Core::get_current_time_gmt() + mt_rand( 6, 18 ) * HOUR_IN_SECONDS + mt_rand( 1, 60 ) * MINUTE_IN_SECONDS;
|
1126 |
+
wp_schedule_single_event( $time, 'itsec_cron_test', array( $time ) );
|
1127 |
+
ITSEC_Modules::set_setting( 'global', 'cron_test_time', $time );
|
1128 |
+
}
|
1129 |
}
|
core/lib/class-itsec-job.php
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ITSEC_Job {
|
4 |
+
|
5 |
+
/** @var ITSEC_Scheduler */
|
6 |
+
private $scheduler;
|
7 |
+
|
8 |
+
/** @var string */
|
9 |
+
private $id;
|
10 |
+
|
11 |
+
/** @var array */
|
12 |
+
private $data;
|
13 |
+
|
14 |
+
/** @var array */
|
15 |
+
private $opts;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* ITSEC_Job constructor.
|
19 |
+
*
|
20 |
+
* @param ITSEC_Scheduler $scheduler
|
21 |
+
* @param string $id
|
22 |
+
* @param array $data
|
23 |
+
* @param array $opts
|
24 |
+
*/
|
25 |
+
public function __construct( ITSEC_Scheduler $scheduler, $id, $data = array(), $opts = array() ) {
|
26 |
+
$this->scheduler = $scheduler;
|
27 |
+
$this->id = $id;
|
28 |
+
$this->data = $data;
|
29 |
+
$this->opts = $opts;
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Reschedule a job in some number of seconds.
|
34 |
+
*
|
35 |
+
* The original event will not fire while a reschedule is pending.
|
36 |
+
*
|
37 |
+
* @param int $seconds
|
38 |
+
*/
|
39 |
+
public function reschedule_in( $seconds ) {
|
40 |
+
$data = $this->get_data();
|
41 |
+
|
42 |
+
if ( isset( $data['retry_count'] ) ) {
|
43 |
+
$data['retry_count'] ++;
|
44 |
+
} else {
|
45 |
+
$data['retry_count'] = 1;
|
46 |
+
}
|
47 |
+
|
48 |
+
$this->scheduler->schedule_once( ITSEC_Core::get_current_time_gmt() + $seconds, $this->id, $data );
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Get the retry count for this job.
|
53 |
+
*
|
54 |
+
* @return int|false
|
55 |
+
*/
|
56 |
+
public function is_retry() {
|
57 |
+
$data = $this->get_data();
|
58 |
+
|
59 |
+
if ( empty( $data['retry_count'] ) ) {
|
60 |
+
return false;
|
61 |
+
}
|
62 |
+
|
63 |
+
return $data['retry_count'];
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Get the ID of this job.
|
68 |
+
*
|
69 |
+
* @return string
|
70 |
+
*/
|
71 |
+
public function get_id() {
|
72 |
+
return $this->id;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Get the data attached to the job.
|
77 |
+
*
|
78 |
+
* @return array
|
79 |
+
*/
|
80 |
+
public function get_data() {
|
81 |
+
return $this->data;
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Is this a single event.
|
86 |
+
*
|
87 |
+
* @return bool
|
88 |
+
*/
|
89 |
+
public function is_single() {
|
90 |
+
return ! empty( $this->opts['single'] );
|
91 |
+
}
|
92 |
+
}
|
core/lib/class-itsec-lib-utility.php
CHANGED
@@ -189,5 +189,28 @@ if ( ! class_exists( 'ITSEC_Lib_Utility' ) ) {
|
|
189 |
|
190 |
return $contents;
|
191 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
192 |
}
|
193 |
}
|
189 |
|
190 |
return $contents;
|
191 |
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Check if an array is associative.
|
195 |
+
*
|
196 |
+
* @param array $array
|
197 |
+
*
|
198 |
+
* @return bool
|
199 |
+
*/
|
200 |
+
public static function is_associative_array( $array ) {
|
201 |
+
if ( ! is_array( $array ) || empty( $array ) ) {
|
202 |
+
return false;
|
203 |
+
}
|
204 |
+
|
205 |
+
$next = 0;
|
206 |
+
|
207 |
+
foreach ( $array as $k => $v ) {
|
208 |
+
if ( $k !== $next ++ ) {
|
209 |
+
return true;
|
210 |
+
}
|
211 |
+
}
|
212 |
+
|
213 |
+
return false;
|
214 |
+
}
|
215 |
}
|
216 |
}
|
core/lib/class-itsec-scheduler-cron.php
ADDED
@@ -0,0 +1,378 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ITSEC_Scheduler_Cron extends ITSEC_Scheduler {
|
4 |
+
|
5 |
+
const HOOK = 'itsec_cron';
|
6 |
+
const OPTION = 'itsec_cron';
|
7 |
+
|
8 |
+
public function run() {
|
9 |
+
add_action( self::HOOK, array( $this, 'process' ), 10, 2 );
|
10 |
+
add_filter( 'cron_schedules', array( $this, 'register_cron_schedules' ) );
|
11 |
+
}
|
12 |
+
|
13 |
+
public function register_cron_schedules( $schedules ) {
|
14 |
+
|
15 |
+
$schedules[ 'itsec-' . self::S_FOUR_DAILY ] = array(
|
16 |
+
'display' => esc_html__( 'Four Times per Day', 'better-wp-security' ),
|
17 |
+
'interval' => DAY_IN_SECONDS / 4,
|
18 |
+
);
|
19 |
+
$schedules[ 'itsec-' . self::S_WEEKLY ] = array(
|
20 |
+
'display' => esc_html__( 'Weekly', 'better-wp-security' ),
|
21 |
+
'interval' => WEEK_IN_SECONDS,
|
22 |
+
);
|
23 |
+
$schedules[ 'itsec-' . self::S_MONTHLY ] = array(
|
24 |
+
'display' => esc_html__( 'Monthly', 'better-wp-security' ),
|
25 |
+
'interval' => MONTH_IN_SECONDS,
|
26 |
+
);
|
27 |
+
|
28 |
+
foreach ( $this->custom_schedules as $schedule => $interval ) {
|
29 |
+
$schedules[ 'itsec-' . $schedule ] = array(
|
30 |
+
'display' => ucfirst( $schedule ),
|
31 |
+
'interval' => $interval,
|
32 |
+
);
|
33 |
+
}
|
34 |
+
|
35 |
+
return $schedules;
|
36 |
+
}
|
37 |
+
|
38 |
+
public function process( $id, $hash = null ) {
|
39 |
+
|
40 |
+
if ( $hash ) {
|
41 |
+
$this->run_single_event_by_hash( $id, $hash );
|
42 |
+
} else {
|
43 |
+
$this->run_recurring_event( $id );
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
public function run_recurring_event( $id ) {
|
48 |
+
|
49 |
+
$storage = $this->get_options();
|
50 |
+
$data = $storage['recurring'][ $id ]['data'];
|
51 |
+
|
52 |
+
$job = $this->make_job( $id, $data );
|
53 |
+
|
54 |
+
if ( $this->is_retry_scheduled( $id, $data ) ) {
|
55 |
+
return;
|
56 |
+
}
|
57 |
+
|
58 |
+
$this->call_action( $job );
|
59 |
+
}
|
60 |
+
|
61 |
+
public function run_single_event( $id, $data = array() ) {
|
62 |
+
$this->run_single_event_by_hash( $id, $this->hash_data( $data ) );
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Run a single event.
|
67 |
+
*
|
68 |
+
* @param string $id
|
69 |
+
* @param string $hash
|
70 |
+
*/
|
71 |
+
private function run_single_event_by_hash( $id, $hash ) {
|
72 |
+
|
73 |
+
$opts = array( 'single' => true );
|
74 |
+
|
75 |
+
$storage = $this->get_options();
|
76 |
+
$data = $storage['single'][ $id ][ $hash ]['data'];
|
77 |
+
|
78 |
+
$job = $this->make_job( $id, $data, $opts );
|
79 |
+
|
80 |
+
$this->call_action( $job );
|
81 |
+
$this->unschedule_single( $id, $data );
|
82 |
+
}
|
83 |
+
|
84 |
+
public function is_recurring_scheduled( $id ) {
|
85 |
+
return (bool) wp_next_scheduled( self::HOOK, array( $id ) );
|
86 |
+
}
|
87 |
+
|
88 |
+
public function is_single_scheduled( $id, $data = array() ) {
|
89 |
+
return (bool) wp_next_scheduled( self::HOOK, array( $id, $this->hash_data( $data ) ) );
|
90 |
+
}
|
91 |
+
|
92 |
+
public function schedule( $schedule, $id, $data = array(), $opts = array() ) {
|
93 |
+
|
94 |
+
if ( ! $this->scheduling_lock() ) {
|
95 |
+
return false;
|
96 |
+
}
|
97 |
+
|
98 |
+
if ( $this->is_recurring_scheduled( $id ) ) {
|
99 |
+
$this->scheduling_unlock();
|
100 |
+
|
101 |
+
return false;
|
102 |
+
}
|
103 |
+
|
104 |
+
$options = $this->get_options();
|
105 |
+
|
106 |
+
$options['recurring'][ $id ] = array( 'data' => $data );
|
107 |
+
$this->set_options( $options );
|
108 |
+
|
109 |
+
$args = array( $id );
|
110 |
+
|
111 |
+
// Prevent a flood of cron events all occurring at the same time.
|
112 |
+
$time = isset( $opts['fire_at'] ) ? $opts['fire_at'] : ITSEC_Core::get_current_time_gmt() + 60 * mt_rand( 1, 30 );
|
113 |
+
$scheduled = wp_schedule_event( $time, $this->cron_name_for_schedule( $schedule ), self::HOOK, $args );
|
114 |
+
$this->scheduling_unlock();
|
115 |
+
|
116 |
+
if ( false === $scheduled ) {
|
117 |
+
return false;
|
118 |
+
}
|
119 |
+
|
120 |
+
return true;
|
121 |
+
}
|
122 |
+
|
123 |
+
public function schedule_once( $at, $id, $data = array() ) {
|
124 |
+
|
125 |
+
if ( ! $this->scheduling_lock() ) {
|
126 |
+
return false;
|
127 |
+
}
|
128 |
+
|
129 |
+
if ( $this->is_single_scheduled( $id, $data ) ) {
|
130 |
+
$this->scheduling_unlock();
|
131 |
+
|
132 |
+
return false;
|
133 |
+
}
|
134 |
+
|
135 |
+
$hash = $this->hash_data( $data );
|
136 |
+
$args = array( $id, $hash );
|
137 |
+
|
138 |
+
$options = $this->get_options();
|
139 |
+
$options['single'][ $id ][ $hash ] = array( 'data' => $data );
|
140 |
+
$this->set_options( $options );
|
141 |
+
|
142 |
+
$scheduled = wp_schedule_single_event( $at, self::HOOK, $args );
|
143 |
+
$this->scheduling_unlock();
|
144 |
+
|
145 |
+
if ( false === $scheduled ) {
|
146 |
+
return false;
|
147 |
+
}
|
148 |
+
|
149 |
+
return true;
|
150 |
+
}
|
151 |
+
|
152 |
+
public function unschedule( $id ) {
|
153 |
+
|
154 |
+
$hash = $this->make_cron_hash( $id );
|
155 |
+
|
156 |
+
if ( $this->unschedule_by_hash( $hash ) ) {
|
157 |
+
|
158 |
+
$options = $this->get_options();
|
159 |
+
unset( $options['recurring'][ $id ] );
|
160 |
+
$this->set_options( $options );
|
161 |
+
|
162 |
+
return true;
|
163 |
+
}
|
164 |
+
|
165 |
+
return false;
|
166 |
+
}
|
167 |
+
|
168 |
+
public function unschedule_single( $id, $data = array() ) {
|
169 |
+
$data_hash = $this->hash_data( $data );
|
170 |
+
$hash = $this->make_cron_hash( $id, $data );
|
171 |
+
|
172 |
+
if ( $this->unschedule_by_hash( $hash ) ) {
|
173 |
+
|
174 |
+
$options = $this->get_options();
|
175 |
+
unset( $options['single'][ $id ][ $data_hash ] );
|
176 |
+
$this->set_options( $options );
|
177 |
+
|
178 |
+
return true;
|
179 |
+
}
|
180 |
+
|
181 |
+
return false;
|
182 |
+
}
|
183 |
+
|
184 |
+
private function unschedule_by_hash( $hash ) {
|
185 |
+
|
186 |
+
$crons = _get_cron_array();
|
187 |
+
$found = false;
|
188 |
+
|
189 |
+
foreach ( $crons as $timestamp => $hooks ) {
|
190 |
+
if ( isset( $hooks[ self::HOOK ][ $hash ] ) ) {
|
191 |
+
$found = true;
|
192 |
+
unset( $crons[ $timestamp ][ self::HOOK ][ $hash ] );
|
193 |
+
break;
|
194 |
+
}
|
195 |
+
}
|
196 |
+
|
197 |
+
if ( $found ) {
|
198 |
+
_set_cron_array( $crons );
|
199 |
+
}
|
200 |
+
|
201 |
+
return $found;
|
202 |
+
}
|
203 |
+
|
204 |
+
public function get_recurring_events() {
|
205 |
+
|
206 |
+
$crons = _get_cron_array();
|
207 |
+
$options = $this->get_options();
|
208 |
+
$events = array();
|
209 |
+
|
210 |
+
foreach ( $crons as $timestamp => $hooks ) {
|
211 |
+
|
212 |
+
if ( ! isset( $hooks[ self::HOOK ] ) ) {
|
213 |
+
continue;
|
214 |
+
}
|
215 |
+
|
216 |
+
foreach ( $hooks[ self::HOOK ] as $key => $cron_event ) {
|
217 |
+
|
218 |
+
list( $id ) = $cron_event['args'];
|
219 |
+
|
220 |
+
if ( ! isset( $options['recurring'][ $id ] ) || isset( $cron_event['args'][1] ) ) {
|
221 |
+
continue;
|
222 |
+
}
|
223 |
+
|
224 |
+
$events[] = array(
|
225 |
+
'id' => $id,
|
226 |
+
'data' => $options['recurring'][ $id ]['data'],
|
227 |
+
'fire_at' => $timestamp,
|
228 |
+
'schedule' => $this->get_api_schedule_from_cron_schedule( $cron_event['schedule'] ),
|
229 |
+
);
|
230 |
+
}
|
231 |
+
}
|
232 |
+
|
233 |
+
return $events;
|
234 |
+
}
|
235 |
+
|
236 |
+
public function get_single_events() {
|
237 |
+
|
238 |
+
$crons = _get_cron_array();
|
239 |
+
$options = $this->get_options();
|
240 |
+
$events = array();
|
241 |
+
|
242 |
+
foreach ( $crons as $timestamp => $hooks ) {
|
243 |
+
|
244 |
+
if ( ! isset( $hooks[ self::HOOK ] ) ) {
|
245 |
+
continue;
|
246 |
+
}
|
247 |
+
|
248 |
+
foreach ( $hooks[ self::HOOK ] as $key => $cron_event ) {
|
249 |
+
|
250 |
+
$id = $cron_event['args'][0];
|
251 |
+
|
252 |
+
if ( ! isset( $options['single'][ $id ], $cron_event['args'][1] ) ) {
|
253 |
+
continue;
|
254 |
+
}
|
255 |
+
|
256 |
+
$hash = $cron_event['args'][1];
|
257 |
+
|
258 |
+
if ( ! isset( $options['single'][ $id ][ $hash ] ) ) {
|
259 |
+
continue; // Sanity check
|
260 |
+
}
|
261 |
+
|
262 |
+
$events[] = array(
|
263 |
+
'id' => $id,
|
264 |
+
'data' => $options['single'][ $id ][ $hash ]['data'],
|
265 |
+
'fire_at' => $timestamp,
|
266 |
+
);
|
267 |
+
}
|
268 |
+
}
|
269 |
+
|
270 |
+
return $events;
|
271 |
+
}
|
272 |
+
|
273 |
+
/**
|
274 |
+
* Is a retry of the given job scheduled.
|
275 |
+
*
|
276 |
+
* @param string $id
|
277 |
+
* @param array $data
|
278 |
+
*
|
279 |
+
* @return bool
|
280 |
+
*/
|
281 |
+
private function is_retry_scheduled( $id, $data ) {
|
282 |
+
$options = $this->get_options();
|
283 |
+
|
284 |
+
if ( ! isset( $options['single'][ $id ] ) ) {
|
285 |
+
return false;
|
286 |
+
}
|
287 |
+
|
288 |
+
foreach ( $options['single'][ $id ] as $hash => $event ) {
|
289 |
+
$maybe_data = $event['data'];
|
290 |
+
|
291 |
+
if ( ! isset( $maybe_data['retry_count'] ) ) {
|
292 |
+
continue;
|
293 |
+
}
|
294 |
+
|
295 |
+
unset( $maybe_data['retry_count'] );
|
296 |
+
|
297 |
+
if ( $this->hash_data( $maybe_data ) === $this->hash_data( $data ) ) {
|
298 |
+
return true;
|
299 |
+
}
|
300 |
+
}
|
301 |
+
|
302 |
+
return false;
|
303 |
+
}
|
304 |
+
|
305 |
+
/**
|
306 |
+
* Make the Cron hash that WordPress uses to uniquely identify cron events by.
|
307 |
+
*
|
308 |
+
* @param string $id
|
309 |
+
* @param array $data
|
310 |
+
*
|
311 |
+
* @return string
|
312 |
+
*/
|
313 |
+
private function make_cron_hash( $id, $data = null ) {
|
314 |
+
|
315 |
+
if ( func_num_args() === 1 ) {
|
316 |
+
return md5( serialize( array( $id ) ) );
|
317 |
+
}
|
318 |
+
|
319 |
+
return md5( serialize( array( $id, $this->hash_data( $data ) ) ) );
|
320 |
+
}
|
321 |
+
|
322 |
+
private function cron_name_for_schedule( $schedule ) {
|
323 |
+
switch ( $schedule ) {
|
324 |
+
case self::S_HOURLY:
|
325 |
+
case self::S_DAILY:
|
326 |
+
return $schedule;
|
327 |
+
case self::S_TWICE_DAILY:
|
328 |
+
return 'twicedaily';
|
329 |
+
default:
|
330 |
+
return "itsec-{$schedule}";
|
331 |
+
}
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Get the API schedule name from the Cron schedule name.
|
336 |
+
*
|
337 |
+
* @param string $cron_schedule
|
338 |
+
*
|
339 |
+
* @return string
|
340 |
+
*/
|
341 |
+
private function get_api_schedule_from_cron_schedule( $cron_schedule ) {
|
342 |
+
$api_schedule = str_replace( 'itsec-', '', $cron_schedule );
|
343 |
+
|
344 |
+
if ( $api_schedule === 'twicedaily' ) {
|
345 |
+
$api_schedule = 'twice-daily';
|
346 |
+
}
|
347 |
+
|
348 |
+
return $api_schedule;
|
349 |
+
}
|
350 |
+
|
351 |
+
private function get_options() {
|
352 |
+
return wp_parse_args( get_site_option( self::OPTION, array() ), array(
|
353 |
+
'single' => array(),
|
354 |
+
'recurring' => array(),
|
355 |
+
) );
|
356 |
+
}
|
357 |
+
|
358 |
+
private function set_options( $options ) {
|
359 |
+
update_site_option( self::OPTION, $options );
|
360 |
+
}
|
361 |
+
|
362 |
+
public function uninstall() {
|
363 |
+
|
364 |
+
$crons = _get_cron_array();
|
365 |
+
|
366 |
+
foreach ( $crons as $timestamp => $args ) {
|
367 |
+
unset( $crons[ $timestamp ][ self::HOOK ] );
|
368 |
+
|
369 |
+
if ( empty( $crons[ $timestamp ] ) ) {
|
370 |
+
unset( $crons[ $timestamp ] );
|
371 |
+
}
|
372 |
+
}
|
373 |
+
|
374 |
+
_set_cron_array( $crons );
|
375 |
+
|
376 |
+
delete_site_option( self::OPTION );
|
377 |
+
}
|
378 |
+
}
|
core/lib/class-itsec-scheduler-page-load.php
ADDED
@@ -0,0 +1,352 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ITSEC_Scheduler_Page_Load extends ITSEC_Scheduler {
|
4 |
+
|
5 |
+
const OPTION = 'itsec_scheduler_page_load';
|
6 |
+
|
7 |
+
private $operating_data;
|
8 |
+
|
9 |
+
public function schedule( $schedule, $id, $data = array(), $opts = array() ) {
|
10 |
+
|
11 |
+
if ( ! $this->scheduling_lock() ) {
|
12 |
+
return false;
|
13 |
+
}
|
14 |
+
|
15 |
+
if ( $this->is_recurring_scheduled( $id ) ) {
|
16 |
+
$this->scheduling_unlock();
|
17 |
+
|
18 |
+
return false;
|
19 |
+
}
|
20 |
+
|
21 |
+
if ( isset( $opts['fire_at'] ) ) {
|
22 |
+
$last_fired = $opts['fire_at'];
|
23 |
+
} else {
|
24 |
+
// Prevent an event stampede
|
25 |
+
$last_fired = ITSEC_Core::get_current_time_gmt() + 60 * mt_rand( 1, 30 );
|
26 |
+
}
|
27 |
+
|
28 |
+
$last_fired -= $this->get_schedule_interval( $schedule );
|
29 |
+
|
30 |
+
$options = $this->operating_data ? $this->operating_data : $this->get_options();
|
31 |
+
|
32 |
+
$options['recurring'][ $id ] = array(
|
33 |
+
'schedule' => $schedule,
|
34 |
+
'last_fired' => $last_fired,
|
35 |
+
'data' => $data,
|
36 |
+
);
|
37 |
+
|
38 |
+
$set = $this->set_options( $options );
|
39 |
+
$this->scheduling_unlock();
|
40 |
+
|
41 |
+
return $set;
|
42 |
+
}
|
43 |
+
|
44 |
+
public function schedule_once( $at, $id, $data = array() ) {
|
45 |
+
|
46 |
+
if ( ! $this->scheduling_lock() ) {
|
47 |
+
return false;
|
48 |
+
}
|
49 |
+
|
50 |
+
if ( $this->is_single_scheduled( $id, $data ) ) {
|
51 |
+
$this->scheduling_unlock();
|
52 |
+
|
53 |
+
return false;
|
54 |
+
}
|
55 |
+
|
56 |
+
$hash = $this->hash_data( $data );
|
57 |
+
$options = $this->operating_data ? $this->operating_data : $this->get_options();
|
58 |
+
|
59 |
+
if ( ! isset( $options['single'][ $id ] ) ) {
|
60 |
+
$options['single'][ $id ] = array();
|
61 |
+
}
|
62 |
+
|
63 |
+
$options['single'][ $id ][ $hash ] = array(
|
64 |
+
'data' => $data,
|
65 |
+
'fire_at' => $at,
|
66 |
+
);
|
67 |
+
|
68 |
+
$set = $this->set_options( $options );
|
69 |
+
$this->scheduling_unlock();
|
70 |
+
|
71 |
+
return $set;
|
72 |
+
}
|
73 |
+
|
74 |
+
public function is_recurring_scheduled( $id ) {
|
75 |
+
$options = $this->get_options();
|
76 |
+
|
77 |
+
return ! empty( $options['recurring'][ $id ] );
|
78 |
+
}
|
79 |
+
|
80 |
+
public function is_single_scheduled( $id, $data = array() ) {
|
81 |
+
|
82 |
+
$hash = $this->hash_data( $data );
|
83 |
+
$options = $this->get_options();
|
84 |
+
|
85 |
+
if ( empty( $options['single'][ $id ] ) ) {
|
86 |
+
return false;
|
87 |
+
}
|
88 |
+
|
89 |
+
if ( empty( $options['single'][ $id ][ $hash ] ) ) {
|
90 |
+
return false;
|
91 |
+
}
|
92 |
+
|
93 |
+
return true;
|
94 |
+
}
|
95 |
+
|
96 |
+
public function unschedule( $id ) {
|
97 |
+
|
98 |
+
$options = $this->operating_data ? $this->operating_data : $this->get_options();
|
99 |
+
|
100 |
+
if ( isset( $options['recurring'][ $id ] ) ) {
|
101 |
+
unset( $options['recurring'][ $id ] );
|
102 |
+
|
103 |
+
return $this->set_options( $options );
|
104 |
+
}
|
105 |
+
|
106 |
+
return false;
|
107 |
+
}
|
108 |
+
|
109 |
+
public function unschedule_single( $id, $data = array() ) {
|
110 |
+
|
111 |
+
$options = $this->operating_data ? $this->operating_data : $this->get_options();
|
112 |
+
$hash = $this->hash_data( $data );
|
113 |
+
|
114 |
+
if ( isset( $options['single'][ $id ][ $hash ] ) ) {
|
115 |
+
unset( $options['single'][ $id ][ $hash ] );
|
116 |
+
|
117 |
+
return $this->set_options( $options );
|
118 |
+
}
|
119 |
+
|
120 |
+
return false;
|
121 |
+
}
|
122 |
+
|
123 |
+
public function get_recurring_events() {
|
124 |
+
$options = $this->get_options();
|
125 |
+
$events = array();
|
126 |
+
|
127 |
+
foreach ( $options['recurring'] as $id => $event ) {
|
128 |
+
$events[] = array(
|
129 |
+
'id' => $id,
|
130 |
+
'data' => $event['data'],
|
131 |
+
'schedule' => $event['schedule'],
|
132 |
+
'fire_at' => $event['last_fired'] + $this->get_schedule_interval( $event['schedule'] ),
|
133 |
+
);
|
134 |
+
}
|
135 |
+
|
136 |
+
return $events;
|
137 |
+
}
|
138 |
+
|
139 |
+
public function get_single_events() {
|
140 |
+
|
141 |
+
$options = $this->get_options();
|
142 |
+
$events = array();
|
143 |
+
|
144 |
+
foreach ( $options['single'] as $id => $hashes ) {
|
145 |
+
foreach ( $hashes as $hash => $event ) {
|
146 |
+
$events[] = array(
|
147 |
+
'id' => $id,
|
148 |
+
'data' => $event['data'],
|
149 |
+
'fire_at' => $event['fire_at'],
|
150 |
+
);
|
151 |
+
}
|
152 |
+
}
|
153 |
+
|
154 |
+
return $events;
|
155 |
+
}
|
156 |
+
|
157 |
+
public function run() {
|
158 |
+
add_action( 'init', array( $this, 'init' ) );
|
159 |
+
}
|
160 |
+
|
161 |
+
public function init() {
|
162 |
+
|
163 |
+
if ( ITSEC_Core::is_api_request() ) {
|
164 |
+
return;
|
165 |
+
}
|
166 |
+
|
167 |
+
$now = ITSEC_Core::get_current_time_gmt();
|
168 |
+
$options = $this->get_options();
|
169 |
+
|
170 |
+
$to_process = array();
|
171 |
+
|
172 |
+
foreach ( $options['single'] as $id => $hashes ) {
|
173 |
+
foreach ( $hashes as $hash => $event ) {
|
174 |
+
if ( $event['fire_at'] < $now ) {
|
175 |
+
$to_process[] = array_merge( $event, array( 'id' => $id ) );
|
176 |
+
}
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
foreach ( $options['recurring'] as $id => $event ) {
|
181 |
+
if ( $this->is_time_to_send( $event['schedule'], $event['last_fired'] ) ) {
|
182 |
+
$to_process[] = array_merge( $event, array( 'id' => $id ) );
|
183 |
+
}
|
184 |
+
}
|
185 |
+
|
186 |
+
if ( ! $to_process ) {
|
187 |
+
return;
|
188 |
+
}
|
189 |
+
|
190 |
+
if ( ! ITSEC_Lib::get_lock( 'scheduler', 120 ) ) {
|
191 |
+
return;
|
192 |
+
}
|
193 |
+
|
194 |
+
$raw = $this->operating_data = ITSEC_Lib::get_uncached_option( self::OPTION );
|
195 |
+
|
196 |
+
foreach ( $to_process as $process ) {
|
197 |
+
if ( isset( $process['fire_at'] ) ) {
|
198 |
+
|
199 |
+
if ( ! isset( $raw['single'][ $process['id'] ][ $this->hash_data( $process['data'] ) ] ) ) {
|
200 |
+
continue; // Another process already fired this single event.
|
201 |
+
}
|
202 |
+
|
203 |
+
$event = $raw['single'][ $process['id'] ][ $this->hash_data( $process['data'] ) ];
|
204 |
+
|
205 |
+
if ( $event['fire_at'] < $now ) {
|
206 |
+
$this->run_single_event( $process['id'], $event['data'] );
|
207 |
+
}
|
208 |
+
} else {
|
209 |
+
$event = $raw['recurring'][ $process['id'] ];
|
210 |
+
|
211 |
+
if ( $this->is_time_to_send( $event['schedule'], $event['last_fired'] ) ) {
|
212 |
+
$this->run_recurring_event( $process['id'] );
|
213 |
+
$this->update_last_fired( $process['id'] );
|
214 |
+
}
|
215 |
+
}
|
216 |
+
}
|
217 |
+
|
218 |
+
$this->operating_data = null;
|
219 |
+
ITSEC_Lib::release_lock( 'scheduler' );
|
220 |
+
}
|
221 |
+
|
222 |
+
public function run_recurring_event( $id ) {
|
223 |
+
|
224 |
+
if ( $this->operating_data ) {
|
225 |
+
$clear_operating_data = false;
|
226 |
+
$storage = $this->operating_data;
|
227 |
+
} else {
|
228 |
+
$clear_operating_data = true;
|
229 |
+
$storage = $this->operating_data = $this->get_options();
|
230 |
+
}
|
231 |
+
|
232 |
+
$event = $storage['recurring'][ $id ];
|
233 |
+
|
234 |
+
$job = $this->make_job( $id, $event['data'] );
|
235 |
+
|
236 |
+
if ( $this->is_retry_scheduled( $id, $event['data'] ) ) {
|
237 |
+
return;
|
238 |
+
}
|
239 |
+
|
240 |
+
$this->call_action( $job );
|
241 |
+
|
242 |
+
if ( $clear_operating_data ) {
|
243 |
+
$this->operating_data = null;
|
244 |
+
}
|
245 |
+
}
|
246 |
+
|
247 |
+
public function run_single_event( $id, $data = array() ) {
|
248 |
+
|
249 |
+
if ( $this->operating_data ) {
|
250 |
+
$clear_operating_data = false;
|
251 |
+
$storage = $this->operating_data;
|
252 |
+
} else {
|
253 |
+
$clear_operating_data = true;
|
254 |
+
$storage = $this->operating_data = $this->get_options();
|
255 |
+
}
|
256 |
+
|
257 |
+
$hash = $this->hash_data( $data );
|
258 |
+
$event = $storage['single'][ $id ][ $hash ];
|
259 |
+
|
260 |
+
$job = $this->make_job( $id, $event['data'], array( 'single' => true ) );
|
261 |
+
|
262 |
+
$this->call_action( $job );
|
263 |
+
|
264 |
+
$this->unschedule_single( $id, $data );
|
265 |
+
|
266 |
+
if ( $clear_operating_data ) {
|
267 |
+
$this->operating_data = null;
|
268 |
+
}
|
269 |
+
}
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Update the time the job was last fired to now.
|
273 |
+
*
|
274 |
+
* @param string $id
|
275 |
+
*/
|
276 |
+
private function update_last_fired( $id ) {
|
277 |
+
|
278 |
+
$storage = $this->operating_data ? $this->operating_data : $this->get_options();
|
279 |
+
|
280 |
+
$storage['recurring'][ $id ]['last_fired'] = ITSEC_Core::get_current_time_gmt();
|
281 |
+
|
282 |
+
$this->set_options( $storage );
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Is a retry of the given job scheduled.
|
287 |
+
*
|
288 |
+
* @param string $id
|
289 |
+
* @param array $data
|
290 |
+
*
|
291 |
+
* @return bool
|
292 |
+
*/
|
293 |
+
private function is_retry_scheduled( $id, $data ) {
|
294 |
+
$options = $this->operating_data ? $this->operating_data : $this->get_options();
|
295 |
+
|
296 |
+
if ( ! isset( $options['single'][ $id ] ) ) {
|
297 |
+
return false;
|
298 |
+
}
|
299 |
+
|
300 |
+
foreach ( $options['single'][ $id ] as $hash => $event ) {
|
301 |
+
|
302 |
+
$event_data = $event['data'];
|
303 |
+
|
304 |
+
if ( ! isset( $event_data['retry_count'] ) ) {
|
305 |
+
continue;
|
306 |
+
}
|
307 |
+
|
308 |
+
unset( $event_data['retry_count'] );
|
309 |
+
|
310 |
+
if ( $this->hash_data( $event_data ) === $this->hash_data( $data ) ) {
|
311 |
+
return true;
|
312 |
+
}
|
313 |
+
}
|
314 |
+
|
315 |
+
return false;
|
316 |
+
}
|
317 |
+
|
318 |
+
private function is_time_to_send( $schedule, $last_sent ) {
|
319 |
+
|
320 |
+
if ( ! $last_sent ) {
|
321 |
+
return true;
|
322 |
+
}
|
323 |
+
|
324 |
+
$period = $this->get_schedule_interval( $schedule );
|
325 |
+
|
326 |
+
if ( ! $period ) {
|
327 |
+
return false;
|
328 |
+
}
|
329 |
+
|
330 |
+
return ( $last_sent + $period ) < ITSEC_Core::get_current_time_gmt();
|
331 |
+
}
|
332 |
+
|
333 |
+
private function get_options() {
|
334 |
+
return wp_parse_args( get_site_option( self::OPTION, array() ), array(
|
335 |
+
'single' => array(),
|
336 |
+
'recurring' => array(),
|
337 |
+
) );
|
338 |
+
}
|
339 |
+
|
340 |
+
private function set_options( $options ) {
|
341 |
+
|
342 |
+
if ( $this->operating_data !== null ) {
|
343 |
+
$this->operating_data = $options;
|
344 |
+
}
|
345 |
+
|
346 |
+
return update_site_option( self::OPTION, $options );
|
347 |
+
}
|
348 |
+
|
349 |
+
public function uninstall() {
|
350 |
+
delete_site_option( self::OPTION );
|
351 |
+
}
|
352 |
+
}
|
core/lib/class-itsec-scheduler.php
ADDED
@@ -0,0 +1,255 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
abstract class ITSEC_Scheduler {
|
4 |
+
|
5 |
+
const S_HOURLY = 'hourly';
|
6 |
+
const S_FOUR_DAILY = 'four-daily';
|
7 |
+
const S_TWICE_DAILY = 'twice-daily';
|
8 |
+
const S_DAILY = 'daily';
|
9 |
+
const S_WEEKLY = 'weekly';
|
10 |
+
const S_MONTHLY = 'monthly';
|
11 |
+
|
12 |
+
const LOCK_SCHEDULING = 'scheduling';
|
13 |
+
|
14 |
+
/** @var array */
|
15 |
+
protected $custom_schedules = array();
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Schedule a recurring event.
|
19 |
+
*
|
20 |
+
* Only one event with the given id can be scheduled at a time.
|
21 |
+
*
|
22 |
+
* @param string $schedule
|
23 |
+
* @param string $id
|
24 |
+
* @param array $data
|
25 |
+
* @param array $opts
|
26 |
+
* - fire_at: Manually specify the first time the event should be fired.
|
27 |
+
*
|
28 |
+
* @return bool
|
29 |
+
*/
|
30 |
+
abstract public function schedule( $schedule, $id, $data = array(), $opts = array() );
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Schedule a single event.
|
34 |
+
*
|
35 |
+
* Only one event with the given id and same set of data can be scheduled at the same time.
|
36 |
+
*
|
37 |
+
* Unlike Core's CRON implementation, event if a single event is more than 10 minutes in the future, it cannot be scheduled.
|
38 |
+
*
|
39 |
+
* @param int $at
|
40 |
+
* @param string $id
|
41 |
+
* @param array $data
|
42 |
+
*
|
43 |
+
* @return bool
|
44 |
+
*/
|
45 |
+
abstract public function schedule_once( $at, $id, $data = array() );
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Is a recurring event scheduled.
|
49 |
+
*
|
50 |
+
* @param string $id
|
51 |
+
*
|
52 |
+
* @return bool
|
53 |
+
*/
|
54 |
+
abstract public function is_recurring_scheduled( $id );
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Is a single event scheduled with the given data.
|
58 |
+
*
|
59 |
+
* @param string $id
|
60 |
+
* @param array $data
|
61 |
+
*
|
62 |
+
* @return bool
|
63 |
+
*/
|
64 |
+
abstract public function is_single_scheduled( $id, $data = array() );
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Unschedule a recurring event.
|
68 |
+
*
|
69 |
+
* @param string $id
|
70 |
+
*
|
71 |
+
* @return bool
|
72 |
+
*/
|
73 |
+
abstract public function unschedule( $id );
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Unschedule a single event.
|
77 |
+
*
|
78 |
+
* The data specified needs to be identical to the data the single event was scheduled with.
|
79 |
+
*
|
80 |
+
* @param string $id
|
81 |
+
* @param array $data
|
82 |
+
*
|
83 |
+
* @return bool
|
84 |
+
*/
|
85 |
+
abstract public function unschedule_single( $id, $data = array() );
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Get all of the scheduled recurring events.
|
89 |
+
*
|
90 |
+
* Each event is an array with the following properties.
|
91 |
+
* - id: The ID the event was scheduled with.
|
92 |
+
* - data: The data the event was scheduled with.
|
93 |
+
* - fire_at: The next time the event should be fired.
|
94 |
+
* - schedule: The selected schedule. See S_HOURLY, etc...
|
95 |
+
*
|
96 |
+
* @return array
|
97 |
+
*/
|
98 |
+
abstract public function get_recurring_events();
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Get all of the single events.
|
102 |
+
*
|
103 |
+
* Each event is an array with the following properties.
|
104 |
+
* - id: The ID the event was scheduled with.
|
105 |
+
* - data: The data the event was scheduled with.
|
106 |
+
* - fire_at: The time the event should be fired.
|
107 |
+
*
|
108 |
+
* @return array
|
109 |
+
*/
|
110 |
+
abstract public function get_single_events();
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Run a recurring event, even if it is not time to.
|
114 |
+
*
|
115 |
+
* This will _not_ update the last fired time.
|
116 |
+
*
|
117 |
+
* @param string $id
|
118 |
+
*
|
119 |
+
* @return void
|
120 |
+
*/
|
121 |
+
abstract public function run_recurring_event( $id );
|
122 |
+
|
123 |
+
/**
|
124 |
+
* Run a single event, even if it is not time to.
|
125 |
+
*
|
126 |
+
* This will clear the event from the schedule.
|
127 |
+
*
|
128 |
+
* @param string $id
|
129 |
+
* @param array $data
|
130 |
+
*
|
131 |
+
* @return void
|
132 |
+
*/
|
133 |
+
abstract public function run_single_event( $id, $data = array() );
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Code executed on every page load to setup the scheduler.
|
137 |
+
*
|
138 |
+
* @return void
|
139 |
+
*/
|
140 |
+
abstract public function run();
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Manually trigger modules to register their scheduled events.
|
144 |
+
*
|
145 |
+
* @return void
|
146 |
+
*/
|
147 |
+
public function register_events() {
|
148 |
+
/**
|
149 |
+
* Register scheduled events.
|
150 |
+
*
|
151 |
+
* Events should be registered in response to a user action, for example activating a module or changing a setting.
|
152 |
+
* Occasionally, iThemes Security will manually ask for all events to be scheduled.
|
153 |
+
*
|
154 |
+
* @param ITSEC_Scheduler $this
|
155 |
+
*/
|
156 |
+
do_action( 'itsec_scheduler_register_events', $this );
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Register a custom schedule.
|
161 |
+
*
|
162 |
+
* @param string $slug
|
163 |
+
* @param int $interval
|
164 |
+
*/
|
165 |
+
public function register_custom_schedule( $slug, $interval ) {
|
166 |
+
$this->custom_schedules[ $slug ] = $interval;
|
167 |
+
}
|
168 |
+
|
169 |
+
/**
|
170 |
+
* Get a lock to be used for scheduling events.
|
171 |
+
*
|
172 |
+
* @return bool
|
173 |
+
*/
|
174 |
+
protected function scheduling_lock() {
|
175 |
+
return ITSEC_Lib::get_lock( self::LOCK_SCHEDULING, 5 );
|
176 |
+
}
|
177 |
+
|
178 |
+
/**
|
179 |
+
* Release the lock used for scheduling events.
|
180 |
+
*/
|
181 |
+
protected function scheduling_unlock() {
|
182 |
+
ITSEC_Lib::release_lock( self::LOCK_SCHEDULING );
|
183 |
+
}
|
184 |
+
|
185 |
+
/**
|
186 |
+
* Make a job object.
|
187 |
+
*
|
188 |
+
* @param string $id
|
189 |
+
* @param array $data
|
190 |
+
* @param array $opts
|
191 |
+
*
|
192 |
+
* @return ITSEC_Job
|
193 |
+
*/
|
194 |
+
protected function make_job( $id, $data, $opts = array() ) {
|
195 |
+
return new ITSEC_Job( $this, $id, $data, $opts );
|
196 |
+
}
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Dispatch the action to execute the scheduled job.
|
200 |
+
*
|
201 |
+
* @param ITSEC_Job $job
|
202 |
+
*/
|
203 |
+
protected final function call_action( ITSEC_Job $job ) {
|
204 |
+
/**
|
205 |
+
* Fires when a scheduled job should be executed.
|
206 |
+
*
|
207 |
+
* @param ITSEC_Job $job
|
208 |
+
*/
|
209 |
+
do_action( "itsec_scheduled_{$job->get_id()}", $job );
|
210 |
+
}
|
211 |
+
|
212 |
+
/**
|
213 |
+
* Generate a unique hash of the data.
|
214 |
+
*
|
215 |
+
* @param array $data
|
216 |
+
*
|
217 |
+
* @return string
|
218 |
+
*/
|
219 |
+
protected function hash_data( $data ) {
|
220 |
+
return md5( serialize( $data ) );
|
221 |
+
}
|
222 |
+
|
223 |
+
/**
|
224 |
+
* Get the interval for the schedule.
|
225 |
+
*
|
226 |
+
* @param string $schedule
|
227 |
+
*
|
228 |
+
* @return int
|
229 |
+
*/
|
230 |
+
protected final function get_schedule_interval( $schedule ) {
|
231 |
+
switch ( $schedule ) {
|
232 |
+
case self::S_HOURLY:
|
233 |
+
return HOUR_IN_SECONDS;
|
234 |
+
case self::S_FOUR_DAILY:
|
235 |
+
return DAY_IN_SECONDS / 4;
|
236 |
+
case self::S_TWICE_DAILY:
|
237 |
+
return DAY_IN_SECONDS / 2;
|
238 |
+
case self::S_DAILY:
|
239 |
+
return DAY_IN_SECONDS;
|
240 |
+
case self::S_WEEKLY:
|
241 |
+
return WEEK_IN_SECONDS;
|
242 |
+
case self::S_MONTHLY:
|
243 |
+
return MONTH_IN_SECONDS;
|
244 |
+
default:
|
245 |
+
return isset( $this->custom_schedules[ $schedule ] ) ? $this->custom_schedules[ $schedule ] : false;
|
246 |
+
}
|
247 |
+
}
|
248 |
+
|
249 |
+
/**
|
250 |
+
* Run code when the plugin is uninstalled.
|
251 |
+
*/
|
252 |
+
public function uninstall() {
|
253 |
+
|
254 |
+
}
|
255 |
+
}
|
core/lib/validator.php
CHANGED
@@ -104,6 +104,14 @@ abstract class ITSEC_Validator {
|
|
104 |
}
|
105 |
}
|
106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
final protected function sanitize_setting( $type, $var, $name, $prevent_save_on_error = true, $trim_value = true ) {
|
108 |
$id = $this->get_id();
|
109 |
|
104 |
}
|
105 |
}
|
106 |
|
107 |
+
final protected function preserve_setting_if_exists( $vars ) {
|
108 |
+
foreach ( (array) $vars as $var ) {
|
109 |
+
if ( array_key_exists( $var, $this->previous_settings ) && ( ! isset( $this->settings['var'] ) || '' === $this->settings[ $var ] ) ) {
|
110 |
+
$this->settings[ $var ] = $this->previous_settings[ $var ];
|
111 |
+
}
|
112 |
+
}
|
113 |
+
}
|
114 |
+
|
115 |
final protected function sanitize_setting( $type, $var, $name, $prevent_save_on_error = true, $trim_value = true ) {
|
116 |
$id = $this->get_id();
|
117 |
|
core/lockout.php
CHANGED
@@ -56,30 +56,21 @@
|
|
56 |
*/
|
57 |
final class ITSEC_Lockout {
|
58 |
|
59 |
-
/** @var ITSEC_Core */
|
60 |
-
private $core;
|
61 |
-
|
62 |
private $lockout_modules;
|
63 |
|
64 |
/**
|
65 |
* ITSEC_Lockout constructor.
|
66 |
-
*
|
67 |
-
* @param ITSEC_Core $core
|
68 |
*/
|
69 |
-
public function __construct(
|
70 |
-
|
71 |
-
$this->core = $core;
|
72 |
$this->lockout_modules = array(); //array to hold information on modules using this feature
|
|
|
73 |
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
}
|
78 |
-
|
79 |
-
add_action( 'itsec_purge_lockouts', array( $this, 'purge_lockouts' ) );
|
80 |
|
81 |
//Check for host lockouts
|
82 |
-
add_action( 'init', array( $this, '
|
83 |
|
84 |
// Ensure that locked out users are prevented from checking logins.
|
85 |
add_filter( 'authenticate', array( $this, 'check_authenticate_lockout' ), 30 );
|
@@ -132,23 +123,17 @@ final class ITSEC_Lockout {
|
|
132 |
}
|
133 |
|
134 |
/**
|
135 |
-
*
|
|
|
|
|
|
|
|
|
136 |
*/
|
137 |
-
public function
|
138 |
-
|
139 |
-
if ( ! is_user_logged_in() ) {
|
140 |
-
return;
|
141 |
-
}
|
142 |
|
143 |
-
|
144 |
-
|
145 |
-
$host = ITSEC_Lib::get_ip();
|
146 |
-
$host_check = $wpdb->get_var( $wpdb->prepare( "SELECT `lockout_host` FROM `{$wpdb->base_prefix}itsec_lockouts` WHERE `lockout_active`=1 AND `lockout_expire_gmt` > %s AND `lockout_host` = %s;", array(
|
147 |
-
date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() ),
|
148 |
-
$host
|
149 |
-
) ) );
|
150 |
|
151 |
-
if ( $
|
152 |
$this->execute_lock();
|
153 |
}
|
154 |
}
|
@@ -274,6 +259,24 @@ final class ITSEC_Lockout {
|
|
274 |
) );
|
275 |
}
|
276 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
/**
|
278 |
* This persists a lockout to storage or performs a permanent ban if appropriate.
|
279 |
*
|
@@ -503,10 +506,22 @@ final class ITSEC_Lockout {
|
|
503 |
@header( 'Expires: Thu, 22 Jun 1978 00:28:00 GMT' );
|
504 |
@header( 'Pragma: no-cache' );
|
505 |
|
506 |
-
|
|
|
|
|
|
|
507 |
}
|
508 |
}
|
509 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
510 |
/**
|
511 |
* Provides a description of lockout configuration for use in module settings.
|
512 |
*
|
@@ -982,6 +997,15 @@ final class ITSEC_Lockout {
|
|
982 |
return true;
|
983 |
}
|
984 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
985 |
/**
|
986 |
* Purges lockouts more than 7 days old from the database
|
987 |
*
|
@@ -1137,8 +1161,7 @@ final class ITSEC_Lockout {
|
|
1137 |
|
1138 |
$error_handler->add( $type, $message );
|
1139 |
|
1140 |
-
|
1141 |
-
|
1142 |
} else {
|
1143 |
|
1144 |
add_settings_error( 'itsec', esc_attr( 'settings_updated' ), $message, $type );
|
56 |
*/
|
57 |
final class ITSEC_Lockout {
|
58 |
|
|
|
|
|
|
|
59 |
private $lockout_modules;
|
60 |
|
61 |
/**
|
62 |
* ITSEC_Lockout constructor.
|
|
|
|
|
63 |
*/
|
64 |
+
public function __construct() {
|
|
|
|
|
65 |
$this->lockout_modules = array(); //array to hold information on modules using this feature
|
66 |
+
}
|
67 |
|
68 |
+
public function run() {
|
69 |
+
add_action( 'itsec_scheduler_register_events', array( $this, 'register_events' ) );
|
70 |
+
add_action( 'itsec_scheduled_purge-lockouts', array( $this, 'purge_lockouts' ) );
|
|
|
|
|
|
|
71 |
|
72 |
//Check for host lockouts
|
73 |
+
add_action( 'init', array( $this, 'check_for_host_lockouts' ) );
|
74 |
|
75 |
// Ensure that locked out users are prevented from checking logins.
|
76 |
add_filter( 'authenticate', array( $this, 'check_authenticate_lockout' ), 30 );
|
123 |
}
|
124 |
|
125 |
/**
|
126 |
+
* On every page load, check if the current host is locked out.
|
127 |
+
*
|
128 |
+
* When a host becomes locked out, iThemes Security performs a quick ban. This will cause an IP block to be
|
129 |
+
* written to the site's server configuration file. This ip block might not immediately take effect, particularly
|
130 |
+
* on Nginx systems. So on every page load we check that if the current host is locked out or not.
|
131 |
*/
|
132 |
+
public function check_for_host_lockouts() {
|
|
|
|
|
|
|
|
|
133 |
|
134 |
+
$host = ITSEC_Lib::get_ip();
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
|
136 |
+
if ( $this->is_host_locked_out( $host ) ) {
|
137 |
$this->execute_lock();
|
138 |
}
|
139 |
}
|
259 |
) );
|
260 |
}
|
261 |
|
262 |
+
/**
|
263 |
+
* Check if a given host is locked out.
|
264 |
+
*
|
265 |
+
* @param string $host
|
266 |
+
*
|
267 |
+
* @return bool
|
268 |
+
*/
|
269 |
+
public function is_host_locked_out( $host ) {
|
270 |
+
|
271 |
+
/** @var wpdb $wpdb */
|
272 |
+
global $wpdb;
|
273 |
+
|
274 |
+
return (bool) $wpdb->get_var( $wpdb->prepare(
|
275 |
+
"SELECT `lockout_host` FROM `{$wpdb->base_prefix}itsec_lockouts` WHERE `lockout_active`=1 AND `lockout_expire_gmt` > %s AND `lockout_host` = %s;",
|
276 |
+
date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() ), $host
|
277 |
+
) );
|
278 |
+
}
|
279 |
+
|
280 |
/**
|
281 |
* This persists a lockout to storage or performs a permanent ban if appropriate.
|
282 |
*
|
506 |
@header( 'Expires: Thu, 22 Jun 1978 00:28:00 GMT' );
|
507 |
@header( 'Pragma: no-cache' );
|
508 |
|
509 |
+
add_filter( 'wp_die_handler', array( $this, 'apply_wp_die_handler' ) );
|
510 |
+
add_filter( 'wp_die_ajax_handler', array( $this, 'apply_wp_die_handler' ) );
|
511 |
+
add_filter( 'wp_die_xmlrpc_handler', array( $this, 'apply_wp_die_handler' ) );
|
512 |
+
wp_die( $message, '', array( 'response' => 403 ) );
|
513 |
}
|
514 |
}
|
515 |
|
516 |
+
/**
|
517 |
+
* Apply the Scalar wp die handler to print a message to the screen.
|
518 |
+
*
|
519 |
+
* @return string
|
520 |
+
*/
|
521 |
+
public function apply_wp_die_handler() {
|
522 |
+
return '_scalar_wp_die_handler';
|
523 |
+
}
|
524 |
+
|
525 |
/**
|
526 |
* Provides a description of lockout configuration for use in module settings.
|
527 |
*
|
997 |
return true;
|
998 |
}
|
999 |
|
1000 |
+
/**
|
1001 |
+
* Register the purge lockout event.
|
1002 |
+
*
|
1003 |
+
* @param ITSEC_Scheduler $scheduler
|
1004 |
+
*/
|
1005 |
+
public function register_events( $scheduler ) {
|
1006 |
+
$scheduler->schedule( ITSEC_Scheduler::S_DAILY, 'purge-lockouts' );
|
1007 |
+
}
|
1008 |
+
|
1009 |
/**
|
1010 |
* Purges lockouts more than 7 days old from the database
|
1011 |
*
|
1161 |
|
1162 |
$error_handler->add( $type, $message );
|
1163 |
|
1164 |
+
ITSEC_Lib::show_error_message( $error_handler );
|
|
|
1165 |
} else {
|
1166 |
|
1167 |
add_settings_error( 'itsec', esc_attr( 'settings_updated' ), $message, $type );
|
core/modules/404-detection/class-itsec-four-oh-four.php
CHANGED
@@ -12,8 +12,7 @@ class ITSEC_Four_Oh_Four {
|
|
12 |
add_filter( 'itsec_logger_modules', array( $this, 'register_logger' ) );
|
13 |
add_filter( 'itsec_logger_displays', array( $this, 'register_logger_displays' ) );
|
14 |
|
15 |
-
add_action( '
|
16 |
-
|
17 |
}
|
18 |
|
19 |
/**
|
12 |
add_filter( 'itsec_logger_modules', array( $this, 'register_logger' ) );
|
13 |
add_filter( 'itsec_logger_displays', array( $this, 'register_logger_displays' ) );
|
14 |
|
15 |
+
add_action( 'wp', array( $this, 'check_404' ), 9999 );
|
|
|
16 |
}
|
17 |
|
18 |
/**
|
core/modules/away-mode/activate.php
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once( dirname( __FILE__ ) . '/utilities.php' );
|
4 |
+
|
5 |
+
ITSEC_Away_Mode_Utilities::create_active_file();
|
core/modules/backup/activate.php
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
$settings = ITSEC_Modules::get_settings( 'backup' );
|
4 |
+
|
5 |
+
if ( $settings['enabled'] && $settings['interval'] > 0 ) {
|
6 |
+
ITSEC_Core::get_scheduler()->schedule( 'backup', 'backup' );
|
7 |
+
}
|
core/modules/backup/class-itsec-backup.php
CHANGED
@@ -40,36 +40,27 @@ class ITSEC_Backup {
|
|
40 |
add_filter( 'itsec_notifications', array( $this, 'register_notification' ) );
|
41 |
add_filter( 'itsec_backup_notification_strings', array( $this, 'notification_strings' ) );
|
42 |
|
43 |
-
if (
|
44 |
-
|
45 |
-
wp_schedule_event( time(), 'daily', 'itsec_execute_backup_cron' );
|
46 |
-
}
|
47 |
-
|
48 |
-
// When ITSEC_BACKUP_CRON is enabled, skip the regular scheduling system.
|
49 |
return;
|
50 |
}
|
51 |
|
|
|
|
|
|
|
52 |
if ( ! $this->settings['enabled'] || $this->settings['interval'] <= 0 ) {
|
53 |
// Don't run when scheduled backups aren't enabled or the interval is zero or less.
|
54 |
return;
|
55 |
}
|
56 |
|
57 |
-
|
58 |
-
|
59 |
-
return;
|
60 |
-
}
|
61 |
-
|
62 |
-
if ( class_exists( 'pb_backupbuddy' ) ) {
|
63 |
-
// Don't run when BackupBuddy is active.
|
64 |
-
return;
|
65 |
-
}
|
66 |
-
|
67 |
-
|
68 |
-
$next_run = $this->settings['last_run'] + $this->settings['interval'] * DAY_IN_SECONDS;
|
69 |
|
70 |
-
|
71 |
-
|
72 |
-
|
|
|
|
|
73 |
}
|
74 |
|
75 |
/**
|
@@ -329,6 +320,20 @@ class ITSEC_Backup {
|
|
329 |
|
330 |
}
|
331 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
332 |
/**
|
333 |
* Register the Backup notification email.
|
334 |
*
|
@@ -340,7 +345,7 @@ class ITSEC_Backup {
|
|
340 |
|
341 |
$method = ITSEC_Modules::get_setting( 'backup', 'method' );
|
342 |
|
343 |
-
if (
|
344 |
$notifications['backup'] = array(
|
345 |
'subject_editable' => true,
|
346 |
'recipient' => ITSEC_Notification_Center::R_EMAIL_LIST,
|
40 |
add_filter( 'itsec_notifications', array( $this, 'register_notification' ) );
|
41 |
add_filter( 'itsec_backup_notification_strings', array( $this, 'notification_strings' ) );
|
42 |
|
43 |
+
if ( class_exists( 'pb_backupbuddy' ) ) {
|
44 |
+
// Don't run when BackupBuddy is active.
|
|
|
|
|
|
|
|
|
45 |
return;
|
46 |
}
|
47 |
|
48 |
+
ITSEC_Core::get_scheduler()->register_custom_schedule( 'backup', DAY_IN_SECONDS * $this->settings['interval'] );
|
49 |
+
add_action( 'itsec_scheduler_register_events', array( $this, 'register_events' ) );
|
50 |
+
|
51 |
if ( ! $this->settings['enabled'] || $this->settings['interval'] <= 0 ) {
|
52 |
// Don't run when scheduled backups aren't enabled or the interval is zero or less.
|
53 |
return;
|
54 |
}
|
55 |
|
56 |
+
add_action( 'itsec_scheduled_backup', array( $this, 'scheduled_callback' ) );
|
57 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
|
59 |
+
/**
|
60 |
+
* Called when it is time for the backup to run.
|
61 |
+
*/
|
62 |
+
public function scheduled_callback() {
|
63 |
+
$this->do_backup();
|
64 |
}
|
65 |
|
66 |
/**
|
320 |
|
321 |
}
|
322 |
|
323 |
+
/**
|
324 |
+
* Register the events.
|
325 |
+
*
|
326 |
+
* @param ITSEC_Scheduler $scheduler
|
327 |
+
*/
|
328 |
+
public function register_events( $scheduler ) {
|
329 |
+
|
330 |
+
$settings = ITSEC_Modules::get_settings( 'backup' );
|
331 |
+
|
332 |
+
if ( $settings['enabled'] && $settings['interval'] > 0 ) {
|
333 |
+
$scheduler->schedule( 'backup', 'backup' );
|
334 |
+
}
|
335 |
+
}
|
336 |
+
|
337 |
/**
|
338 |
* Register the Backup notification email.
|
339 |
*
|
345 |
|
346 |
$method = ITSEC_Modules::get_setting( 'backup', 'method' );
|
347 |
|
348 |
+
if ( 0 === $method || 1 === $method ) {
|
349 |
$notifications['backup'] = array(
|
350 |
'subject_editable' => true,
|
351 |
'recipient' => ITSEC_Notification_Center::R_EMAIL_LIST,
|
core/modules/backup/deactivate.php
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
<?php
|
2 |
+
ITSEC_Core::get_scheduler()->unschedule( 'backup' );
|
core/modules/backup/settings-page.php
CHANGED
@@ -142,16 +142,14 @@ final class ITSEC_Backup_Settings_Page extends ITSEC_Module_Settings_Page {
|
|
142 |
<label for="itsec-backup-enabled"><?php _e( 'Enable Scheduled Database Backups', 'better-wp-security' ); ?></label>
|
143 |
</td>
|
144 |
</tr>
|
145 |
-
|
146 |
-
<
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
</tr>
|
154 |
-
<?php endif; ?>
|
155 |
</table>
|
156 |
<?php
|
157 |
|
142 |
<label for="itsec-backup-enabled"><?php _e( 'Enable Scheduled Database Backups', 'better-wp-security' ); ?></label>
|
143 |
</td>
|
144 |
</tr>
|
145 |
+
<tr class="itsec-backup-enabled-content">
|
146 |
+
<th scope="row"><label for="itsec-backup-interval"><?php _e( 'Backup Interval', 'better-wp-security' ); ?></label></th>
|
147 |
+
<td>
|
148 |
+
<?php $form->add_text( 'interval', array( 'class' => 'small-text' ) ); ?>
|
149 |
+
<label for="itsec-backup-interval"><?php _e( 'Days', 'better-wp-security' ); ?></label>
|
150 |
+
<p class="description"><?php _e( 'The number of days between database backups.', 'better-wp-security' ); ?></p>
|
151 |
+
</td>
|
152 |
+
</tr>
|
|
|
|
|
153 |
</table>
|
154 |
<?php
|
155 |
|
core/modules/backup/settings.php
CHANGED
@@ -22,6 +22,17 @@ final class ITSEC_Backup_Settings extends ITSEC_Settings {
|
|
22 |
'last_run' => 0,
|
23 |
);
|
24 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
}
|
26 |
|
27 |
ITSEC_Modules::register_settings( new ITSEC_Backup_Settings() );
|
22 |
'last_run' => 0,
|
23 |
);
|
24 |
}
|
25 |
+
|
26 |
+
protected function handle_settings_changes( $old_settings ) {
|
27 |
+
|
28 |
+
if ( $old_settings['enabled'] !== $this->settings['enabled'] ) {
|
29 |
+
if ( $this->settings['enabled'] ) {
|
30 |
+
ITSEC_Core::get_scheduler()->schedule( 'backup', 'backup' );
|
31 |
+
} else {
|
32 |
+
ITSEC_Core::get_scheduler()->unschedule( 'backup' );
|
33 |
+
}
|
34 |
+
}
|
35 |
+
}
|
36 |
}
|
37 |
|
38 |
ITSEC_Modules::register_settings( new ITSEC_Backup_Settings() );
|
core/modules/backup/setup.php
CHANGED
@@ -107,6 +107,10 @@ if ( ! class_exists( 'ITSEC_Backup_Setup' ) ) {
|
|
107 |
if ( $build < 4069 ) {
|
108 |
delete_site_option( 'itsec_backup' );
|
109 |
}
|
|
|
|
|
|
|
|
|
110 |
}
|
111 |
|
112 |
}
|
107 |
if ( $build < 4069 ) {
|
108 |
delete_site_option( 'itsec_backup' );
|
109 |
}
|
110 |
+
|
111 |
+
if ( $build < 4079 ) {
|
112 |
+
wp_clear_scheduled_hook( 'itsec_execute_backup_cron' );
|
113 |
+
}
|
114 |
}
|
115 |
|
116 |
}
|
core/modules/file-change/activate.php
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
$split = ITSEC_Modules::get_setting( 'file-change', 'split', false );
|
4 |
+
$interval = $split ? ITSEC_Scheduler::S_FOUR_DAILY : ITSEC_Scheduler::S_DAILY;
|
5 |
+
|
6 |
+
ITSEC_Core::get_scheduler()->schedule( $interval, 'file-change' );
|
core/modules/file-change/class-itsec-file-change.php
CHANGED
@@ -24,14 +24,6 @@ class ITSEC_File_Change {
|
|
24 |
*/
|
25 |
function run() {
|
26 |
|
27 |
-
$settings = ITSEC_Modules::get_settings( 'file-change' );
|
28 |
-
$interval = 86400; //Run daily
|
29 |
-
|
30 |
-
// If we're splitting the file check run it every 6 hours.
|
31 |
-
if ( isset( $settings['split'] ) && true === $settings['split'] ) {
|
32 |
-
$interval = 12342;
|
33 |
-
}
|
34 |
-
|
35 |
add_action( 'itsec_execute_file_check_cron', array( $this, 'run_scan' ) ); //Action to execute during a cron run.
|
36 |
|
37 |
add_filter( 'itsec_logger_displays', array( $this, 'itsec_logger_displays' ) ); //adds logs metaboxes
|
@@ -40,23 +32,8 @@ class ITSEC_File_Change {
|
|
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 |
-
|
45 |
-
( ! defined( 'DOING_AJAX' ) || DOING_AJAX === false ) &&
|
46 |
-
isset( $settings['last_run'] ) &&
|
47 |
-
( ITSEC_Core::get_current_time() - $interval ) > $settings['last_run'] &&
|
48 |
-
( ! defined( 'ITSEC_FILE_CHECK_CRON' ) || false === ITSEC_FILE_CHECK_CRON )
|
49 |
-
) {
|
50 |
-
|
51 |
-
wp_clear_scheduled_hook( 'itsec_file_check' );
|
52 |
-
add_action( 'init', array( $this, 'run_scan' ) );
|
53 |
-
|
54 |
-
} elseif ( defined( 'ITSEC_FILE_CHECK_CRON' ) && true === ITSEC_FILE_CHECK_CRON && ! wp_next_scheduled( 'itsec_execute_file_check_cron' ) ) { //Use cron if needed
|
55 |
-
|
56 |
-
wp_schedule_event( time(), 'daily', 'itsec_execute_file_check_cron' );
|
57 |
-
|
58 |
-
}
|
59 |
-
|
60 |
}
|
61 |
|
62 |
public function run_scan() {
|
@@ -65,6 +42,20 @@ class ITSEC_File_Change {
|
|
65 |
return ITSEC_File_Change_Scanner::run_scan();
|
66 |
}
|
67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
/**
|
69 |
* Register file change detection for logger
|
70 |
*
|
24 |
*/
|
25 |
function run() {
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
add_action( 'itsec_execute_file_check_cron', array( $this, 'run_scan' ) ); //Action to execute during a cron run.
|
28 |
|
29 |
add_filter( 'itsec_logger_displays', array( $this, 'itsec_logger_displays' ) ); //adds logs metaboxes
|
32 |
add_filter( 'itsec_notifications', array( $this, 'register_notification' ) );
|
33 |
add_filter( 'itsec_file-change_notification_strings', array( $this, 'register_notification_strings' ) );
|
34 |
|
35 |
+
add_action( 'itsec_scheduler_register_events', array( $this, 'register_event' ) );
|
36 |
+
add_action( 'itsec_scheduled_file-change', array( $this, 'run_scan' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
}
|
38 |
|
39 |
public function run_scan() {
|
42 |
return ITSEC_File_Change_Scanner::run_scan();
|
43 |
}
|
44 |
|
45 |
+
/**
|
46 |
+
* Register the file change scan event.
|
47 |
+
*
|
48 |
+
* @param ITSEC_Scheduler $scheduler
|
49 |
+
*/
|
50 |
+
public function register_event( $scheduler ) {
|
51 |
+
|
52 |
+
// If we're splitting the file check run it every 6 hours.
|
53 |
+
$split = ITSEC_Modules::get_setting( 'file-change', 'split', false );
|
54 |
+
$interval = $split ? ITSEC_Scheduler::S_FOUR_DAILY : ITSEC_Scheduler::S_DAILY;
|
55 |
+
|
56 |
+
$scheduler->schedule( $interval, 'file-change' );
|
57 |
+
}
|
58 |
+
|
59 |
/**
|
60 |
* Register file change detection for logger
|
61 |
*
|
core/modules/file-change/deactivate.php
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
<?php
|
2 |
+
ITSEC_Core::get_scheduler()->unschedule( 'file-change' );
|
core/modules/file-change/settings.php
CHANGED
@@ -25,6 +25,16 @@ final class ITSEC_File_Change_Settings extends ITSEC_Settings {
|
|
25 |
'latest_changes' => array(),
|
26 |
);
|
27 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
}
|
29 |
|
30 |
ITSEC_Modules::register_settings( new ITSEC_File_Change_Settings() );
|
25 |
'latest_changes' => array(),
|
26 |
);
|
27 |
}
|
28 |
+
|
29 |
+
protected function handle_settings_changes( $old_settings ) {
|
30 |
+
$split = isset( $old_settings['split'] ) ? $old_settings['split'] : false;
|
31 |
+
|
32 |
+
if ( $split !== $this->settings['split'] ) {
|
33 |
+
ITSEC_Core::get_scheduler()->unschedule( 'file-change' );
|
34 |
+
$interval = $this->settings['split'] ? ITSEC_Scheduler::S_FOUR_DAILY : ITSEC_Scheduler::S_DAILY;
|
35 |
+
ITSEC_Core::get_scheduler()->schedule( $interval, 'file-change' );
|
36 |
+
}
|
37 |
+
}
|
38 |
}
|
39 |
|
40 |
ITSEC_Modules::register_settings( new ITSEC_File_Change_Settings() );
|
core/modules/file-change/setup.php
CHANGED
@@ -149,6 +149,10 @@ if ( ! class_exists( 'ITSEC_File_Change_Setup' ) ) {
|
|
149 |
}
|
150 |
}
|
151 |
|
|
|
|
|
|
|
|
|
152 |
}
|
153 |
|
154 |
}
|
149 |
}
|
150 |
}
|
151 |
|
152 |
+
if ( $itsec_old_version < 4079 ) {
|
153 |
+
wp_clear_scheduled_hook( 'itsec_execute_file_check_cron' );
|
154 |
+
}
|
155 |
+
|
156 |
}
|
157 |
|
158 |
}
|
core/modules/file-change/validator.php
CHANGED
@@ -18,7 +18,8 @@ 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 |
$this->vars_to_skip_validate_matching_fields[] = 'email';
|
24 |
|
18 |
$this->settings['show_warning'] = $previous_settings['show_warning'];
|
19 |
}
|
20 |
|
21 |
+
$this->set_previous_if_empty( array( 'latest_changes' ) );
|
22 |
+
$this->preserve_setting_if_exists( array( 'email' ) );
|
23 |
$this->vars_to_skip_validate_matching_types[] = 'last_chunk';
|
24 |
$this->vars_to_skip_validate_matching_fields[] = 'email';
|
25 |
|
core/modules/global/active.php
CHANGED
@@ -11,6 +11,10 @@ function itsec_global_add_notice() {
|
|
11 |
ITSEC_Core::add_notice( 'itsec_global_show_new_dashboard_notice' );
|
12 |
}
|
13 |
|
|
|
|
|
|
|
|
|
14 |
if ( ITSEC_Core::is_temp_disable_modules_set() && ITSEC_Core::current_user_can_manage() ) {
|
15 |
ITSEC_Core::add_notice( 'itsec_show_temp_disable_modules_notice', true );
|
16 |
}
|
@@ -63,3 +67,100 @@ add_action( 'wp_ajax_itsec-dismiss-notice-brute_force_network', 'itsec_network_b
|
|
63 |
function itsec_show_temp_disable_modules_notice() {
|
64 |
ITSEC_Lib::show_error_message( esc_html__( 'The ITSEC_DISABLE_MODULES define is set. All iThemes Security protections are disabled. Please make the necessary settings changes and remove the define as quickly as possible.', 'better-wp-security' ) );
|
65 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
ITSEC_Core::add_notice( 'itsec_global_show_new_dashboard_notice' );
|
12 |
}
|
13 |
|
14 |
+
if ( ! defined( 'ITSEC_USE_CRON' ) && ITSEC_Core::current_user_can_manage() ) {
|
15 |
+
ITSEC_Core::add_notice( 'itsec_show_disable_cron_constants_notice' );
|
16 |
+
}
|
17 |
+
|
18 |
if ( ITSEC_Core::is_temp_disable_modules_set() && ITSEC_Core::current_user_can_manage() ) {
|
19 |
ITSEC_Core::add_notice( 'itsec_show_temp_disable_modules_notice', true );
|
20 |
}
|
67 |
function itsec_show_temp_disable_modules_notice() {
|
68 |
ITSEC_Lib::show_error_message( esc_html__( 'The ITSEC_DISABLE_MODULES define is set. All iThemes Security protections are disabled. Please make the necessary settings changes and remove the define as quickly as possible.', 'better-wp-security' ) );
|
69 |
}
|
70 |
+
|
71 |
+
function itsec_show_disable_cron_constants_notice() {
|
72 |
+
|
73 |
+
$check = array( 'ITSEC_BACKUP_CRON', 'ITSEC_FILE_CHECK_CRON' );
|
74 |
+
$using = array();
|
75 |
+
|
76 |
+
foreach ( $check as $constant ) {
|
77 |
+
if ( defined( $constant ) && constant( $constant ) ) {
|
78 |
+
$using[] = "<span class='code'>{$constant}</span>";
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
if ( $using ) {
|
83 |
+
$message = wp_sprintf( esc_html(
|
84 |
+
_n( 'The %l define is deprecated. Please use %s instead.', 'The %l defines are deprecated. Please use %s instead.', count( $using ), 'better-wp-security' )
|
85 |
+
), $using, '<span class="code">ITSEC_USE_CRON</span>' );
|
86 |
+
|
87 |
+
echo "<div class='notice notice-error'><p>{$message}</p></div>";
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* On every page load, check if the cron test has successfully fired in time.
|
93 |
+
*
|
94 |
+
* If not, update the cron status and turn off using cron.
|
95 |
+
*/
|
96 |
+
function itsec_cron_test_fail_safe() {
|
97 |
+
|
98 |
+
if ( defined( 'ITSEC_DISABLE_CRON_TEST' ) && ITSEC_DISABLE_CRON_TEST ) {
|
99 |
+
return;
|
100 |
+
}
|
101 |
+
|
102 |
+
$time = ITSEC_Modules::get_setting( 'global', 'cron_test_time' );
|
103 |
+
|
104 |
+
if ( ! $time ) {
|
105 |
+
if ( ITSEC_Lib::get_lock( 'cron_test_fail_safe' ) ) {
|
106 |
+
ITSEC_Lib::schedule_cron_test();
|
107 |
+
ITSEC_Lib::release_lock( 'cron_test_fail_safe' );
|
108 |
+
}
|
109 |
+
|
110 |
+
return;
|
111 |
+
}
|
112 |
+
|
113 |
+
$threshold = HOUR_IN_SECONDS + DAY_IN_SECONDS;
|
114 |
+
|
115 |
+
if ( ITSEC_Core::get_current_time_gmt() <= $time + $threshold + 5 * MINUTE_IN_SECONDS ) {
|
116 |
+
return;
|
117 |
+
}
|
118 |
+
|
119 |
+
if ( ! ITSEC_Lib::get_lock( 'cron_test_fail_safe' ) ) {
|
120 |
+
return;
|
121 |
+
}
|
122 |
+
|
123 |
+
$uncached = ITSEC_Lib::get_uncached_option( 'itsec-storage' );
|
124 |
+
$time = $uncached['global']['cron_test_time'];
|
125 |
+
|
126 |
+
if ( ITSEC_Core::get_current_time_gmt() > $time + $threshold + 5 * MINUTE_IN_SECONDS ) {
|
127 |
+
if ( ( ! defined( 'ITSEC_USE_CRON' ) || ! ITSEC_USE_CRON ) && ITSEC_Lib::use_cron() ) {
|
128 |
+
ITSEC_Modules::set_setting( 'global', 'use_cron', false );
|
129 |
+
}
|
130 |
+
|
131 |
+
ITSEC_Modules::set_setting( 'global', 'cron_status', 0 );
|
132 |
+
}
|
133 |
+
|
134 |
+
ITSEC_Lib::schedule_cron_test();
|
135 |
+
ITSEC_Lib::release_lock( 'cron_test_fail_safe' );
|
136 |
+
}
|
137 |
+
|
138 |
+
add_action( 'init', 'itsec_cron_test_fail_safe' );
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Callback for testing whether we should suggest the cron scheduler be enabled.
|
142 |
+
*
|
143 |
+
* @param int $time
|
144 |
+
*/
|
145 |
+
function itsec_cron_test_callback( $time ) {
|
146 |
+
|
147 |
+
$threshold = HOUR_IN_SECONDS + DAY_IN_SECONDS;
|
148 |
+
|
149 |
+
if ( empty( $time ) || ITSEC_Core::get_current_time_gmt() > $time + $threshold ) {
|
150 |
+
// Disable cron if the user hasn't set the use cron constant to true.
|
151 |
+
if ( ( ! defined( 'ITSEC_USE_CRON' ) || ! ITSEC_USE_CRON ) && ITSEC_Lib::use_cron() ) {
|
152 |
+
ITSEC_Modules::set_setting( 'global', 'use_cron', false );
|
153 |
+
}
|
154 |
+
|
155 |
+
ITSEC_Modules::set_setting( 'global', 'cron_status', 0 );
|
156 |
+
} elseif ( ! ITSEC_Lib::use_cron() ) {
|
157 |
+
ITSEC_Modules::set_setting( 'global', 'cron_status', 1 );
|
158 |
+
ITSEC_Modules::set_setting( 'global', 'use_cron', true );
|
159 |
+
} else {
|
160 |
+
ITSEC_Modules::set_setting( 'global', 'cron_status', 1 );
|
161 |
+
}
|
162 |
+
|
163 |
+
ITSEC_Lib::schedule_cron_test();
|
164 |
+
}
|
165 |
+
|
166 |
+
add_action( 'itsec_cron_test', 'itsec_cron_test_callback' );
|
core/modules/global/settings.php
CHANGED
@@ -23,7 +23,7 @@ final class ITSEC_Global_Settings_New extends ITSEC_Settings {
|
|
23 |
'write_files' => true,
|
24 |
'nginx_file' => ABSPATH . 'nginx.conf',
|
25 |
'infinitewp_compatibility' => false,
|
26 |
-
|
27 |
'lock_file' => false,
|
28 |
'proxy_override' => false,
|
29 |
'hide_admin_bar' => false,
|
@@ -32,6 +32,9 @@ final class ITSEC_Global_Settings_New extends ITSEC_Settings {
|
|
32 |
'show_security_check' => true,
|
33 |
'build' => 0,
|
34 |
'activation_timestamp' => 0,
|
|
|
|
|
|
|
35 |
);
|
36 |
}
|
37 |
|
@@ -40,6 +43,44 @@ final class ITSEC_Global_Settings_New extends ITSEC_Settings {
|
|
40 |
ITSEC_Response::regenerate_server_config();
|
41 |
ITSEC_Response::regenerate_wp_config();
|
42 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
}
|
44 |
}
|
45 |
|
23 |
'write_files' => true,
|
24 |
'nginx_file' => ABSPATH . 'nginx.conf',
|
25 |
'infinitewp_compatibility' => false,
|
26 |
+
'did_upgrade' => false,
|
27 |
'lock_file' => false,
|
28 |
'proxy_override' => false,
|
29 |
'hide_admin_bar' => false,
|
32 |
'show_security_check' => true,
|
33 |
'build' => 0,
|
34 |
'activation_timestamp' => 0,
|
35 |
+
'cron_status' => - 1,
|
36 |
+
'use_cron' => true,
|
37 |
+
'cron_test_time' => 0,
|
38 |
);
|
39 |
}
|
40 |
|
43 |
ITSEC_Response::regenerate_server_config();
|
44 |
ITSEC_Response::regenerate_wp_config();
|
45 |
}
|
46 |
+
|
47 |
+
if ( $this->settings['use_cron'] !== $old_settings['use_cron'] ) {
|
48 |
+
$this->handle_cron_change( $this->settings['use_cron'] );
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
+
private function handle_cron_change( $new_use_cron ) {
|
53 |
+
$class = $new_use_cron ? 'ITSEC_Scheduler_Cron' : 'ITSEC_Scheduler_Page_Load';
|
54 |
+
$this->handle_scheduler_change( $class );
|
55 |
+
}
|
56 |
+
|
57 |
+
private function handle_scheduler_change( $new_class ) {
|
58 |
+
$choices = array(
|
59 |
+
'ITSEC_Scheduler_Cron' => ITSEC_Core::get_core_dir() . 'lib/class-itsec-scheduler-cron.php',
|
60 |
+
'ITSEC_Scheduler_Page_Load' => ITSEC_Core::get_core_dir() . 'lib/class-itsec-scheduler-page-load.php',
|
61 |
+
);
|
62 |
+
|
63 |
+
require_once( $choices[ $new_class ] );
|
64 |
+
|
65 |
+
/** @var ITSEC_Scheduler $new */
|
66 |
+
$new = new $new_class();
|
67 |
+
$current = ITSEC_Core::get_scheduler();
|
68 |
+
|
69 |
+
$new->uninstall();
|
70 |
+
|
71 |
+
foreach ( $current->get_recurring_events() as $event ) {
|
72 |
+
$new->schedule( $event['schedule'], $event['id'], $event['data'], array(
|
73 |
+
'fire_at' => $event['fire_at'],
|
74 |
+
) );
|
75 |
+
}
|
76 |
+
|
77 |
+
foreach ( $current->get_single_events() as $event ) {
|
78 |
+
$new->schedule_once( $event['fire_at'], $event['id'], $event['data'] );
|
79 |
+
}
|
80 |
+
|
81 |
+
$new->run();
|
82 |
+
ITSEC_Core::set_scheduler( $new );
|
83 |
+
$current->uninstall();
|
84 |
}
|
85 |
}
|
86 |
|
core/modules/global/validator.php
CHANGED
@@ -20,8 +20,9 @@ class ITSEC_Global_Validator extends ITSEC_Validator {
|
|
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', '
|
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' ) );
|
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', 'build', 'activation_timestamp', 'lock_file', 'cron_status', 'use_cron', 'cron_test_time' ) );
|
24 |
$this->set_default_if_empty( array( 'log_location', 'nginx_file' ) );
|
25 |
+
$this->preserve_setting_if_exists( array( 'digest_email', 'email_notifications', 'notification_email', 'backup_email' ) );
|
26 |
|
27 |
|
28 |
$this->sanitize_setting( 'bool', 'write_files', __( 'Write to Files', 'better-wp-security' ) );
|
core/modules/hide-backend/settings.php
CHANGED
@@ -15,6 +15,48 @@ final class ITSEC_Hide_Backend_Settings extends ITSEC_Settings {
|
|
15 |
'post_logout_slug' => '',
|
16 |
);
|
17 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
}
|
19 |
|
20 |
ITSEC_Modules::register_settings( new ITSEC_Hide_Backend_Settings() );
|
15 |
'post_logout_slug' => '',
|
16 |
);
|
17 |
}
|
18 |
+
|
19 |
+
protected function handle_settings_changes( $old_settings ) {
|
20 |
+
|
21 |
+
if ( $this->settings['enabled'] && $this->settings['slug'] !== $old_settings['slug'] ) {
|
22 |
+
$url = get_site_url() . '/' . $this->settings['slug'];
|
23 |
+
} elseif ( $this->settings['enabled'] && ! $old_settings['enabled'] ) {
|
24 |
+
$url = get_site_url() . '/' . $this->settings['slug'];
|
25 |
+
} elseif ( ! $this->settings['enabled'] && $old_settings['enabled'] ) {
|
26 |
+
$url = get_site_url() . '/wp-login.php';
|
27 |
+
} else {
|
28 |
+
return;
|
29 |
+
}
|
30 |
+
|
31 |
+
$this->send_new_login_url( $url );
|
32 |
+
}
|
33 |
+
|
34 |
+
private function send_new_login_url( $url ) {
|
35 |
+
if ( ITSEC_Core::doing_data_upgrade() ) {
|
36 |
+
// Do not send emails when upgrading data. This prevents spamming users with notifications just because the
|
37 |
+
// data was ported from an old version to a new version.
|
38 |
+
return;
|
39 |
+
}
|
40 |
+
|
41 |
+
$nc = ITSEC_Core::get_notification_center();
|
42 |
+
$nc->clear_notifications_cache();
|
43 |
+
|
44 |
+
$mail = $nc->mail();
|
45 |
+
|
46 |
+
$mail->add_header( esc_html__( 'New Login URL', 'better-wp-security' ), esc_html__( 'New Login URL', 'better-wp-security' ) );
|
47 |
+
$mail->add_text( ITSEC_Lib::replace_tags( $nc->get_message( 'hide-backend' ), array(
|
48 |
+
'login_url' => '<code>' . esc_url( $url ) . '</code>',
|
49 |
+
'site_title' => get_bloginfo( 'name', 'display' ),
|
50 |
+
'site_url' => $mail->get_display_url(),
|
51 |
+
) ) );
|
52 |
+
$mail->add_button( esc_html__( 'Login Now', 'better-wp-security' ), $url );
|
53 |
+
$mail->add_footer();
|
54 |
+
|
55 |
+
$subject = $mail->prepend_site_url_to_subject( $nc->get_subject( 'hide-backend' ) );
|
56 |
+
$subject = apply_filters( 'itsec_hide_backend_email_subject', $subject );
|
57 |
+
$mail->set_subject( $subject, false );
|
58 |
+
$nc->send( 'hide-backend', $mail );
|
59 |
+
}
|
60 |
}
|
61 |
|
62 |
ITSEC_Modules::register_settings( new ITSEC_Hide_Backend_Settings() );
|
core/modules/hide-backend/validator.php
CHANGED
@@ -50,7 +50,6 @@ final class ITSEC_Hide_Backend_Validator extends ITSEC_Validator {
|
|
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'] ) {
|
@@ -59,7 +58,6 @@ final class ITSEC_Hide_Backend_Validator extends ITSEC_Validator {
|
|
59 |
}
|
60 |
|
61 |
if ( isset( $url ) ) {
|
62 |
-
$this->send_new_login_url( $url );
|
63 |
ITSEC_Response::prevent_modal_close();
|
64 |
}
|
65 |
|
@@ -67,31 +65,6 @@ final class ITSEC_Hide_Backend_Validator extends ITSEC_Validator {
|
|
67 |
ITSEC_Response::reload_module( $this->get_id() );
|
68 |
}
|
69 |
|
70 |
-
private function send_new_login_url( $url ) {
|
71 |
-
if ( ITSEC_Core::doing_data_upgrade() ) {
|
72 |
-
// Do not send emails when upgrading data. This prevents spamming users with notifications just because the
|
73 |
-
// data was ported from an old version to a new version.
|
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 |
/**
|
96 |
* Set HTML content type for email
|
97 |
*
|
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 |
$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 Notification Center.', 'better-wp-security' ), esc_url( $url ) ) );
|
55 |
} else if ( ! $this->settings['enabled'] && $this->previous_settings['enabled'] ) {
|
58 |
}
|
59 |
|
60 |
if ( isset( $url ) ) {
|
|
|
61 |
ITSEC_Response::prevent_modal_close();
|
62 |
}
|
63 |
|
65 |
ITSEC_Response::reload_module( $this->get_id() );
|
66 |
}
|
67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
/**
|
69 |
* Set HTML content type for email
|
70 |
*
|
core/modules/notification-center/settings-page.php
CHANGED
@@ -99,12 +99,12 @@ class ITSEC_Notification_Center_Settings_Page extends ITSEC_Module_Settings_Page
|
|
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 |
-
$
|
103 |
|
104 |
-
if ( is_wp_error( $
|
105 |
-
$message = $
|
106 |
-
} elseif ( is_array( $error ) && isset( $
|
107 |
-
$message = $
|
108 |
} else {
|
109 |
$message = __( 'Unknown error encountered while sending.', 'better-wp-security' );
|
110 |
}
|
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 |
+
$details = $error['error'];
|
103 |
|
104 |
+
if ( is_wp_error( $details ) ) {
|
105 |
+
$message = $details->get_error_message();
|
106 |
+
} elseif ( is_array( $error ) && isset( $details['message'] ) && is_string( $details['message'] ) ) {
|
107 |
+
$message = $details['message'];
|
108 |
} else {
|
109 |
$message = __( 'Unknown error encountered while sending.', 'better-wp-security' );
|
110 |
}
|
core/modules/notification-center/validator.php
CHANGED
@@ -30,8 +30,7 @@ class ITSEC_Notification_Center_Validator extends ITSEC_Validator {
|
|
30 |
$config = ITSEC_Core::get_notification_center()->get_notification( $notification );
|
31 |
|
32 |
if ( ! $config ) {
|
33 |
-
|
34 |
-
break;
|
35 |
}
|
36 |
|
37 |
$strings = ITSEC_Core::get_notification_center()->get_notification_strings( $notification );
|
30 |
$config = ITSEC_Core::get_notification_center()->get_notification( $notification );
|
31 |
|
32 |
if ( ! $config ) {
|
33 |
+
continue;
|
|
|
34 |
}
|
35 |
|
36 |
$strings = ITSEC_Core::get_notification_center()->get_notification_strings( $notification );
|
core/modules/salts/utilities.php
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<?php
|
2 |
|
3 |
final class ITSEC_WordPress_Salts_Utilities {
|
4 |
-
public function generate_new_salts() {
|
5 |
if ( ! ITSEC_Modules::get_setting( 'global', 'write_files' ) ) {
|
6 |
return new WP_Error( 'itsec-wordpress-salts-utilities-write-files-disabled', __( 'The "Write to Files" setting is disabled in Global Settings. In order to use this feature, you must enable the "Write to Files" setting.', 'better-wp-security' ) );
|
7 |
}
|
@@ -38,12 +38,12 @@ final class ITSEC_WordPress_Salts_Utilities {
|
|
38 |
if ( empty( $salt ) ) {
|
39 |
$salt = wp_generate_password( 64, true, true );
|
40 |
}
|
41 |
-
|
42 |
$salt = str_replace( '$', '\\$', $salt );
|
43 |
$regex = "/(define\s*\(\s*(['\"])$define\\2\s*,\s*)(['\"]).+?\\3(\s*\)\s*;)/";
|
44 |
$config = preg_replace( $regex, "\${1}'$salt'\${4}", $config );
|
45 |
}
|
46 |
-
|
47 |
$write_result = ITSEC_Lib_File::write( $config_file_path, $config );
|
48 |
|
49 |
if ( is_wp_error( $write_result ) ) {
|
1 |
<?php
|
2 |
|
3 |
final class ITSEC_WordPress_Salts_Utilities {
|
4 |
+
public static function generate_new_salts() {
|
5 |
if ( ! ITSEC_Modules::get_setting( 'global', 'write_files' ) ) {
|
6 |
return new WP_Error( 'itsec-wordpress-salts-utilities-write-files-disabled', __( 'The "Write to Files" setting is disabled in Global Settings. In order to use this feature, you must enable the "Write to Files" setting.', 'better-wp-security' ) );
|
7 |
}
|
38 |
if ( empty( $salt ) ) {
|
39 |
$salt = wp_generate_password( 64, true, true );
|
40 |
}
|
41 |
+
|
42 |
$salt = str_replace( '$', '\\$', $salt );
|
43 |
$regex = "/(define\s*\(\s*(['\"])$define\\2\s*,\s*)(['\"]).+?\\3(\s*\)\s*;)/";
|
44 |
$config = preg_replace( $regex, "\${1}'$salt'\${4}", $config );
|
45 |
}
|
46 |
+
|
47 |
$write_result = ITSEC_Lib_File::write( $config_file_path, $config );
|
48 |
|
49 |
if ( is_wp_error( $write_result ) ) {
|
core/setup.php
CHANGED
@@ -9,6 +9,7 @@
|
|
9 |
final class ITSEC_Setup {
|
10 |
public static function handle_activation() {
|
11 |
self::setup_plugin_data();
|
|
|
12 |
}
|
13 |
|
14 |
public static function handle_deactivation() {
|
@@ -90,8 +91,9 @@ final class ITSEC_Setup {
|
|
90 |
$itsec_modules = ITSEC_Modules::get_instance();
|
91 |
$itsec_modules->run_activation();
|
92 |
|
93 |
-
|
94 |
-
|
|
|
95 |
// Existing install. Perform data upgrades.
|
96 |
|
97 |
if ( $build < 4031 ) {
|
@@ -113,6 +115,34 @@ final class ITSEC_Setup {
|
|
113 |
$itsec_files = ITSEC_Core::get_itsec_files();
|
114 |
$itsec_files->do_activate();
|
115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
// Update stored build number.
|
117 |
ITSEC_Modules::set_setting( 'global', 'build', ITSEC_Core::get_plugin_build() );
|
118 |
}
|
@@ -125,6 +155,8 @@ final class ITSEC_Setup {
|
|
125 |
$itsec_files = ITSEC_Core::get_itsec_files();
|
126 |
$itsec_files->do_deactivate();
|
127 |
|
|
|
|
|
128 |
delete_site_option( 'itsec_temp_whitelist_ip' );
|
129 |
delete_site_transient( 'itsec_notification_running' );
|
130 |
delete_site_transient( 'itsec_wp_upload_dir' );
|
9 |
final class ITSEC_Setup {
|
10 |
public static function handle_activation() {
|
11 |
self::setup_plugin_data();
|
12 |
+
ITSEC_Core::get_scheduler()->register_events();
|
13 |
}
|
14 |
|
15 |
public static function handle_deactivation() {
|
91 |
$itsec_modules = ITSEC_Modules::get_instance();
|
92 |
$itsec_modules->run_activation();
|
93 |
|
94 |
+
if ( empty( $build ) ) {
|
95 |
+
ITSEC_Lib::schedule_cron_test();
|
96 |
+
} else {
|
97 |
// Existing install. Perform data upgrades.
|
98 |
|
99 |
if ( $build < 4031 ) {
|
115 |
$itsec_files = ITSEC_Core::get_itsec_files();
|
116 |
$itsec_files->do_activate();
|
117 |
|
118 |
+
if ( $build < 4079 ) {
|
119 |
+
ITSEC_Core::get_scheduler()->register_events();
|
120 |
+
|
121 |
+
wp_clear_scheduled_hook( 'itsec_purge_lockouts' );
|
122 |
+
wp_clear_scheduled_hook( 'itsec_clear_locks' );
|
123 |
+
|
124 |
+
ITSEC_Lib::schedule_cron_test();
|
125 |
+
}
|
126 |
+
|
127 |
+
if ( $build < 4080 ) {
|
128 |
+
ITSEC_Core::get_scheduler()->uninstall();
|
129 |
+
ITSEC_Core::get_scheduler()->register_events();
|
130 |
+
|
131 |
+
$crons = _get_cron_array();
|
132 |
+
|
133 |
+
foreach ( $crons as $timestamp => $args ) {
|
134 |
+
unset( $crons[ $timestamp ]['itsec_cron_test'] );
|
135 |
+
|
136 |
+
if ( empty( $crons[ $timestamp ] ) ) {
|
137 |
+
unset( $crons[ $timestamp ] );
|
138 |
+
}
|
139 |
+
}
|
140 |
+
|
141 |
+
_set_cron_array( $crons );
|
142 |
+
|
143 |
+
ITSEC_Lib::schedule_cron_test();
|
144 |
+
}
|
145 |
+
|
146 |
// Update stored build number.
|
147 |
ITSEC_Modules::set_setting( 'global', 'build', ITSEC_Core::get_plugin_build() );
|
148 |
}
|
155 |
$itsec_files = ITSEC_Core::get_itsec_files();
|
156 |
$itsec_files->do_deactivate();
|
157 |
|
158 |
+
ITSEC_Core::get_scheduler()->uninstall();
|
159 |
+
|
160 |
delete_site_option( 'itsec_temp_whitelist_ip' );
|
161 |
delete_site_transient( 'itsec_notification_running' );
|
162 |
delete_site_transient( 'itsec_wp_upload_dir' );
|
history.txt
CHANGED
@@ -696,3 +696,16 @@
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
699 |
+
6.8.0 - 2018-01-10 - Chris Jean & Timothy Jacobs
|
700 |
+
New Feature: Introduces a scheduling framework for handling events. Cron is now used by default, and will switch to using an alternate scheduling system if it detects an error. To disable this detection set ITSEC_DISABLE_CRON_TEST in your wp-config.php file.
|
701 |
+
Important: The ITSEC_FILE_CHECK_CRON and ITSEC_BACKUP_CRON constants have been deprecated. Use ITSEC_USE_CRON instead.
|
702 |
+
Enhancement: Preserve notification settings when the responsible module is deactivated.
|
703 |
+
Bug Fix: Process 404 lockouts on the 'wp' hook to prevent a headers have already been sent warning message.
|
704 |
+
Bug Fix: Ensure Hide Backend emails are properly sent when activating Hide Backend before saving the Notification Center for the first time.
|
705 |
+
Bug Fix: Prevent warning from being issued on new installs by allowing previous settings to be preserved if they exist.
|
706 |
+
Bug Fix: Better handle WP_Error objects in mail errors that occurred before updating to first patch release.
|
707 |
+
Bug Fix: A non static method was being called statically.
|
708 |
+
Bug Fix: Fix occasional duplicate backups and file scans.
|
709 |
+
Bug Fix: Fixed issue where scheduled events could repeat on sites that do not properly support WordPress's cron system.
|
710 |
+
Bug Fix: Reactivating Away Mode now replaces the active file if you had previously removed it.
|
711 |
+
Bug Fix: Ensure lockouts take effect immediately, even on systems where changes to server configuration files do not take effect immediately.
|
readme.txt
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
=== iThemes Security (formerly Better WP Security) ===
|
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.
|
5 |
-
Tested up to: 4.9
|
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,20 @@ Free support may be available with the help of the community in the <a href="htt
|
|
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.
|
@@ -377,5 +391,5 @@ Free support may be available with the help of the community in the <a href="htt
|
|
377 |
|
378 |
== Upgrade Notice ==
|
379 |
|
380 |
-
= 6.
|
381 |
-
Version 6.
|
1 |
=== iThemes Security (formerly Better WP Security) ===
|
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.7
|
5 |
+
Tested up to: 4.9.1
|
6 |
+
Stable tag: 6.8.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.8.0 =
|
192 |
+
* New Feature: Introduces a scheduling framework for handling events. Cron is now used by default, and will switch to using an alternate scheduling system if it detects an error. To disable this detection set ITSEC_DISABLE_CRON_TEST in your wp-config.php file.
|
193 |
+
* Important: The ITSEC_FILE_CHECK_CRON and ITSEC_BACKUP_CRON constants have been deprecated. Use ITSEC_USE_CRON instead.
|
194 |
+
* Enhancement: Preserve notification settings when the responsible module is deactivated.
|
195 |
+
* Bug Fix: Process 404 lockouts on the 'wp' hook to prevent a headers have already been sent warning message.
|
196 |
+
* Bug Fix: Ensure Hide Backend emails are properly sent when activating Hide Backend before saving the Notification Center for the first time.
|
197 |
+
* Bug Fix: Prevent warning from being issued on new installs by allowing previous settings to be preserved if they exist.
|
198 |
+
* Bug Fix: Better handle WP_Error objects in mail errors that occurred before updating to first patch release.
|
199 |
+
* Bug Fix: A non static method was being called statically.
|
200 |
+
* Bug Fix: Fix occasional duplicate backups and file scans.
|
201 |
+
* Bug Fix: Fixed issue where scheduled events could repeat on sites that do not properly support WordPress's cron system.
|
202 |
+
* Bug Fix: Reactivating Away Mode now replaces the active file if you had previously removed it.
|
203 |
+
* Bug Fix: Ensure lockouts take effect immediately, even on systems where changes to server configuration files do not take effect immediately.
|
204 |
+
|
205 |
= 6.7.0 =
|
206 |
* New Feature: Introduces the Notification Center, a centralized place to manage and customize email notifications sent by iThemes Security.
|
207 |
* Enhancement: Updated queries and prepare statements to account for changes to the esc_sql() function in WordPress 4.8.3.
|
391 |
|
392 |
== Upgrade Notice ==
|
393 |
|
394 |
+
= 6.8.0 =
|
395 |
+
Version 6.8.0 contains important bug fixes and improvements. It is recommended for all users.
|