updated plugin Jetpack Protect version 3.0.2

This commit is contained in:
2024-10-09 12:44:31 +00:00
committed by Gitium
parent a35dc419bc
commit f970470c59
283 changed files with 6970 additions and 2338 deletions

View File

@ -5,6 +5,51 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.18.5] - 2024-09-06
### Changed
- Updated package dependencies. [#39253]
### Fixed
- Ensure that request body is parsed correctly [#39262]
## [0.18.4] - 2024-08-26
### Changed
- Updated package dependencies. [#39004]
## [0.18.3] - 2024-08-19
### Changed
- Internal updates.
## [0.18.2] - 2024-08-15
### Fixed
- Fix incorrect next-version tokens in php `@since` and/or `@deprecated` docs. [#38869]
## [0.18.1] - 2024-08-08
### Security
- Parse request body when method used is not POST [#38621]
### Added
- Brute Force Protection: Add `jetpack_has_login_ability` hook. [#38518]
## [0.18.0] - 2024-08-01
### Added
- Adds global statistics [#38388]
### Fixed
- Fix global stats type check [#38634]
## [0.17.0] - 2024-07-22
### Added
- Added the ability to toggle IP block and allow lists individually. [#38184]
## [0.16.10] - 2024-06-26
### Changed
- Internal updates.
## [0.16.9] - 2024-06-03
### Changed
- Phab baseline file update. [#36968]
## [0.16.8] - 2024-05-20
### Changed
- Internal updates.
@ -321,6 +366,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Core: do not ship .phpcs.dir.xml in production builds.
[0.18.5]: https://github.com/Automattic/jetpack-waf/compare/v0.18.4...v0.18.5
[0.18.4]: https://github.com/Automattic/jetpack-waf/compare/v0.18.3...v0.18.4
[0.18.3]: https://github.com/Automattic/jetpack-waf/compare/v0.18.2...v0.18.3
[0.18.2]: https://github.com/Automattic/jetpack-waf/compare/v0.18.1...v0.18.2
[0.18.1]: https://github.com/Automattic/jetpack-waf/compare/v0.18.0...v0.18.1
[0.18.0]: https://github.com/Automattic/jetpack-waf/compare/v0.17.0...v0.18.0
[0.17.0]: https://github.com/Automattic/jetpack-waf/compare/v0.16.10...v0.17.0
[0.16.10]: https://github.com/Automattic/jetpack-waf/compare/v0.16.9...v0.16.10
[0.16.9]: https://github.com/Automattic/jetpack-waf/compare/v0.16.8...v0.16.9
[0.16.8]: https://github.com/Automattic/jetpack-waf/compare/v0.16.7...v0.16.8
[0.16.7]: https://github.com/Automattic/jetpack-waf/compare/v0.16.6...v0.16.7
[0.16.6]: https://github.com/Automattic/jetpack-waf/compare/v0.16.5...v0.16.6

View File

@ -5,15 +5,15 @@
"license": "GPL-2.0-or-later",
"require": {
"php": ">=7.0",
"automattic/jetpack-connection": "^2.8.3",
"automattic/jetpack-constants": "^2.0.2",
"automattic/jetpack-ip": "^0.2.2",
"automattic/jetpack-status": "^3.1.0",
"automattic/jetpack-connection": "^4.0.0",
"automattic/jetpack-constants": "^2.0.4",
"automattic/jetpack-ip": "^0.2.3",
"automattic/jetpack-status": "^4.0.0",
"wikimedia/aho-corasick": "^1.0"
},
"require-dev": {
"yoast/phpunit-polyfills": "1.1.0",
"automattic/jetpack-changelogger": "^4.2.4",
"yoast/phpunit-polyfills": "^1.1.1",
"automattic/jetpack-changelogger": "^4.2.6",
"automattic/wordbless": "@dev"
},
"suggest": {
@ -52,7 +52,7 @@
"link-template": "https://github.com/Automattic/jetpack-waf/compare/v${old}...v${new}"
},
"branch-alias": {
"dev-trunk": "0.16.x-dev"
"dev-trunk": "0.18.x-dev"
}
},
"config": {

View File

@ -14,6 +14,7 @@ use Automattic\Jetpack\IP\Utils as IP_Utils;
use Automattic\Jetpack\Modules;
use Automattic\Jetpack\Waf\Waf_Compatibility;
use Automattic\Jetpack\Waf\Waf_Constants;
use Automattic\Jetpack\Waf\Waf_Rules_Manager;
use Jetpack_IXR_Client;
use Jetpack_Options;
use WP_Error;
@ -131,6 +132,7 @@ class Brute_Force_Protection {
add_action( 'jetpack_modules_loaded', array( $this, 'modules_loaded' ) );
add_action( 'login_form', array( $this, 'check_use_math' ), 0 );
add_filter( 'authenticate', array( $this, 'check_preauth' ), 10, 3 );
add_filter( 'jetpack_has_login_ability', array( $this, 'has_login_ability' ) );
add_action( 'wp_login', array( $this, 'log_successful_login' ), 10, 2 );
add_action( 'wp_login_failed', array( $this, 'log_failed_attempt' ) );
add_action( 'admin_init', array( $this, 'maybe_update_headers' ) );
@ -633,6 +635,15 @@ class Brute_Force_Protection {
return $output;
}
/**
* Whether or not the IP allow list is enabled.
*
* @return bool
*/
public static function ip_allow_list_enabled() {
return get_option( Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME, true );
}
/**
* Checks if the IP address is in the allow list.
*
@ -658,6 +669,11 @@ class Brute_Force_Protection {
return true;
}
// Allow list must be enabled.
if ( ! $this->ip_allow_list_enabled() ) {
return false;
}
$allow_list = Brute_Force_Protection_Shared_Functions::get_local_allow_list();
if ( is_multisite() ) {

View File

@ -28,6 +28,8 @@ class Waf_Compatibility {
add_filter( 'default_option_' . Waf_Initializer::NEEDS_UPDATE_OPTION_NAME, __CLASS__ . '::default_option_waf_needs_update', 10, 3 );
add_filter( 'default_option_' . Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME, __CLASS__ . '::default_option_waf_ip_allow_list', 10, 3 );
add_filter( 'option_' . Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME, __CLASS__ . '::filter_option_waf_ip_allow_list', 10, 1 );
add_filter( 'default_option_' . Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME, __CLASS__ . '::default_option_waf_ip_allow_list_enabled', 10, 3 );
add_filter( 'default_option_' . Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME, __CLASS__ . '::default_option_waf_ip_block_list_enabled', 10, 3 );
}
/**
@ -229,4 +231,58 @@ class Waf_Compatibility {
public static function is_brute_force_running_in_jetpack() {
return defined( 'JETPACK__VERSION' ) && version_compare( JETPACK__VERSION, '12', '<' );
}
/**
* Default the allow list enabled option to the value of the generic IP lists enabled option it replaced.
*
* @since 0.17.0
*
* @param mixed $default The default value to return if the option does not exist in the database.
* @param string $option Option name.
* @param bool $passed_default Was get_option() passed a default value.
*
* @return mixed The default value to return if the option does not exist in the database.
*/
public static function default_option_waf_ip_allow_list_enabled( $default, $option, $passed_default ) {
// Allow get_option() to override this default value
if ( $passed_default ) {
return $default;
}
// If the deprecated IP lists option was set to false, disable the allow list.
// @phan-suppress-next-line PhanDeprecatedClassConstant -- Needed for backwards compatibility.
$deprecated_option = Jetpack_Options::get_raw_option( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME, true );
if ( ! $deprecated_option ) {
return false;
}
// If the allow list is empty, disable the allow list.
if ( ! Jetpack_Options::get_raw_option( Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME ) ) {
return false;
}
// Default to enabling the allow list.
return true;
}
/**
* Default the block list enabled option to the value of the generic IP lists enabled option it replaced.
*
* @since 0.17.0
*
* @param mixed $default The default value to return if the option does not exist in the database.
* @param string $option Option name.
* @param bool $passed_default Was get_option() passed a default value.
*
* @return mixed The default value to return if the option does not exist in the database.
*/
public static function default_option_waf_ip_block_list_enabled( $default, $option, $passed_default ) {
// Allow get_option() to override this default value
if ( $passed_default ) {
return $default;
}
// @phan-suppress-next-line PhanDeprecatedClassConstant -- Needed for backwards compatibility.
return Jetpack_Options::get_raw_option( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME, false );
}
}

View File

@ -103,42 +103,53 @@ class REST_Controller {
public static function update_waf( $request ) {
// Automatic Rules Enabled
if ( isset( $request[ Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME ] ) ) {
update_option( Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME, (bool) $request->get_param( Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME ) );
update_option( Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME, $request->get_param( Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME ) ? '1' : '' );
}
// IP Lists Enabled
if ( isset( $request[ Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME ] ) ) {
update_option( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME, (bool) $request->get_param( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME ) );
/**
* IP Lists Enabled
*
* @deprecated 0.17.0 This is a legacy option maintained here for backwards compatibility.
*/
if ( isset( $request['jetpack_waf_ip_list'] ) ) {
update_option( Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME, $request['jetpack_waf_ip_list'] ? '1' : '' );
update_option( Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME, $request['jetpack_waf_ip_list'] ? '1' : '' );
}
// IP Block List
if ( isset( $request[ Waf_Rules_Manager::IP_BLOCK_LIST_OPTION_NAME ] ) ) {
update_option( Waf_Rules_Manager::IP_BLOCK_LIST_OPTION_NAME, $request[ Waf_Rules_Manager::IP_BLOCK_LIST_OPTION_NAME ] );
}
if ( isset( $request[ Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME ] ) ) {
update_option( Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME, $request[ Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME ] ? '1' : '' );
}
// IP Allow List
if ( isset( $request[ Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME ] ) ) {
update_option( Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME, $request[ Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME ] );
}
if ( isset( $request[ Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME ] ) ) {
update_option( Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME, $request[ Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME ] ? '1' : '' );
}
// Share Data
if ( isset( $request[ Waf_Runner::SHARE_DATA_OPTION_NAME ] ) ) {
// If a user disabled the regular share we should disable the debug share data option.
if ( false === $request[ Waf_Runner::SHARE_DATA_OPTION_NAME ] ) {
update_option( Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME, false );
if ( ! $request[ Waf_Runner::SHARE_DATA_OPTION_NAME ] ) {
update_option( Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME, '' );
}
update_option( Waf_Runner::SHARE_DATA_OPTION_NAME, (bool) $request[ Waf_Runner::SHARE_DATA_OPTION_NAME ] );
update_option( Waf_Runner::SHARE_DATA_OPTION_NAME, $request[ Waf_Runner::SHARE_DATA_OPTION_NAME ] ? '1' : '' );
}
// Share Debug Data
if ( isset( $request[ Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME ] ) ) {
// If a user toggles the debug share we should enable the regular share data option.
if ( true === $request[ Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME ] ) {
update_option( Waf_Runner::SHARE_DATA_OPTION_NAME, true );
if ( $request[ Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME ] ) {
update_option( Waf_Runner::SHARE_DATA_OPTION_NAME, 1 );
}
update_option( Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME, (bool) $request[ Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME ] );
update_option( Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME, $request[ Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME ] ? '1' : '' );
}
// Brute Force Protection

View File

@ -181,11 +181,6 @@ class Waf_Initializer {
Waf_Compatibility::run_compatibility_migrations();
Waf_Constants::define_mode();
if ( ! Waf_Runner::is_allowed_mode( JETPACK_WAF_MODE ) ) {
return new WP_Error( 'waf_mode_invalid', 'Invalid firewall mode.' );
}
try {
Waf_Rules_Manager::generate_ip_rules();
Waf_Rules_Manager::generate_rules();

View File

@ -334,13 +334,22 @@ class Waf_Request {
* @return array{string, scalar}[]
*/
public function get_post_vars() {
// Attempt to decode JSON requests.
if ( strpos( $this->get_header( 'content-type' ), 'application/json' ) !== false ) {
$content_type = $this->get_header( 'content-type' );
if ( ! empty( $_POST ) ) {
// If $_POST is populated, use it.
return flatten_array( $_POST );
} elseif ( strpos( $content_type, 'application/json' ) !== false ) {
// Attempt to decode JSON requests.
$decoded_json = json_decode( $this->get_body(), true ) ?? array();
return flatten_array( $decoded_json, 'json', true );
} elseif ( strpos( $content_type, 'application/x-www-form-urlencoded' ) !== false ) {
// Attempt to decode url-encoded data
parse_str( $this->get_body(), $params );
return flatten_array( $params );
} else {
// Don't try to parse any other content types
return array();
}
return flatten_array( $_POST );
}
/**

View File

@ -24,18 +24,53 @@ class Waf_Rules_Manager {
// WAF Options
const VERSION_OPTION_NAME = 'jetpack_waf_rules_version';
const AUTOMATIC_RULES_ENABLED_OPTION_NAME = 'jetpack_waf_automatic_rules';
const IP_LISTS_ENABLED_OPTION_NAME = 'jetpack_waf_ip_list';
const IP_ALLOW_LIST_OPTION_NAME = 'jetpack_waf_ip_allow_list';
const IP_ALLOW_LIST_ENABLED_OPTION_NAME = 'jetpack_waf_ip_allow_list_enabled';
const IP_BLOCK_LIST_OPTION_NAME = 'jetpack_waf_ip_block_list';
const IP_BLOCK_LIST_ENABLED_OPTION_NAME = 'jetpack_waf_ip_block_list_enabled';
const RULE_LAST_UPDATED_OPTION_NAME = 'jetpack_waf_last_updated_timestamp';
const AUTOMATIC_RULES_LAST_UPDATED_OPTION_NAME = 'jetpack_waf_automatic_rules_last_updated_timestamp';
/**
* IP Lists Enabled Option Name
*
* @deprecated 0.17.0 Use Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME and Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME instead.
*/
const IP_LISTS_ENABLED_OPTION_NAME = 'jetpack_waf_ip_list';
// Rule Files
const RULES_ENTRYPOINT_FILE = '/rules/rules.php';
const AUTOMATIC_RULES_FILE = '/rules/automatic-rules.php';
const IP_ALLOW_RULES_FILE = '/rules/allow-ip.php';
const IP_BLOCK_RULES_FILE = '/rules/block-ip.php';
/**
* Whether automatic rules are enabled.
*
* @return bool
*/
public static function automatic_rules_enabled() {
return (bool) get_option( self::AUTOMATIC_RULES_ENABLED_OPTION_NAME );
}
/**
* Whether IP allow list is enabled.
*
* @return bool
*/
public static function ip_allow_list_enabled() {
return (bool) get_option( self::IP_ALLOW_LIST_ENABLED_OPTION_NAME );
}
/**
* Whether IP block list is enabled.
*
* @return bool
*/
public static function ip_block_list_enabled() {
return (bool) get_option( self::IP_BLOCK_LIST_ENABLED_OPTION_NAME );
}
/**
* Register WordPress hooks for the WAF rules.
*
@ -45,10 +80,12 @@ class Waf_Rules_Manager {
// Re-activate the WAF any time an option is added or updated.
add_action( 'add_option_' . self::AUTOMATIC_RULES_ENABLED_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
add_action( 'update_option_' . self::AUTOMATIC_RULES_ENABLED_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
add_action( 'add_option_' . self::IP_LISTS_ENABLED_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
add_action( 'update_option_' . self::IP_LISTS_ENABLED_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
add_action( 'add_option_' . self::IP_ALLOW_LIST_ENABLED_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
add_action( 'update_option_' . self::IP_ALLOW_LIST_ENABLED_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
add_action( 'add_option_' . self::IP_ALLOW_LIST_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
add_action( 'update_option_' . self::IP_ALLOW_LIST_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
add_action( 'add_option_' . self::IP_BLOCK_LIST_ENABLED_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
add_action( 'update_option_' . self::IP_BLOCK_LIST_ENABLED_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
add_action( 'add_option_' . self::IP_BLOCK_LIST_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
add_action( 'update_option_' . self::IP_BLOCK_LIST_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
// Register the cron job.
@ -74,11 +111,6 @@ class Waf_Rules_Manager {
* @return bool|WP_Error True if rules update is successful, WP_Error on failure.
*/
public static function update_rules_cron() {
Waf_Constants::define_mode();
if ( ! Waf_Runner::is_allowed_mode( JETPACK_WAF_MODE ) ) {
return new WP_Error( 'waf_invalid_mode', 'Invalid firewall mode.' );
}
try {
self::generate_automatic_rules();
self::generate_ip_rules();
@ -115,10 +147,6 @@ class Waf_Rules_Manager {
* @return void
*/
public static function update_rules_if_changed() {
Waf_Constants::define_mode();
if ( ! Waf_Runner::is_allowed_mode( JETPACK_WAF_MODE ) ) {
throw new Waf_Exception( 'Invalid firewall mode.' );
}
$version = get_option( self::VERSION_OPTION_NAME );
if ( self::RULES_VERSION !== $version ) {
self::generate_automatic_rules();
@ -213,14 +241,18 @@ class Waf_Rules_Manager {
}
}
// Add manual rules
if ( get_option( self::IP_LISTS_ENABLED_OPTION_NAME ) ) {
// Add IP allow list
if ( self::ip_allow_list_enabled() ) {
$rules .= self::wrap_require( Waf_Runner::get_waf_file_path( self::IP_ALLOW_RULES_FILE ) ) . "\n";
}
// Add IP block list
if ( self::ip_block_list_enabled() ) {
$rules .= self::wrap_require( Waf_Runner::get_waf_file_path( self::IP_BLOCK_RULES_FILE ), "return \$waf->block( 'block', -1, 'ip block list' );" ) . "\n";
}
// Add automatic rules
if ( get_option( self::AUTOMATIC_RULES_ENABLED_OPTION_NAME ) ) {
if ( self::automatic_rules_enabled() ) {
$rules .= self::wrap_require( Waf_Runner::get_waf_file_path( self::AUTOMATIC_RULES_FILE ) ) . "\n";
}

View File

@ -160,16 +160,26 @@ class Waf_Runner {
*/
public static function get_config() {
return array(
Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME => get_option( Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME ),
Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME => get_option( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME ),
Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME => Waf_Rules_Manager::automatic_rules_enabled(),
Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME => get_option( Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME ),
Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME => Waf_Rules_Manager::ip_allow_list_enabled(),
Waf_Rules_Manager::IP_BLOCK_LIST_OPTION_NAME => get_option( Waf_Rules_Manager::IP_BLOCK_LIST_OPTION_NAME ),
Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME => Waf_Rules_Manager::ip_block_list_enabled(),
self::SHARE_DATA_OPTION_NAME => get_option( self::SHARE_DATA_OPTION_NAME ),
self::SHARE_DEBUG_DATA_OPTION_NAME => get_option( self::SHARE_DEBUG_DATA_OPTION_NAME ),
'bootstrap_path' => self::get_bootstrap_file_path(),
'standalone_mode' => self::get_standalone_mode_status(),
'automatic_rules_available' => (bool) self::automatic_rules_available(),
'brute_force_protection' => (bool) Brute_Force_Protection::is_enabled(),
/**
* Provide the deprecated IP lists options for backwards compatibility with older versions of the Jetpack and Protect plugins.
* i.e. If one plugin is updated and the other is not, the latest version of this package will be used by both plugins.
*
* @deprecated 0.17.0
*/
// @phan-suppress-next-line PhanDeprecatedClassConstant -- Needed for backwards compatibility.
Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME => Waf_Rules_Manager::ip_allow_list_enabled() || Waf_Rules_Manager::ip_block_list_enabled(),
);
}
@ -235,10 +245,10 @@ class Waf_Runner {
// if something terrible happens during the WAF running, we don't want to interfere with the rest of the site,
// so we intercept errors ONLY while the WAF is running, then we remove our handler after the WAF finishes.
$display_errors = ini_get( 'display_errors' );
// phpcs:ignore
ini_set( 'display_errors', 'Off' );
// phpcs:ignore
set_error_handler( array( self::class, 'errorHandler' ) );
ini_set( 'display_errors', 'Off' ); // phpcs:ignore WordPress.PHP.IniSet.display_errors_Disallowed -- We only customize error reporting while the WAF is running, and remove our handler afterwards.
set_error_handler( array( self::class, 'errorHandler' ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler -- We only customize error reporting while the WAF is running, and remove our handler afterwards.
try {
@ -257,8 +267,9 @@ class Waf_Runner {
// remove the custom error handler, so we don't interfere with the site.
restore_error_handler();
// phpcs:ignore
ini_set( 'display_errors', $display_errors );
// Restore the original value.
ini_set( 'display_errors', $display_errors ); // phpcs:ignore WordPress.PHP.IniSet.display_errors_Disallowed -- We only customize error reporting while the WAF is running, and remove our handler afterwards.
}
/**
@ -302,11 +313,6 @@ class Waf_Runner {
* @return void
*/
public static function activate() {
Waf_Constants::define_mode();
if ( ! self::is_allowed_mode( JETPACK_WAF_MODE ) ) {
throw new Waf_Exception( 'Invalid firewall mode.' );
}
$version = get_option( Waf_Rules_Manager::VERSION_OPTION_NAME );
if ( ! $version ) {
add_option( Waf_Rules_Manager::VERSION_OPTION_NAME, Waf_Rules_Manager::RULES_VERSION );
@ -439,10 +445,8 @@ class Waf_Runner {
// Delete the automatic rules last updated option.
delete_option( Waf_Rules_Manager::AUTOMATIC_RULES_LAST_UPDATED_OPTION_NAME );
$automatic_rules_enabled = get_option( Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME );
// If automatic rules setting is enabled, disable it.
if ( $automatic_rules_enabled ) {
if ( Waf_Rules_Manager::automatic_rules_enabled() ) {
update_option( Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME, false );
}

View File

@ -14,6 +14,13 @@ use Automattic\Jetpack\IP\Utils as IP_Utils;
*/
class Waf_Stats {
/**
* The global stats cache
*
* @var array|null
*/
public static $global_stats = null;
/**
* Get IP allow list count
*
@ -69,4 +76,85 @@ class Waf_Stats {
public static function get_automatic_rules_last_updated() {
return get_option( Waf_Rules_Manager::AUTOMATIC_RULES_LAST_UPDATED_OPTION_NAME );
}
/**
* Checks if the current cached global stats is expired and should be renewed
*
* @return boolean
*/
public static function is_global_stats_cache_expired() {
$option_timestamp = get_option( 'jetpack_protect_global_stats_timestamp' );
if ( ! $option_timestamp ) {
return true;
}
return time() > (int) $option_timestamp;
}
/**
* Checks if we should consider the stored cache or bypass it
*
* @return boolean
*/
public static function should_use_global_stats_cache() {
return ! ( defined( 'JETPACK_PROTECT_DEV__BYPASS_CACHE' ) && JETPACK_PROTECT_DEV__BYPASS_CACHE );
}
/**
* Get the global stats from the API endpoint
*/
public static function fetch_global_stats_from_api() {
$url = esc_url_raw( 'https://public-api.wordpress.com/wpcom/v2/jetpack-protect-global-stats' );
$response = wp_remote_get( $url );
$response_code = wp_remote_retrieve_response_code( $response );
if ( is_wp_error( $response ) || 200 !== $response_code || empty( $response['body'] ) ) {
return new \WP_Error( 'failed_fetching_global_stats', 'Failed to fetch global stats data from the server', array( 'status' => $response_code ) );
}
$body = json_decode( wp_remote_retrieve_body( $response ) );
update_option( 'jetpack_protect_global_stats', maybe_serialize( $body ) );
update_option( 'jetpack_protect_global_stats_timestamp', time() + 86400 ); // Caches expires after 24 hours.
return $body;
}
/**
* Gets the current cached global stats
*
* @return bool|array False if value is not found. Array with values if cache is found.
*/
public static function get_global_stats_from_options() {
return maybe_unserialize( get_option( 'jetpack_protect_global_stats' ) );
}
/**
* Get the global stats
* If the cache is expired, it will fetch the data from the API
* If the cache is not expired, it will return the cached data
*
* @param bool $refresh_from_wpcom Whether to refresh the data from the API.
* @return array|\WP_Error
*/
public static function get_global_stats( $refresh_from_wpcom = false ) {
if ( self::$global_stats !== null ) {
return self::$global_stats;
}
if ( $refresh_from_wpcom || ! self::should_use_global_stats_cache() || self::is_global_stats_cache_expired() ) {
$global_stats = self::fetch_global_stats_from_api();
} else {
$global_stats = self::get_global_stats_from_options();
}
// Ensure that $global_stats is of the correct type
if ( ( ! is_object( $global_stats ) && ! ( $global_stats instanceof \WP_Error ) ) ) {
return new \WP_Error( 'unexpected_type', 'Unexpected type or null returned for global stats' );
}
return $global_stats;
}
}