| 1 |
<?php |
| 2 |
|
| 3 |
// Do not allow the file to be called directly. |
| 4 |
if ( ! defined( 'ABSPATH' ) ) { |
| 5 |
exit; |
| 6 |
} |
| 7 |
|
| 8 |
/** |
| 9 |
* This class is used to schedule the tasks used by Patchstack. |
| 10 |
*/ |
| 11 |
class P_Cron extends P_Core { |
| 12 |
|
| 13 |
/** |
| 14 |
* Add the actions required for the task scheduler. |
| 15 |
* |
| 16 |
* @param Patchstack $core |
| 17 |
* @return void |
| 18 |
*/ |
| 19 |
public function __construct( $core ) { |
| 20 |
parent::__construct( $core ); |
| 21 |
add_action( 'init', [ $this, 'schedule_events' ] ); |
| 22 |
add_filter( 'cron_schedules', [ $this, 'cron_schedules' ] ); |
| 23 |
add_action( 'patchstack_check_env', [ $this, 'check_env' ] ); |
| 24 |
} |
| 25 |
|
| 26 |
/** |
| 27 |
* Define our own custom cron schedules. |
| 28 |
* |
| 29 |
* @param array $schedules |
| 30 |
* @return array |
| 31 |
*/ |
| 32 |
public function cron_schedules( $schedules ) { |
| 33 |
// Define the scheduled tasks. |
| 34 |
$schedules['patchstack_15minute'] = [ |
| 35 |
'interval' => ( 60 * 15 ), |
| 36 |
'display' => esc_attr__( 'Every 15 Minutes' ), |
| 37 |
]; |
| 38 |
|
| 39 |
$schedules['patchstack_hourly'] = [ |
| 40 |
'interval' => ( 60 * 60 ), |
| 41 |
'display' => esc_attr__( 'Every Hour' ), |
| 42 |
]; |
| 43 |
|
| 44 |
$schedules['patchstack_trihourly'] = [ |
| 45 |
'interval' => ( 60 * 60 * 3 ), |
| 46 |
'display' => esc_attr__( 'Every 3 Hours' ), |
| 47 |
]; |
| 48 |
|
| 49 |
$schedules['patchstack_twicedaily'] = [ |
| 50 |
'interval' => ( 60 * 60 * 12 ), |
| 51 |
'display' => esc_attr__( '2 Times Daily' ), |
| 52 |
]; |
| 53 |
|
| 54 |
$schedules['patchstack_daily'] = [ |
| 55 |
'interval' => ( 60 * 60 * 24 ), |
| 56 |
'display' => esc_attr__( '1 Time Daily' ), |
| 57 |
]; |
| 58 |
|
| 59 |
return $schedules; |
| 60 |
} |
| 61 |
|
| 62 |
/** |
| 63 |
* Initialize our scheduled tasks. |
| 64 |
* |
| 65 |
* @return void |
| 66 |
*/ |
| 67 |
public function schedule_events() { |
| 68 |
// Random time throughout the day to make sure not all sites synchronize at the same time. |
| 69 |
$crons = get_option( 'patchstack_cron_offset', false ); |
| 70 |
if ( ! $crons || ! isset ( $crons['patchstack_daily'] ) ) { |
| 71 |
$crons = [ |
| 72 |
'patchstack_daily' => strtotime( 'today' ) + mt_rand( 0, 86399 ), |
| 73 |
'patchstack_hourly' => strtotime( 'today' ) + mt_rand( 0, 3600 ), |
| 74 |
'patchstack_trihourly' => strtotime( 'today' ) + mt_rand( 0, 9599 ), |
| 75 |
'patchstack_twicedaily' => strtotime( 'today' ) + mt_rand( 0, 43199 ), |
| 76 |
'patchstack_15minute' => strtotime( 'today' ) + mt_rand( 0, 899 ), |
| 77 |
]; |
| 78 |
update_option( 'patchstack_cron_offset', $crons ); |
| 79 |
|
| 80 |
// Clear existing scheduled events so we can use the new timestamps. |
| 81 |
foreach ( [ 'patchstack_send_software_data', 'patchstack_send_hacker_logs', 'patchstack_post_firewall_rules', 'patchstack_post_firewall_htaccess_rules', 'patchstack_post_dynamic_firewall_rules', 'patchstack_update_license_status', 'patchstack_send_event_logs', 'patchstack_update_plugins', 'patchstack_send_ping' ] as $event ) { |
| 82 |
wp_clear_scheduled_hook( $event ); |
| 83 |
} |
| 84 |
} |
| 85 |
|
| 86 |
// List of the different events. |
| 87 |
$free = [ |
| 88 |
'patchstack_send_software_data' => 'patchstack_twicedaily', |
| 89 |
'patchstack_update_license_status' => 'patchstack_twicedaily', |
| 90 |
'patchstack_send_ping' => 'patchstack_trihourly', |
| 91 |
'patchstack_update_plugins' => 'patchstack_15minute' |
| 92 |
]; |
| 93 |
|
| 94 |
$premium = [ |
| 95 |
'patchstack_send_hacker_logs' => 'patchstack_15minute', |
| 96 |
'patchstack_post_firewall_rules' => 'patchstack_daily', |
| 97 |
'patchstack_post_dynamic_firewall_rules' => 'patchstack_hourly', |
| 98 |
'patchstack_send_event_logs' => 'patchstack_15minute', |
| 99 |
'patchstack_check_env' => 'patchstack_trihourly' |
| 100 |
]; |
| 101 |
|
| 102 |
// Schedule the events if they are not scheduled yet. |
| 103 |
if ( $this->get_option( 'patchstack_clientid', false ) ) { |
| 104 |
// These events should always be scheduled for activated sites. |
| 105 |
foreach ( $free as $event => $interval ) { |
| 106 |
if ( ! wp_next_scheduled( $event ) ) { |
| 107 |
wp_schedule_event( $crons[ $interval ], $interval, $event ); |
| 108 |
} |
| 109 |
} |
| 110 |
|
| 111 |
// Only schedule these events for protected sites. |
| 112 |
if ( $this->get_option( 'patchstack_license_free', 0 ) != 1 && $this->license_is_active() ) { |
| 113 |
foreach ( $premium as $event => $interval ) { |
| 114 |
if ( ! wp_next_scheduled( $event ) ) { |
| 115 |
wp_schedule_event( $crons[ $interval ], $interval, $event ); |
| 116 |
} |
| 117 |
} |
| 118 |
} |
| 119 |
} |
| 120 |
} |
| 121 |
|
| 122 |
/** |
| 123 |
* Determine if the environment has been changed, we must do this to determine if the |
| 124 |
* real IP address header has changed to a different HTTP field. |
| 125 |
* |
| 126 |
* @return void |
| 127 |
*/ |
| 128 |
public function check_env() { |
| 129 |
$hash = $this->get_option( 'patchstack_environment_hash', '' ); |
| 130 |
$computed = $this->get_option( 'patchstack_ip_header_computed', 0 ); |
| 131 |
$env_hash = $this->get_env_hash(); |
| 132 |
|
| 133 |
// If hash has not been computed yet, but IP header has been computed, we ignore for the first time. |
| 134 |
if ( $hash == '' && $computed ) { |
| 135 |
update_option( 'patchstack_environment_hash', $env_hash ); |
| 136 |
return; |
| 137 |
} |
| 138 |
|
| 139 |
// If computed hash and previous hash are the same, we ignore. |
| 140 |
if ( $hash == $env_hash ) { |
| 141 |
return; |
| 142 |
} |
| 143 |
|
| 144 |
// At this point we can assume the previous environment hash and the current environment hash are different. |
| 145 |
// In this scenario, we want to determine which IP address header contains the appropriate IP address. |
| 146 |
update_option( 'patchstack_ip_header_force_compute', 1 ); |
| 147 |
update_option( 'patchstack_environment_hash', $env_hash ); |
| 148 |
do_action( 'patchstack_send_header_request' ); |
| 149 |
} |
| 150 |
|
| 151 |
/** |
| 152 |
* Compute a hash of several server specific values. |
| 153 |
* |
| 154 |
* @return string |
| 155 |
*/ |
| 156 |
private function get_env_hash() { |
| 157 |
// Parameters of which we want the full string. |
| 158 |
$params_full = [ 'SERVER_ADDR', 'SERVER_NAME', 'SERVER_SOFTWARE' ]; |
| 159 |
|
| 160 |
// Parameters of which we want to get boolean value. |
| 161 |
$params_boolean = [ 'REMOTE_ADDR', 'HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR' ]; |
| 162 |
|
| 163 |
// String to compute hash value of. |
| 164 |
$string = ''; |
| 165 |
|
| 166 |
// Append full parameter to string. |
| 167 |
foreach ( $params_full as $param ) { |
| 168 |
$string .= isset( $_SERVER[$param] ) ? $_SERVER[$param] : ''; |
| 169 |
} |
| 170 |
|
| 171 |
// Append existence to string, only if not running under cli. |
| 172 |
$sapi = function_exists( 'php_sapi_name' ) ? php_sapi_name() : false; |
| 173 |
if ( $sapi && substr( $sapi, 0, 3 ) != 'cli' ) { |
| 174 |
foreach ( $params_boolean as $param ) { |
| 175 |
$string .= isset( $_SERVER[$param] ) ? '1' : '0'; |
| 176 |
} |
| 177 |
} |
| 178 |
|
| 179 |
return sha1( $string ); |
| 180 |
} |
| 181 |
} |
| 182 |
|