updated plugin Jetpack Protect
version 3.0.2
This commit is contained in:
@ -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
|
||||
|
@ -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": {
|
||||
|
@ -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() ) {
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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";
|
||||
}
|
||||
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user