PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
← All changes | src/component/class-password-protection.php +81 -48 5.4.0 → 6.3.0 View file →
@@ -10,8 +10,9 @@
10 10 use WP_User;
11 11 use WP_Error;
12 12 use Calotes\Helper\HTTP;
13 13 use WP_Defender\Component;
14 +use WP_Defender\Integrations\Woocommerce;
14 15 use WP_Defender\Model\Setting\Password_Reset;
15 16 use WP_Defender\Component\Security_Tweaks\Servers\Server;
16 17 use WP_Defender\Model\Setting\Password_Protection as Password_Protection_Settings;
17 18
@@ -60,11 +61,11 @@
60 61 * @return string
61 62 */
62 63 public function get_submitted_password() {
63 64 $password = '';
64 - foreach ( array( 'pwd', 'pass1', 'password', 'edd_user_pass' ) as $key ) {
65 + foreach ( array( 'pwd', 'pass1', 'password', 'edd_user_pass', 'password_1', 'account_password' ) as $key ) {
65 66 $submitted_pass = HTTP::post( $key );
66 - if ( ! empty( $submitted_pass ) ) {
67 + if ( '' !== $submitted_pass ) {
67 68 $password = $submitted_pass;
68 69 break;
69 70 }
70 71 }
@@ -86,12 +87,9 @@
86 87 $url = $this->pwned_api . $subhash;
87 88 $args = array(
88 89 'method' => 'GET',
89 90 'headers' => array(
90 - 'user-agent' => sprintf(
91 - 'Mozilla/5.0 (compatible; WPMU DEV Defender/%1$s; +https://wpmudev.com)',
92 - DEFENDER_VERSION
93 - ),
91 + 'user-agent' => defender_get_own_user_agent(),
94 92 ),
95 93 );
96 94
97 95 $request = wp_remote_request( $url, $args );
@@ -126,14 +124,14 @@
126 124 if ( is_multisite() && is_super_admin( $user->ID ) ) {
127 125 return false;
128 126 }
129 127
130 - if ( empty( $user->roles ) ) {
128 + if ( ! isset( $user->roles ) || array() === $user->roles ) {
131 129 // WP_User does have data about roles sometimes, e.g. on the Profile page, so we get it from userdata.
132 130 $user_id = $user->ID;
133 131 if ( ! is_multisite() ) {
134 132 $user_meta = get_userdata( $user_id );
135 - if ( empty( $user_meta->roles ) ) {
133 + if ( ! isset( $user_meta->roles ) || array() === $user_meta->roles ) {
136 134 // User should have roles.
137 135 $this->log( sprintf( "User ID: %d doesn't have roles.", $user_id ), self::PASSWORD_LOG );
138 136
139 137 return false;
@@ -140,9 +138,9 @@
140 138 }
141 139 $user_roles = $user_meta->roles;
142 140 } else {
143 141 $arr_user_blogs = get_blogs_of_user( $user_id );
144 - if ( empty( $arr_user_blogs ) ) {
142 + if ( ! is_array( $arr_user_blogs ) || array() === $arr_user_blogs ) {
145 143 // User should be associated with some site.
146 144 $this->log( sprintf( 'User ID: %d is not associated with any site.', $user_id ), self::PASSWORD_LOG );
147 145
148 146 return false;
@@ -148,9 +146,9 @@
148 146 return false;
149 147 }
150 148 $user_blog_id = array_key_first( $arr_user_blogs );
151 149 $user = new WP_User( $user_id, '', $user_blog_id );
152 - if ( empty( $user->roles ) ) {
150 + if ( ! isset( $user->roles ) || array() === $user->roles ) {
153 151 $this->log( sprintf( "User ID: %d doesn't have roles on MU.", $user->ID ), self::PASSWORD_LOG );
154 152
155 153 return false;
156 154 }
@@ -159,9 +157,10 @@
159 157 } else {
160 158 $user_roles = $user->roles;
161 159 }
162 160
163 - return ! empty( array_intersect( $selected_user_roles, $user_roles ) );
161 + $common_roles = array_intersect( $selected_user_roles, $user_roles );
162 + return array() !== $common_roles;
164 163 }
165 164
166 165 /**
167 166 * Get reset password redirect URL.
@@ -167,24 +166,32 @@
167 166 * Get reset password redirect URL.
168 167 *
169 168 * @param WP_User $user The user for whom to generate the URL.
170 169 *
171 - * @return string|null
170 + * @return string
172 171 */
173 - public function get_reset_password_redirect_url( $user ) {
174 - $url = null;
175 -
172 + public function get_reset_password_redirect_url( $user ): string {
173 + $url = '';
176 174 $key = get_password_reset_key( $user );
177 175 if ( ! is_wp_error( $key ) ) {
178 - $url = add_query_arg(
179 - array(
180 - 'action' => 'rp',
181 - 'key' => $key,
182 - 'login' => $user->user_login,
183 - ),
184 - wp_login_url()
185 - );
186 - // Extra hosting checks.
176 + if ( wd_di()->get( Woocommerce::class )->is_wc_login_context() && function_exists( 'wc_lostpassword_url' ) ) {
177 + $url = add_query_arg(
178 + array(
179 + 'key' => $key,
180 + 'login' => $user->user_login,
181 + ),
182 + wc_lostpassword_url()
183 + );
184 + } else {
185 + $url = add_query_arg(
186 + array(
187 + 'action' => 'rp',
188 + 'key' => $key,
189 + 'login' => $user->user_login,
190 + ),
191 + wp_login_url()
192 + );
193 + }
187 194 $this->hosting_compatibility( $key, $user->user_login );
188 195 }
189 196
190 197 return $url;
@@ -190,26 +197,8 @@
190 197 return $url;
191 198 }
192 199
193 200 /**
194 - * Reset password redirect.
195 - *
196 - * @param string|null $url The URL to redirect to.
197 - * @param bool $safe Whether to use safe redirect.
198 - *
199 - * @return void
200 - */
201 - public function reset_password_redirect( $url, $safe = false ) {
202 - if ( empty( $url ) ) {
203 - return;
204 - }
205 - $url = esc_url_raw( $url );
206 - header( 'Cache-Control: no-store, no-cache' );
207 - $safe ? wp_safe_redirect( $url ) : wp_redirect( $url ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
208 - exit();
209 - }
210 -
211 - /**
212 201 * Sets a cookie notice.
213 202 *
214 203 * @param string $name The name of the cookie.
215 204 * @param string $value The value of the cookie.
@@ -216,9 +205,19 @@
216 205 * @param int $time The expiration time of the cookie.
217 206 */
218 207 public function set_cookie_notice( $name, $value, $time ) {
219 208 if ( ! isset( $_COOKIE[ $name ] ) ) {
220 - setcookie( $name, $value, $time, '/' );
209 + setcookie(
210 + $name,
211 + $value,
212 + array(
213 + 'expires' => $time,
214 + 'path' => '/',
215 + 'secure' => is_ssl(),
216 + 'httponly' => true,
217 + 'samesite' => 'Lax',
218 + )
219 + );
221 220 }
222 221 }
223 222
224 223 /**
@@ -231,10 +230,20 @@
231 230 * @return void
232 231 * @since 4.3.0 Removed the $time parameter.
233 232 */
234 233 public function remove_cookie_notice( string $name ): void {
235 - if ( isset( $_COOKIE[ $name ] ) ) {
236 - setcookie( $name, '', time() - YEAR_IN_SECONDS, '/' );
234 + if ( isset( $_COOKIE[ $name ] ) && ! headers_sent() ) {
235 + setcookie(
236 + $name,
237 + '',
238 + array(
239 + 'expires' => time() - YEAR_IN_SECONDS,
240 + 'path' => '/',
241 + 'secure' => is_ssl(),
242 + 'httponly' => true,
243 + 'samesite' => 'Lax',
244 + )
245 + );
237 246 }
238 247 $this->remove_extra_cookies();
239 248 }
240 249
@@ -252,9 +261,10 @@
252 261
253 262 $changed = (int) get_user_meta( $user->ID, 'wd_last_password_change', true );
254 263
255 264 if ( ! $changed ) {
256 - return (int) strtotime( $user->user_registered );
265 + $changed = strtotime( $user->user_registered );
266 + $changed = ! is_int( $changed ) ? (int) $changed : $changed;
257 267 }
258 268
259 269 return $changed;
260 270 }
@@ -304,9 +314,9 @@
304 314 /**
305 315 * Removes extra cookies set during the password reset process.
306 316 */
307 317 protected function remove_extra_cookies() {
308 - if ( isset( $_COOKIE[ 'wp-resetpass-' . COOKIEHASH ] ) && 'flywheel' === Server::get_current_server() ) {
318 + if ( isset( $_COOKIE[ 'wp-resetpass-' . COOKIEHASH ] ) && 'flywheel' === Server::get_current_server() && ! headers_sent() ) {
309 319 setcookie(
310 320 'wp-resetpass-' . COOKIEHASH,
311 321 '',
312 322 time() - YEAR_IN_SECONDS,
@@ -385,9 +395,32 @@
385 395 * @since 2.5.6
386 396 */
387 397 do_action( 'wd_forced_reset_password_url', $url, $action );
388 398 // Redirect to the reset password page.
389 - $this->reset_password_redirect( $url );
399 + if ( '' !== $url ) {
400 + $url = esc_url_raw( $url );
401 + header( 'Cache-Control: no-store, no-cache' );
402 + wp_safe_redirect( $url );
403 + exit();
404 + }
405 + }
406 +
407 + /**
408 + * Add WooCommerce error message for password reset warnings.
409 + *
410 + * @param string $wc_message WooCommerce default error message.
411 + * @return string WooCommerce error message.
412 + */
413 + public function add_woocommerce_error_message( $wc_message ) {
414 + if ( isset( $_COOKIE['display_pwned_password_warning'] ) && function_exists( 'wc_print_notice' ) ) {
415 + wc_print_notice( $this->password_protection_model->pwned_actions['force_change_message'], 'error' );
416 + $this->remove_cookie_notice( 'display_pwned_password_warning' );
417 + }
418 + if ( isset( $_COOKIE['display_reset_password_warning'] ) && function_exists( 'wc_print_notice' ) ) {
419 + wc_print_notice( $this->model->message, 'error' );
420 + $this->remove_cookie_notice( 'display_reset_password_warning' );
421 + }
422 + return $wc_message;
390 423 }
391 424
392 425 /**
393 426 * Verify if password is weak.