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-antibot-global-firewall.php

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

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