$message['message'], 'type' => $message['type'], ); } } return $matched; } /** * Run the event to fetch the data. * * @param ITSEC_Job $job */ public static function run_event( $job ) { $fetched = self::fetch(); if ( is_wp_error( $fetched ) ) { $job->reschedule_in( 5 * MINUTE_IN_SECONDS ); return; } } /** * Fetches and stores the remote messages response. * * @return null|WP_Error */ public static function fetch() { $response = wp_remote_get( self::URL, array( 'user-agent' => 'WordPress', ) ); if ( is_wp_error( $response ) ) { return $response; } $data = wp_remote_retrieve_body( $response ); if ( ! $data ) { return new WP_Error( 'empty_body', __( 'Empty response body.', 'it-l10n-ithemes-security-pro' ) ); } $json = json_decode( $data, true ); if ( ! $json ) { return new WP_Error( 'invalid_json', __( 'Invalid json response.', 'it-l10n-ithemes-security-pro' ) ); } $sanitized = self::sanitize_response( $json ); update_site_option( self::OPTION, array( 'response' => $sanitized, 'ttl' => $sanitized['ttl'], 'requested' => ITSEC_Core::get_current_time_gmt(), ) ); return null; } /** * Sanitizes the JSON response. * * @param array $json * * @return array */ public static function sanitize_response( $json ) { $json = wp_parse_args( $json, array( 'ttl' => HOUR_IN_SECONDS, 'messages' => array(), 'actions' => array(), 'features' => array(), ) ); $sanitized = array( 'ttl' => absint( $json['ttl'] ), 'messages' => array(), 'features' => array(), 'actions' => wp_parse_slug_list( $json['actions'] ), ); foreach ( $json['messages'] as $message ) { $sanitized['messages'][] = array( 'message' => self::sanitize_message( $message['message'] ), 'type' => self::sanitize_type( $message['type'] ), 'placement' => $message['placement'], ); } foreach ( $json['features'] as $feature => $f_config ) { $sanitized['features'][ $feature ] = [ 'rate' => isset( $f_config['rate'] ) ? (int) $f_config['rate'] : false, 'disabled' => ! empty( $f_config['disabled'] ), 'requirements' => isset( $f_config['requirements'] ) && is_array( $f_config['requirements'] ) ? $f_config['requirements'] : [], ]; } return $sanitized; } private static function sanitize_message( $message ) { return wp_kses( $message, array( 'a' => array( 'href' => true ) ) ); } private static function sanitize_type( $type ) { if ( in_array( $type, array( 'success', 'info', 'warning', 'error' ), true ) ) { return $type; } return 'info'; } private static function get_response() { if ( ! ITSEC_Core::is_pro() ) { return array(); } if ( ! isset( self::$_response ) ) { self::$_response = self::load_response(); } return apply_filters( 'itsec_remote_messages', self::$_response ); } /** * Loads the response from the local cache or the server. * * @return array|mixed */ private static function load_response() { $data = self::get_stored_response(); if ( ! $data['response'] ) { self::schedule_check(); return array(); } if ( $data['requested'] + $data['ttl'] < ITSEC_Core::get_current_time_gmt() ) { self::schedule_check(); $events = ITSEC_Core::get_scheduler()->get_single_events(); foreach ( $events as $event ) { // If we are less than an hour late for processing the refresh, return the stale data. if ( self::EVENT === $event['id'] ) { if ( $event['fire_at'] + HOUR_IN_SECONDS > ITSEC_Core::get_current_time_gmt() ) { return $data['response']; } // If its been more than a day, call the API right now. if ( $event['fire_at'] + DAY_IN_SECONDS > ITSEC_Core::get_current_time_gmt() ) { ITSEC_Core::get_scheduler()->run_single_event( self::EVENT ); $data = self::get_stored_response(); if ( $data['requested'] === ITSEC_Core::get_current_time_gmt() ) { return $data['response']; } } } } return array(); } return $data['response']; } private static function get_stored_response() { $data = get_site_option( self::OPTION, array() ); $data = wp_parse_args( $data, array( 'response' => array(), 'requested' => 0, 'ttl' => 0, ) ); return $data; } private static function schedule_check() { $s = ITSEC_Core::get_scheduler(); if ( ! $s->is_single_scheduled( self::EVENT, null ) ) { $s->schedule_once( ITSEC_Core::get_current_time_gmt() + 60, self::EVENT ); } } }