PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.1.0
Defender Security – Malware Scanner, Login Security & Firewall v6.1.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 / class-admin.php

class-admin.php in Defender Security – Malware Scanner, Login Security & Firewall 6.1.0, at src/class-admin.php

693 lines 23.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles WordPress admin page related tasks.
4 *
5 * @package WP_Defender
6 */
7
8 namespace WP_Defender;
9
10 use WP_Defender\Component\Rate;
11 use WP_Defender\Behavior\WPMUDEV;
12 use WP_Defender\Component\Firewall;
13 use WP_Defender\Integrations\Dashboard_Whitelabel;
14 use WP_Defender\Component\Config\Config_Hub_Helper;
15 use WP_Defender\Helper\Analytics\Deactivation_Survey;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 die();
19 }
20
21 /**
22 * Handles WordPress admin page related tasks.
23 *
24 * @since 2.4
25 */
26 class Admin {
27
28 /**
29 * Is the Free version?
30 *
31 * @var bool
32 */
33 public $is_wp_org_version;
34
35 /**
36 * Constructor for the Admin class.
37 */
38 public function __construct() {
39 $this->is_wp_org_version = defender_is_wp_org_version();
40 add_action( 'wp_ajax_defender_ip_detection_notice_dismiss', array( $this, 'dismiss_notice' ) );
41 add_action( 'wp_ajax_defender_ip_detection_switch_to_xff', array( $this, 'switch_to_xff' ) );
42 add_action( 'wp_ajax_defender_track_deactivate', array( $this, 'track_deactivate' ) );
43 add_action( 'admin_head', array( $this, 'add_global_styles' ) );
44
45 // Deactivation survey.
46 add_action( 'admin_footer-plugins.php', array( $this, 'load_deactivation_survey_modal' ) );
47 }
48
49 /**
50 * Add global styles.
51 */
52 public function add_global_styles() {
53 echo '<style>
54 #toplevel_page_wp-defender ul.wp-submenu li a[href="admin.php?page=wdf-ip-lockout"] { display: flex; justify-content: space-between; align-items: center; }
55 #adminmenu li.wp-has-current-submenu a.wp-has-current-submenu { background-color: #4763E4 !important; }
56 #adminmenu .toplevel_page_wp-defender div.wp-menu-image.svg { width: 16px; height: 16px; margin-top: 10px; margin-left: 10px; background-size: 16px auto; }
57 </style>';
58 if ( ! $this->is_wp_org_version ) {
59 echo '<style>
60 #adminmenu .defender-admin-menu-pro-tag {
61 display: inline-block;
62 padding: 0;
63 color: inherit;
64 border: 1px solid currentColor;
65 border-radius: 9px;
66 line-height: 16px;
67 font-size: 11px;
68 height: 16px;
69 width: 28px;
70 text-align: center;
71 margin-left: 5px;
72 }
73 </style>';
74 }
75 }
76
77 /**
78 * Init admin actions.
79 */
80 public function init() {
81 // Display plugin links.
82 add_filter( 'network_admin_plugin_action_links_' . DEFENDER_PLUGIN_BASENAME, array( $this, 'settings_link' ) );
83 add_filter( 'plugin_action_links_' . DEFENDER_PLUGIN_BASENAME, array( $this, 'settings_link' ) );
84 add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 3 );
85 // Only for plugin pages and actions are only for wp.org members.
86 if ( $this->is_wp_org_version ) {
87 /**
88 * Action hook that fires after a scan issue is fixed.
89 *
90 * @since 4.4.0
91 */
92 add_action(
93 'wpdef_fixed_scan_issue',
94 array( $this, 'after_scan_fix' ),
95 10
96 );
97 // For submenu callout.
98 add_action( 'admin_head', array( $this, 'retarget_submenu_callout' ) );
99 if ( ! wd_di()->get( WPMUDEV::class )->is_wpmu_hosting() ) {
100 $upsell_menu_title = sprintf(
101 '<span class="defender-upsell-label">%1$s<span class="defender-upsell-pro-tag">%2$s</span></span><svg class="defender-upsell-arrow" width="9" height="9" viewBox="0 0 9 9" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0.225625 8.7625C0.0881251 8.62917 0.013125 8.47083 0.000624999 8.2875C-0.00770833 8.10417 0.0672918 7.93125 0.225625 7.76875L5.86313 2.125L7.16313 0.93125C7.31313 0.789584 7.47146 0.722917 7.63812 0.73125C7.80479 0.739583 7.94854 0.804167 8.06938 0.925C8.19021 1.04583 8.25062 1.18958 8.25062 1.35625C8.25479 1.52292 8.18812 1.67708 8.05062 1.81875L6.85063 3.11875L1.21313 8.75C1.05896 8.90417 0.890209 8.97917 0.706875 8.975C0.527709 8.975 0.367292 8.90417 0.225625 8.7625ZM7.61938 4.4625L7.76312 1.24375L4.43188 1.3625H2.30687C2.11521 1.3625 1.94854 1.29792 1.80688 1.16875C1.66521 1.03542 1.59438 0.875 1.59438 0.6875C1.59438 0.5 1.66104 0.339584 1.79438 0.20625C1.93188 0.0687502 2.10688 0 2.31938 0H8.25688C8.48188 0 8.66104 0.0687502 8.79437 0.20625C8.92771 0.34375 8.99438 0.520834 8.99438 0.7375V6.66875C8.99438 6.87292 8.92563 7.04583 8.78813 7.1875C8.65063 7.325 8.48812 7.39375 8.30062 7.39375C8.10896 7.39375 7.94646 7.325 7.81313 7.1875C7.68396 7.04583 7.61938 6.87708 7.61938 6.68125V4.4625Z" fill="white"/></svg>',
102 esc_html__( 'Upgrade', 'defender-security' ),
103 esc_html__( 'Pro', 'defender-security' )
104 );
105 add_submenu_page(
106 'wp-defender',
107 esc_html__( 'Upgrade to Pro', 'defender-security' ),
108 $upsell_menu_title,
109 is_multisite() ? 'manage_network_options' : 'manage_options',
110 $this->get_link( 'upsell', 'defender_new-submenu_upsell' )
111 );
112 global $submenu;
113 if ( ! empty( $submenu['wp-defender'] ) ) {
114 $last = array_key_last( $submenu['wp-defender'] );
115 $submenu['wp-defender'][ $last ][4] = 'defender-menu-upsell'; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
116 }
117 }
118 }
119
120 // Display IP detection notice.
121 if ( is_multisite() ) {
122 add_action( 'network_admin_notices', array( $this, 'admin_notices' ) );
123 } else {
124 add_action( 'admin_notices', array( $this, 'admin_notices' ) );
125 }
126 }
127
128 /**
129 * Initialize the deactivation survey modal.
130 */
131 public function init_deactivation_survey() {
132 global $pagenow;
133
134 if ( 'plugins.php' !== $pagenow ) {
135 return;
136 }
137
138 wp_enqueue_style( 'def-sui' );
139 wp_enqueue_style( 'def-admin' );
140
141 if ( ! wp_script_is( 'clipboard', 'enqueued' ) ) {
142 wp_enqueue_script( 'clipboard' );
143 }
144
145 wp_enqueue_script( 'wpmudev-sui' );
146 wp_enqueue_script( 'def-deactivation-survey' );
147 wp_enqueue_script( 'def-admin' );
148 }
149
150 /**
151 * Retrieves the display name of the plugin.
152 *
153 * @return string The display name of the plugin with a trailing hyphen.
154 */
155 public function get_plugin_display_name(): string {
156 // Check if the plugin is the WordPress.org version (i.e., the free version) and set the label accordingly.
157 $plugin_label = $this->is_wp_org_version
158 ? esc_html__( 'Defender', 'defender-security' )
159 : esc_html__( 'Defender Pro', 'defender-security' );
160
161 // Instantiate the Dashboard_Whitelabel class only if necessary.
162 $whitelabel = new Dashboard_Whitelabel();
163
164 // If whitelabeling is enabled and a custom name is provided, use it.
165 if ( $whitelabel->can_whitelabel() ) {
166 $custom_label = $whitelabel->get_plugin_name( Config_Hub_Helper::WDP_ID );
167 if ( is_string( $custom_label ) && '' !== trim( $custom_label ) ) {
168 $plugin_label = $custom_label;
169 }
170 }
171
172 // Return the final plugin label with the appended dash.
173 return $plugin_label . ' - ';
174 }
175
176 /**
177 * The method is a stub without content.
178 */
179 private function menu_nope(): void {
180 }
181
182 /**
183 * Generates the submenu callout for the WP Defender plugin.
184 *
185 * @return void
186 */
187 public function retarget_submenu_callout(): void {
188 ?>
189 <style>
190 #adminmenu .wp-submenu li.defender-menu-upsell > a,
191 #adminmenu .wp-submenu li.defender-menu-upsell > a:hover,
192 #adminmenu .wp-submenu li.defender-menu-upsell > a:active,
193 #adminmenu .wp-submenu li.defender-menu-upsell > a:focus {
194 display: flex;
195 align-items: center;
196 justify-content: space-between;
197 height: 32px;
198 padding: 7px 12px;
199 box-sizing: border-box;
200 background: #571EE7;
201 color: #ffffff;
202 font-size: 14px;
203 font-weight: 400;
204 line-height: 18px;
205 }
206
207 #adminmenu .wp-submenu li.defender-menu-upsell > a .defender-upsell-label {
208 display: inline-flex;
209 align-items: center;
210 }
211
212 #adminmenu .wp-submenu li.defender-menu-upsell > a .defender-upsell-pro-tag {
213 display: inline-flex;
214 align-items: center;
215 justify-content: center;
216 margin-left: 6px;
217 padding: 0 5px;
218 border: 1px solid #ffffff;
219 border-radius: 9px;
220 width: 30px;
221 height: 18px;
222 box-sizing: border-box;
223 font-family: 'Roboto', Arial, sans-serif;
224 font-size: 12px;
225 font-weight: 400;
226 line-height: 20px;
227 letter-spacing: 0.1px;
228 }
229
230 #adminmenu .wp-submenu li.defender-menu-upsell > a .defender-upsell-arrow {
231 margin-right: 4px;
232 }
233
234 #toplevel_page_wp-defender.wp-not-current-submenu .wp-submenu li.defender-menu-upsell > a,
235 #toplevel_page_wp-defender.wp-not-current-submenu .wp-submenu li.defender-menu-upsell > a:hover,
236 #toplevel_page_wp-defender.wp-not-current-submenu .wp-submenu li.defender-menu-upsell > a:active,
237 #toplevel_page_wp-defender.wp-not-current-submenu .wp-submenu li.defender-menu-upsell > a:focus,
238 #toplevel_page_wp-defender.wp-not-current-submenu > ul > li > a[href="admin.php?page=defender_cross_sell"],
239 #toplevel_page_wp-defender.wp-not-current-submenu > ul > li > a[href="admin.php?page=defender_cross_sell"]:hover,
240 #toplevel_page_wp-defender.wp-not-current-submenu > ul > li > a[href="admin.php?page=defender_cross_sell"]:active,
241 #toplevel_page_wp-defender.wp-not-current-submenu > ul > li > a[href="admin.php?page=defender_cross_sell"]:focus {
242 margin-left: -4px;
243 }
244 </style>
245 <script type='text/javascript'>
246 jQuery(function ($) {
247 $('#adminmenu li.defender-menu-upsell > a').attr("target", "_blank");
248 });
249 </script>
250 <?php
251 }
252
253 /**
254 * Fired when the scan issue is fixed.
255 *
256 * @return void
257 */
258 public function after_scan_fix(): void {
259 Rate::run_counter_of_fixed_scans();
260 }
261
262 /**
263 * Return URL link.
264 *
265 * @param string $link_for Accepts: 'docs', 'plugin', 'rate' and etc.
266 * @param string $campaign Utm campaign tag to be used in link. Default: ''.
267 * @param string $adv_path Advanced path. Default: ''.
268 * @param string $source UTM source. Default: 'defender'.
269 *
270 * @return string
271 */
272 public function get_link( $link_for, $campaign = '', $adv_path = '', $source = 'defender' ): string {
273 $domain = 'https://wpmudev.com';
274 $wp_org = 'https://wordpress.org';
275 $utm_tags = "?utm_source={$source}&utm_medium=plugin&utm_campaign={$campaign}";
276 switch ( $link_for ) {
277 case 'docs':
278 $link = "{$domain}/docs/wpmu-dev-plugins/defender/{$utm_tags}";
279 break;
280 case 'plugin':
281 case 'upsell':
282 $link = "{$domain}/project/wp-defender/{$utm_tags}";
283 break;
284 case 'rate':
285 $link = "{$wp_org}/support/plugin/defender-security/reviews/#new-post";
286 break;
287 case 'support':
288 $link = $this->is_wp_org_version
289 ? "{$wp_org}/support/plugin/defender-security/"
290 : "{$domain}/get-support/";
291 break;
292 case 'support_with_utm':
293 $link = "{$domain}/hub2/support/{$utm_tags}";
294 break;
295 case 'roadmap':
296 $link = "{$domain}/roadmap/";
297 break;
298 case 'pro_link':
299 $link = "{$domain}/$adv_path";
300 break;
301 default:
302 $link = '';
303 break;
304 }
305
306 return $link;
307 }
308
309 /**
310 * Adds a settings link on plugin page.
311 *
312 * @param array $links Current links.
313 *
314 * @return array
315 */
316 public function settings_link( $links ) {
317 $action_links = array();
318 $wpmu_dev = new WPMUDEV();
319 // Dashboard-link.
320 $action_links['dashboard'] = '<a href="' . network_admin_url( 'admin.php?page=wp-defender' ) . '" aria-label="' . esc_attr(
321 esc_html__(
322 'Go to Defender Dashboard',
323 'defender-security'
324 )
325 ) . '">' . esc_html__( 'Dashboard', 'defender-security' ) . '</a>';
326 // Documentation-link.
327 $action_links['docs'] = '<a target="_blank" href="' . $this->get_link(
328 'docs',
329 'defender_pluginlist_docs'
330 ) . '" aria-label="' . esc_attr(
331 esc_html__(
332 'Docs',
333 'defender-security'
334 )
335 ) . '">' . esc_html__( 'Docs', 'defender-security' ) . '</a>';
336 if ( ! $wpmu_dev->is_member() ) {
337 if ( WP_DEFENDER_PRO_PATH !== DEFENDER_PLUGIN_BASENAME ) {
338 if ( ! wd_di()->get( WPMUDEV::class )->is_wpmu_hosting() ) {
339 $action_links['upgrade'] = '<a style="color: #8D00B1;" target="_blank" href="' . $this->get_link(
340 'plugin',
341 'defender_pluginlist_upgrade'
342 ) . '" aria-label="' . esc_attr(
343 esc_html__(
344 'Upgrade to Defender Pro',
345 'defender-security'
346 )
347 ) . '">' . esc_html__( 'Get Defender Pro', 'defender-security' ) . '</a>';
348 }
349 } elseif ( ! $wpmu_dev->is_hosted_site_connected_to_tfh() ) {
350 $action_links['renew'] = '<a style="color: #8D00B1;" target="_blank" href="' . $this->get_link(
351 'plugin',
352 'defender_pluginlist_renew'
353 ) . '" aria-label="' . esc_attr(
354 esc_html__(
355 'Renew Your Membership',
356 'defender-security'
357 )
358 ) . '">' . esc_html__( 'Renew Membership', 'defender-security' ) . '</a>';
359 }
360 }
361
362 return array_merge( $action_links, $links );
363 }
364
365 /**
366 * Show row meta on the plugin screen.
367 *
368 * @param string[] $links Plugin Row Meta.
369 * @param string $file Plugin Base file.
370 * @param array $plugin_data Plugin data.
371 *
372 * @return array
373 */
374 public function plugin_row_meta( $links, $file, $plugin_data ) {
375 $row_meta = array();
376 if ( ! defined( 'DEFENDER_PLUGIN_BASENAME' ) || DEFENDER_PLUGIN_BASENAME !== $file ) {
377 return $links;
378 }
379
380 // Change AuthorURI link.
381 if ( isset( $links[1] ) ) {
382 $author_uri = $this->is_wp_org_version ? 'https://profiles.wordpress.org/wpmudev/' : 'https://wpmudev.com/';
383 $author_uri = sprintf(
384 '<a href="%s" target="_blank">%s</a>',
385 $author_uri,
386 esc_html__( 'WPMU DEV', 'defender-security' )
387 );
388 $links[1] = sprintf(
389 /* translators: %s: Author URI. */
390 esc_html__( 'By %s', 'defender-security' ),
391 $author_uri
392 );
393 }
394
395 if ( $this->is_wp_org_version ) {
396 // Change AuthorURI link.
397 if ( isset( $links[2] ) && false === strpos( $links[2], 'target="_blank"' ) ) {
398 if ( ! isset( $plugin_data['slug'] ) && $plugin_data['Name'] ) {
399 $links[2] = sprintf(
400 '<a href="%s" class="thickbox open-plugin-details-modal" aria-label="%s" data-title="%s">%s</a>',
401 esc_url(
402 network_admin_url(
403 'plugin-install.php?tab=plugin-information&plugin=defender-security&TB_iframe=true&width=600&height=550'
404 )
405 ),
406 /* translators: %s: Plugin name. */
407 esc_attr( sprintf( esc_html__( 'More information about %s', 'defender-security' ), $plugin_data['Name'] ) ),
408 esc_attr( $plugin_data['Name'] ),
409 esc_html__( 'View details', 'defender-security' )
410 );
411 } else {
412 $links[2] = str_replace( 'href=', 'target="_blank" href=', $links[2] );
413 }
414 }
415 $row_meta['rate'] = '<a href="' . esc_url( $this->get_link( 'rate' ) ) . '" aria-label="' . esc_attr__(
416 'Rate Defender',
417 'defender-security'
418 ) . '" target="_blank">' . Rate::get_rate_button_title() . '</a>';
419 $row_meta['support'] = '<a href="' . esc_url( $this->get_link( 'support' ) ) . '" aria-label="' . esc_attr__(
420 'Support',
421 'defender-security'
422 ) . '" target="_blank">' . esc_html__( 'Support', 'defender-security' ) . '</a>';
423 } else {
424 // Change 'Visit plugins' link to 'View details'.
425 if ( isset( $links[2] ) && false !== strpos( $links[2], 'project/wp-defender' ) ) {
426 $links[2] = sprintf(
427 '<a href="%s" target="_blank">%s</a>',
428 esc_url( $this->get_link( 'pro_link', '', 'project/wp-defender/' ) ),
429 esc_html__( 'View details', 'defender-security' )
430 );
431 }
432 $row_meta['support'] = '<a href="' . esc_url( $this->get_link( 'support' ) ) . '" aria-label="' . esc_attr__(
433 'Premium Support',
434 'defender-security'
435 ) . '" target="_blank">' . esc_html__( 'Premium Support', 'defender-security' ) . '</a>';
436 }
437 $row_meta['roadmap'] = '<a href="' . esc_url( $this->get_link( 'roadmap' ) ) . '" aria-label="' . esc_attr__(
438 'Roadmap',
439 'defender-security'
440 ) . '" target="_blank">' . esc_html__( 'Roadmap', 'defender-security' ) . '</a>';
441
442 return array_merge( $links, $row_meta );
443 }
444
445 /**
446 * Display IP detection notices:
447 * - if user site is behind proxy, e.g. Cloudflare or something else, and only for admins,
448 * - only on the plugin's pages.
449 *
450 * @return void
451 */
452 public function admin_notices(): void {
453 if ( ! current_user_can( 'manage_options' ) || ! is_defender_page() ) {
454 return;
455 }
456 $header = $this->get_plugin_display_name();
457 if ( Firewall::is_cf_notice_ready() ) {
458 $is_show = 'cf';
459 $class_notice = 'notice-info';
460 $header .= esc_html__(
461 'Cloudflare Usage Detected: Switched to CF-Connecting-IP for Better Compatibility',
462 'defender-security'
463 );
464 } elseif ( Firewall::is_xff_notice_ready() ) {
465 $is_show = 'xff';
466 $class_notice = 'notice-warning';
467 $header .= esc_html__(
468 'Improve IP Detection: We suggest Switching to X-Forward-For IP Detection Method',
469 'defender-security'
470 );
471 } else {
472 return;
473 }
474 ?>
475 <div class="defender_ip_detection_notice notice <?php echo esc_attr( $class_notice ); ?> is-dismissible"
476 data-nonce="<?php echo esc_attr( wp_create_nonce( 'defender_ip_detection_notice_dismiss' ) ); ?>"
477 data-prop="notice-for-<?php echo esc_attr( $is_show ); ?>">
478 <h3 style="margin-bottom:0;">
479 <?php echo esc_html( $header ); ?>
480 </h3>
481 <?php if ( 'cf' === $is_show ) { ?>
482 <p style="color: #72777C; line-height: 22px;">
483 <?php
484 printf(
485 /* translators: %s: Link. */
486 esc_html__(
487 'We have switched to using the CF-Connecting-IP HTTP header for IP detection, offering enhanced compatibility for users behind Cloudflare Proxy. If you wish to change this setting, you can do so from %s.',
488 'defender-security'
489 ),
490 '<a style="font-weight:bold;" href="' . esc_url_raw( network_admin_url( 'admin.php?page=wdf-ip-lockout&view=settings#detect-ip-addresses' ) ) . '">' . esc_html__( 'here', 'defender-security' ) . '</a>'
491 );
492 ?>
493 </p>
494 <p>
495 <button type="button" class="button button-primary button-large defender_ip_detection_action_hide"
496 data-prop="defender_ip_detection_notice_success">
497 <?php
498 esc_html_e(
499 'Ok, I understand',
500 'defender-security'
501 );
502 ?>
503 </button>
504 </p>
505 <?php } elseif ( 'xff' === $is_show ) { ?>
506 <p style="color: #72777C; line-height: 22px;">
507 <?php
508 printf(
509 /* translators: %s: Link. */
510 esc_html__(
511 'Based on your server configuration, we recommend switching to the X-Forwarded-For method for accurate IP detection and to prevent firewall blocks. Easily modify your settings %s.',
512 'defender-security'
513 ),
514 '<a style="font-weight:bold;" href="' . esc_url_raw( network_admin_url( 'admin.php?page=wdf-ip-lockout&view=settings#detect-ip-addresses' ) ) . '">' . esc_html__( 'here', 'defender-security' ) . '</a>'
515 );
516 ?>
517 </p>
518 <p>
519 <button type="button" class="button button-primary button-large"
520 id="defender_ip_detection_action_switch"
521 data-prop="defender_ip_detection_notice_success">
522 <?php esc_html_e( 'Switch to X-Forwarded-For', 'defender-security' ); ?>
523 </button>
524 <a href="#" class="defender_ip_detection_action_hide"
525 style="margin-left: 11px; line-height: 16px; text-decoration: none; font-weight: bold;"
526 data-prop="defender_ip_detection_notice_dismiss"><?php esc_html_e( 'Dismiss', 'defender-security' ); ?></a>
527 </p>
528 <?php } ?>
529 </div>
530 <script type="text/javascript">
531 //Switch.
532 jQuery('#defender_ip_detection_action_switch').on('click', function (e) {
533 e.preventDefault();
534 var $notice = jQuery(e.currentTarget).closest('.defender_ip_detection_notice'),
535 ajaxUrl = '<?php echo esc_url_raw( admin_url( 'admin-ajax.php' ) ); ?>';
536
537 jQuery.post(
538 ajaxUrl,
539 {
540 action: 'defender_ip_detection_switch_to_xff',
541 _ajax_nonce: $notice.data('nonce')
542 }
543 ).always(function () {
544 $notice.hide();
545 });
546 });
547 //Hide.
548 jQuery('body').on('click', '.defender_ip_detection_notice .notice-dismiss, .defender_ip_detection_action_hide', function (e) {
549 e.preventDefault();
550 var $notice = jQuery(e.currentTarget).closest('.defender_ip_detection_notice'),
551 ajaxUrl = '<?php echo esc_url_raw( admin_url( 'admin-ajax.php' ) ); ?>';
552
553 jQuery.post(
554 ajaxUrl,
555 {
556 action: 'defender_ip_detection_notice_dismiss',
557 prop: $notice.data('prop'),
558 _ajax_nonce: $notice.data('nonce')
559 }
560 ).always(function () {
561 $notice.hide();
562 });
563 });
564 </script>
565 <?php
566 }
567
568 /**
569 * Dismiss notice.
570 *
571 * @return void
572 */
573 public function dismiss_notice(): void {
574 if (
575 ! current_user_can( 'manage_options' ) ||
576 ! check_ajax_referer( 'defender_ip_detection_notice_dismiss' )
577 ) {
578 wp_send_json_error(
579 array( 'message' => esc_html__( 'Invalid request, you are not allowed to do that action.', 'defender-security' ) )
580 );
581 }
582
583 $prop = defender_get_data_from_request( 'prop', 'p' );
584 $notice_type = '' !== trim( $prop ) ? $prop : false;
585 if ( 'notice-for-cf' === $notice_type ) {
586 update_site_option( Firewall::IP_DETECTION_CF_DISMISS_SLUG, true );
587 wp_send_json_success();
588 } elseif ( 'notice-for-xff' === $notice_type ) {
589 update_site_option( Firewall::IP_DETECTION_XFF_DISMISS_SLUG, true );
590 wp_send_json_success();
591 } else {
592 wp_send_json_error(
593 array( 'message' => esc_html__( 'Invalid request, allowed data not provided.', 'defender-security' ) )
594 );
595 }
596 }
597
598 /**
599 * Switch to XFF option.
600 *
601 * @return void
602 */
603 public function switch_to_xff(): void {
604 if (
605 ! current_user_can( 'manage_options' ) ||
606 ! check_ajax_referer( 'defender_ip_detection_notice_dismiss' )
607 ) {
608 wp_send_json_error(
609 array( 'message' => esc_html__( 'Invalid request, you are not allowed to do that action.', 'defender-security' ) )
610 );
611 }
612 // Change model's data.
613 $model_firewall = wd_di()->get( Model\Setting\Firewall::class );
614 $model_firewall->http_ip_header = 'HTTP_X_FORWARDED_FOR';
615 $xff_ip = defender_get_data_from_request( 'HTTP_X_FORWARDED_FOR', 's' );
616 if ( '' === $model_firewall->trusted_proxies_ip ) {
617 $model_firewall->trusted_proxies_ip = $xff_ip;
618 } else {
619 // Todo: improve the code using a separate method. This will be useful when the user switches between different proxy headeres (IP detection options).
620 $separator = "\r\n";
621 // Check if the XFF header contains multiple IPs.
622 $xff_ip = str_replace( array( ',', ' ,' ), $separator, $xff_ip );
623 $model_firewall->trusted_proxies_ip = $model_firewall->trusted_proxies_ip . $separator . $xff_ip;
624 }
625 $model_firewall->save();
626 // Save Dismiss slug.
627 update_site_option( Firewall::IP_DETECTION_XFF_DISMISS_SLUG, true );
628 wp_send_json_success();
629 }
630
631 /**
632 * Load deactivation survey modal.
633 */
634 public function load_deactivation_survey_modal() {
635 $deactivation_survey_template_file = WP_DEFENDER_DIR .
636 'src' . DIRECTORY_SEPARATOR .
637 'view' . DIRECTORY_SEPARATOR .
638 'modal' . DIRECTORY_SEPARATOR .
639 'deactivation-survey.php';
640
641 if ( ! file_exists( $deactivation_survey_template_file ) ) {
642 return;
643 }
644
645 // Data to be passed to the template file.
646 $is_pro = wd_di()->get( WPMUDEV::class )->is_pro();
647 $docs_link = $this->get_link( 'support_with_utm', 'defender_deactivation_survey_help', '', $is_pro ? 'defender-pro' : 'defender' );
648
649 ob_start();
650 require_once $deactivation_survey_template_file;
651 // Everything escaped in all template files.
652 echo ob_get_clean(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
653 }
654
655 /**
656 * Track deactivation.
657 */
658 public function track_deactivate() {
659 if (
660 ! current_user_can( 'manage_options' ) ||
661 ! check_ajax_referer( 'defender_deactivation_survey_modal' )
662 ) {
663 wp_send_json_error(
664 array( 'message' => esc_html__( 'Invalid request, you are not allowed to do that action.', 'defender-security' ) )
665 );
666 }
667 $posted_data = defender_get_data_from_request( null, 'p' );
668 if ( ! is_array( $posted_data['properties'] ) ) {
669 wp_send_json_error(
670 array( 'message' => esc_html__( 'Invalid request, allowed data not provided.', 'defender-security' ) )
671 );
672 }
673 $properties = $posted_data['properties'];
674 if (
675 ! isset(
676 $properties['Reason'],
677 $properties['Message'],
678 $properties['Modal Action'],
679 $properties['Requested Assistance'],
680 $properties['Tracking Status']
681 )
682 ) {
683 wp_send_json_error(
684 array( 'message' => esc_html__( 'Missing field(s).', 'defender-security' ) )
685 );
686 }
687
688 wd_di()->get( Deactivation_Survey::class )->track_deactivation_survey( $properties );
689
690 wp_send_json_success();
691 }
692 }
693