PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
jetpack / jetpack_vendor / automattic / jetpack-account-protection / src / class-password-manager.php

class-password-manager.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3, at jetpack_vendor/automattic/jetpack-account-protection/src/class-password-manager.php

155 lines 4.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class used to define Password Manager.
4 *
5 * @package automattic/jetpack-account-protection
6 */
7
8 namespace Automattic\Jetpack\Account_Protection;
9
10 /**
11 * Class Password_Manager
12 */
13 class Password_Manager {
14 /**
15 * Validaton service instance
16 *
17 * @var Validation_Service
18 */
19 private $validation_service;
20
21 /**
22 * Validation_Service constructor.
23 *
24 * @param ?Validation_Service $validation_service Password manager instance.
25 */
26 public function __construct( ?Validation_Service $validation_service = null ) {
27 $this->validation_service = $validation_service ?? new Validation_Service();
28 }
29
30 /**
31 * Validate the profile update.
32 *
33 * @param \WP_Error $errors The error object.
34 * @param bool $update Whether the user is being updated.
35 * @param \stdClass $user A copy of the new user object.
36 *
37 * @return void
38 */
39 public function validate_profile_update( \WP_Error $errors, bool $update, \stdClass $user ): void {
40 if ( empty( $user->user_pass ) ) {
41 return;
42 }
43
44 // If bypass is enabled, do not validate the password
45 // phpcs:ignore WordPress.Security.NonceVerification
46 if ( isset( $_POST['pw_weak'] ) && 'on' === $_POST['pw_weak'] ) {
47 return;
48 }
49
50 $core_validation_errors = $errors->get_error_messages( 'pass' );
51 $jetpack_validation_errors = $this->validation_service->get_validation_errors( $user->user_pass, true, $user );
52 $validation_errors = array_diff( $jetpack_validation_errors, $core_validation_errors );
53
54 foreach ( $validation_errors as $validation_error ) {
55 $errors->add( 'pass', $validation_error, array( 'form-field' => 'pass1' ) );
56 }
57 }
58
59 /**
60 * Validate the password reset.
61 *
62 * @param \WP_Error $errors The error object.
63 * @param \WP_User|\WP_Error $user The user object.
64 *
65 * @return void
66 */
67 public function validate_password_reset( \WP_Error $errors, $user ): void {
68 if ( is_wp_error( $user ) ) {
69 return;
70 }
71
72 // phpcs:ignore WordPress.Security.NonceVerification
73 if ( empty( $_POST['pass1'] ) ) {
74 return;
75 }
76
77 // If bypass is enabled, do not validate the password
78 // phpcs:ignore WordPress.Security.NonceVerification
79 if ( isset( $_POST['pw_weak'] ) && 'on' === $_POST['pw_weak'] ) {
80 return;
81 }
82
83 // phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
84 $password = wp_unslash( $_POST['pass1'] );
85
86 $core_validation_errors = $errors->get_error_messages( 'pass' );
87 $jetpack_validation_errors = $this->validation_service->get_validation_errors( $password );
88 $validation_errors = array_diff( $jetpack_validation_errors, $core_validation_errors );
89
90 foreach ( $validation_errors as $validation_error ) {
91 $errors->add( 'pass', $validation_error, array( 'form-field' => 'pass1' ) );
92 }
93 }
94
95 /**
96 * Handle the profile update.
97 *
98 * @param int $user_id The user ID.
99 * @param \WP_User|\stdClass|null $old_user_data Object containing user data prior to update.
100 *
101 * @return void
102 */
103 public function on_profile_update( int $user_id, $old_user_data ): void {
104 if ( ! is_object( $old_user_data ) || empty( $old_user_data->user_pass ) ) {
105 return;
106 }
107
108 // phpcs:ignore WordPress.Security.NonceVerification
109 if ( isset( $_POST['action'] ) && $_POST['action'] === 'update' ) {
110 $this->save_recent_password_hash( $user_id, $old_user_data->user_pass );
111 }
112 }
113
114 /**
115 * Handle the password reset.
116 *
117 * @param \WP_User|\stdClass|null $user The user object.
118 *
119 * @return void
120 */
121 public function on_password_reset( $user ): void {
122 if ( ! is_object( $user ) || ! isset( $user->ID ) || empty( $user->user_pass ) ) {
123 return;
124 }
125
126 $this->save_recent_password_hash( $user->ID, $user->user_pass );
127 }
128
129 /**
130 * Save the new password hash to the user's recent passwords list.
131 *
132 * @param int $user_id The user ID.
133 * @param string $password_hash The password hash to store.
134 *
135 * @return void
136 */
137 public function save_recent_password_hash( int $user_id, string $password_hash ): void {
138 $recent_passwords = get_user_meta( $user_id, Config::RECENT_PASSWORD_HASHES_USER_META_KEY, true );
139
140 if ( ! is_array( $recent_passwords ) ) {
141 $recent_passwords = array();
142 }
143
144 if ( in_array( $password_hash, $recent_passwords, true ) ) {
145 return;
146 }
147
148 // Add the new hashed password and keep only the last 10
149 array_unshift( $recent_passwords, $password_hash );
150 $recent_passwords = array_slice( $recent_passwords, 0, Config::PASSWORD_MANAGER_RECENT_PASSWORDS_LIMIT );
151
152 update_user_meta( $user_id, Config::RECENT_PASSWORD_HASHES_USER_META_KEY, $recent_passwords );
153 }
154 }
155