-------------------------------------------------------------------- */ /** TOOLS =================================================================================== */ /** ----------------------------------------------------------------------------------------- */ /** * Tell if a API key is well formatted. * * @since 3.2.3 * @access public * @author Grégory Viguier * * @param string $api_key An API kay. * @return array|bool An array with the keys 'k' and 's' (required by the API) if valid. False otherwise. */ public static function is_api_key_valid( $api_key ) { if ( '' !== $api_key && preg_match( '@^(?[a-z0-9]{32})/(?[a-z0-9]{32})$@', $api_key, $matches ) ) { return $matches; } return false; } /** * Clear Sucuri firewall cache. * * @since 3.2 * @access private * @author Grégory Viguier * * @return bool|object True on success. A WP_Error object on failure. */ private function clean_firewall_cache() { $api_key = $this->get_api_key(); if ( is_wp_error( $api_key ) ) { return $api_key; } $response = $this->request_api( [ 'a' => 'clear_cache', 'k' => $api_key['k'], 's' => $api_key['s'], ] ); if ( is_wp_error( $response ) ) { return $response; } Logger::info( 'Sucuri firewall cache cleared.', [ 'sucuri firewall cache', ] ); return true; } /** * Get the API key. * * @since 3.2 * @access private * @author Grégory Viguier * * @return array|object An array with the keys 'k' and 's', required by the API. A WP_Error object if no key or invalid key. */ private function get_api_key() { $api_key = trim( $this->options->get( 'sucury_waf_api_key', '' ) ); if ( ! $api_key ) { Logger::error( 'API key was not found.', [ 'sucuri firewall cache', ] ); return new \WP_Error( 'no_sucuri_api_key', __( 'Sucuri firewall API key was not found.', 'rocket' ) ); } $matches = self::is_api_key_valid( $api_key ); if ( ! $matches ) { Logger::error( 'API key is invalid.', [ 'sucuri firewall cache', ] ); return new \WP_Error( 'invalid_sucuri_api_key', __( 'Sucuri firewall API key is invalid.', 'rocket' ) ); } return [ 'k' => $matches['k'], 's' => $matches['s'], ]; } /** * Request against the API. * * @since 3.2 * @access private * @author Grégory Viguier * * @param array $params Parameters to send. * @return array|object The response data on success. A WP_Error object on failure. */ private function request_api( $params = [] ) { $params['time'] = time(); $params = $this->build_query( $params ); $url = sprintf( static::API_URL, $params ); try { /** * Filters the arguments for the Sucuri API request * * @since 3.3.4 * @author Soponar Cristina * * @param array $args Arguments for the request. */ $args = apply_filters( 'rocket_sucuri_api_request_args', [ 'timeout' => 5, 'redirection' => 5, 'httpversion' => '1.1', 'blocking' => true, /** This filter is documented in wp-includes/class-wp-http-streams.php */ 'sslverify' => apply_filters( 'https_ssl_verify', true ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound ] ); $response = wp_remote_get( $url, $args ); } catch ( \Exception $e ) { Logger::error( 'Error when contacting the API.', [ 'sucuri firewall cache', 'url' => $url, 'response' => $e->getMessage(), ] ); return new \WP_Error( 'error_sucuri_api', __( 'Error when contacting Sucuri firewall API.', 'rocket' ) ); } if ( is_wp_error( $response ) ) { Logger::error( 'Error when contacting the API.', [ 'sucuri firewall cache', 'url' => $url, 'response' => $response->get_error_message(), ] ); /* translators: %s is an error message. */ return new \WP_Error( 'wp_error_sucuri_api', sprintf( __( 'Error when contacting Sucuri firewall API. Error message was: %s', 'rocket' ), $response->get_error_message() ) ); } $contents = wp_remote_retrieve_body( $response ); if ( ! $contents ) { Logger::error( 'Could not get a response from the API.', [ 'sucuri firewall cache', 'url' => $url, 'response' => $response, ] ); return new \WP_Error( 'sucuri_api_no_response', __( 'Could not get a response from the Sucuri firewall API.', 'rocket' ) ); } $data = @json_decode( $contents, true ); if ( ! $data || ! is_array( $data ) ) { Logger::error( 'Invalid response from the API.', [ 'sucuri firewall cache', 'url' => $url, 'response_body' => $contents, ] ); return new \WP_Error( 'sucuri_api_invalid_response', __( 'Got an invalid response from the Sucuri firewall API.', 'rocket' ) ); } if ( empty( $data['status'] ) ) { Logger::error( 'The action failed.', [ 'sucuri firewall cache', 'url' => $url, 'response_data' => $data, ] ); if ( empty( $data['messages'] ) || ! is_array( $data['messages'] ) ) { return new \WP_Error( 'sucuri_api_error_status', __( 'The Sucuri firewall API returned an unknown error.', 'rocket' ) ); } /* translators: %s is an error message. */ $message = _n( 'The Sucuri firewall API returned the following error: %s', 'The Sucuri firewall API returned the following errors: %s', count( $data['messages'] ), 'rocket' ); $message = sprintf( $message, '
' . implode( '
', $data['messages'] ) ); return new \WP_Error( 'sucuri_api_error_status', $message ); } return $data; } /** * An i18n-firendly alternative to the built-in PHP method `http_build_query()`. * * @param array|object $params An array or object containing properties. * @return string A URL-encoded string. */ private function build_query( $params ) { if ( ! $params ) { return ''; } $params = (array) $params; foreach ( $params as $param => $value ) { $params[ $param ] = $param . '=' . rawurlencode( (string) $value ); } return implode( '&', $params ); } }