PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.0.0
Defender Security – Malware Scanner, Login Security & Firewall v6.0.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-antibot-global-firewall.php

class-antibot-global-firewall.php in Defender Security – Malware Scanner, Login Security & Firewall 6.0.0, at src/controller/class-antibot-global-firewall.php

794 lines 22.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * It handles functionalities such as saving settings and handle the request for downloading the IPs from AntiBot Global Firewall.
4 *
5 * @package WP_Defender\Controller
6 */
7
8 namespace WP_Defender\Controller;
9
10 use Calotes\Component\Request;
11 use Calotes\Component\Response;
12 use WP_Defender\Component\Network_Cron_Manager;
13 use WP_Defender\Component\Config\Config_Hub_Helper;
14 use WP_Defender\Event;
15 use WP_Defender\Traits\Setting;
16 use WP_Defender\Traits\Defender_Dashboard_Client;
17 use WP_Defender\Model\Setting\Antibot_Global_Firewall_Setting;
18 use WP_Defender\Behavior\WPMUDEV;
19 use WP_Defender\Component\IP\Antibot_Global_Firewall as Antibot_Global_Firewall_Component;
20 use WP_Defender\Component\Blacklist_Lockout;
21 use WP_Defender\Component\IP\Global_IP;
22 use WP_Defender\Component\Scheduler\Scheduler;
23 use WP_Defender\Helper\Analytics\Antibot as Antibot_Analytics;
24
25 /**
26 * Class Antibot_Global_Firewall.
27 */
28 class Antibot_Global_Firewall extends Event {
29 use Setting;
30 use Defender_Dashboard_Client;
31
32 /**
33 * The slug identifier for this controller.
34 *
35 * @var string
36 */
37 protected $slug = 'wdf-ip-lockout';
38
39 /**
40 * The model for handling AntiBot Global Firewall settings.
41 *
42 * @var Antibot_Global_Firewall_Setting
43 */
44 protected $model;
45
46 /**
47 * The service for handling AntiBot Global Firewall logic.
48 *
49 * @var Antibot_Global_Firewall_Component
50 */
51 protected $service;
52
53 /**
54 * The WPMUDEV instance.
55 *
56 * @var WPMUDEV
57 */
58 private $wpmudev;
59
60 /**
61 * Initializes the class with model and service.
62 *
63 * @param Antibot_Global_Firewall_Setting $model The model for handling AntiBot Global Firewall settings.
64 * @param Antibot_Global_Firewall_Component $service The service for handling AntiBot Global Firewall logic.
65 * @param WPMUDEV $wpmudev The WPMUDEV instance.
66 */
67 public function __construct( Antibot_Global_Firewall_Setting $model, Antibot_Global_Firewall_Component $service, WPMUDEV $wpmudev ) {
68 $this->register_routes();
69 add_action( 'defender_enqueue_assets', array( $this, 'enqueue_assets' ) );
70
71 $this->model = $model;
72 $this->service = $service;
73 $this->wpmudev = $wpmudev;
74
75 add_action( 'admin_init', array( $this, 'maybe_hcm_connection_attempt' ), 20 );
76 add_action( 'wpdef_hub_connector_synced', array( $this, 'maybe_hcm_connection_attempt' ) );
77 add_action( 'wpmudev_hub_connector_first_sync_completed', array( $this, 'maybe_hcm_connection_attempt' ) );
78
79 /**
80 * Download and store Blocklist from the API.
81 */
82 if ( $this->service->is_active_via_plugin() ) {
83 /**
84 * Network Cron Manager
85 *
86 * @var Network_Cron_Manager $network_cron_manager
87 */
88 $network_cron_manager = wd_di()->get( Network_Cron_Manager::class );
89 $network_cron_manager->register_callback(
90 'wpdef_antibot_global_firewall_fetch_blocklist',
91 array( $this, 'handle_download_and_store_blocklist' ),
92 12 * HOUR_IN_SECONDS,
93 time() + 15
94 );
95 } elseif ( wp_next_scheduled( 'wpdef_antibot_global_firewall_fetch_blocklist' ) ) {
96 wp_clear_scheduled_hook( 'wpdef_antibot_global_firewall_fetch_blocklist' );
97 }
98
99 if ( $this->wpmudev->is_wpmu_hosting() ) {
100 add_action( 'init', array( $this, 'sync_state' ) );
101 }
102 add_action( 'init', array( $this, 'handle_expired_membership' ) );
103 add_action( 'init', array( $this->service, 'maybe_set_notice_time' ) );
104 }
105
106 /**
107 * Handle request to save settings.
108 *
109 * @param Request $request The request object.
110 *
111 * @defender_route
112 * @return Response
113 */
114 public function save_settings( Request $request ) {
115 $data = $request->get_data(
116 array(
117 'enabled' => array( 'type' => 'bool' ),
118 'managed_by' => array( 'type' => 'string' ),
119 // Temporary property.
120 'module_title' => array(
121 'type' => 'string',
122 'sanitize' => 'sanitize_text_field',
123 ),
124 'module_location' => array(
125 'type' => 'string',
126 'sanitize' => 'sanitize_text_field',
127 ),
128 'redirect_to_feature_page' => array( 'type' => 'bool' ),
129 // End.
130 )
131 );
132 $old_enabled = $this->model->enabled;
133
134 $location = 'Feature Page';
135 // Split module's titles and locations.
136 if ( isset( $data['module_title'] ) && 'antibot' === $data['module_title'] ) {
137 if ( ! isset( $data['module_location'] ) || '' === $data['module_location'] ) {
138 $location = 'Dashboard';
139 } else {
140 $location = $data['module_location'];
141 unset( $data['module_location'] );
142 }
143 unset( $data['module_title'] );
144 }
145
146 $this->model->import( $data );
147 if ( $this->model->validate() ) {
148 $this->model->save();
149
150 if ( 'plugin' === $this->service->get_managed_by() ) {
151 if ( $old_enabled !== $this->model->enabled ) {
152 if ( ! $this->model->enabled ) {
153 $this->service->delete_blocklist();
154 } elseif ( $this->model->enabled && $this->service->maybe_download() ) {
155 $this->service->download_and_store_blocklist();
156 }
157 }
158 } else {
159 $old_enabled = $this->service->frontend_is_enabled();
160 $result = $this->service->toggle_on_hosting( $this->model->enabled );
161
162 if ( is_wp_error( $result ) ) {
163 return new Response(
164 false,
165 array( 'message' => esc_html__( 'Something wrong happened, please try again!', 'defender-security' ) )
166 );
167 }
168 }
169
170 Config_Hub_Helper::set_clear_active_flag();
171
172 // Hide the Antibot notice on the Dashboard page.
173 if ( isset( $data['enabled'] ) && true === (bool) $data['enabled'] ) {
174 delete_site_option( Antibot_Global_Firewall_Component::NOTICE_SLUG );
175 }
176 // Maybe track.
177 if ( ! defender_is_wp_cli() && $old_enabled !== $data['enabled'] ) {
178 wd_di()->get( Antibot_Analytics::class )->track_antibot( $old_enabled, $location );
179 }
180
181 $update_message = $this->get_update_message( $data, $old_enabled, Antibot_Global_Firewall_Setting::get_module_name() );
182 $referrer = wp_get_referer();
183 if ( $referrer && strpos( $referrer, 'page=wp-defender' ) !== false ) {
184 $update_message = sprintf(
185 /* translators: 1: Module name. */
186 __( '%s is now enabled.', 'defender-security' ),
187 '<strong>' . Antibot_Global_Firewall_Setting::get_module_name() . '</strong>'
188 );
189 }
190
191 $data_frontend = $this->data_frontend();
192
193 if ( isset( $data['redirect_to_feature_page'] ) && $data['redirect_to_feature_page'] ) {
194 $data_frontend['redirect'] = network_admin_url( 'admin.php?page=wdf-ip-lockout' );
195 }
196
197 return new Response(
198 true,
199 array_merge(
200 array(
201 'message' => $update_message,
202 'auto_close' => true,
203 ),
204 $data_frontend
205 )
206 );
207 }
208
209 return new Response(
210 false,
211 array( 'message' => $this->model->get_formatted_errors() )
212 );
213 }
214
215 /**
216 * Hide the Antibot notice.
217 *
218 * @return Response
219 * @defender_route
220 */
221 public function hide_antibot_notice(): Response {
222 delete_site_option( Antibot_Global_Firewall_Component::NOTICE_SLUG );
223
224 return new Response( true, array() );
225 }
226
227 /**
228 * Queue assets and require data.
229 *
230 * @return void
231 */
232 public function enqueue_assets() {
233 if ( ! $this->is_page_active() ) {
234 return;
235 }
236 }
237
238 /**
239 * All the variables that we will show on frontend, both in the main page, or dashboard widget.
240 *
241 * @return array
242 */
243 public function data_frontend(): array {
244 /**
245 * Show the onboarding reminder notice if:
246 * 1. If the reminder time is set and the time difference is greater than a week.
247 * 2. No click on the Cross icon before.
248 * 3. This is not on Unlimited hosting.
249 */
250 $is_reminder = false;
251 $last_reminder = (int) get_site_option( Onboard::REMINDER_KEY, 0 );
252 if ( $last_reminder > 0 ) {
253 $time_diff = time() - $last_reminder;
254 if ( $time_diff > WEEK_IN_SECONDS ) {
255 $is_reminder = true;
256 }
257 }
258
259 $model_export = $this->model->export();
260 $model_export['managed_by'] = $this->service->get_managed_by();
261 $module_name = Antibot_Global_Firewall_Setting::get_module_name();
262
263 return array_merge(
264 array(
265 'model' => $model_export,
266 'misc' => array(
267 'module_slug' => Antibot_Global_Firewall_Setting::get_module_slug(),
268 'module_name' => $module_name,
269 'show_notice' => $is_reminder
270 && (bool) get_site_option( Antibot_Global_Firewall_Component::NOTICE_SLUG )
271 && ! defender_is_unlimited_hosting(),
272 'sync_schedule' => __( 'Twice Daily', 'defender-security' ),
273 'ips_count' => $this->service->get_blocklisted_ip_count(),
274 'blocklist_stats_full' => $this->service->get_cached_blocklist_stats_data(),
275 'frontend_is_enabled' => $this->service->frontend_is_enabled(),
276 'frontend_mode' => $this->service->frontend_mode(),
277 'is_active' => $this->service->is_active(),
278 'show_stats_button' => ! $this->wpmudev->is_whitelabel_enabled(),
279 'show_checker' => ! $this->wpmudev->is_wpmu_hosting()
280 || $this->wpmudev->is_wpmu_dev_admin()
281 || ! ( $this->service->is_active_via_hosting() && $this->wpmudev->is_whitelabel_enabled() ),
282 'active_tooltip_text' => __( 'List of exploit attempts detected and blocked across all connected sites by AntiBot Firewall.', 'defender-security' ),
283 'inactive_tooltip_text' => sprintf(
284 /* translators: %s: Module name. */
285 __( '%s is Inactive.', 'defender-security' ),
286 $module_name
287 ),
288 'current_user' => esc_html( wp_get_current_user()->display_name ?? __( 'User', 'defender-security' ) ),
289 'is_expired_membership' => $this->is_expired_membership_type(),
290 'should_show_global_notice' => $this->service->should_show_global_notice(),
291 'show_antibot_options' => $this->service->get_states_of_antibot_options_for_different_hosting_types(),
292 ),
293 ),
294 $this->dump_routes_and_nonces()
295 );
296 }
297
298 /**
299 * Download and store blocklist.
300 *
301 * @return void
302 */
303 public function handle_download_and_store_blocklist(): void {
304 if ( is_multisite() ) {
305 $next_run = (int) get_site_option( Antibot_Global_Firewall_Component::DOWNLOAD_SYNC_NEXT_RUN_OPTION, 0 );
306 if ( $next_run > 0 && $next_run > time() ) {
307 return;
308 }
309
310 $interval = (int) wd_di()->get( Scheduler::class )->get_cron_schedule_interval( Antibot_Global_Firewall_Component::DOWNLOAD_SYNC_SCHEDULE );
311 $next_run = time() + ( $interval > 0 ? $interval : 12 * HOUR_IN_SECONDS );
312 update_site_option( Antibot_Global_Firewall_Component::DOWNLOAD_SYNC_NEXT_RUN_OPTION, $next_run );
313 }
314
315 if ( true === $this->service->is_active_via_plugin() ) {
316 $is_switch_to_main_site = is_multisite() && ! is_main_site();
317 if ( $is_switch_to_main_site ) {
318 switch_to_blog( get_main_site_id() );
319 }
320
321 $this->service->download_and_store_blocklist();
322
323 if ( $is_switch_to_main_site ) {
324 restore_current_blog();
325 }
326 }
327 }
328
329 /**
330 * Handle the HCM connection attempt via Antibot page.
331 *
332 * @return void
333 */
334 public function maybe_hcm_connection_attempt() {
335 $data = get_site_transient( Hub_Connector::TRANSIENT_KEY );
336 $module_slug = $data['module_slug'] ?? '';
337
338 if ( Antibot_Global_Firewall_Setting::get_module_slug() === $module_slug && self::get_hcm_status() ) {
339 delete_site_transient( Hub_Connector::TRANSIENT_KEY );
340
341 if ( 'plugin' === $this->service->get_managed_by() ) {
342 $this->service->managed_by_plugin_action();
343 } else {
344 $this->service->managed_by_hosting_action();
345 }
346 }
347 }
348
349 /**
350 * Export the data of this module, we will use this for export to HUB, create a preset etc.
351 *
352 * @return array
353 */
354 public function to_array(): array {
355 return array();
356 }
357
358 /**
359 * Import the data from the HUB, or from the preset.
360 *
361 * @param array $data The data to be imported.
362 *
363 * @return void
364 */
365 public function import_data( $data ) {
366 $model = $this->model;
367 if ( isset( $data['antibot'] ) ) {
368 $model->enabled = (bool) $data['antibot'];
369 } else {
370 $model->enabled = true;
371 }
372 $model->save();
373 }
374
375 /**
376 * Remove all settings, configs generated in this container runtime.
377 */
378 public function remove_settings() {}
379
380 /**
381 * Remove all data.
382 */
383 public function remove_data() {
384 $this->service->delete_blocklist();
385
386 delete_site_option( Antibot_Global_Firewall_Component::NOTICE_SLUG );
387 delete_site_option( Antibot_Global_Firewall_Component::DOWNLOAD_SYNC_NEXT_RUN_OPTION );
388 delete_site_option( Antibot_Global_Firewall_Component::GLOBAL_NOTICE_TIME_OPTION );
389 delete_site_transient( Antibot_Global_Firewall_Component::BLOCKLIST_STATS_KEY . '_' . Antibot_Global_Firewall_Setting::MODE_BASIC );
390 delete_site_transient( Antibot_Global_Firewall_Component::BLOCKLIST_STATS_KEY . '_' . Antibot_Global_Firewall_Setting::MODE_STRICT );
391 delete_site_transient( Antibot_Global_Firewall_Component::BLOCKLIST_STATS_FULL_KEY );
392 delete_site_transient( Antibot_Global_Firewall_Component::IS_SWITCHING_TO_PLUGIN_IN_PROGRESS );
393 }
394
395 /**
396 * Export strings.
397 *
398 * @return array
399 */
400 public function export_strings() {
401 return array();
402 }
403
404 /**
405 * Handle request to switch managed by.
406 *
407 * @defender_route
408 * @return Response
409 */
410 public function switch_managed_by(): Response {
411 $result = $this->service->switch_managed_by();
412 if ( false !== $result ) {
413 return new Response(
414 true,
415 array(
416 'message' => sprintf(
417 /* translators: 1. Open tag. 2. Close tag. 3. Managed by label. */
418 __( '%1$sAntiBot%2$s blocklist is now being managed by %3$s.', 'defender-security' ),
419 '<strong>',
420 '</strong>',
421 $this->service->get_managed_by_label()
422 ),
423 'managed_by' => $result,
424 'frontend_mode' => $this->service->frontend_mode(),
425 'ips_count' => $this->service->get_blocklisted_ip_count(),
426 'auto_close' => true,
427 )
428 );
429 }
430
431 return new Response(
432 false,
433 array(
434 'message' => __( 'Failed to switch. Please try again.', 'defender-security' ),
435 'auto_close' => true,
436 )
437 );
438 }
439
440 /**
441 * Various actions during form submission.
442 *
443 * @param Request $request The HTTP request object.
444 *
445 * @defender_route
446 * @return Response
447 */
448 public function blocklist_checker_submit_trusted_ip_form( Request $request ): Response {
449 $data = $request->get_data(
450 array(
451 'ip' => array(
452 'type' => 'string',
453 'sanitize' => 'sanitize_text_field',
454 ),
455 'email' => array(
456 'type' => 'string',
457 'sanitize' => 'sanitize_email',
458 ),
459 'service' => array(
460 'type' => 'string',
461 'sanitize' => 'sanitize_text_field',
462 ),
463 'reason' => array(
464 'type' => 'string',
465 'sanitize' => 'sanitize_text_field',
466 ),
467 )
468 );
469
470 $reporter_email = isset( $data['email'] ) ? trim( $data['email'] ) : '';
471 if ( '' === $reporter_email || ! is_email( $reporter_email ) ) {
472 return new Response(
473 false,
474 array(
475 'message' => esc_html__( 'A valid email address is required.', 'defender-security' ),
476 )
477 );
478 }
479
480 // Logging.
481 $message = sprintf(
482 'IP: %s, email: %s, service: %s, reason: %s',
483 $data['ip'],
484 $reporter_email,
485 $data['service'],
486 $data['reason']
487 );
488 $this->service->log_ip_message( $message );
489
490 // Track the request. Forced so it operates independently of tracking consent.
491 $this->forced_track(
492 'def_request_trusted_ip',
493 array(
494 'IP Address' => $data['ip'],
495 'User Email' => $reporter_email,
496 'Service' => $data['service'],
497 'Reason' => $data['reason'],
498 )
499 );
500
501 return new Response( true, array() );
502 }
503
504 /**
505 * Check if an IP exists in the Local, Custom and AntiBot blocklist.
506 *
507 * @param Request $request The HTTP request object.
508 *
509 * @defender_route
510 * @return Response
511 */
512 public function blocklist_checker_search( Request $request ): Response {
513 $data = $request->get_data(
514 array(
515 'ip' => array(
516 'type' => 'string',
517 'sanitize' => 'sanitize_text_field',
518 ),
519 )
520 );
521
522 if ( false === filter_var( $data['ip'], FILTER_VALIDATE_IP ) ) {
523 return new Response(
524 false,
525 array(
526 'success' => false,
527 'show_notice' => false,
528 'message' => __( 'Invalid IP address.', 'defender-security' ),
529 )
530 );
531 }
532
533 $bl_service = wd_di()->get( Blacklist_Lockout::class );
534 $gi_service = wd_di()->get( Global_IP::class );
535
536 $ip = $data['ip'];
537
538 $is_ip_allowed = $bl_service->is_ip_whitelisted( $ip )
539 || $bl_service->is_country_whitelist( $ip )
540 || ( $gi_service->is_global_ip_enabled() && $gi_service->is_ip_allowed( $ip ) );
541
542 // Fetch the latest Custom IP blocklist from the Hub so we don't rely on stale cached data.
543 $gi_service->fetch_global_ip_list();
544
545 return new Response(
546 true,
547 array(
548 'success' => true,
549 'show_notice' => false,
550 'message' => __( 'The IP address is searched successfully.', 'defender-security' ),
551 'local' => ! $is_ip_allowed && $bl_service->is_blacklist( $data['ip'] ),
552 'central' => ! $is_ip_allowed && $gi_service->is_global_ip_enabled() && $gi_service->is_ip_blocked( $data['ip'] ),
553 'antibot' => ! $is_ip_allowed && $this->service->is_ip_blocked( $ip ),
554 )
555 );
556 }
557
558 /**
559 * Add IP to AntiBot allowlist.
560 *
561 * @param Request $request The HTTP request object.
562 *
563 * @defender_route
564 * @return Response
565 */
566 public function blocklist_checker_add_ip_to_allowlist( Request $request ): Response {
567 $data = $request->get_data(
568 array(
569 'ip' => array(
570 'type' => 'string',
571 'sanitize' => 'sanitize_text_field',
572 ),
573 )
574 );
575 $ip = $data['ip'];
576 if ( false === filter_var( $ip, FILTER_VALIDATE_IP ) ) {
577 return new Response(
578 false,
579 array(
580 'message' => esc_html__( 'Invalid IP address.', 'defender-security' ),
581 )
582 );
583 }
584 $collection = 'allowlist';
585 $model = wd_di()->get( \WP_Defender\Model\Setting\Blacklist_Lockout::class );
586 $already_in_list = $model->is_ip_in_list( $ip, $collection );
587
588 // Add to Local allowlist.
589 if ( ! $already_in_list ) {
590 $model->add_to_list( $ip, $collection );
591 }
592 // Add to Custom IP allowlist.
593 $global_ip_service = wd_di()->get( Global_IP::class );
594 if ( ! $already_in_list && $global_ip_service->can_central_ip_autosync() ) {
595 $data = array(
596 'allow_list' => array( $ip ),
597 );
598
599 $res = $global_ip_service->add_to_global_ip_list( $data );
600 if ( is_wp_error( $res ) ) {
601 return new Response(
602 false,
603 array(
604 'message' => $res->get_error_message(),
605 )
606 );
607 }
608 }
609
610 $manage_link_open = '<a href="' . network_admin_url( 'admin.php?page=wdf-ip-lockout&view=blocklist#tab-ip-allowlist' ) . '">';
611 $manage_link_close = '</a>';
612
613 if ( $already_in_list ) {
614 $message = sprintf(
615 /* translators: 1: IP address. 2: Opening anchor tag. 3: Closing anchor tag. */
616 esc_html__(
617 'IP %1$s is already in your Site\'s allowlist. You can manage it in %2$sIP Lockouts%3$s.',
618 'defender-security'
619 ),
620 $ip,
621 $manage_link_open,
622 $manage_link_close
623 );
624 } else {
625 $message = sprintf(
626 /* translators: 1: IP address. 2: Opening anchor tag. 3: Closing anchor tag. */
627 esc_html__(
628 'IP %1$s has been added to your Site\'s allowlist. You can manage it in %2$sIP Lockouts%3$s.',
629 'defender-security'
630 ),
631 $ip,
632 $manage_link_open,
633 $manage_link_close
634 );
635 }
636
637 return new Response(
638 true,
639 array(
640 'message' => $message,
641 'already_in_list' => $already_in_list,
642 )
643 );
644 }
645
646 /**
647 * Sync AntiBot status with Hosting.
648 * If AntiBot is enabled in Hosting, update the 'managed_by' and 'enabled' status.
649 * If AntiBot is disabled in Hosting, do nothing.
650 *
651 * @return void
652 */
653 public function sync_state(): void {
654 $hosting_enabled = defender_get_hosting_feature_state( 'antibot' );
655
656 if (
657 true === $hosting_enabled
658 && 'plugin' === $this->model->managed_by
659 && true !== get_site_transient( Antibot_Global_Firewall_Component::IS_SWITCHING_TO_PLUGIN_IN_PROGRESS )
660 ) {
661 $this->model->enabled = false;
662 $this->model->managed_by = 'hosting';
663 $this->model->save();
664 }
665 }
666
667 /**
668 * Handle request to switch mode.
669 *
670 * @defender_route
671 * @return Response
672 */
673 public function switch_mode(): Response {
674 $result = $this->process_switch_mode();
675 if ( $result['success'] ) {
676 if ( $this->maybe_track() ) {
677 wd_di()->get( Antibot_Analytics::class )->track_antibot( false, 'Feature Page' );
678 }
679 return new Response( true, $result['data'] );
680 }
681
682 return new Response( false, $result['data'] );
683 }
684
685 /**
686 * Process request to switch mode.
687 *
688 * @return array
689 */
690 public function process_switch_mode(): array {
691 $result = $this->service->switch_mode();
692 if ( false !== $result && ! is_wp_error( $result ) ) {
693 return array(
694 'success' => true,
695 'data' => array(
696 'message' => sprintf(
697 /* translators: 1. Open tag. 2. Close tag. 3. Mode. */
698 __( '%1$sAntiBot Firewall%2$s mode updated – You\'re now using %3$s Mode.', 'defender-security' ),
699 '<strong>',
700 '</strong>',
701 ucfirst( $result )
702 ),
703 'mode' => $result,
704 'ips_count' => $this->service->get_blocklisted_ip_count(),
705 'auto_close' => true,
706 ),
707 );
708 }
709
710 return array(
711 'success' => false,
712 'data' => array(
713 'message' => __( 'Failed to switch. Please try again.', 'defender-security' ),
714 'auto_close' => true,
715 ),
716 );
717 }
718
719 /**
720 * Handle expired membership by automatically disabling the AntiBot Global Firewall module.
721 * Logs the action when the feature is disabled due to expired membership.
722 *
723 * @return void
724 */
725 public function handle_expired_membership(): void {
726 if ( $this->model->enabled && $this->is_expired_membership_type() ) {
727 $this->service->managed_by_plugin_action( false );
728 $this->log( 'AntiBot Global Firewall automatically disabled due to expired membership.', Antibot_Global_Firewall_Component::LOG_FILE_NAME );
729 }
730 }
731
732 /**
733 * Handle request to send feedback.
734 *
735 * @param Request $request The request object.
736 *
737 * @defender_route
738 * @return Response
739 */
740 public function send_feedback( Request $request ) {
741 $data = $request->get_data(
742 array(
743 'feedback' => array( 'type' => 'string' ),
744 )
745 );
746 if ( '' !== $data['feedback'] ) {
747 // Send feedback.
748 $this->track_feature(
749 'Antibot Survey',
750 array(
751 'Notice Action' => 'Share feedback',
752 'Feedback' => $data['feedback'],
753 )
754 );
755 }
756 // Dismiss the global notice.
757 $this->service->dismiss_global_notice();
758
759 $message = sprintf(
760 /* translators: 1: Open tag, 2: Close tag */
761 __( '%1$sThanks for your feedback!%2$s It helps us make Defender even better.', 'defender-security' ),
762 '<strong>',
763 '</strong>'
764 );
765
766 return new Response(
767 true,
768 array(
769 'message' => $message,
770 'auto_close' => true,
771 )
772 );
773 }
774
775 /**
776 * Dismiss the global notice.
777 *
778 * @defender_route
779 * @return Response
780 */
781 public function dismiss_global_notice(): Response {
782 $this->service->dismiss_global_notice();
783
784 return new Response(
785 true,
786 array(
787 'message' => __( 'The global notice has been dismissed.', 'defender-security' ),
788 'success' => true,
789 'show_notice' => false,
790 )
791 );
792 }
793 }
794