Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jetpack: Account Protection #40925

Open
wants to merge 50 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
06293a9
Initialize project branch
dkmyta Jan 9, 2025
c203587
Update lock files
dkmyta Jan 17, 2025
b9ad727
Jetpack: Add Account Protection security settings (#40938)
dkmyta Jan 24, 2025
e3953dd
Protect: Add Account Protection settings (#40942)
dkmyta Jan 24, 2025
b531690
Account Protection: Add password detection flow (#41105)
dkmyta Jan 24, 2025
e1293ac
Account Protection: Remove strict mode (#41316)
dkmyta Jan 29, 2025
1ca311f
Account Protection: Update password detection flow (#41365)
dkmyta Jan 30, 2025
48c607f
Account Protection: Add tests for newly added code (#41463)
ArSn Jan 31, 2025
022c552
Jetpack: Update Account Protection copy (#41404)
dkmyta Jan 31, 2025
6534ee8
Protect: Update Account Protection copy (#41402)
dkmyta Jan 31, 2025
1c68a00
Add wordbless dep, update consumer lock files
dkmyta Feb 2, 2025
708190e
Allow core installer
dkmyta Feb 2, 2025
2a7cf79
Update lock files
dkmyta Feb 2, 2025
d64ef26
Account Protection: Fix invalid auth early return (#41652)
dkmyta Feb 11, 2025
588e1d9
Reset to base (#41691)
dkmyta Feb 11, 2025
8139f4b
Account Protection: Restore JetpackTestEnvironment (#41736)
nateweller Feb 12, 2025
27634b3
Account Protection: Add password validation (#41401)
dkmyta Feb 12, 2025
5a29c1d
Protect: Fix Account Protection initial toggle state on activation (#…
dkmyta Feb 12, 2025
ac4f572
Fix BFP recovery process conflict (#41739)
dkmyta Feb 12, 2025
3d1cc94
Account Protection: Add custom password strength meter (#41485)
dkmyta Feb 13, 2025
a73f7b2
Improve the display of error notices on the password detection screen…
dkmyta Feb 13, 2025
7435950
Account Protection: Improve auth success flow (#41727)
dkmyta Feb 15, 2025
490a68b
Account Protection: clean up changelogs (#41833)
nateweller Feb 16, 2025
ae73a5a
Update projects/plugins/jetpack/modules/account-protection.php
dkmyta Feb 16, 2025
64c086b
Update projects/packages/account-protection/src/class-password-manage…
dkmyta Feb 16, 2025
18872c0
Update projects/plugins/jetpack/modules/account-protection.php
dkmyta Feb 16, 2025
aa077ba
Account Protection: Add Settings Class (#41829)
nateweller Feb 16, 2025
a7250ca
Account Protection: Disable setting in Protect in unsupported environ…
nateweller Feb 16, 2025
a7807fa
Account Protection: Disable setting in Jetpack in unsupported environ…
nateweller Feb 16, 2025
ab7ab55
Adjust account protection settings UI in Jetpack (#41832)
nateweller Feb 16, 2025
224484c
Protect: Fix unsupported environment notice display while toggling (…
dkmyta Feb 18, 2025
5ed355f
Add optimistic update revert, remove async from sync function (#41878)
nateweller Feb 18, 2025
dfcb134
Jetpack E2E: add account protection tests (#41835)
nateweller Feb 20, 2025
76ef7cf
Account Protection: Fix interim-login handling (#41924)
dkmyta Feb 20, 2025
8cbeebf
Account Protection: Improve strength meter implementation (#41802)
dkmyta Feb 21, 2025
da1c52b
Change actions to filters (#41914)
nateweller Feb 23, 2025
ee342d1
Protect: Add Account Protection feature to pricing table (#41929)
dkmyta Feb 24, 2025
0e82078
Brute Force Protection: Do not log failed attempt logging on password…
dkmyta Feb 24, 2025
38b70c5
Account Protection: Update support links (#41950)
dkmyta Feb 24, 2025
b55a7b7
Fix typo
dkmyta Feb 24, 2025
fb74e34
Protect: Disable Account Protection when unsupported Jetpack version …
dkmyta Feb 24, 2025
9837cda
Merge custom errors with core error on form submission (#41938)
dkmyta Feb 24, 2025
aa854fe
Account Protection: Update auth code email handling (#41801)
dkmyta Feb 24, 2025
dbe73d0
Account Protection: disable on WordPress.com Simple sites (#42009)
nateweller Feb 28, 2025
47bf01e
Add additional E2E tests for account protection (#41882)
nateweller Feb 28, 2025
bb57991
Account Protection: Strength Meter reorg and optimization (#42077)
dkmyta Feb 28, 2025
d224ab8
Account Protection: Fix Brute Force Protection recovery bypass (#42010)
dkmyta Feb 28, 2025
888f827
Update pnpm-lock.yaml
nateweller Feb 28, 2025
29ec0df
Update composer.lock
nateweller Feb 28, 2025
fb6976d
Fix import order
nateweller Feb 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
987 changes: 595 additions & 392 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Add initial account protection features
4 changes: 3 additions & 1 deletion projects/packages/account-protection/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"type": "jetpack-library",
"license": "GPL-2.0-or-later",
"require": {
"php": ">=7.2"
"php": ">=7.2",
"automattic/jetpack-connection": "@dev",
"automattic/jetpack-status": "@dev"
},
"require-dev": {
"yoast/phpunit-polyfills": "^1.1.1",
Expand Down
23 changes: 23 additions & 0 deletions projects/packages/account-protection/src/assets/jetpack-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
256 changes: 252 additions & 4 deletions projects/packages/account-protection/src/class-account-protection.php
Original file line number Diff line number Diff line change
@@ -1,16 +1,264 @@
<?php
/**
* Package description here
* Class used to define Account Protection.
*
* @package automattic/jetpack-account-protection
*/

namespace Automattic\Jetpack;
namespace Automattic\Jetpack\Account_Protection;

use Automattic\Jetpack\Modules;
use Automattic\Jetpack\Status\Host;

/**
* Class description.
* Class Account_Protection
*/
class Account_Protection {
const PACKAGE_VERSION = '0.1.0-alpha';
const ACCOUNT_PROTECTION_MODULE_NAME = 'account-protection';

/**
* Flag to track if hooks have been registered.
*
* @var bool
*/
private static $hooks_registered = false;

/**
* Modules instance.
*
* @var Modules
*/
private $modules;

/**
* Password detection instance.
*
* @var Password_Detection
*/
private $password_detection;

/**
* Password manager instance
*
* @var Password_Manager
*/
private $password_manager;

/**
* Password_Strength_Meter instance
*
* @var Password_Strength_Meter
*/
private $password_strength_meter;

/**
* Account_Protection constructor.
*
* @param ?Modules $modules Modules instance.
* @param ?Password_Detection $password_detection Password detection instance.
* @param ?Password_Manager $password_manager Password manager instance.
* @param ?Password_Strength_Meter $password_strength_meter Password strength meter instance.
*/
public function __construct( ?Modules $modules = null, ?Password_Detection $password_detection = null, ?Password_Manager $password_manager = null, ?Password_Strength_Meter $password_strength_meter = null ) {
$this->modules = $modules ?? new Modules();
$this->password_detection = $password_detection ?? new Password_Detection();
$this->password_manager = $password_manager ?? new Password_Manager();
$this->password_strength_meter = $password_strength_meter ?? new Password_Strength_Meter();
}

/**
* Initializes the configurations needed for the account protection module.
*
* @return void
*/
public function init(): void {
if ( self::$hooks_registered ) {
return;
}

$this->register_hooks();

if ( $this->is_enabled() ) {
$this->register_runtime_hooks();
}

self::$hooks_registered = true;
}

/**
* Register hooks for module activation and environment validation.
*
* @return void
*/
protected function register_hooks(): void {
// Account protection activation/deactivation hooks
add_action( 'jetpack_activate_module_' . self::ACCOUNT_PROTECTION_MODULE_NAME, array( $this, 'on_account_protection_activation' ) );
add_action( 'jetpack_deactivate_module_' . self::ACCOUNT_PROTECTION_MODULE_NAME, array( $this, 'on_account_protection_deactivation' ) );

// Do not run in unsupported environments
add_filter( 'jetpack_get_available_modules', array( $this, 'remove_module_on_unsupported_environments' ) );
add_filter( 'jetpack_get_available_standalone_modules', array( $this, 'remove_standalone_module_on_unsupported_environments' ) );
}

/**
* Register hooks for runtime operations.
*
* @return void
*/
protected function register_runtime_hooks(): void {
// Validate password after successful login
add_action( 'wp_authenticate_user', array( $this->password_detection, 'login_form_password_detection' ), 10, 2 );

// Handle password detection login failure
add_action( 'wp_login_failed', array( $this->password_detection, 'handle_password_detection_validation_error' ), 10, 2 );

// Add password detection flow
add_action( 'login_form_password-detection', array( $this->password_detection, 'render_page' ), 10, 2 );
add_action( 'wp_enqueue_scripts', array( $this->password_detection, 'enqueue_styles' ) );

// Add password validation
add_action( 'user_profile_update_errors', array( $this->password_manager, 'validate_profile_update' ), 10, 3 );
add_action( 'validate_password_reset', array( $this->password_manager, 'validate_password_reset' ), 10, 2 );

// Update recent passwords list
add_action( 'profile_update', array( $this->password_manager, 'on_profile_update' ), 10, 2 );
add_action( 'after_password_reset', array( $this->password_manager, 'on_password_reset' ), 10, 1 );

// Enqueue password strength meter scripts
add_action( 'admin_enqueue_scripts', array( $this->password_strength_meter, 'enqueue_jetpack_password_strength_meter_profile_script' ) );
add_action( 'login_enqueue_scripts', array( $this->password_strength_meter, 'enqueue_jetpack_password_strength_meter_reset_script' ) );

// AJAX endpoint for password validation
add_action( 'wp_ajax_validate_password_ajax', array( $this->password_strength_meter, 'validate_password_ajax' ) );
add_action( 'wp_ajax_nopriv_validate_password_ajax', array( $this->password_strength_meter, 'validate_password_ajax' ) );
}

/**
* Activate the account protection on module activation.
*
* @return void
*/
public function on_account_protection_activation(): void {
// Activation logic can be added here
}

/**
* Deactivate the account protection on module deactivation.
*
* @return void
*/
public function on_account_protection_deactivation(): void {
// Deactivation logic can be added here
}

/**
* Determines if the account protection module is enabled on the site.
*
* @return bool
*/
public function is_enabled(): bool {
return $this->modules->is_active( self::ACCOUNT_PROTECTION_MODULE_NAME );
}

/**
* Enables the account protection module.
*
* @return bool
*/
public function enable(): bool {
// Return true if already enabled.
if ( $this->is_enabled() ) {
return true;
}
return $this->modules->activate( self::ACCOUNT_PROTECTION_MODULE_NAME, false, false );
}

/**
* Disables the account protection module.
*
* @return bool
*/
public function disable(): bool {
// Return true if already disabled.
if ( ! $this->is_enabled() ) {
return true;
}
return $this->modules->deactivate( self::ACCOUNT_PROTECTION_MODULE_NAME );
}

/**
* Determines if Account Protection is supported in the current environment.
*
* @return bool
*/
public function is_supported_environment(): bool {
// Do not run when killswitch is enabled
if ( defined( 'DISABLE_JETPACK_ACCOUNT_PROTECTION' ) && DISABLE_JETPACK_ACCOUNT_PROTECTION ) {
return false;
}

// Do not run for WordPress.com Simple sites
if ( ( new Host() )->is_wpcom_simple() ) {
return false;
}

return true;
}

/**
* Determines if the current Jetpack version is supported.
*
* @return bool
*/
public function has_unsupported_jetpack_version(): bool {
// Do not run when Jetpack version is less than 14.5
if ( defined( 'JETPACK__VERSION' ) ) {
$jetpack_version = JETPACK__VERSION;

if ( is_string( $jetpack_version ) && version_compare( $jetpack_version, '14.5', '<' ) ) {
return true;
}
}

return false;
}

/**
* Disables the Account Protection module when on an unsupported platform in Jetpack.
*
* @param array $modules Filterable value for `jetpack_get_available_modules`.
*
* @return array Array of module slugs.
*/
public function remove_module_on_unsupported_environments( array $modules ): array {
if ( ! $this->is_supported_environment() ) {
// Account protection should never be available on unsupported platforms.
unset( $modules[ self::ACCOUNT_PROTECTION_MODULE_NAME ] );
}

return $modules;
}

/**
* Disables the Account Protection module when on an unsupported platform in a standalone plugin.
*
* @param array $modules Filterable value for `jetpack_get_available_standalone_modules`.
*
* @return array Array of module slugs.
*/
public function remove_standalone_module_on_unsupported_environments( array $modules ): array {
if ( ! $this->is_supported_environment() ) {
// Account Protection should never be available on unsupported platforms.
$modules = array_filter(
$modules,
function ( $module ) {
return $module !== self::ACCOUNT_PROTECTION_MODULE_NAME;
}
);

}

const PACKAGE_VERSION = '0.1.0-alpha';
return $modules;
}
}
29 changes: 29 additions & 0 deletions projects/packages/account-protection/src/class-config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
/**
* Class used to define Config.
*
* @package automattic/jetpack-account-protection
*/

namespace Automattic\Jetpack\Account_Protection;

/**
* Class Config
*/
class Config {
public const SUPPORT_LINK = 'https://jetpack.com/?post_type=jetpack_support&p=324199';
public const TRANSIENT_PREFIX = 'jetpack_account_protection';
public const RECENT_PASSWORD_HASHES_USER_META_KEY = 'jetpack_account_protection_recent_password_hashes';

// Password Detection Constants
public const PASSWORD_DETECTION_ERROR_CODE = 'password_detection_validation_error';
public const PASSWORD_DETECTION_EMAIL_SENT_EXPIRATION = 600; // 10 minutes
public const PASSWORD_DETECTION_EMAIL_REQUEST_LIMIT = 4;

// Password Manager Constants
public const PASSWORD_MANAGER_RECENT_PASSWORDS_LIMIT = 10;

// Validation Service Constants
public const VALIDATION_SERVICE_MIN_LENGTH = 6;
public const VALIDATION_SERVICE_MAX_LENGTH = 150;
}
Loading
Loading