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

Account Protection: Add custom password strength meter #41485

Merged
Show file tree
Hide file tree
Changes from 189 commits
Commits
Show all changes
196 commits
Select commit Hold shift + click to select a range
3f56ee7
Add Account Protection toggle to Jetpack security settings
dkmyta Jan 9, 2025
719f950
Import package and run activation/deactivation on module toggle
dkmyta Jan 9, 2025
c83c604
changelog
dkmyta Jan 9, 2025
ab4f99a
Add Protect Settings page and hook up Account Protection toggle
dkmyta Jan 9, 2025
c2e8f1e
changelog
dkmyta Jan 9, 2025
b64fdaf
Update changelog
dkmyta Jan 9, 2025
13949a6
Merge branch 'add/jetpack/account-protection-security-settings' into …
dkmyta Jan 9, 2025
3f68536
Register modules on plugin activation
dkmyta Jan 9, 2025
3628b02
Ensure package is initialized on plugin activation
dkmyta Jan 9, 2025
3f90fe4
Make account protection class init static
dkmyta Jan 9, 2025
911e1db
Merge branch 'add/jetpack/account-protection-security-settings' into …
dkmyta Jan 9, 2025
3bfbcb3
Add auth hooks, redirect and a custom login action template
dkmyta Jan 13, 2025
289dbdb
Reorg, add Password_Detection class
dkmyta Jan 14, 2025
7eabdd3
Remove user cxn req and banner
dkmyta Jan 14, 2025
5a1af0b
Do not enabled module by default
dkmyta Jan 14, 2025
3b35efe
Add strict mode option and settings toggle
dkmyta Jan 15, 2025
4ddb644
changelog
dkmyta Jan 15, 2025
2a0e811
Merge branch 'add/jetpack/account-protection-security-settings' into …
dkmyta Jan 15, 2025
b62811b
Add strict mode toggle
dkmyta Jan 15, 2025
28f5820
Add strict mode toggle and endpoints
dkmyta Jan 15, 2025
da260ea
Rebase
dkmyta Jan 15, 2025
b72e93a
Reorg and add kill switch and is supported check
dkmyta Jan 15, 2025
7fad7f9
Add testing infrastructure
dkmyta Jan 15, 2025
39a28d5
Add email handlings, resend AJAX action, and attempt limitations
dkmyta Jan 16, 2025
da85a18
Add nonces, checks and template error handling
dkmyta Jan 17, 2025
6a43ec0
Use method over template to avoid lint errors
dkmyta Jan 17, 2025
7557056
Improve render_password_detection_template, update SVG file ext
dkmyta Jan 17, 2025
16845a7
Remove template file and include
dkmyta Jan 17, 2025
5f959f1
Prep for validation endpoints
dkmyta Jan 17, 2025
a4ba959
Update classes to be dynamic
dkmyta Jan 17, 2025
992f288
Add constructors
dkmyta Jan 17, 2025
43d4cd0
Reorg user meta methods
dkmyta Jan 17, 2025
3cec891
Add type declarations and hinting
dkmyta Jan 17, 2025
c61877b
Simplify method naming
dkmyta Jan 17, 2025
92d0ea6
Rebase, fix conflicts
dkmyta Jan 20, 2025
7634ed2
Use dynamic classes
dkmyta Jan 20, 2025
692db33
Update class dependencies
dkmyta Jan 20, 2025
22d2678
Fix copy
dkmyta Jan 20, 2025
0fd3e41
Revert unrelated changes
dkmyta Jan 20, 2025
805b367
Rebase, fix conflicts
dkmyta Jan 20, 2025
4383b5e
Revert unrelated changes
dkmyta Jan 20, 2025
9a70647
Fix method calls
dkmyta Jan 20, 2025
969102f
Do not activate by default
dkmyta Jan 20, 2025
8356bd4
Fix phan errors
dkmyta Jan 20, 2025
dad19c7
Merge branch 'add/jetpack/account-protection-security-settings' into …
dkmyta Jan 20, 2025
a5f1467
Rebase, fix conflicts
dkmyta Jan 20, 2025
32f3ef6
Changelog
dkmyta Jan 20, 2025
b02d511
Update composer deps
dkmyta Jan 20, 2025
7c255ac
Update lock files, add constructor method
dkmyta Jan 20, 2025
cdb0ac8
Fix php warning
dkmyta Jan 20, 2025
19efaea
Merge branch 'add/jetpack/account-protection-security-settings' into …
dkmyta Jan 20, 2025
1ce68b9
Update lock file
dkmyta Jan 20, 2025
7a06508
Changelog
dkmyta Jan 20, 2025
ddfa535
Rebase
dkmyta Jan 20, 2025
c128cf5
Fix Password_Detection constructor
dkmyta Jan 20, 2025
7a56b48
Changelog
dkmyta Jan 20, 2025
bc7aa77
More changelogs
dkmyta Jan 20, 2025
b28c8cf
Remove comments
dkmyta Jan 20, 2025
4bb5401
Fix static analysis errors
dkmyta Jan 20, 2025
20dec01
Remove top level phpunit.xml.dist
dkmyta Jan 20, 2025
2bdbf8e
Remove never return type
dkmyta Jan 20, 2025
a80c024
Revert tests dir changes in favour of a dedicated task
dkmyta Jan 20, 2025
f07e52e
Add tests dir
dkmyta Jan 20, 2025
80d0e92
Reapply default test infrastructure
dkmyta Jan 20, 2025
c03d626
Reorg and rename
dkmyta Jan 20, 2025
ae3b6b6
Update @package
dkmyta Jan 20, 2025
30f2329
Use never phpdoc return type as per static analysis error
dkmyta Jan 21, 2025
55ccadb
Merge branch 'add/account-protection' into add/jetpack/account-protec…
dkmyta Jan 21, 2025
3fed240
Merge branch 'add/jetpack/account-protection-security-settings' into …
dkmyta Jan 21, 2025
2beaca5
Merge branch 'add/protect/account-protection-settings' into add/packa…
dkmyta Jan 21, 2025
aad7ff6
Enable module by default
dkmyta Jan 21, 2025
de4fc75
Merge branch 'add/jetpack/account-protection-security-settings' into …
dkmyta Jan 21, 2025
448079b
Enable module by default
dkmyta Jan 21, 2025
bc263e0
Merge branch 'add/protect/account-protection-settings' into add/packa…
dkmyta Jan 21, 2025
4b18375
Remove all reference to and functionality of strict mode
dkmyta Jan 24, 2025
bbec51a
Rebase, fix conflicts
dkmyta Jan 24, 2025
7d72fd9
Remove unneeded strict mode code, update Protect settings UI
dkmyta Jan 24, 2025
36f0945
Updates/fixes
dkmyta Jan 24, 2025
37e0aa2
Fix import
dkmyta Jan 24, 2025
d51016d
Update placeholder content
dkmyta Jan 24, 2025
30b86d5
Revert unrelated changes
dkmyta Jan 24, 2025
6b34d25
Remove missed code
dkmyta Jan 24, 2025
40a6edf
Update reset email to two factor auth email
dkmyta Jan 27, 2025
528ee1d
Updates and improvements
dkmyta Jan 28, 2025
612f655
Reorg
dkmyta Jan 28, 2025
9b2bb3e
Optimizations and reorganizations
dkmyta Jan 28, 2025
664558b
Hook up email service
dkmyta Jan 28, 2025
915504d
Update error handling todos, fix weak password check
dkmyta Jan 29, 2025
87445c2
Test
dkmyta Jan 29, 2025
9ef7e9d
Localize text content
dkmyta Jan 29, 2025
4c794c5
Fix lint warnings/errors
dkmyta Jan 29, 2025
0b493b8
Update todos
dkmyta Jan 29, 2025
82d9ff2
Add error handling, enforce input restrictions
dkmyta Jan 29, 2025
b466475
Move main constants back entry file
dkmyta Jan 29, 2025
7f7b57d
Fix package version check
dkmyta Jan 29, 2025
fe79de3
Optimize setting error transient
dkmyta Jan 29, 2025
6743841
Add nonce check for resend email action
dkmyta Jan 29, 2025
88eed6e
Fix spacing
dkmyta Jan 29, 2025
4e0be98
Fix resend nonce handling
dkmyta Jan 29, 2025
8f79bab
Merge branch 'add/account-protection' into update/packages/account-pr…
dkmyta Jan 29, 2025
490e50b
Email service fixes
dkmyta Jan 29, 2025
d47a220
Fixes, improvements to doc consistency
dkmyta Jan 29, 2025
7e87875
Add remaining password validation
dkmyta Jan 29, 2025
38a2d15
Update weak password check returns
dkmyta Jan 29, 2025
9838e09
Fix phan errors
dkmyta Jan 29, 2025
7d4b46f
Revert prior change
dkmyta Jan 29, 2025
6c52261
Fix meta key
dkmyta Jan 29, 2025
c9acdcb
Rebase
dkmyta Jan 29, 2025
06f6008
Add process for add/updating recent pass list
dkmyta Jan 30, 2025
730407a
Send auth code via wpcom only
dkmyta Jan 30, 2025
39cd995
Update method name
dkmyta Jan 30, 2025
022f9ab
Rebase, fix weak password method returns
dkmyta Jan 30, 2025
abfe635
Rebase, fix conflicts
dkmyta Jan 30, 2025
56ee7aa
Optimize validation
dkmyta Jan 31, 2025
c5e658e
Fix key, remove testing code
dkmyta Jan 31, 2025
9637bd3
Fix docs
dkmyta Jan 31, 2025
96e3fd1
Add foundation for the custom password strength meter
dkmyta Jan 31, 2025
fd002db
Rebase, fix conflicts
dkmyta Jan 31, 2025
1ce02ff
Merge branch 'add/packages/account-protection-password-validation' in…
dkmyta Jan 31, 2025
81a2325
Fix tests
dkmyta Jan 31, 2025
46a77ce
Merge branch 'add/packages/account-protection-password-validation' in…
dkmyta Jan 31, 2025
78e272b
Add ajax request for password validation
dkmyta Feb 1, 2025
b173e09
Merge branch 'add/account-protection' into add/packages/account-prote…
dkmyta Feb 2, 2025
924c68b
Merge branch 'add/packages/account-protection-password-validation' in…
dkmyta Feb 2, 2025
61ca3ed
Merge branch 'add/account-protection' into add/packages/account-prote…
dkmyta Feb 2, 2025
1721af3
Merge branch 'add/packages/account-protection-password-validation' in…
dkmyta Feb 2, 2025
8159db7
Merge branch 'add/account-protection' into add/packages/account-prote…
dkmyta Feb 2, 2025
b1fe35e
Merge branch 'add/packages/account-protection-password-validation' in…
dkmyta Feb 2, 2025
5e96389
Improve matches user data logic
dkmyta Feb 3, 2025
c5c8acd
Remove password reset nonce verification code
dkmyta Feb 3, 2025
8f8f934
Updates and fixes
dkmyta Feb 3, 2025
eafecc0
Updates and improvements
dkmyta Feb 3, 2025
f83f86c
Rebase
dkmyta Feb 3, 2025
8388caa
Include tests for new validation methods
dkmyta Feb 3, 2025
2c59a84
Include tests for new validation methods
dkmyta Feb 3, 2025
7fb0b5a
Add password manager class tests
dkmyta Feb 4, 2025
e7cf410
Merge branch 'add/packages/account-protection-password-validation' in…
dkmyta Feb 4, 2025
108e3e1
Add password validation status handling and hook up ajax callback
dkmyta Feb 4, 2025
529005b
Update variables names
dkmyta Feb 4, 2025
d156dcf
Add loading state
dkmyta Feb 4, 2025
84c5ecb
Remove todos
dkmyta Feb 4, 2025
523b195
Add nonce to ajax request
dkmyta Feb 5, 2025
b651b2b
Remove custom nonce, add core create-user nonce check
dkmyta Feb 5, 2025
16d54a6
Remove todos - always run server side validation
dkmyta Feb 5, 2025
c9f5d32
Update constant naming
dkmyta Feb 5, 2025
5559bce
Translate error message
dkmyta Feb 5, 2025
b716b6f
Ensure styles are enqueued when viewing the password detection page
dkmyta Feb 5, 2025
d296b26
Use global page now and action check to enqueue styles
dkmyta Feb 5, 2025
5515183
Skip recent password checks during create user action
dkmyta Feb 5, 2025
a8e6b8d
Additional skips, and comment clarification
dkmyta Feb 5, 2025
b5699a6
Revert skips of user specific reset form validation, hook provides ac…
dkmyta Feb 5, 2025
556fc84
Revert unintended additions
dkmyta Feb 5, 2025
6e725cb
Return early if update is irrelevant
dkmyta Feb 6, 2025
afb4621
Only verify nonce if pass is set
dkmyta Feb 6, 2025
62d30c2
Skip validation if bypass enabled
dkmyta Feb 6, 2025
1157e6c
Improve logic
dkmyta Feb 6, 2025
9e0d65f
Rebase
dkmyta Feb 6, 2025
e093fab
Improvements and reorg
dkmyta Feb 6, 2025
f0448ef
Add info popovers
dkmyta Feb 6, 2025
8381d5d
Add core req to initial validation state
dkmyta Feb 6, 2025
73c3db2
Generalize core info popover message
dkmyta Feb 6, 2025
b76ee4b
Fix core strength meter status
dkmyta Feb 6, 2025
ab15e8d
Remove testing code
dkmyta Feb 6, 2025
20ac033
Ensure save enabled when appropriate
dkmyta Feb 6, 2025
70b18a6
Update todos
dkmyta Feb 6, 2025
e82172c
Center validation items
dkmyta Feb 6, 2025
fe525c7
Fix tests
dkmyta Feb 6, 2025
e96a8dd
Save alt approach
dkmyta Feb 6, 2025
9d4da96
Fix styling, centralize core references
dkmyta Feb 7, 2025
ec88c39
Reorg
dkmyta Feb 7, 2025
79997c6
Use global pagenow for context, restrict user specific check to profi…
dkmyta Feb 7, 2025
6723799
Compartmentalize generating and appending validation meter and status…
dkmyta Feb 7, 2025
5db6af0
Optimization and reorg improvements
dkmyta Feb 7, 2025
f3d5c46
Remove todos
dkmyta Feb 7, 2025
33fcc0b
Remove unneeded comments
dkmyta Feb 7, 2025
e0c08b8
Ensure info popover fits in all form views
dkmyta Feb 7, 2025
c55e5d2
Fix test
dkmyta Feb 7, 2025
6c6eea4
Merge branch 'add/account-protection' into add/packages/account-prote…
dkmyta Feb 11, 2025
11cb01b
Merge branch 'add/packages/account-protection-password-validation' in…
dkmyta Feb 11, 2025
55f5617
Merge branch 'add/account-protection' into add/packages/account-prote…
dkmyta Feb 12, 2025
22852ce
Merge branch 'add/packages/account-protection-password-validation' in…
dkmyta Feb 12, 2025
3a2993c
Fix test
dkmyta Feb 12, 2025
cbe4946
Merge branch 'add/packages/account-protection-password-validation' in…
dkmyta Feb 12, 2025
7c5733c
Update methods, removes nonce checks, fix tests
dkmyta Feb 12, 2025
ca7c827
Rebase, fix conflicts
dkmyta Feb 12, 2025
bd3e654
Fix test
dkmyta Feb 12, 2025
647be75
Remove comment
dkmyta Feb 12, 2025
d2d1d3b
Merge branch 'add/packages/account-protection-password-validation' in…
dkmyta Feb 12, 2025
9d873f2
Fix conflicts
dkmyta Feb 12, 2025
a303e59
Fix bindEvents
dkmyta Feb 12, 2025
8848350
Correct colors
dkmyta Feb 12, 2025
7b0243c
Add aria-live attr to strength-meter
dkmyta Feb 12, 2025
90ba7db
Remove core input mods and use custom selectors to apply strength met…
dkmyta Feb 12, 2025
d7a7285
Update core validation item message, and display only on failure
dkmyta Feb 12, 2025
8fc4e5a
Add clarifying comment
dkmyta Feb 12, 2025
affbff3
Remove unnecessary user->ID check, and redundant method
dkmyta Feb 13, 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
4 changes: 4 additions & 0 deletions projects/packages/account-protection/src/assets/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions projects/packages/account-protection/src/assets/cross.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions projects/packages/account-protection/src/assets/info.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions projects/packages/account-protection/src/assets/loading.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,26 @@ class Account_Protection {
*/
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 Validation service instance.
* @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 ) {
$this->modules = $modules ?? new Modules();
$this->password_detection = $password_detection ?? new Password_Detection();
$this->password_manager = $password_manager ?? new Password_Manager();
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();
}

