PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.2.3
Defender Security – Malware Scanner, Login Security & Firewall v6.2.3
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 3.1.1 All 140 releases
defender-security / src / model / setting / class-captcha.php

class-captcha.php in Defender Security – Malware Scanner, Login Security & Firewall 6.2.3, at src/model/setting/class-captcha.php

420 lines 10.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handle Captcha settings.
4 *
5 * @package WP_Defender\Model\Setting
6 */
7
8 namespace WP_Defender\Model\Setting;
9
10 use Calotes\Model\Setting;
11
12 /**
13 * Model for Captcha settings.
14 */
15 class Captcha extends Setting {
16 /**
17 * Turnstile provider key.
18 */
19 const TURNSTILE = 'turnstile';
20
21 /**
22 * Option name.
23 * We'll keep the current table for all Captcha for backward compatibility. There's no need to edit the table name to store settings in the database.
24 *
25 * @var string
26 */
27 protected $table = 'wd_recaptcha_settings';
28
29 /**
30 * Feature status.
31 *
32 * @var bool
33 * @defender_property
34 */
35 public $enabled = false;
36
37 /**
38 * Captcha Provider.
39 *
40 * @var string
41 * @defender_property
42 */
43 public $provider = 'recaptcha';
44
45 /**
46 * Active Captcha type.
47 *
48 * @var string
49 * @defender_property
50 * @rule required
51 * @rule in[v2_checkbox,v2_invisible,v3_recaptcha,turnstile]
52 */
53 public $active_type = 'v2_checkbox';
54
55 /**
56 * Data for v2 checkbox reCaptcha.
57 *
58 * @var array
59 * @defender_property
60 */
61 public $data_v2_checkbox;
62
63 /**
64 * Data for v2 invisible reCaptcha.
65 *
66 * @var array
67 * @defender_property
68 */
69 public $data_v2_invisible;
70
71 /**
72 * Data for v3 reCaptcha.
73 *
74 * @var array
75 * @defender_property
76 */
77 public $data_v3_recaptcha;
78
79 /**
80 * Data for Cloudflare Turnstile.
81 *
82 * @var array
83 * @defender_property
84 */
85 public $data_turnstile;
86
87 /**
88 * Language for Captcha.
89 *
90 * @var string
91 * @defender_property
92 * @rule required
93 */
94 public $language = '';
95
96 /**
97 * Message for reCaptcha.
98 *
99 * @var string
100 * @defender_property
101 * @sanitize sanitize_textarea_field
102 */
103 public $message = '';
104
105 /**
106 * Locations for Captcha.
107 *
108 * @var array
109 * @defender_property
110 * @rule required
111 */
112 public $locations = array();
113
114 /**
115 * Flag to detect WooCommerce.
116 *
117 * @var bool
118 * @defender_property
119 */
120 public $detect_woo = false;
121
122 /**
123 * Checked locations for WooCommerce.
124 *
125 * @var array
126 * @defender_property
127 * @rule required
128 */
129 public $woo_checked_locations = array();
130
131 /**
132 * Flag to detect BuddyPress.
133 *
134 * @var bool
135 * @defender_property
136 */
137 public $detect_buddypress = false;
138
139 /**
140 * Checked locations for BuddyPress.
141 *
142 * @var array
143 * @defender_property
144 * @rule required
145 */
146 public $buddypress_checked_locations = array();
147
148 /**
149 * Flag to disable Captcha for known users.
150 *
151 * @var bool
152 * @defender_property
153 */
154 public $disable_for_known_users = true;
155
156 /**
157 * Rules for validating the Captcha settings.
158 *
159 * @var array
160 */
161 protected $rules = array(
162 array( array( 'enabled', 'detect_woo', 'detect_buddypress' ), 'boolean' ),
163 array( array( 'active_type' ), 'in', array( 'v2_checkbox', 'v2_invisible', 'v3_recaptcha', self::TURNSTILE ) ),
164 );
165
166 /**
167 * Retrieves the default values for the Captcha settings.
168 *
169 * @return array An associative array containing the default values.
170 */
171 public function get_default_values(): array {
172 return array(
173 'message' => esc_html__( 'reCAPTCHA verification failed. Please try again.', 'defender-security' ),
174 'turnstile_message' => esc_html__( 'Turnstile verification failed. Please try again.', 'defender-security' ),
175 );
176 }
177
178 /**
179 * Load default values.
180 *
181 * @return void
182 */
183 protected function before_load(): void {
184 $default_values = $this->get_default_values();
185 $this->provider = 'recaptcha';
186 $this->message = $default_values['message'];
187 $this->language = 'automatic';
188 $this->data_v2_checkbox = array(
189 'key' => '',
190 'secret' => '',
191 'verified' => false,
192 'size' => 'normal',
193 'style' => 'light',
194 );
195 $this->data_v2_invisible = array(
196 'key' => '',
197 'secret' => '',
198 'verified' => false,
199 );
200 $this->data_v3_recaptcha = array(
201 'key' => '',
202 'secret' => '',
203 'verified' => false,
204 'threshold' => '0.5',
205 );
206 $this->data_turnstile = array(
207 'key' => '',
208 'secret' => '',
209 'verified' => false,
210 'size' => 'normal',
211 'style' => 'auto',
212 'message' => $default_values['turnstile_message'],
213 'language' => 'auto',
214 );
215 }
216
217 /**
218 * Backfill new keys (e.g. 'verified') into data arrays loaded from settings saved by an older version.
219 *
220 * @return void
221 */
222 protected function after_load(): void {
223 $this->data_v2_checkbox = wp_parse_args( $this->data_v2_checkbox, array( 'verified' => false ) );
224 $this->data_v2_invisible = wp_parse_args( $this->data_v2_invisible, array( 'verified' => false ) );
225 $this->data_v3_recaptcha = wp_parse_args( $this->data_v3_recaptcha, array( 'verified' => false ) );
226 $this->data_turnstile = wp_parse_args( $this->data_turnstile, array( 'verified' => false ) );
227 }
228
229 /**
230 * Checks if the given Captcha type is valid and has all the necessary data.
231 *
232 * @param string $active_type The Captcha type to check.
233 *
234 * @return bool Returns true if the Captcha type is valid and has all the necessary data, false otherwise.
235 */
236 private function check_captcha_type( string $active_type ): bool {
237 if (
238 'v2_checkbox' === $active_type
239 && '' !== $this->data_v2_checkbox['key']
240 && '' !== $this->data_v2_checkbox['secret']
241 ) {
242 return true;
243 } elseif (
244 'v2_invisible' === $active_type
245 && '' !== $this->data_v2_invisible['key']
246 && '' !== $this->data_v2_invisible['secret']
247 ) {
248 return true;
249 } elseif (
250 'v3_recaptcha' === $active_type
251 && '' !== $this->data_v3_recaptcha['key'] && '' !== $this->data_v3_recaptcha['secret']
252 ) {
253 return true;
254 } elseif (
255 self::TURNSTILE === $active_type &&
256 '' !== $this->data_turnstile['key'] &&
257 '' !== $this->data_turnstile['secret']
258 ) {
259 return true;
260 } else {
261 return false;
262 }
263 }
264
265 /**
266 * Checks if the CAPTCHA is active.
267 *
268 * @return bool Returns true if the CAPTCHA is active, false otherwise.
269 */
270 public function is_active(): bool {
271 $hook_name = self::TURNSTILE === $this->active_type ? 'wd_turnstile_enable' : 'wd_recaptcha_enable';
272 $enable = apply_filters(
273 $hook_name,
274 $this->enabled
275 && '' !== $this->active_type
276 && '' !== $this->language
277 // For each Captcha type.
278 && $this->check_captcha_type( $this->active_type )
279 );
280
281 return is_bool( $enable ) ? $enable : (bool) $enable;
282 }
283
284 /**
285 * Is activated any default location?
286 *
287 * @return bool
288 */
289 public function enable_default_location(): bool {
290 return array() !== $this->locations;
291 }
292
293 /**
294 * Level#2 check by any activated location. Only if the plugin is enabled.
295 *
296 * @return bool
297 */
298 public function enable_woo_location(): bool {
299 return $this->detect_woo && array() !== $this->woo_checked_locations;
300 }
301
302 /**
303 * Level#2 check by deactivated locations. Only if the plugin is enabled.
304 *
305 * @return bool
306 */
307 public function is_unchecked_woo_locations(): bool {
308 return $this->detect_woo && array() === $this->woo_checked_locations;
309 }
310
311 /**
312 * Level#1 check. If the plugin is disabled, there is no point further.
313 *
314 * @param bool $is_woo_activated Whether WooCommerce is activated or not.
315 *
316 * @return bool
317 */
318 public function check_woo_locations( $is_woo_activated ): bool {
319 if ( ! $is_woo_activated ) {
320 return false;
321 }
322
323 return $this->enable_woo_location();
324 }
325
326 /**
327 * Level#2 check by any activated location. Only if the plugin is enabled.
328 *
329 * @return bool
330 */
331 public function enable_buddypress_location(): bool {
332 return $this->detect_buddypress && array() !== $this->buddypress_checked_locations;
333 }
334
335 /**
336 * Level#2 check by deactivated locations. Only if the plugin is enabled.
337 *
338 * @return bool
339 */
340 public function is_unchecked_buddypress_locations(): bool {
341 return $this->detect_buddypress && array() === $this->buddypress_checked_locations;
342 }
343
344 /**
345 * Level#1 Checks if the BuddyPress locations are valid and have all the necessary data.
346 *
347 * @param bool $is_buddypress_activated Whether BuddyPress is activated or not.
348 *
349 * @return bool Returns true if the BuddyPress locations are valid and have all the necessary data, false otherwise.
350 */
351 public function check_buddypress_locations( $is_buddypress_activated ): bool {
352 if ( ! $is_buddypress_activated ) {
353 return false;
354 }
355
356 return $this->enable_buddypress_location();
357 }
358
359 /**
360 * Define settings labels.
361 *
362 * @return array
363 */
364 public function labels(): array {
365 return array(
366 'enabled' => self::get_module_name(),
367 'active_type' => esc_html__( 'Configure CAPTCHA', 'defender-security' ),
368 'v2_checkbox' => esc_html__( 'V2 Checkbox', 'defender-security' ),
369 'v2_invisible' => esc_html__( 'V2 Invisible', 'defender-security' ),
370 'v3_recaptcha' => esc_html__( 'reCAPTCHA V3', 'defender-security' ),
371 'language' => esc_html__( 'Language', 'defender-security' ),
372 'message' => esc_html__( 'Error Message', 'defender-security' ),
373 'locations' => esc_html__( 'CAPTCHA Locations', 'defender-security' ),
374 'detect_woo' => esc_html__( 'WooCommerce', 'defender-security' ),
375 'detect_buddypress' => esc_html__( 'BuddyPress', 'defender-security' ),
376 'disable_for_known_users' => esc_html__( 'Disable for logged in users', 'defender-security' ),
377 );
378 }
379
380 /**
381 * Disable for logged in users or enable.
382 *
383 * @return bool
384 */
385 public function display_for_known_users(): bool {
386 return ! ( $this->disable_for_known_users && is_user_logged_in() );
387 }
388
389 /**
390 * Get module name.
391 *
392 * @return string
393 */
394 public static function get_module_name(): string {
395 return esc_html__( 'CAPTCHA', 'defender-security' );
396 }
397
398 /**
399 * Get active captcha data based on provider and active type.
400 *
401 * @param string|null $provider The provider name.
402 * @param string|null $active_type The active type.
403 *
404 * @return array The captcha data for the specified provider.
405 */
406 public function get_active_captcha_data( ?string $provider = null, ?string $active_type = null ): array {
407 $provider = $provider ?? $this->provider;
408 $active_type = $active_type ?? $this->active_type;
409 if ( self::TURNSTILE === $provider ) {
410 return $this->data_turnstile;
411 }
412 return match ( $active_type ) {
413 'v2_checkbox' => $this->data_v2_checkbox,
414 'v2_invisible' => $this->data_v2_invisible,
415 'v3_recaptcha' => $this->data_v3_recaptcha,
416 default => array(),
417 };
418 }
419 }
420