Skip to content

Commit

Permalink
Add individual controls for toggling the IP block and allow lists.
Browse files Browse the repository at this point in the history
  • Loading branch information
nateweller committed Jul 5, 2024
1 parent 104007b commit 51c4a90
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 9 deletions.
4 changes: 4 additions & 0 deletions projects/packages/waf/changelog/add-waf-ip-list-toggles
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Added the ability to toggle IP block and allow lists individually.
2 changes: 1 addition & 1 deletion projects/packages/waf/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,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.17.x-dev"
}
},
"config": {
Expand Down
15 changes: 15 additions & 0 deletions projects/packages/waf/src/class-brute-force-protection.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
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;
Expand Down Expand Up @@ -633,6 +634,15 @@ public function get_headers() {
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.
*
Expand All @@ -658,6 +668,11 @@ public function ip_is_allowed( $ip ) {
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() ) {
Expand Down
56 changes: 56 additions & 0 deletions projects/packages/waf/src/class-compatibility.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public static function add_compatibility_hooks() {
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 );
}

/**
Expand Down Expand Up @@ -229,4 +231,58 @@ public static function default_option_waf_ip_allow_list( $default, $option, $pas
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 $next-version$
*
* @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 ) {
// 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 = get_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 ( ! get_option( Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME ) ) {
return false;
}

// Allow get_option() to override this default value
if ( $passed_default ) {
return $default;
}

// 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 $next-version$
*
* @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 get_option( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME, false );
}
}
8 changes: 8 additions & 0 deletions projects/packages/waf/src/class-rest-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,27 @@ public static function update_waf( $request ) {
}

// IP Lists Enabled
// @phan-suppress-next-line PhanDeprecatedClassConstant -- Needed for backwards compatibility.
if ( isset( $request[ Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME ] ) ) {
// @phan-suppress-next-line PhanDeprecatedClassConstant -- Needed for backwards compatibility.
update_option( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME, (bool) $request->get_param( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME ) );
}

// 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 ] );
}

// 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 ] );
}

// Share Data
if ( isset( $request[ Waf_Runner::SHARE_DATA_OPTION_NAME ] ) ) {
Expand Down
22 changes: 19 additions & 3 deletions projects/packages/waf/src/class-waf-rules-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,20 @@ 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 $next-version$ 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';
Expand All @@ -45,11 +53,15 @@ public static function add_hooks() {
// 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 );
// @phan-suppress-next-line PhanDeprecatedClassConstant -- Needed for backwards compatibility.
add_action( 'add_option_' . self::IP_LISTS_ENABLED_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
// @phan-suppress-next-line PhanDeprecatedClassConstant -- Needed for backwards compatibility.
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_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_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( '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_OPTION_NAME, array( static::class, 'reactivate_on_rules_option_change' ), 10, 0 );
// Register the cron job.
add_action( 'jetpack_waf_rules_update_cron', array( static::class, 'update_rules_cron' ) );
Expand Down Expand Up @@ -213,9 +225,13 @@ public static function generate_rules() {
}
}

// Add manual rules
if ( get_option( self::IP_LISTS_ENABLED_OPTION_NAME ) ) {
// Add IP allow list
if ( get_option( self::IP_ALLOW_LIST_ENABLED_OPTION_NAME ) ) {
$rules .= self::wrap_require( Waf_Runner::get_waf_file_path( self::IP_ALLOW_RULES_FILE ) ) . "\n";
}

// Add IP block list
if ( get_option( self::IP_BLOCK_LIST_ENABLED_OPTION_NAME ) ) {
$rules .= self::wrap_require( Waf_Runner::get_waf_file_path( self::IP_BLOCK_RULES_FILE ), "return \$waf->block( 'block', -1, 'ip block list' );" ) . "\n";
}

Expand Down
12 changes: 11 additions & 1 deletion projects/packages/waf/src/class-waf-runner.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,25 @@ public static function disable() {
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::IP_ALLOW_LIST_OPTION_NAME => get_option( Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME ),
Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME => get_option( Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME ),
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 => get_option( Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME ),
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 $next-version$
*/
// @phan-suppress-next-line PhanDeprecatedClassConstant -- Needed for backwards compatibility.
Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME => get_option( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME ),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,40 @@ public function testAutomaticRulesOptionInheritsFromModuleStatus() {
// Check that the automatic rules option is enabled by default.
$this->assertTrue( Waf_Runner::is_enabled() );
}

/**
* Test the default options for the IP allow and block lists.
*/
public function testIpListsDefaultOptions() {
// Enable the WAF module.
Waf_Runner::enable();

// Validate default options on fresh installs.
$this->assertFalse( get_option( Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME ) );
$this->assertFalse( get_option( Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME ) );

// Add content to the allow list.
update_option( Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME, '1.2.3.4' );

$this->assertTrue( get_option( Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME ) );
$this->assertFalse( get_option( Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME ) );

// Toggle the old generic option from true to false.
// @phan-suppress-next-line PhanDeprecatedClassConstant -- Needed for backwards compatibility.
update_option( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME, true );
// @phan-suppress-next-line PhanDeprecatedClassConstant -- Needed for backwards compatibility.
update_option( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME, false );

// Options default to false when the old generic option is set to false.
$this->assertFalse( get_option( Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME ) );
$this->assertFalse( get_option( Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME ) );

// Set the old generic option to true.
// @phan-suppress-next-line PhanDeprecatedClassConstant -- Needed for backwards compatibility.
update_option( Waf_Rules_Manager::IP_LISTS_ENABLED_OPTION_NAME, true );

// Options default to true when the old generic option is set to true.
$this->assertTrue( get_option( Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME ) );
$this->assertTrue( get_option( Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME ) );
}
}
5 changes: 5 additions & 0 deletions projects/plugins/jetpack/changelog/add-waf-ip-list-toggles
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: other
Comment: Updated composer.lock.


4 changes: 2 additions & 2 deletions projects/plugins/jetpack/composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions projects/plugins/protect/changelog/add-waf-ip-list-toggles
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: changed
Comment: Updated composer.lock.


4 changes: 2 additions & 2 deletions projects/plugins/protect/composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 51c4a90

Please sign in to comment.