PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.8.1
Defender Security – Malware Scanner, Login Security & Firewall v5.8.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-hub.php

class-hub.php in Defender Security – Malware Scanner, Login Security & Firewall 5.8.1, at src/controller/class-hub.php

913 lines 26.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handle various actions and interactions with the WPMUDEV Hub.
4 *
5 * @package WP_Defender\Controller
6 */
7
8 namespace WP_Defender\Controller;
9
10 use WP_Defender\Event;
11 use WP_Defender\Traits\IO;
12 use WP_Defender\Traits\Formats;
13 use WP_Defender\Behavior\WPMUDEV;
14 use WP_Defender\Model\Lockout_Log;
15 use WP_Defender\Component\Quarantine;
16 use WP_Defender\Model\Setting\Two_Fa;
17 use WP_Defender\Component\IP\Antibot_Global_Firewall;
18 use WP_Defender\Component\IP\Global_IP;
19 use WP_Defender\Component\Backup_Settings;
20 use WP_Defender\Model\Setting\Login_Lockout;
21 use WP_Defender\Model\Setting\Notfound_Lockout;
22 use WP_Defender\Model\Notification\Audit_Report;
23 use WP_Defender\Model\Setting\Blacklist_Lockout;
24 use WP_Defender\Model\Setting\Global_Ip_Lockout;
25 use WP_Defender\Component\Config\Config_Adapter;
26 use WP_Defender\Model\Setting\User_Agent_Lockout;
27 use WP_Defender\Model\Notification\Malware_Report;
28 use WP_Defender\Model\Notification\Tweak_Reminder;
29 use WP_Defender\Component\Config\Config_Hub_Helper;
30 use WP_Defender\Model\Notification\Firewall_Report;
31 use WP_Defender\Model\Notification\Malware_Notification;
32 use WP_Defender\Model\Notification\Firewall_Notification;
33 use WP_Defender\Model\Setting\Audit_Logging as Model_Audit_Logging;
34 use WP_Defender\Model\Setting\Security_Tweaks as Model_Security_Tweaks;
35 use WP_Defender\Model\Setting\Antibot_Global_Firewall_Setting;
36
37 /**
38 * Handles various actions and interactions with the WPMUDEV Hub.
39 */
40 class HUB extends Event {
41
42 use IO;
43 use Formats;
44
45 /**
46 * Flag indicating whether to display the onboarding view or not.
47 *
48 * @var bool
49 */
50 private $view_onboard = false;
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->attach_behavior( WPMUDEV::class, WPMUDEV::class );
57 add_action( 'wdp_register_hub_action', array( $this, 'add_hub_endpoint' ) );
58 add_action( 'defender_hub_sync', array( $this, 'hub_sync' ) );
59 }
60
61 /**
62 * Add various hub endpoints to the actions array.
63 *
64 * @param array $actions An array of actions.
65 *
66 * @return array The updated actions array with hub endpoints added.
67 */
68 public function add_hub_endpoint( $actions ) {
69 $actions['defender_new_scan'] = array( $this, 'new_scan' );
70 $actions['defender_schedule_scan'] = array( $this, 'schedule_scan' );
71 $actions['defender_manage_audit_log'] = array( $this, 'manage_audit_log' );
72 $actions['defender_manage_lockout'] = array( $this, 'manage_lockout' );
73 $actions['defender_whitelist_ip'] = array( $this, 'whitelist_ip' );
74 $actions['defender_blacklist_ip'] = array( $this, 'blacklist_ip' );
75 $actions['defender_get_scan_progress'] = array( $this, 'get_scan_progress' );
76 $actions['defender_manage_recaptcha'] = array( $this, 'manage_recaptcha' );
77 $actions['defender_manage_2fa'] = array( $this, 'manage_2fa' );
78 $actions['defender_manage_global_ip_list'] = array( $this, 'manage_global_ip_list' );
79 $actions['defender_set_global_ip_list'] = array( $this, 'set_global_ips' );
80 $actions['defender_set_antibot_status'] = array( $this, 'set_antibot_status' );
81 // Backup/restore settings.
82 $actions['defender_export_settings'] = array( $this, 'export_settings' );
83 $actions['defender_import_settings'] = array( $this, 'import_settings' );
84 // Get stats, version#1.
85 $actions['defender_get_stats'] = array( $this, 'get_stats' );
86 // Version#2.
87 $actions['defender_get_stats_v2'] = array( $this, 'defender_get_stats_v2' );
88
89 $actions['defender_get_quarantined_files'] = array( $this, 'get_quarantined_files' );
90 $actions['defender_restore_quarantined_file'] = array( $this, 'restore_quarantined_file' );
91
92 return $actions;
93 }
94
95 /**
96 * Create new scan, triggered from HUB.
97 */
98 public function new_scan() {
99 $scan = \WP_Defender\Model\Scan::create();
100 if ( is_wp_error( $scan ) ) {
101 wp_send_json_error(
102 array(
103 'message' => $scan->get_error_message(),
104 )
105 );
106 }
107
108 wd_di()->get( Scan::class )->run_scan_mechanisms_from( 'hub' );
109
110 wp_send_json_success();
111 }
112
113 /**
114 * Schedule a scan, from HUB.
115 *
116 * @param array $params Schedule config.
117 */
118 public function schedule_scan( $params ) {
119 $frequency = $params['frequency'];
120 $day = $params['day'];
121 $time = $params['time'];
122 $allowed_freq = array( 1, 7, 30 );
123 if (
124 ! in_array( $frequency, $allowed_freq, true )
125 || ! in_array( $day, $this->get_days_of_week(), true )
126 || ! in_array( $time, $this->get_times(), true )
127 ) {
128 wp_send_json_error();
129 }
130 $malware_report = new Malware_Report();
131 $malware_report->frequency = $frequency;
132 $malware_report->day = $day;
133 $malware_report->time = $time;
134 $malware_report->save();
135
136 wp_send_json_success();
137 }
138
139 /**
140 * Track a feature activation or deactivation from the Hub.
141 *
142 * @param bool $is_active Whether the feature is being activated or deactivated.
143 * @param string $feature_title The title of the feature being tracked.
144 */
145 protected function track_feature_from_hub( bool $is_active, string $feature_title ) {
146 $event = $is_active ? 'def_feature_activated' : 'def_feature_deactivated';
147 $data = array(
148 'Feature' => $feature_title,
149 'Triggered From' => 'Hub',
150 );
151
152 $this->track_feature( $event, $data );
153 }
154
155 /**
156 * Manage the audit log settings by toggling the enabled status of the Audit Logging feature.
157 *
158 * @return void
159 */
160 public function manage_audit_log() {
161 $response = null;
162 if ( class_exists( Model_Audit_Logging::class ) ) {
163 $settings = new Model_Audit_Logging();
164 $response = array();
165 if ( true === $settings->enabled ) {
166 $settings->enabled = false;
167 $response['enabled'] = false;
168 } else {
169 $settings->enabled = true;
170 $response['enabled'] = true;
171 }
172 $settings->save();
173 // Track.
174 if ( $this->is_tracking_active() ) {
175 $this->track_feature_from_hub( ! $settings->enabled, 'Audit Logging' );
176 }
177 }
178
179 wp_send_json_success( $response );
180 }
181
182 /**
183 * Manages the lockout feature based on the given parameters.
184 *
185 * @param array $params The parameters for managing the lockout.
186 * - type (string): The type of lockout to manage. Possible values: 'login', '404',
187 * 'ua-lockout'.
188 * @param string $action The action to perform on the lockout.
189 *
190 * @return void
191 */
192 public function manage_lockout( $params, $action ) {
193 $type = $params['type'];
194 $response = array();
195 if ( 'login' === $type ) {
196 $settings = new Login_Lockout();
197 if ( $settings->enabled ) {
198 $settings->enabled = false;
199 $response[ $type ] = 'disabled';
200 } else {
201 $settings->enabled = true;
202 $response[ $type ] = 'enabled';
203 }
204 $settings->save();
205 $feature = 'Login Protection';
206 } elseif ( '404' === $type ) {
207 $settings = new Notfound_Lockout();
208 if ( $settings->enabled ) {
209 $settings->enabled = false;
210 $response[ $type ] = 'disabled';
211 } else {
212 $settings->enabled = true;
213 $response[ $type ] = 'enabled';
214 }
215 $settings->save();
216 $feature = '404 Detection';
217 } elseif ( User_Agent_Lockout::get_module_slug() === $type ) {
218 $settings = new User_Agent_Lockout();
219 if ( $settings->enabled ) {
220 $settings->enabled = false;
221 $response[ $type ] = 'disabled';
222 } else {
223 $settings->enabled = true;
224 $response[ $type ] = 'enabled';
225 }
226 $settings->save();
227 } else {
228 $response[ $type ] = 'invalid';
229 }
230 // Track. Only for Login & NF Lockouts. Ignoring phpcs error due to all possible types.
231 if ( $this->is_tracking_active() && in_array( $type, array( 'login', '404' ), true ) ) {
232 $event = $settings->enabled ? 'def_feature_deactivated' : 'def_feature_activated';
233 $data = array(
234 'Feature' => $feature,
235 'Triggered From' => 'Hub',
236 );
237
238 $this->track_feature( $event, $data );
239 }
240
241 wp_send_json_success( $response );
242 }
243
244 /**
245 * Whitelists an IP address by removing it from the block list and adding it to the allow list.
246 *
247 * @param array $params An array containing the IP address to whitelist.
248 * @param string $action The action to perform.
249 *
250 * @return void
251 */
252 public function whitelist_ip( $params, $action ) {
253 $settings = new Blacklist_Lockout();
254 $ip = $params['ip'];
255 if ( $ip && filter_var( $ip, FILTER_VALIDATE_IP ) ) {
256 $settings->remove_from_list( $ip, 'blocklist' );
257 $settings->add_to_list( $ip, 'allowlist' );
258 } else {
259 wp_send_json_error();
260 }
261 wp_send_json_success();
262 }
263
264 /**
265 * Blacklist an IP address by removing it from the allow list and adding it to the block list.
266 *
267 * @param array $params An array containing the IP address to blacklist.
268 * @param string $action The action to perform.
269 */
270 public function blacklist_ip( $params, $action ) {
271 $settings = new Blacklist_Lockout();
272 $ip = $params['ip'];
273 if ( $ip && filter_var( $ip, FILTER_VALIDATE_IP ) ) {
274 $settings->remove_from_list( $ip, 'allowlist' );
275 $settings->add_to_list( $ip, 'blocklist' );
276 } else {
277 wp_send_json_error();
278 }
279 wp_send_json_success();
280 }
281
282 /**
283 * Push data into HUB. It's without timezone.
284 *
285 * @param array $params An array containing the data to push.
286 * @param string $action The action to perform.
287 */
288 public function get_stats( $params, $action ) {
289 $data = $this->build_stats_to_hub();
290 wp_send_json_success(
291 array( 'stats' => $data )
292 );
293 }
294
295 /**
296 * Push scan data into HUB.
297 */
298 public function get_scan_progress() {
299 $model = \WP_Defender\Model\Scan::get_active();
300 if ( ! is_object( $model ) ) {
301 wp_send_json_success(
302 array( 'progress' => - 1 )
303 );
304 }
305 $percent = $model->percent;
306 if ( $percent > 100 ) {
307 $percent = 100;
308 }
309 wp_send_json_success(
310 array( 'progress' => $percent )
311 );
312 }
313
314 /**
315 * Export settings to HUB.
316 * Analog to export_strings but return not array. So separated method.
317 */
318 public function export_settings() {
319 $config_component = wd_di()->get( Backup_Settings::class );
320 $data = $config_component->parse_data_for_hub();
321 // Replace all the new line in configs.
322 $configs = $data['configs'];
323 foreach ( $configs as $module => $mdata ) {
324 foreach ( $mdata as $key => $value ) {
325 if ( is_string( $value ) ) {
326 $value = str_replace( array( "\r", "\n" ), '{nl}', $value );
327 $mdata[ $key ] = $value;
328 }
329 }
330 $configs[ $module ] = $mdata;
331 }
332 $data['configs'] = $configs;
333 wp_send_json_success( $data );
334 }
335
336 /**
337 * Import settings from HUB.
338 * Analog to import_data but with object $params. So separated method.
339 *
340 * @param object object $params Request parameters.
341 */
342 public function import_settings( $params ) {
343 // Dirty but quick.
344 if (
345 ! isset( $params->configs )
346 || ! ( is_array( $params->configs ) || is_object( $params->configs ) )
347 || ( is_array( $params->configs ) && array() === $params->configs )
348 || ( is_object( $params->configs ) && 0 === count( get_object_vars( $params->configs ) ) )
349 ) {
350 wp_send_json_error(
351 array( 'message' => esc_html__( 'Invalid config', 'defender-security' ) )
352 );
353 }
354
355 $configs = json_decode( wp_json_encode( $params->configs ), true );
356 if ( array() === $configs ) {
357 wp_send_json_error(
358 array( 'message' => esc_html__( 'Empty data', 'defender-security' ) )
359 );
360 }
361
362 $config_component = wd_di()->get( Backup_Settings::class );
363 $lockout_service = wd_di()->get( \WP_Defender\Component\Blacklist_Lockout::class );
364 foreach ( $configs as $module => $mdata ) {
365 foreach ( $mdata as $key => $value ) {
366 // Todo: update logic to import/export whitelisted/blocklisted countries via maxmind_license_key.
367 if ( in_array( $key, array( 'geoIP_db', 'geodb_path' ), true ) ) {
368 if ( is_string( $value ) && '' !== trim( $value ) ) {
369 // Download it.
370 $lockout_service->is_geodb_downloaded();
371 } else {
372 // Reset it.
373 $mdata[ $key ] = '';
374 }
375 } elseif ( is_string( $value ) ) {
376 $value = str_replace( '{nl}', PHP_EOL, $value );
377 $mdata[ $key ] = $value;
378 }
379 }
380 $configs[ $module ] = $mdata;
381 }
382
383 // If it's old config structure then we upgrade configs to new format.
384 if ( array() !== $configs && ! $config_component->check_for_new_structure( $configs ) ) {
385 $adapter = wd_di()->get( Config_Adapter::class );
386 $configs = $adapter->upgrade( $configs );
387 }
388 $restore_result = $config_component->restore_data( $configs, 'hub' );
389 if ( is_string( $restore_result ) ) {
390 wp_send_json_error(
391 array( 'message' => $restore_result )
392 );
393 }
394
395 // Active config.
396 Config_Hub_Helper::active_config_from_hub_id( (int) $params->hub_config_id );
397
398 wp_send_json_success();
399 }
400
401 /**
402 * Build the json data for HUB 2.0.
403 */
404 public function defender_get_stats_v2() {
405 global $wp_version;
406
407 $audit_log = wd_di()->get( Audit_Logging::class );
408 $audit = $audit_log->summary_data( true );
409
410 $scan = \WP_Defender\Model\Scan::get_last();
411 $total = 0;
412 if ( is_object( $scan ) ) {
413 $total += count( $scan->get_issues() );
414 }
415 // Total number of Scan issues and Ignored items.
416 $scan_total_issues = $total;
417 // Exclude direct call of data_frontend().
418 $tweak_arr = wd_di()->get( Model_Security_Tweaks::class )->get_tweak_types();
419
420 $total += $tweak_arr['count_issues'];
421 // Get statuses of login/404/ua-request if Firewall Notification is enabled.
422 $firewall_notification = wd_di()->get( Firewall_Notification::class );
423
424 if ( 'enabled' === $firewall_notification->status ) {
425 $login_lockout = $firewall_notification->configs['login_lockout'];
426 $nf_lockout = $firewall_notification->configs['nf_lockout'];
427 // since 3.3.0.
428 $ua_lockout = $firewall_notification->configs['ua_lockout'] ?? false;
429 } else {
430 $login_lockout = false;
431 $nf_lockout = false;
432 $ua_lockout = false;
433 }
434
435 $status_active = \WP_Defender\Model\Notification::STATUS_ACTIVE;
436 $model_sec_headers = wd_di()->get( \WP_Defender\Model\Setting\Security_Headers::class );
437 $scan_report = wd_di()->get( Malware_Report::class );
438 $two_fa = wd_di()->get( Two_Fa::class );
439
440 $quarantined_files = class_exists( 'WP_Defender\Component\Quarantine' ) ?
441 wd_di()->get( Quarantine::class )->hub_list() : array();
442 $antibot_service = wd_di()->get( Antibot_Global_Firewall::class );
443
444 $ret = array(
445 'summary' => array(
446 'count' => $total,
447 'next_scan' => $scan_report->get_next_run_for_hub(),
448 ),
449 'report' => array(
450 'malware_scan' => $scan_report->get_next_run_as_string( true ),
451 'firewall' => wd_di()->get( Firewall_Report::class )->get_next_run_as_string( true ),
452 'audit_logging' => wd_di()->get( Audit_Report::class )->get_next_run_as_string( true ),
453 ),
454 'security_tweaks' => array(
455 'issues' => $tweak_arr['count_issues'],
456 'fixed' => $tweak_arr['count_fixed'],
457 'notification' => wd_di()->get( Tweak_Reminder::class )->status === $status_active,
458 'wp_version' => $wp_version,
459 'php_version' => PHP_VERSION,
460 ),
461 'malware_scan' => array(
462 'count' => $scan_total_issues,
463 'notification' => wd_di()->get( Malware_Notification::class )->status === $status_active,
464 ),
465 'firewall' => array(
466 'last_lockout' => Lockout_Log::get_last_lockout_date( true ),
467 '24_hours' => array(
468 'login_lockout' => Lockout_Log::count(
469 strtotime( '-24 hours' ),
470 time(),
471 array( Lockout_Log::AUTH_LOCK )
472 ),
473 '404_lockout' => Lockout_Log::count(
474 strtotime( '-24 hours' ),
475 time(),
476 array( Lockout_Log::LOCKOUT_404 )
477 ),
478 'user_agent_lockout' => Lockout_Log::count(
479 strtotime( '-24 hours' ),
480 time(),
481 array( Lockout_Log::LOCKOUT_UA )
482 ),
483 ),
484 '7_days' => array(
485 'login_lockout' => Lockout_Log::count_login_lockout_last_7_days(),
486 '404_lockout' => Lockout_Log::count_404_lockout_last_7_days(),
487 'user_agent_lockout' => Lockout_Log::count_ua_lockout_last_7_days(),
488 ),
489 '30_days' => array(
490 'login_lockout' => Lockout_Log::count(
491 strtotime( '-30 days' ),
492 time(),
493 array( Lockout_Log::AUTH_LOCK )
494 ),
495 '404_lockout' => Lockout_Log::count(
496 strtotime( '-30 days' ),
497 time(),
498 array( Lockout_Log::LOCKOUT_404 )
499 ),
500 'user_agent_lockout' => Lockout_Log::count(
501 strtotime( '-30 days' ),
502 time(),
503 array( Lockout_Log::LOCKOUT_UA )
504 ),
505 ),
506 'notification_status' => array(
507 'login_lockout' => $login_lockout,
508 '404_lockout' => $nf_lockout,
509 'ua_lockout' => $ua_lockout,
510 ),
511 'login_lockout_enabled' => wd_di()->get( Login_Lockout::class )->enabled,
512 'lockout_404_enabled' => wd_di()->get( Notfound_Lockout::class )->enabled,
513 'user_agent_lockout_enabled' => wd_di()->get( User_Agent_Lockout::class )->enabled,
514 'global_ip_list_enabled' => wd_di()->get( Global_Ip_Lockout::class )->enabled,
515 'antibot_enabled' => $antibot_service->frontend_is_enabled(),
516 'antibot_mode' => $antibot_service->frontend_mode(),
517 ),
518 'audit' => array(
519 'last_event' => $audit['lastEvent'],
520 '24_hours' => $audit['dayCount'],
521 '7_days' => $audit['weekCount'],
522 '30_days' => $audit['monthCount'],
523 'enabled' => $audit_log->model->is_active(),
524 ),
525 'advanced_tools' => array(
526 'security_headers' => array(
527 'sh_xframe' => $model_sec_headers->sh_xframe,
528 'sh_xss_protection' => $model_sec_headers->sh_xss_protection,
529 'sh_content_type_options' => $model_sec_headers->sh_content_type_options,
530 'sh_strict_transport' => $model_sec_headers->sh_strict_transport,
531 'sh_referrer_policy' => $model_sec_headers->sh_referrer_policy,
532 'sh_feature_policy' => $model_sec_headers->sh_feature_policy,
533 ),
534 'mask_login' => wd_di()->get( \WP_Defender\Model\Setting\Mask_Login::class )->is_active(),
535 // We'll change 'google_recaptcha'-key to 'captcha' in the future.
536 'google_recaptcha' => array(
537 'status' => wd_di()->get( \WP_Defender\Model\Setting\Captcha::class )->is_active(),
538 ),
539 'password_protection' => array(
540 'status' => wd_di()->get( \WP_Defender\Model\Setting\Password_Protection::class )->is_active(),
541 ),
542 ),
543 'two_fa' => array(
544 'status' => $two_fa->enabled,
545 'lost_phone' => $two_fa->lost_phone,
546 ),
547 'quarantined_files' => $quarantined_files,
548 );
549
550 wp_send_json_success(
551 array( 'stats' => $ret )
552 );
553 }
554
555 /**
556 * Synchronizes the data with the hub by making a POST request to the WPMUDEV API.
557 *
558 * @return void
559 */
560 public function hub_sync() {
561 $data = $this->build_stats_to_hub();
562 $this->make_wpmu_request(
563 WPMUDEV::API_HUB_SYNC,
564 $data,
565 array( 'method' => 'POST' )
566 );
567 }
568
569 /**
570 * Removes settings for all submodules.
571 */
572 public function remove_settings() {
573 }
574
575 /**
576 * Delete all the data & the cache.
577 */
578 public function remove_data() {
579 }
580
581 /**
582 * Placeholder for frontend data.
583 *
584 * @return void
585 */
586 public function data_frontend() {
587 }
588
589 /**
590 * Converts the current object state to an array.
591 *
592 * @return array The array representation of the object.
593 */
594 public function to_array(): array {
595 return array();
596 }
597
598 /**
599 * Placeholder for importing data.
600 *
601 * @param array $data Data to import.
602 */
603 public function import_data( array $data ) {
604 }
605
606 /**
607 * Exports strings.
608 *
609 * @return array An array of strings.
610 */
611 public function export_strings(): array {
612 return array();
613 }
614
615 /**
616 * Display Onboard if the bool value 'true' and vice versa.
617 *
618 * @param bool $is_show Settings to display.
619 */
620 public function set_onboarding_status( $is_show ) {
621 $this->view_onboard = $is_show;
622 }
623
624 /**
625 * Retrieve the Onboard status.
626 *
627 * @return bool
628 */
629 public function get_onboarding_status(): bool {
630 return $this->view_onboard;
631 }
632
633 /**
634 * Activate/deactivate Captcha from HUB.
635 */
636 public function manage_recaptcha() {
637 $response = null;
638 if ( class_exists( \WP_Defender\Model\Setting\Captcha::class ) ) {
639 $settings = new \WP_Defender\Model\Setting\Captcha();
640 $response = array();
641 if ( true === $settings->enabled ) {
642 $settings->enabled = false;
643 $response['enabled'] = false;
644 } else {
645 $settings->enabled = true;
646 $response['enabled'] = true;
647 }
648 $settings->save();
649 // Track.
650 if ( $this->is_tracking_active() ) {
651 $this->track_feature_from_hub( ! $settings->enabled, 'Google reCAPTCHA' );
652 }
653 }
654 wp_send_json_success( $response );
655 }
656
657 /**
658 * Activate/deactivate 2FA from HUB.
659 *
660 * @param array $params Request parameters.
661 */
662 public function manage_2fa( array $params ) {
663 $response = null;
664 if ( class_exists( Two_Fa::class ) ) {
665 $settings = wd_di()->get( Two_Fa::class );
666 $response = array();
667 if ( true === $settings->enabled ) {
668 $settings->enabled = false;
669 $response['enabled'] = false;
670 } else {
671 $settings->enabled = true;
672 $response['enabled'] = true;
673 }
674 $settings->save();
675 // Track.
676 if ( $this->is_tracking_active() ) {
677 // Only deactivation from the Hub.
678 $this->track_feature_from_hub( false, 'Two-Factor Authentication' );
679 }
680 }
681
682 wp_send_json_success( $response );
683 }
684
685 /**
686 * Activate/deactivate Global IP list from HUB.
687 *
688 * @param object $params Request parameters.
689 *
690 * @return void
691 * @since 3.4.0
692 */
693 public function manage_global_ip_list( object $params ): void {
694 if ( ! isset( $params->enable ) ) {
695 wp_send_json_error(
696 array( 'message' => esc_html__( 'Missing parameter(s)', 'defender-security' ) )
697 );
698 }
699
700 $response = null;
701 if ( class_exists( Global_Ip_Lockout::class ) ) {
702 $settings = wd_di()->get( Global_Ip_Lockout::class );
703
704 $response = array();
705 if ( true === $params->enable ) {
706 $settings->enabled = true;
707 $response['enabled'] = true;
708 } else {
709 $settings->enabled = false;
710 $response['enabled'] = false;
711 }
712 $settings->save();
713 }
714 wp_send_json_success( $response );
715 }
716
717 /**
718 * Set Global IP list.
719 *
720 * @param object $params Request parameters.
721 *
722 * @return void
723 * @since 3.4.0
724 */
725 public function set_global_ips( object $params ): void {
726 $global_ip_component = wd_di()->get( Global_IP::class );
727 $result = $global_ip_component->set_global_ip_list( (array) $params );
728
729 if ( is_wp_error( $result ) ) {
730 wp_send_json_error(
731 array(
732 'message' => implode( ' ', $result->get_error_messages() ),
733 )
734 );
735 }
736
737 wp_send_json_success(
738 array( 'enabled' => $global_ip_component->is_global_ip_enabled() )
739 );
740 }
741
742 /**
743 * Get recent quarantined files.
744 */
745 public function get_quarantined_files(): void {
746 if ( ! class_exists( 'WP_Defender\Component\Quarantine' ) ) {
747 $result = array(
748 'message' => defender_quarantine_pro_only(),
749 'success' => false,
750 );
751
752 wp_send_json_error( $result );
753 }
754
755 $quarantine_obj = wd_di()->get( Quarantine::class );
756
757 $quarantined_files = $quarantine_obj->hub_list();
758
759 wp_send_json_success(
760 array( 'quarantined_files' => $quarantined_files )
761 );
762 }
763
764 /**
765 * Restores a quarantined file based on the provided parameters.
766 *
767 * @param object $params The parameters for restoring the quarantined file.
768 * Requires the 'id' property to be set.
769 *
770 * @return void
771 */
772 public function restore_quarantined_file( object $params ): void {
773 if ( ! class_exists( 'WP_Defender\Component\Quarantine' ) ) {
774 $result = array(
775 'message' => defender_quarantine_pro_only(),
776 'success' => false,
777 );
778
779 wp_send_json_error( $result );
780 }
781
782 if ( isset( $params->id ) ) {
783 $id = (int) $params->id;
784
785 $quarantine_obj = wd_di()->get( Quarantine::class );
786
787 $result = $quarantine_obj->restore_file( $id );
788
789 if ( isset( $result['success'] ) && false === $result['success'] ) {
790 wp_send_json_error( $result );
791 }
792
793 wp_send_json_success( $result );
794 }
795
796 wp_send_json_error(
797 array(
798 'message' => esc_html__( 'Missing parameter: id.', 'defender-security' ),
799 )
800 );
801 }
802
803 /**
804 * Handle plugin deactivation.
805 *
806 * @param string $plugin Path to the plugin file relative to the plugins directory.
807 *
808 * @return void
809 */
810 public function intercept_deactivate( $plugin ) {
811 if ( ! $this->is_tracking_active() ) {
812 return;
813 }
814
815 // Only if Defender.
816 if ( DEFENDER_PLUGIN_BASENAME !== $plugin ) {
817 return;
818 }
819
820 $action = defender_get_data_from_request( 'action', 'r' );
821 // Todo: this is a default value. Need to update it in the future.
822 $triggered_from = 'Unknown';
823 // Deactivated from WPMUDEV Dashboard.
824 if ( 'wdp-project-deactivate' === $action ) {
825 $triggered_from = 'Plugin deactivation - dashboard';
826 } elseif ( 'deactivate' === $action ) {
827 // Deactivated from WP plugins page.
828 $triggered_from = 'Plugin deactivation - wpadmin';
829 } elseif ( $this->is_hub_request() ) {
830 $triggered_from = 'Plugin deactivation - hub';
831 }
832
833 // Send plugin deactivation event.
834 $this->track_opt_toggle( false, $triggered_from );
835 }
836
837 /**
838 * Enable/Disable Antibot Functionality. Only for third party site.
839 *
840 * @param object $params Request parameters.
841 *
842 * @return void
843 * @since 4.11.0
844 */
845 public function set_antibot_status( object $params ): void {
846 if ( ! isset( $params->enable ) && ! isset( $params->mode ) ) {
847 wp_send_json_error(
848 array( 'message' => esc_html__( 'Missing parameter(s)', 'defender-security' ) )
849 );
850 }
851
852 if ( ! class_exists( Antibot_Global_Firewall_Setting::class ) ) {
853 wp_send_json_error(
854 array( 'message' => esc_html__( 'Missing class', 'defender-security' ) )
855 );
856 }
857
858 $is_updated = false;
859 $antibot_settings = wd_di()->get( Antibot_Global_Firewall_Setting::class );
860
861 if ( isset( $params->mode ) ) {
862 if ( ! in_array( $params->mode, Antibot_Global_Firewall_Setting::get_valid_modes(), true ) ) {
863 wp_send_json_error(
864 array( 'message' => esc_html__( 'Invalid mode', 'defender-security' ) )
865 );
866 }
867
868 $old_mode = $antibot_settings->mode;
869 $new_mode = $params->mode;
870 if ( $old_mode !== $new_mode ) {
871 $is_updated = true;
872 $antibot_settings->mode = $new_mode;
873 }
874 }
875
876 if ( isset( $params->enable ) ) {
877 $old_enabled = $antibot_settings->enabled;
878 $new_enabled = (bool) $params->enable;
879 if ( $old_enabled !== $new_enabled ) {
880 $is_updated = true;
881 $antibot_settings->enabled = $new_enabled;
882
883 // Track.
884 if ( $this->is_tracking_active() ) {
885 wd_di()->get( \WP_Defender\Helper\Analytics\Antibot::class )
886 ->track_antibot( $old_enabled, 'Hub' );
887 }
888 }
889 }
890
891 if ( $is_updated ) {
892 $antibot_settings->save();
893
894 /**
895 * Download and store the blocklist.
896 *
897 * @var Antibot_Global_Firewall $antibot_service
898 */
899 $antibot_service = wd_di()->get( Antibot_Global_Firewall::class );
900 if ( 'plugin' === $antibot_service->get_managed_by() && $antibot_service->is_enabled() ) {
901 $antibot_service->download_and_store_blocklist();
902 }
903 }
904
905 wp_send_json_success(
906 array(
907 'enabled' => $antibot_settings->enabled,
908 'mode' => $antibot_settings->mode,
909 )
910 );
911 }
912 }
913