PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.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
← All changes | src/controller/class-antibot-global-firewall.php +151 -83 5.6.1 → 6.3.0 View file →
@@ -71,8 +71,10 @@
71 71 $this->model = $model;
72 72 $this->service = $service;
73 73 $this->wpmudev = $wpmudev;
74 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' ) );
75 77 add_action( 'wpmudev_hub_connector_first_sync_completed', array( $this, 'maybe_hcm_connection_attempt' ) );
76 78
77 79 /**
78 80 * Download and store Blocklist from the API.
@@ -110,28 +112,29 @@
110 112 */
111 113 public function save_settings( Request $request ) {
112 114 $data = $request->get_data(
113 115 array(
114 - 'enabled' => array( 'type' => 'bool' ),
115 - 'managed_by' => array( 'type' => 'string' ),
116 + 'enabled' => array( 'type' => 'bool' ),
117 + 'managed_by' => array( 'type' => 'string' ),
116 118 // Temporary property.
117 - 'module_title' => array(
119 + 'module_title' => array(
118 120 'type' => 'string',
119 121 'sanitize' => 'sanitize_text_field',
120 122 ),
121 - 'module_location' => array(
123 + 'module_location' => array(
122 124 'type' => 'string',
123 125 'sanitize' => 'sanitize_text_field',
124 126 ),
127 + 'redirect_to_feature_page' => array( 'type' => 'bool' ),
125 128 // End.
126 129 )
127 130 );
128 - $old_enabled = (bool) $this->model->enabled;
131 + $old_enabled = $this->model->enabled;
129 132
130 133 $location = 'Feature Page';
131 134 // Split module's titles and locations.
132 135 if ( isset( $data['module_title'] ) && 'antibot' === $data['module_title'] ) {
133 - if ( empty( $data['module_location'] ) ) {
136 + if ( ! isset( $data['module_location'] ) || '' === $data['module_location'] ) {
134 137 $location = 'Dashboard';
135 138 } else {
136 139 $location = $data['module_location'];
137 140 unset( $data['module_location'] );
@@ -163,13 +166,8 @@
163 166 }
164 167 }
165 168
166 169 Config_Hub_Helper::set_clear_active_flag();
167 -
168 - // Hide the Antibot notice on the Dashboard page.
169 - if ( ! empty( $data['enabled'] ) ) {
170 - delete_site_option( Antibot_Global_Firewall_Component::NOTICE_SLUG );
171 - }
172 170 // Maybe track.
173 171 if ( ! defender_is_wp_cli() && $old_enabled !== $data['enabled'] ) {
174 172 wd_di()->get( Antibot_Analytics::class )->track_antibot( $old_enabled, $location );
175 173 }
@@ -177,13 +175,20 @@
177 175 $update_message = $this->get_update_message( $data, $old_enabled, Antibot_Global_Firewall_Setting::get_module_name() );
178 176 $referrer = wp_get_referer();
179 177 if ( $referrer && strpos( $referrer, 'page=wp-defender' ) !== false ) {
180 178 $update_message = sprintf(
181 - /* translators: 1: Bold open tag, 2: Bold close tag */
179 + /* translators: 1: Module name. */
182 180 __( '%s is now enabled.', 'defender-security' ),
183 181 '<strong>' . Antibot_Global_Firewall_Setting::get_module_name() . '</strong>'
184 182 );
185 183 }
184 +
185 + $data_frontend = $this->data_frontend();
186 +
187 + if ( isset( $data['redirect_to_feature_page'] ) && $data['redirect_to_feature_page'] ) {
188 + $data_frontend['redirect'] = network_admin_url( 'admin.php?page=wdf-ip-lockout' );
189 + }
190 +
186 191 return new Response(
187 192 true,
188 193 array_merge(
189 194 array(
@@ -189,9 +194,9 @@
189 194 array(
190 195 'message' => $update_message,
191 196 'auto_close' => true,
192 197 ),
193 - $this->data_frontend()
198 + $data_frontend
194 199 )
195 200 );
196 201 }
197 202
@@ -201,27 +206,15 @@
201 206 );
202 207 }
203 208
204 209 /**
205 - * Hide the Antibot notice.
206 - *
207 - * @return Response
208 - * @defender_route
209 - */
210 - public function hide_antibot_notice(): Response {
211 - delete_site_option( Antibot_Global_Firewall_Component::NOTICE_SLUG );
212 -
213 - return new Response( true, array() );
214 - }
215 -
216 - /**
217 210 * Queue assets and require data.
218 211 *
219 212 * @return void
220 213 */
221 214 public function enqueue_assets() {
222 - if ( $this->is_page_active() ) {
223 - wp_localize_script( 'def-iplockout', 'antibot', $this->data_frontend() );
215 + if ( ! $this->is_page_active() ) {
216 + return;
224 217 }
225 218 }
226 219
227 220 /**
@@ -229,22 +222,8 @@
229 222 *
230 223 * @return array
231 224 */
232 225 public function data_frontend(): array {
233 - /**
234 - * Show the onboarding reminder notice if:
235 - * 1. If the reminder time is set and the time difference is greater than a week.
236 - * 2. No click on the Cross icon before.
237 - */
238 - $is_reminder = false;
239 - $last_reminder = get_site_option( Onboard::REMINDER_KEY, 0 );
240 - if ( ! empty( $last_reminder ) ) {
241 - $time_diff = time() - $last_reminder;
242 - if ( $time_diff > WEEK_IN_SECONDS ) {
243 - $is_reminder = true;
244 - }
245 - }
246 -
247 226 $model_export = $this->model->export();
248 227 $model_export['managed_by'] = $this->service->get_managed_by();
249 228 $module_name = Antibot_Global_Firewall_Setting::get_module_name();
250 229
@@ -253,12 +232,12 @@
253 232 'model' => $model_export,
254 233 'misc' => array(
255 234 'module_slug' => Antibot_Global_Firewall_Setting::get_module_slug(),
256 235 'module_name' => $module_name,
257 - 'show_notice' => $is_reminder
258 - && (bool) get_site_option( Antibot_Global_Firewall_Component::NOTICE_SLUG, false ),
236 + 'show_notice' => false,
259 237 'sync_schedule' => __( 'Twice Daily', 'defender-security' ),
260 238 'ips_count' => $this->service->get_blocklisted_ip_count(),
239 + 'blocklist_stats_full' => $this->service->get_cached_blocklist_stats_data(),
261 240 'frontend_is_enabled' => $this->service->frontend_is_enabled(),
262 241 'frontend_mode' => $this->service->frontend_mode(),
263 242 'is_active' => $this->service->is_active(),
264 243 'show_stats_button' => ! $this->wpmudev->is_whitelabel_enabled(),
@@ -271,10 +250,10 @@
271 250 __( '%s is Inactive.', 'defender-security' ),
272 251 $module_name
273 252 ),
274 253 'current_user' => esc_html( wp_get_current_user()->display_name ?? __( 'User', 'defender-security' ) ),
275 - 'current_plan' => $this->get_membership_type(),
276 254 'is_expired_membership' => $this->is_expired_membership_type(),
255 + 'show_antibot_options' => $this->service->get_states_of_antibot_options_for_different_hosting_types(),
277 256 ),
278 257 ),
279 258 $this->dump_routes_and_nonces()
280 259 );
@@ -286,15 +265,15 @@
286 265 * @return void
287 266 */
288 267 public function handle_download_and_store_blocklist(): void {
289 268 if ( is_multisite() ) {
290 - $next_run = get_site_option( Antibot_Global_Firewall_Component::DOWNLOAD_SYNC_NEXT_RUN_OPTION, 0 );
291 - if ( ! empty( $next_run ) && $next_run > time() ) {
269 + $next_run = (int) get_site_option( Antibot_Global_Firewall_Component::DOWNLOAD_SYNC_NEXT_RUN_OPTION, 0 );
270 + if ( $next_run > 0 && $next_run > time() ) {
292 271 return;
293 272 }
294 273
295 - $interval = wd_di()->get( Scheduler::class )->get_cron_schedule_interval( Antibot_Global_Firewall_Component::DOWNLOAD_SYNC_SCHEDULE );
296 - $next_run = time() + ( ! empty( $interval ) ? $interval : 12 * HOUR_IN_SECONDS );
274 + $interval = (int) wd_di()->get( Scheduler::class )->get_cron_schedule_interval( Antibot_Global_Firewall_Component::DOWNLOAD_SYNC_SCHEDULE );
275 + $next_run = time() + ( $interval > 0 ? $interval : 12 * HOUR_IN_SECONDS );
297 276 update_site_option( Antibot_Global_Firewall_Component::DOWNLOAD_SYNC_NEXT_RUN_OPTION, $next_run );
298 277 }
299 278
300 279 if ( true === $this->service->is_active_via_plugin() ) {
@@ -319,9 +298,9 @@
319 298 public function maybe_hcm_connection_attempt() {
320 299 $data = get_site_transient( Hub_Connector::TRANSIENT_KEY );
321 300 $module_slug = $data['module_slug'] ?? '';
322 301
323 - if ( Antibot_Global_Firewall_Setting::get_module_slug() === $module_slug && self::get_status() ) {
302 + if ( Antibot_Global_Firewall_Setting::get_module_slug() === $module_slug && self::get_hcm_status() ) {
324 303 delete_site_transient( Hub_Connector::TRANSIENT_KEY );
325 304
326 305 if ( 'plugin' === $this->service->get_managed_by() ) {
327 306 $this->service->managed_by_plugin_action();
@@ -332,10 +311,14 @@
332 311 }
333 312
334 313 /**
335 314 * Export the data of this module, we will use this for export to HUB, create a preset etc.
315 + *
316 + * @return array
336 317 */
337 - public function to_array() {}
318 + public function to_array(): array {
319 + return array();
320 + }
338 321
339 322 /**
340 323 * Import the data from the HUB, or from the preset.
341 324 *
@@ -363,12 +346,16 @@
363 346 */
364 347 public function remove_data() {
365 348 $this->service->delete_blocklist();
366 349
350 + delete_site_option( Antibot_Global_Firewall_Component::DOWNLOAD_SYNC_NEXT_RUN_OPTION );
351 + // Don't display Antibot global notice. We can delete slugs about this notice in the future.
367 352 delete_site_option( Antibot_Global_Firewall_Component::NOTICE_SLUG );
368 - delete_site_option( Antibot_Global_Firewall_Component::DOWNLOAD_SYNC_NEXT_RUN_OPTION );
353 + delete_site_option( Antibot_Global_Firewall_Component::GLOBAL_NOTICE_TIME_OPTION );
354 + // Blocklist stats data.
369 355 delete_site_transient( Antibot_Global_Firewall_Component::BLOCKLIST_STATS_KEY . '_' . Antibot_Global_Firewall_Setting::MODE_BASIC );
370 356 delete_site_transient( Antibot_Global_Firewall_Component::BLOCKLIST_STATS_KEY . '_' . Antibot_Global_Firewall_Setting::MODE_STRICT );
357 + delete_site_transient( Antibot_Global_Firewall_Component::BLOCKLIST_STATS_FULL_KEY );
371 358 delete_site_transient( Antibot_Global_Firewall_Component::IS_SWITCHING_TO_PLUGIN_IN_PROGRESS );
372 359 }
373 360
374 361 /**
@@ -380,19 +367,8 @@
380 367 return array();
381 368 }
382 369
383 370 /**
384 - * Disconnect site from HUB.
385 - *
386 - * @defender_route
387 - * @return Response
388 - */
389 - public function disconnect_site(): Response {
390 - $this->logout();
391 - return new Response( true, array( 'message' => __( 'Your site has been disconnected successfully!', 'defender-security' ) ) );
392 - }
393 -
394 - /**
395 371 * Handle request to switch managed by.
396 372 *
397 373 * @defender_route
398 374 * @return Response
@@ -443,9 +419,9 @@
443 419 'sanitize' => 'sanitize_text_field',
444 420 ),
445 421 'email' => array(
446 422 'type' => 'string',
447 - 'sanitize' => 'sanitize_text_field',
423 + 'sanitize' => 'sanitize_email',
448 424 ),
449 425 'service' => array(
450 426 'type' => 'string',
451 427 'sanitize' => 'sanitize_text_field',
@@ -455,18 +431,40 @@
455 431 'sanitize' => 'sanitize_text_field',
456 432 ),
457 433 )
458 434 );
435 +
436 + $reporter_email = isset( $data['email'] ) ? trim( $data['email'] ) : '';
437 + if ( '' === $reporter_email || ! is_email( $reporter_email ) ) {
438 + return new Response(
439 + false,
440 + array(
441 + 'message' => esc_html__( 'A valid email address is required.', 'defender-security' ),
442 + )
443 + );
444 + }
445 +
459 446 // Logging.
460 447 $message = sprintf(
461 448 'IP: %s, email: %s, service: %s, reason: %s',
462 449 $data['ip'],
463 - $data['email'],
450 + $reporter_email,
464 451 $data['service'],
465 452 $data['reason']
466 453 );
467 454 $this->service->log_ip_message( $message );
468 455
456 + // Track the request. Forced so it operates independently of tracking consent.
457 + $this->forced_track(
458 + 'def_request_trusted_ip',
459 + array(
460 + 'IP Address' => $data['ip'],
461 + 'User Email' => $reporter_email,
462 + 'Service' => $data['service'],
463 + 'Reason' => $data['reason'],
464 + )
465 + );
466 +
469 467 return new Response( true, array() );
470 468 }
471 469
472 470 /**
@@ -500,8 +498,17 @@
500 498
501 499 $bl_service = wd_di()->get( Blacklist_Lockout::class );
502 500 $gi_service = wd_di()->get( Global_IP::class );
503 501
502 + $ip = $data['ip'];
503 +
504 + $is_ip_allowed = $bl_service->is_ip_whitelisted( $ip )
505 + || $bl_service->is_country_whitelist( $ip )
506 + || ( $gi_service->is_global_ip_enabled() && $gi_service->is_ip_allowed( $ip ) );
507 +
508 + // Fetch the latest Custom IP blocklist from the Hub so we don't rely on stale cached data.
509 + $gi_service->fetch_global_ip_list();
510 +
504 511 return new Response(
505 512 true,
506 513 array(
507 514 'success' => true,
@@ -506,11 +513,11 @@
506 513 array(
507 514 'success' => true,
508 515 'show_notice' => false,
509 516 'message' => __( 'The IP address is searched successfully.', 'defender-security' ),
510 - 'local' => $bl_service->is_blacklist( $data['ip'] ),
511 - 'central' => $gi_service->is_global_ip_enabled() && $gi_service->is_ip_blocked( $data['ip'] ),
512 - 'antibot' => $this->service->is_ip_blocked( $data['ip'] ),
517 + 'local' => ! $is_ip_allowed && $bl_service->is_blacklist( $data['ip'] ),
518 + 'central' => ! $is_ip_allowed && $gi_service->is_global_ip_enabled() && $gi_service->is_ip_blocked( $data['ip'] ),
519 + 'antibot' => ! $is_ip_allowed && $this->service->is_ip_blocked( $ip ),
513 520 )
514 521 );
515 522 }
516 523
@@ -539,17 +546,19 @@
539 546 'message' => esc_html__( 'Invalid IP address.', 'defender-security' ),
540 547 )
541 548 );
542 549 }
543 - $collection = 'allowlist';
550 + $collection = 'allowlist';
551 + $model = wd_di()->get( \WP_Defender\Model\Setting\Blacklist_Lockout::class );
552 + $already_in_list = $model->is_ip_in_list( $ip, $collection );
553 +
544 554 // Add to Local allowlist.
545 - $model = wd_di()->get( \WP_Defender\Model\Setting\Blacklist_Lockout::class );
546 - if ( ! $model->is_ip_in_list( $ip, $collection ) ) {
555 + if ( ! $already_in_list ) {
547 556 $model->add_to_list( $ip, $collection );
548 557 }
549 558 // Add to Custom IP allowlist.
550 559 $global_ip_service = wd_di()->get( Global_IP::class );
551 - if ( $global_ip_service->can_central_ip_autosync() ) {
560 + if ( ! $already_in_list && $global_ip_service->can_central_ip_autosync() ) {
552 561 $data = array(
553 562 'allow_list' => array( $ip ),
554 563 );
555 564
@@ -563,22 +572,40 @@
563 572 );
564 573 }
565 574 }
566 575
576 + $manage_link_open = '<a href="' . network_admin_url( 'admin.php?page=wdf-ip-lockout&view=blocklist#tab-ip-allowlist' ) . '">';
577 + $manage_link_close = '</a>';
578 +
579 + if ( $already_in_list ) {
580 + $message = sprintf(
581 + /* translators: 1: IP address. 2: Opening anchor tag. 3: Closing anchor tag. */
582 + esc_html__(
583 + 'IP %1$s is already in your Site\'s allowlist. You can manage it in %2$sIP Lockouts%3$s.',
584 + 'defender-security'
585 + ),
586 + $ip,
587 + $manage_link_open,
588 + $manage_link_close
589 + );
590 + } else {
591 + $message = sprintf(
592 + /* translators: 1: IP address. 2: Opening anchor tag. 3: Closing anchor tag. */
593 + esc_html__(
594 + 'IP %1$s has been added to your Site\'s allowlist. You can manage it in %2$sIP Lockouts%3$s.',
595 + 'defender-security'
596 + ),
597 + $ip,
598 + $manage_link_open,
599 + $manage_link_close
600 + );
601 + }
602 +
567 603 return new Response(
568 604 true,
569 605 array(
570 - 'message' => sprintf(
571 - /* translators: 1: IP address. 2: Opening anchor tag. 3: Closing anchor tag. */
572 - esc_html__(
573 - 'IP %1$s has been added to your Site\'s allowlist. You can manage it in %2$sIP Lockouts%3$s.',
574 - 'defender-security'
575 - ),
576 - $ip,
577 - '<a href="' . network_admin_url( 'admin.php?page=wdf-ip-lockout&view=blocklist#tab-ip-allowlist' ) . '">',
578 - '</a>'
579 - ),
580 - 'interval' => 5,
606 + 'message' => $message,
607 + 'already_in_list' => $already_in_list,
581 608 )
582 609 );
583 610 }
584 611
@@ -661,10 +688,51 @@
661 688 *
662 689 * @return void
663 690 */
664 691 public function handle_expired_membership(): void {
665 - if ( $this->is_expired_membership_type() && $this->model->enabled ) {
692 + if ( $this->model->enabled && $this->is_expired_membership_type() ) {
666 693 $this->service->managed_by_plugin_action( false );
667 694 $this->log( 'AntiBot Global Firewall automatically disabled due to expired membership.', Antibot_Global_Firewall_Component::LOG_FILE_NAME );
668 695 }
696 + }
697 +
698 + /**
699 + * Handle request to send feedback.
700 + *
701 + * @param Request $request The request object.
702 + *
703 + * @defender_route
704 + * @return Response
705 + */
706 + public function send_feedback( Request $request ) {
707 + $data = $request->get_data(
708 + array(
709 + 'feedback' => array( 'type' => 'string' ),
710 + )
711 + );
712 + if ( '' !== $data['feedback'] ) {
713 + // Send feedback.
714 + $this->track_feature(
715 + 'Antibot Survey',
716 + array(
717 + 'Notice Action' => 'Share feedback',
718 + 'Feedback' => $data['feedback'],
719 + )
720 + );
721 + }
722 +
723 + $message = sprintf(
724 + /* translators: 1: Open tag, 2: Close tag */
725 + __( '%1$sThanks for your feedback!%2$s It helps us make Defender even better.', 'defender-security' ),
726 + '<strong>',
727 + '</strong>'
728 + );
729 +
730 + return new Response(
731 + true,
732 + array(
733 + 'message' => $message,
734 + 'auto_close' => true,
735 + )
736 + );
669 737 }
670 738 }