/**
Expand Down Expand Up @@ -115,6 +124,14 @@ protected function register_runtime_hooks(): void {
// 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' ) );
}

/**
Expand Down
9 changes: 8 additions & 1 deletion projects/packages/account-protection/src/class-config.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@
* Class Config
*/
class Config {
// Password Detection Constants
public const PASSWORD_DETECTION_TRANSIENT_PREFIX = 'password_detection';
public const PASSWORD_DETECTION_ERROR_CODE = 'password_detection_validation_error';
public const PASSWORD_DETECTION_EMAIL_SENT_EXPIRATION = 600; // 10 minutes
public const PASSWORD_DETECTION_MAX_RESEND_ATTEMPTS = 3;

public const VALIDATION_SERVICE_RECENT_PASSWORD_HASHES_USER_META_KEY = 'jetpack_account_protection_recent_password_hashes';
// Password Manager Constants
public const PASSWORD_MANAGER_RECENT_PASSWORD_HASHES_USER_META_KEY = 'jetpack_account_protection_recent_password_hashes';
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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -355,15 +355,19 @@ private function set_transient_error( int $user_id, string $message, int $expira
* @return void
*/
public function enqueue_styles(): void {
global $pagenow;
if ( ! isset( $pagenow ) || $pagenow !== 'wp-login.php' ) {
return;
}
// No nonce verification necessary - reading only
// phpcs:disable WordPress.Security.NonceVerification
if ( ( isset( $GLOBALS['pagenow'] ) && $GLOBALS['pagenow'] === 'wp-login.php' ) && ( isset( $_GET['action'] ) && $_GET['action'] === 'password-detection' ) ) {
wp_enqueue_style(
'password-detection-styles',
plugin_dir_url( __FILE__ ) . 'css/password-detection.css',
array(),
Account_Protection::PACKAGE_VERSION
);
if ( isset( $_GET['action'] ) && $_GET['action'] === 'password-detection' ) {
wp_enqueue_style(
'password-detection-styles',
plugin_dir_url( __FILE__ ) . 'css/password-detection.css',
array(),
Account_Protection::PACKAGE_VERSION
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,7 @@ public function validate_profile_update( \WP_Error $errors, bool $update, \stdCl
return;
}

if ( $update ) {
if ( $this->validation_service->is_current_password( $user->ID, $user->user_pass ) ) {
$errors->add( 'password_error', __( '<strong>Error:</strong> The password was used recently.', 'jetpack-account-protection' ) );
return;
}
}

$context = $update ? 'update' : 'create-user';
$error = $this->validation_service->return_first_validation_error( $user, $user->user_pass, $context );
$error = $this->validation_service->get_first_validation_error( $user->user_pass, true, $user );

if ( ! empty( $error ) ) {
$errors->add( 'password_error', $error );
Expand Down Expand Up @@ -89,12 +81,7 @@ public function validate_password_reset( \WP_Error $errors, $user ): void {

// phpcs:ignore WordPress.Security.NonceVerification
$password = sanitize_text_field( wp_unslash( $_POST['pass1'] ) );
if ( $this->validation_service->is_current_password( $user->ID, $password ) ) {
$errors->add( 'password_error', __( '<strong>Error:</strong> The password was used recently.', 'jetpack-account-protection' ) );
return;
}

$error = $this->validation_service->return_first_validation_error( $user, $password, 'reset' );
$error = $this->validation_service->get_first_validation_error( $password );
if ( ! empty( $error ) ) {
$errors->add( 'password_error', $error );
return;
Expand Down Expand Up @@ -136,7 +123,7 @@ public function on_password_reset( $user ): void {
* @return void
*/
public function save_recent_password( int $user_id, string $password_hash ): void {
$recent_passwords = get_user_meta( $user_id, Config::VALIDATION_SERVICE_RECENT_PASSWORD_HASHES_USER_META_KEY, true );
$recent_passwords = get_user_meta( $user_id, Config::PASSWORD_MANAGER_RECENT_PASSWORD_HASHES_USER_META_KEY, true );

if ( ! is_array( $recent_passwords ) ) {
$recent_passwords = array();
Expand All @@ -148,8 +135,8 @@ public function save_recent_password( int $user_id, string $password_hash ): voi

// Add the new hashed password and keep only the last 10
array_unshift( $recent_passwords, $password_hash );
$recent_passwords = array_slice( $recent_passwords, 0, 10 );
$recent_passwords = array_slice( $recent_passwords, 0, Config::PASSWORD_MANAGER_RECENT_PASSWORDS_LIMIT );

update_user_meta( $user_id, Config::VALIDATION_SERVICE_RECENT_PASSWORD_HASHES_USER_META_KEY, $recent_passwords );
update_user_meta( $user_id, Config::PASSWORD_MANAGER_RECENT_PASSWORD_HASHES_USER_META_KEY, $recent_passwords );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?php
/**
* Class used to define Password Strength Meter.
*
* @package automattic/jetpack-account-protection
*/

namespace Automattic\Jetpack\Account_Protection;

/**
* Class Password_Strength_Meter
*/
class Password_Strength_Meter {
/**
* Validaton service instance
*
* @var Validation_Service
*/
private $validation_service;

/**
* Validation_Service constructor.
*
* @param ?Validation_Service $validation_service Password manager instance.
*/
public function __construct( ?Validation_Service $validation_service = null ) {
$this->validation_service = $validation_service ?? new Validation_Service();
}

/**
* AJAX endpoint for password validation.
*
* @return void
*/
public function validate_password_ajax(): void {
if ( ! isset( $_POST['password'] ) ) {
wp_send_json_error( array( 'message' => __( 'No password provided.', 'jetpack-account-protection' ) ) );
}

if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'validate_password_nonce' ) ) {
wp_send_json_error( array( 'message' => __( 'Invalid nonce.', 'jetpack-account-protection' ) ) );
}

$user_specific = false;
if ( isset( $_POST['user_specific'] ) ) {
$user_specific = filter_var( sanitize_text_field( wp_unslash( $_POST['user_specific'] ) ), FILTER_VALIDATE_BOOLEAN );
}

$password = sanitize_text_field( wp_unslash( $_POST['password'] ) );
$state = $this->validation_service->get_validation_state( $password, $user_specific );

wp_send_json_success( array( 'state' => $state ) );
}

/**
* Enqueue the password strength meter script on the profile page.
*
* @return void
*/
public function enqueue_jetpack_password_strength_meter_profile_script(): void {
global $pagenow;

if ( ! isset( $pagenow ) || ! in_array( $pagenow, array( 'profile.php', 'user-new.php', 'user-edit.php' ), true ) ) {
return;
}

$this->enqueue_script();
$this->enqueue_styles();

// Only profile page should run user specific checks.
$this->localize_jetpack_data( 'profile.php' === $pagenow );
}

/**
* Enqueue the password strength meter script on the reset password page.
*
* @return void
*/
public function enqueue_jetpack_password_strength_meter_reset_script(): void {
// No nonce verification necessary as the action includes a robust verification process
// phpcs:disable WordPress.Security.NonceVerification
if ( isset( $_GET['action'] ) && ( 'rp' === $_GET['action'] || 'resetpass' === $_GET['action'] ) ) {
$this->enqueue_script();
$this->enqueue_styles();
$this->localize_jetpack_data();
}
}

/**
* Localize the Jetpack data for the password strength meter.
*
* @param bool $user_specific Whether or not to run user specific checks.
*
* @return void
*/
public function localize_jetpack_data( bool $user_specific = false ): void {
wp_localize_script(
'jetpack-password-strength-meter',
'jetpackData',
array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'validate_password_nonce' ),
'userSpecific' => $user_specific,
'logo' => plugin_dir_url( __FILE__ ) . 'assets/jetpack-logo.svg',
'infoIcon' => plugin_dir_url( __FILE__ ) . 'assets/info.svg',
'checkIcon' => plugin_dir_url( __FILE__ ) . 'assets/check.svg',
'crossIcon' => plugin_dir_url( __FILE__ ) . 'assets/cross.svg',
'loadingIcon' => plugin_dir_url( __FILE__ ) . 'assets/loading.svg',
'validationInitialState' => $this->validation_service->get_validation_initial_state( $user_specific ),
)
);
}

/**
* Enqueue the password strength meter script.
*
* @return void
*/
public function enqueue_script(): void {
wp_enqueue_script(
'jetpack-password-strength-meter',
plugin_dir_url( __FILE__ ) . 'js/jetpack-password-strength-meter.js',
array( 'jquery' ),
Account_Protection::PACKAGE_VERSION,
true
);
}

/**
* Enqueue the password strength meter styles.
*
* @return void
*/
public function enqueue_styles(): void {
wp_enqueue_style(
'strength-meter-styles',
plugin_dir_url( __FILE__ ) . 'css/strength-meter.css',
array(),
Account_Protection::PACKAGE_VERSION
);
}
}
Loading
Loading