PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.1.0
Defender Security – Malware Scanner, Login Security & Firewall v6.1.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
defender-security / src / controller / class-strong-password.php

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

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