PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.3.1
Defender Security – Malware Scanner, Login Security & Firewall v5.3.1
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
defender-security / src / controller / class-password-reset.php

class-password-reset.php in Defender Security – Malware Scanner, Login Security & Firewall 5.3.1, at src/controller/class-password-reset.php

351 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles password reset operations.
4 *
5 * @package WP_Defender\Controller
6 */
7
8 namespace WP_Defender\Controller;
9
10 use WP_User;
11 use WP_Error;
12 use Exception;
13 use WP_Defender\Event;
14 use Calotes\Component\Request;
15 use Calotes\Component\Response;
16 use WP_Defender\Traits\Formats;
17 use WP_Defender\Component\Config\Config_Hub_Helper;
18
19 /**
20 * Handles password reset operations.
21 */
22 class Password_Reset extends Event {
23
24 use Formats;
25
26 /**
27 * The model for handling the data.
28 *
29 * @var \WP_Defender\Model\Setting\Password_Reset
30 */
31 protected $model;
32
33 /**
34 * Service for handling logic.
35 *
36 * @var \WP_Defender\Component\Password_Protection
37 */
38 protected $service;
39
40 /**
41 * Default message.
42 *
43 * @var string
44 */
45 public $default_msg;
46
47 /**
48 * Initializes the model and service, registers routes, and sets up scheduled events if the model is active.
49 */
50 public function __construct() {
51 $this->model = $this->get_model();
52 $this->service = wd_di()->get( \WP_Defender\Component\Password_Protection::class );
53 $default_values = $this->model->get_default_values();
54 $this->default_msg = $default_values['message'];
55 add_filter( 'wp_defender_advanced_tools_data', array( $this, 'script_data' ) );
56 $this->register_routes();
57 if ( $this->model->is_active() ) {
58 // Update site url on sub-site when MaskLogin is disabled.
59 if (
60 is_multisite() && ! is_main_site()
61 && ! wd_di()->get( \WP_Defender\Model\Setting\Mask_Login::class )->is_active()
62 ) {
63 add_filter( 'network_site_url', array( $this, 'filter_site_url' ), 100, 2 );
64 }
65 add_action( 'validate_password_reset', array( $this, 'handle_reset_check_password' ), 10, 2 );
66 add_action( 'profile_update', array( $this, 'handle_update_user' ), 10, 2 );
67 add_action( 'password_reset', array( $this, 'handle_password_reset' ), 10 );
68 add_action( 'wp_authenticate_user', array( $this, 'handle_login_password' ), 999, 2 );
69 // No use 'user_profile_update_errors' because there aren't checks for password resetting for logged user in.
70 }
71 }
72
73 /**
74 * Filters the site URL for password resetting on sub-sites.
75 *
76 * @param string $url The original site URL.
77 * @param string $path The path to append to the site URL.
78 *
79 * @return string The modified site URL.
80 */
81 public function filter_site_url( string $url, string $path ) {
82 $action = defender_get_data_from_request( 'action', 'g' );
83 if ( $path && is_string( $path )
84 && in_array( $action, array( 'rp', 'resetpass' ), true )
85 && false !== stristr( $url, 'wp-login.php' )
86 ) {
87 return get_option( 'siteurl' ) . '/' . ltrim( $path, '/' );
88 }
89
90 return $url;
91 }
92
93 /**
94 * Get model.
95 *
96 * @return \WP_Defender\Model\Setting\Password_Reset
97 */
98 private function get_model() {
99 if ( is_object( $this->model ) ) {
100 return $this->model;
101 }
102
103 return new \WP_Defender\Model\Setting\Password_Reset();
104 }
105
106 /**
107 * Handle password update on login.
108 *
109 * @param WP_User|WP_Error $user WP_User object or WP_Error.
110 * @param string $password Password plain string.
111 *
112 * @return WP_User|WP_Error Return user object or error object.
113 */
114 public function handle_login_password( $user, $password ) {
115 if ( is_wp_error( $user ) || ! $user instanceof WP_User ) {
116 return $user;
117 }
118 if ( empty( $password ) ) {
119 return new WP_Error(
120 'defender_invalid_password',
121 esc_html__( 'Invalid user data.', 'defender-security' )
122 );
123 }
124 $this->service->do_force_reset( $user, $password );
125
126 return $user;
127 }
128
129 /**
130 * Handle password update on password reset.
131 *
132 * @param WP_Error $errors Error object.
133 * @param WP_Error|WP_User $user WP_User object or WP_Error.
134 *
135 * @return null|WP_Error
136 */
137 public function handle_reset_check_password( WP_Error $errors, $user ) {
138 if ( is_wp_error( $user ) ) {
139 return;
140 }
141
142 if ( ! $this->service->is_enabled_by_user_role( $user, $this->model->user_roles ) ) {
143 return;
144 }
145
146 // Check if display_reset_password_warning cookie enabled then show warning message on reset password page.
147 if ( isset( $_COOKIE['display_reset_password_warning'] ) ) {
148 $message = empty( $this->model->message ) ? $this->default_msg : $this->model->message;
149 $errors->add( 'defender_password_reset', $message );
150 // Remove the one time cookie notice once it's displayed.
151 $this->service->remove_cookie_notice( 'display_reset_password_warning' );
152
153 return $errors;
154 }
155
156 $login_password = $this->service->get_submitted_password();
157 if (
158 ! empty( $user->ID )
159 && ! empty( $login_password )
160 && wp_check_password( $login_password, get_userdata( $user->ID )->user_pass, $user->ID )
161 ) {
162 $message = wp_kses(
163 esc_html__( 'This password has been used already. Please choose a different one.', 'defender-security' ),
164 array( 'strong' => array() )
165 );
166 $errors->add( 'defender_password_reset', $message );
167
168 return $errors;
169 }
170
171 return $errors;
172 }
173
174 /**
175 * Update the time when a user resets their password.
176 *
177 * @param WP_User $user User object.
178 *
179 * @return void
180 */
181 public function handle_password_reset( WP_User $user ): void {
182 $this->service->handle_password_updated( $user );
183 }
184
185 /**
186 * Update password data when a user object is set or updated.
187 *
188 * @param int $user_id User ID.
189 * @param WP_User $old_user_data Old user data.
190 *
191 * @return void
192 */
193 public function handle_update_user( int $user_id, WP_User $old_user_data ) {
194 $user = get_userdata( $user_id );
195
196 if ( $user->user_pass === $old_user_data->user_pass ) {
197 return;
198 }
199
200 $this->service->handle_password_updated( $user );
201 }
202
203 /**
204 * Provide data to the frontend via localized script.
205 *
206 * @param array $data Data collection is ready to passed.
207 *
208 * @return array Modified data array with added this controller data.
209 */
210 public function script_data( array $data ): array {
211 $data['password_reset'] = $this->data_frontend();
212
213 return $data;
214 }
215
216 /**
217 * Save settings.
218 *
219 * @param Request $request The request object containing new settings data.
220 *
221 * @return Response
222 * @defender_route
223 */
224 public function save_settings( Request $request ): Response {
225 $data = $request->get_data_by_model( $this->model );
226 $this->model->import( $data );
227 if ( $this->model->validate() ) {
228 $this->model->save();
229 Config_Hub_Helper::set_clear_active_flag();
230
231 $response = array(
232 'message' => esc_html__( 'Your settings have been updated.', 'defender-security' ),
233 'auto_close' => true,
234 );
235
236 return new Response( true, array_merge( $response, $this->data_frontend() ) );
237 }
238
239 return new Response(
240 false,
241 array(
242 'message' => $this->model->get_formatted_errors(),
243 )
244 );
245 }
246
247 /**
248 * Save settings.
249 *
250 * @param Request $request The request object containing new settings data.
251 *
252 * @return Response
253 * @defender_route
254 */
255 public function toggle_reset( Request $request ) {
256 $response = array();
257 $data = $request->get_data_by_model( $this->model );
258 if ( isset( $data['expire_force'] ) && true === $data['expire_force'] ) {
259 $data['force_time'] = time();
260 $response = array(
261 'message' => esc_html__(
262 'Selected user roles are required to reset their password upon next login.',
263 'defender-security'
264 ),
265 );
266 } else {
267 $response['message'] = esc_html__( 'Force Reset Password has been disabled.', 'defender-security' );
268 }
269 $this->model->import( $data );
270 if ( $this->model->validate() ) {
271 $this->model->save();
272 Config_Hub_Helper::set_clear_active_flag();
273
274 return new Response( true, array_merge( $response, $this->data_frontend() ) );
275 }
276
277 return new Response(
278 false,
279 array(
280 'message' => $this->model->get_formatted_errors(),
281 )
282 );
283 }
284
285 /**
286 * Removes settings for all submodules.
287 */
288 public function remove_settings() {
289 }
290
291 /**
292 * Delete all the data & the cache.
293 */
294 public function remove_data(): void {
295 delete_metadata( 'user', null, 'wd_last_password_change', null, true );
296 }
297
298 /**
299 * Provides data for the frontend.
300 *
301 * @return array An array of data for the frontend.
302 */
303 public function data_frontend(): array {
304 $model = $this->get_model();
305
306 return array_merge(
307 array(
308 'model' => $model->export(),
309 'all_roles' => wp_list_pluck( get_editable_roles(), 'name' ),
310 'reset_last' => empty( $model->force_time ) ? '' : $this->format_date_time( $model->force_time ),
311 'default_message' => $this->default_msg,
312 ),
313 $this->dump_routes_and_nonces()
314 );
315 }
316
317 /**
318 * Imports data into the model.
319 *
320 * @param array $data Data to be imported into the model.
321 *
322 * @throws Exception If table is not defined.
323 */
324 public function import_data( array $data ) {
325 $model = $this->get_model();
326
327 $model->import( $data );
328 if ( $model->validate() ) {
329 $model->save();
330 }
331 }
332
333 /**
334 * Converts the current object state to an array.
335 *
336 * @return array The array representation of the object.
337 */
338 public function to_array(): array {
339 return array();
340 }
341
342 /**
343 * Exports strings.
344 *
345 * @return array An array of strings.
346 */
347 public function export_strings() {
348 return array();
349 }
350 }
351