PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.7.2
Defender Security – Malware Scanner, Login Security & Firewall v5.7.2
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-strong-password.php

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

296 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handle strong password module.
4 *
5 * @package WP_Defender\Controller
6 */
7
8 namespace WP_Defender\Controller;
9
10 use WP_Defender\Event;
11 use Calotes\Component\Request;
12 use Calotes\Component\Response;
13 use WP_Defender\Integrations\Woocommerce;
14 use WP_Defender\Component\Config\Config_Hub_Helper;
15 use WP_Defender\Component\Strong_Password as Service;
16 use WP_Defender\Model\Setting\Strong_Password as Settings;
17
18 /**
19 * Handle strong password module.
20 */
21 class Strong_Password extends Event {
22
23 /**
24 * The model for the strong password module.
25 *
26 * @var Settings|null
27 */
28 protected ?Settings $model = null;
29
30 /**
31 * The service for the strong password module.
32 *
33 * @var Service|null
34 */
35 protected ?Service $service = null;
36
37 /**
38 * Helper instance for reuse methods from pwned password protection.
39 *
40 * @var Password_Protection|null
41 */
42 private ?Password_Protection $helper;
43
44 /**
45 * WooCommerce integration instance.
46 *
47 * @var Woocommerce|null
48 */
49 private ?Woocommerce $woo;
50
51 /**
52 * Initializes the model and service, registers routes, and sets up scheduled events if the model is active.
53 */
54 public function __construct() {
55 $this->model = wd_di()->get( Settings::class );
56 $this->service = wd_di()->get( Service::class );
57 $this->helper = wd_di()->get( Password_Protection::class );
58 $this->woo = wd_di()->get( Woocommerce::class );
59 add_filter( 'wp_defender_advanced_tools_data', array( $this, 'script_data' ) );
60 $this->register_routes();
61 if ( $this->model->is_active() ) {
62 if ( ! wp_using_themes() ) {
63 $this->setup_core_hooks();
64 }
65 if ( $this->woo->is_activated() ) {
66 add_action( 'woocommerce_init', array( $this, 'setup_woo_hooks' ) );
67 }
68 }
69 }
70
71 /**
72 * Set up core WordPress hooks for strong password functionality.
73 * These hooks work independently of WooCommerce settings.
74 */
75 private function setup_core_hooks() {
76 // Update site url on sub-site when MaskLogin is disabled.
77 if (
78 is_multisite() && ! is_main_site()
79 && ! wd_di()->get( \WP_Defender\Model\Setting\Mask_Login::class )->is_active()
80 ) {
81 add_filter( 'network_site_url', array( $this->helper, 'filter_site_url' ), 100, 2 );
82 }
83
84 // Remove conflicting plugins.
85 remove_action( 'user_profile_update_errors', 'slt_fsp_validate_profile_update', 0 );
86 remove_action( 'resetpass_form', 'slt_fsp_validate_resetpass_form', 10 );
87
88 // Admin hooks.
89 if ( is_admin() ) {
90 add_action( 'admin_enqueue_scripts', array( $this->service, 'scripts' ) );
91 add_action( 'user_profile_update_errors', array( $this->service, 'on_profile_update' ), 100, 3 );
92 }
93
94 // Core WordPress authentication and password hooks.
95 add_action( 'login_enqueue_scripts', array( $this->service, 'scripts' ) );
96 add_action( 'validate_password_reset', array( $this->service, 'on_password_reset' ), 100, 2 );
97 add_action( 'wp_authenticate_user', array( $this->service, 'during_core_authentication' ), 100, 2 );
98 add_filter( 'random_password', array( $this->service, 'generate_password' ), 10, 2 );
99 add_filter( 'lostpassword_url', array( $this->service, 'lostpassword_url' ), 10, 1 );
100 }
101
102 /**
103 * Add hooks for handling strong password in WooCommerce forms.
104 */
105 public function setup_woo_hooks() {
106 $woo_locations = $this->model->forms['woocommerce'] ?? array();
107
108 if ( array() === $woo_locations ) {
109 return;
110 }
111
112 if ( in_array( Woocommerce::WOO_LOGIN_FORM, $woo_locations, true ) ) {
113 add_filter( 'woocommerce_process_login_errors', array( $this->service, 'during_woo_authentication' ), 10, 3 );
114 }
115
116 $referer = wp_get_referer();
117 $add_woo_reset_password_hooks = false;
118 if ( $referer && function_exists( 'wc_get_page_id' ) ) {
119 $my_account_page_id = wc_get_page_id( 'myaccount' );
120 if ( $my_account_page_id > 0 ) {
121 $my_account_url = get_permalink( $my_account_page_id );
122 $add_woo_reset_password_hooks = strpos( $referer, $my_account_url ) === 0;
123 }
124 }
125
126 if (
127 in_array( Woocommerce::WOO_LOST_PASSWORD_FORM, $woo_locations, true ) ||
128 $add_woo_reset_password_hooks
129 ) {
130 add_action( 'wp_enqueue_scripts', array( $this->service, 'scripts' ) );
131 add_action( 'validate_password_reset', array( $this->service, 'on_password_reset' ), 100, 2 );
132 add_filter( 'woocommerce_reset_password_message', array( $this->service, 'add_woocommerce_error_message' ) );
133 add_action( 'woocommerce_save_account_details_errors', array( $this->service, 'on_woo_account_update' ), 10, 2 );
134 }
135
136 if (
137 in_array( Woocommerce::WOO_REGISTER_FORM, $woo_locations, true ) ||
138 in_array( Woocommerce::WOO_CHECKOUT_FORM, $woo_locations, true )
139 ) {
140 add_action( 'wp_enqueue_scripts', array( $this->service, 'scripts' ) );
141 add_filter( 'woocommerce_registration_errors', array( $this->service, 'during_woo_registration' ) );
142 }
143 }
144
145 /**
146 * Provide data to the frontend via localized script.
147 *
148 * @param array $data Data collection is ready to passed.
149 *
150 * @return array Modified data array with added this controller data.
151 */
152 public function script_data( array $data ): array {
153 $data['strong_password'] = $this->data_frontend();
154
155 return $data;
156 }
157
158 /**
159 * All the variables that we will show on frontend, both in the main page, or dashboard widget.
160 *
161 * @return array
162 */
163 public function data_frontend(): array {
164 return array_merge(
165 array(
166 'is_active' => $this->model->is_active(),
167 'model' => $this->model->export(),
168 'all_roles' => wp_list_pluck( get_editable_roles(), 'name' ),
169 'woo_forms' => Woocommerce::get_forms(),
170 'is_woo_active' => wd_di()->get( Woocommerce::class )->is_activated(),
171 ),
172 $this->dump_routes_and_nonces()
173 );
174 }
175
176 /**
177 * Save settings.
178 *
179 * @param Request $request The request object containing new settings data.
180 *
181 * @return Response
182 * @defender_route
183 */
184 public function save_settings( Request $request ): Response {
185 $model_data = $request->get_data_by_model( $this->model );
186 $this->model->import( $model_data );
187 if ( $this->model->validate() ) {
188 $this->model->save();
189 Config_Hub_Helper::set_clear_active_flag();
190
191 $response = array(
192 'auto_close' => true,
193 );
194 if ( $this->model->enabled && array() === $this->model->user_roles ) {
195 // we need to control this message in front.
196 $response['warning'] = sprintf(
197 /* translators: 1. Open tag. 2. Close tag. */
198 esc_html__( 'You need to check at least one of the %1$sStrong Passwords checks preferences below%2$s and save your settings to enable Strong Password Protection.', 'defender-security' ),
199 '<b>',
200 '</b>'
201 );
202
203 return new Response( true, array_merge( $response, $this->data_frontend() ) );
204 }
205
206 if ( $this->maybe_track() ) {
207 $prev_data = $this->model->get_old_settings();
208 if ( array() !== $prev_data ) {
209 if ( $this->model->enabled && ! $prev_data['enabled'] ) {
210 $need_track = true;
211 $event = 'def_feature_activated';
212 } elseif ( ! $this->model->enabled && $prev_data['enabled'] ) {
213 $need_track = true;
214 $event = 'def_feature_deactivated';
215 } else {
216 $need_track = false;
217 }
218
219 if ( $need_track ) {
220 $data = array(
221 'Feature' => 'Strong Password',
222 'Triggered From' => 'Feature page',
223 );
224 $this->track_feature( $event, $data );
225 }
226 }
227 }
228
229 return new Response( true, array_merge( $response, $this->data_frontend() ) );
230 }
231
232 return new Response(
233 false,
234 array(
235 'message' => $this->model->get_formatted_errors(),
236 )
237 );
238 }
239
240 /**
241 * Export the data of this module, we will use this for export to HUB, create a preset etc.
242 *
243 * @return array
244 */
245 public function to_array() {
246 return array();
247 }
248
249 /**
250 * Import the data of other source into this, it can be when HUB trigger the import, or user apply a preset.
251 *
252 * @param array $data Data from other source.
253 *
254 * @return null|void
255 */
256 public function import_data( array $data ) {
257 $this->model->import( $data );
258 if ( $this->model->validate() ) {
259 $this->model->save();
260 }
261 }
262
263 /**
264 * Remove all settings, configs generated in this container runtime.
265 *
266 * @return mixed
267 */
268 public function remove_settings() {
269 }
270
271 /**
272 * Remove all data.
273 */
274 public function remove_data() {}
275
276 /**
277 * Export strings.
278 *
279 * @return array
280 */
281 public function export_strings(): array {
282 return array(
283 $this->model->is_active() ? esc_html__( 'Active', 'defender-security' ) : esc_html__( 'Inactive', 'defender-security' ),
284 );
285 }
286
287 /**
288 * Provides data for the dashboard widget.
289 *
290 * @return array An array of dashboard widget data.
291 */
292 public function dashboard_widget(): array {
293 return array( 'model' => $this->model->export() );
294 }
295 }
296