PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.2.3
Defender Security – Malware Scanner, Login Security & Firewall v6.2.3
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 3.1.1 All 140 releases
defender-security / src / class-admin.php

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

702 lines 23.8 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 ( isset( $submenu['wp-defender'] ) && is_array( $submenu['wp-defender'] ) && array() !== $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 * Generates the submenu callout for the WP Defender plugin.
178 *
179 * @return void
180 */
181 public function retarget_submenu_callout(): void {
182 ?>
183 <style>
184 #adminmenu .wp-submenu li.defender-menu-upsell > a,
185 #adminmenu .wp-submenu li.defender-menu-upsell > a:hover,
186 #adminmenu .wp-submenu li.defender-menu-upsell > a:active,
187 #adminmenu .wp-submenu li.defender-menu-upsell > a:focus {
188 display: flex;
189 align-items: center;
190 justify-content: space-between;
191 height: 32px;
192 padding: 7px 12px;
193 box-sizing: border-box;
194 background: #571EE7;
195 color: #ffffff;
196 font-size: 14px;
197 font-weight: 400;
198 line-height: 18px;
199 }
200
201 #adminmenu .wp-submenu li.defender-menu-upsell > a .defender-upsell-label {
202 display: inline-flex;
203 align-items: center;
204 }
205
206 #adminmenu .wp-submenu li.defender-menu-upsell > a .defender-upsell-pro-tag {
207 display: inline-flex;
208 align-items: center;
209 justify-content: center;
210 margin-left: 6px;
211 padding: 0 5px;
212 border: 1px solid #ffffff;
213 border-radius: 9px;
214 width: 30px;
215 height: 18px;
216 box-sizing: border-box;
217 font-family: 'Roboto', Arial, sans-serif;
218 font-size: 12px;
219 font-weight: 400;
220 line-height: 20px;
221 letter-spacing: 0.1px;
222 }
223
224 #adminmenu .wp-submenu li.defender-menu-upsell > a .defender-upsell-arrow {
225 margin-right: 4px;
226 }
227
228 #toplevel_page_wp-defender.wp-not-current-submenu .wp-submenu li.defender-menu-upsell > a,
229 #toplevel_page_wp-defender.wp-not-current-submenu .wp-submenu li.defender-menu-upsell > a:hover,
230 #toplevel_page_wp-defender.wp-not-current-submenu .wp-submenu li.defender-menu-upsell > a:active,
231 #toplevel_page_wp-defender.wp-not-current-submenu .wp-submenu li.defender-menu-upsell > a:focus {
232 margin-left: -4px;
233 }
234 </style>
235 <script type='text/javascript'>
236 jQuery(function ($) {
237 $('#adminmenu li.defender-menu-upsell > a').attr("target", "_blank");
238 });
239 </script>
240 <?php
241 }
242
243 /**
244 * Fired when the scan issue is fixed.
245 *
246 * @return void
247 */
248 public function after_scan_fix(): void {
249 Rate::run_counter_of_fixed_scans();
250 }
251
252 /**
253 * Return URL link.
254 *
255 * @param string $link_for Accepts: 'docs', 'plugin', 'rate' and etc.
256 * @param string $campaign Utm campaign tag to be used in link. Default: ''.
257 * @param string $adv_path Advanced path. Default: ''.
258 * @param string $source UTM source. Default: 'defender'.
259 *
260 * @return string
261 */
262 public function get_link( $link_for, $campaign = '', $adv_path = '', $source = 'defender' ): string {
263 $domain = 'https://wpmudev.com';
264 $wp_org = 'https://wordpress.org';
265 $utm_tags = "?utm_source={$source}&utm_medium=plugin&utm_campaign={$campaign}";
266 switch ( $link_for ) {
267 case 'docs':
268 $link = "{$domain}/docs/wpmu-dev-plugins/defender/{$utm_tags}";
269 break;
270 case 'plugin':
271 case 'upsell':
272 $link = "{$domain}/project/wp-defender/{$utm_tags}";
273 break;
274 case 'rate':
275 $link = "{$wp_org}/support/plugin/defender-security/reviews/#new-post";
276 break;
277 case 'support':
278 $link = $this->is_wp_org_version
279 ? "{$wp_org}/support/plugin/defender-security/"
280 : "{$domain}/get-support/";
281 break;
282 case 'support_with_utm':
283 $link = "{$domain}/hub2/support/{$utm_tags}";
284 break;
285 case 'roadmap':
286 $link = "{$domain}/roadmap/";
287 break;
288 case 'pro_link':
289 $link = "{$domain}/$adv_path";
290 break;
291 default:
292 $link = '';
293 break;
294 }
295
296 return $link;
297 }
298
299 /**
300 * Adds a settings link on plugin page.
301 *
302 * @param array $links Current links.
303 *
304 * @return array
305 */
306 public function settings_link( $links ) {
307 $action_links = array();
308 $wpmu_dev = new WPMUDEV();
309 // Dashboard-link.
310 $action_links['dashboard'] = '<a href="' . network_admin_url( 'admin.php?page=wp-defender' ) . '" aria-label="' . esc_attr(
311 esc_html__(
312 'Go to Defender Dashboard',
313 'defender-security'
314 )
315 ) . '">' . esc_html__( 'Dashboard', 'defender-security' ) . '</a>';
316 // Documentation-link.
317 $action_links['docs'] = '<a target="_blank" href="' . $this->get_link(
318 'docs',
319 'defender_pluginlist_docs'
320 ) . '" aria-label="' . esc_attr(
321 esc_html__(
322 'Docs',
323 'defender-security'
324 )
325 ) . '">' . esc_html__( 'Docs', 'defender-security' ) . '</a>';
326 if ( ! $wpmu_dev->is_member() ) {
327 if ( WP_DEFENDER_PRO_PATH !== DEFENDER_PLUGIN_BASENAME ) {
328 if ( ! wd_di()->get( WPMUDEV::class )->is_wpmu_hosting() ) {
329 $action_links['upgrade'] = '<a style="color: #8D00B1;" target="_blank" href="' . $this->get_link(
330 'plugin',
331 'defender_pluginlist_upgrade'
332 ) . '" aria-label="' . esc_attr(
333 esc_html__(
334 'Upgrade to Defender Pro',
335 'defender-security'
336 )
337 ) . '">' . esc_html__( 'Get Defender Pro', 'defender-security' ) . '</a>';
338 }
339 } elseif ( ! $wpmu_dev->is_hosted_site_connected_to_tfh() ) {
340 $action_links['renew'] = '<a style="color: #8D00B1;" target="_blank" href="' . $this->get_link(
341 'plugin',
342 'defender_pluginlist_renew'
343 ) . '" aria-label="' . esc_attr(
344 esc_html__(
345 'Renew Your Membership',
346 'defender-security'
347 )
348 ) . '">' . esc_html__( 'Renew Membership', 'defender-security' ) . '</a>';
349 }
350 }
351
352 return array_merge( $action_links, $links );
353 }
354
355 /**
356 * Show row meta on the plugin screen.
357 *
358 * @param string[] $links Plugin Row Meta.
359 * @param string $file Plugin Base file.
360 * @param array $plugin_data Plugin data.
361 *
362 * @return array
363 */
364 public function plugin_row_meta( $links, $file, $plugin_data ) {
365 $row_meta = array();
366 if ( ! defined( 'DEFENDER_PLUGIN_BASENAME' ) || DEFENDER_PLUGIN_BASENAME !== $file ) {
367 return $links;
368 }
369
370 // Change AuthorURI link.
371 if ( isset( $links[1] ) ) {
372 $author_uri = $this->is_wp_org_version ? 'https://profiles.wordpress.org/wpmudev/' : 'https://wpmudev.com/';
373 $author_uri = sprintf(
374 '<a href="%s" target="_blank">%s</a>',
375 $author_uri,
376 esc_html__( 'WPMU DEV', 'defender-security' )
377 );
378 $links[1] = sprintf(
379 /* translators: %s: Author URI. */
380 esc_html__( 'By %s', 'defender-security' ),
381 $author_uri
382 );
383 }
384
385 if ( $this->is_wp_org_version ) {
386 // Change AuthorURI link.
387 if ( isset( $links[2] ) && false === strpos( $links[2], 'target="_blank"' ) ) {
388 if ( ! isset( $plugin_data['slug'] ) && $plugin_data['Name'] ) {
389 $links[2] = sprintf(
390 '<a href="%s" class="thickbox open-plugin-details-modal" aria-label="%s" data-title="%s">%s</a>',
391 esc_url(
392 network_admin_url(
393 'plugin-install.php?tab=plugin-information&plugin=defender-security&TB_iframe=true&width=600&height=550'
394 )
395 ),
396 /* translators: %s: Plugin name. */
397 esc_attr( sprintf( esc_html__( 'More information about %s', 'defender-security' ), $plugin_data['Name'] ) ),
398 esc_attr( $plugin_data['Name'] ),
399 esc_html__( 'View details', 'defender-security' )
400 );
401 } else {
402 $links[2] = str_replace( 'href=', 'target="_blank" href=', $links[2] );
403 }
404 }
405 $row_meta['rate'] = '<a href="' . esc_url( $this->get_link( 'rate' ) ) . '" aria-label="' . esc_attr__(
406 'Rate Defender',
407 'defender-security'
408 ) . '" target="_blank">' . Rate::get_rate_button_title() . '</a>';
409 $row_meta['support'] = '<a href="' . esc_url( $this->get_link( 'support' ) ) . '" aria-label="' . esc_attr__(
410 'Support',
411 'defender-security'
412 ) . '" target="_blank">' . esc_html__( 'Support', 'defender-security' ) . '</a>';
413 } else {
414 // Change 'Visit plugins' link to 'View details'.
415 if ( isset( $links[2] ) && false !== strpos( $links[2], 'project/wp-defender' ) ) {
416 $links[2] = sprintf(
417 '<a href="%s" target="_blank">%s</a>',
418 esc_url( $this->get_link( 'pro_link', '', 'project/wp-defender/' ) ),
419 esc_html__( 'View details', 'defender-security' )
420 );
421 }
422 $row_meta['support'] = '<a href="' . esc_url( $this->get_link( 'support' ) ) . '" aria-label="' . esc_attr__(
423 'Premium Support',
424 'defender-security'
425 ) . '" target="_blank">' . esc_html__( 'Premium Support', 'defender-security' ) . '</a>';
426 }
427 $row_meta['roadmap'] = '<a href="' . esc_url( $this->get_link( 'roadmap' ) ) . '" aria-label="' . esc_attr__(
428 'Roadmap',
429 'defender-security'
430 ) . '" target="_blank">' . esc_html__( 'Roadmap', 'defender-security' ) . '</a>';
431
432 return array_merge( $links, $row_meta );
433 }
434
435 /**
436 * Display IP detection notices:
437 * - if user site is behind proxy, e.g. Cloudflare or something else, and only for admins,
438 * - only on the plugin's pages.
439 *
440 * @return void
441 */
442 public function admin_notices(): void {
443 if ( ! current_user_can( 'manage_options' ) || ! is_defender_page() ) {
444 return;
445 }
446 $header = $this->get_plugin_display_name();
447 if ( Firewall::is_cf_notice_ready() ) {
448 $is_show = 'cf';
449 $class_notice = 'notice-info';
450 $header .= esc_html__(
451 'Cloudflare Usage Detected: Switched to CF-Connecting-IP for Better Compatibility',
452 'defender-security'
453 );
454 } elseif ( Firewall::is_xff_notice_ready() ) {
455 $is_show = 'xff';
456 $class_notice = 'notice-warning';
457 $header .= esc_html__(
458 'Improve IP Detection: We suggest Switching to X-Forward-For IP Detection Method',
459 'defender-security'
460 );
461 } else {
462 return;
463 }
464 ?>
465 <div class="defender_ip_detection_notice notice <?php echo esc_attr( $class_notice ); ?> is-dismissible"
466 data-nonce="<?php echo esc_attr( wp_create_nonce( 'defender_ip_detection_notice_dismiss' ) ); ?>"
467 data-prop="notice-for-<?php echo esc_attr( $is_show ); ?>">
468 <h3 style="margin-bottom:0;">
469 <?php echo esc_html( $header ); ?>
470 </h3>
471 <?php if ( 'cf' === $is_show ) { ?>
472 <p style="color: #72777C; line-height: 22px;">
473 <?php
474 printf(
475 /* translators: %s: Link. */
476 esc_html__(
477 '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.',
478 'defender-security'
479 ),
480 '<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>'
481 );
482 ?>
483 </p>
484 <p>
485 <button type="button" class="button button-primary button-large defender_ip_detection_action_hide"
486 data-prop="defender_ip_detection_notice_success">
487 <?php
488 esc_html_e(
489 'Ok, I understand',
490 'defender-security'
491 );
492 ?>
493 </button>
494 </p>
495 <?php } elseif ( 'xff' === $is_show ) { ?>
496 <p style="color: #72777C; line-height: 22px;">
497 <?php
498 printf(
499 /* translators: %s: Link. */
500 esc_html__(
501 '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.',
502 'defender-security'
503 ),
504 '<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>'
505 );
506 ?>
507 </p>
508 <p>
509 <button type="button" class="button button-primary button-large"
510 id="defender_ip_detection_action_switch"
511 data-prop="defender_ip_detection_notice_success">
512 <?php esc_html_e( 'Switch to X-Forwarded-For', 'defender-security' ); ?>
513 </button>
514 <a href="#" class="defender_ip_detection_action_hide"
515 style="margin-left: 11px; line-height: 16px; text-decoration: none; font-weight: bold;"
516 data-prop="defender_ip_detection_notice_dismiss"><?php esc_html_e( 'Dismiss', 'defender-security' ); ?></a>
517 </p>
518 <?php } ?>
519 </div>
520 <script type="text/javascript">
521 //Switch.
522 jQuery('#defender_ip_detection_action_switch').on('click', function (e) {
523 e.preventDefault();
524 var $notice = jQuery(e.currentTarget).closest('.defender_ip_detection_notice'),
525 ajaxUrl = '<?php echo esc_url_raw( admin_url( 'admin-ajax.php' ) ); ?>';
526
527 jQuery.post(
528 ajaxUrl,
529 {
530 action: 'defender_ip_detection_switch_to_xff',
531 _ajax_nonce: $notice.data('nonce')
532 }
533 ).always(function () {
534 $notice.hide();
535 });
536 });
537 //Hide.
538 jQuery('body').on('click', '.defender_ip_detection_notice .notice-dismiss, .defender_ip_detection_action_hide', function (e) {
539 e.preventDefault();
540 var $notice = jQuery(e.currentTarget).closest('.defender_ip_detection_notice'),
541 ajaxUrl = '<?php echo esc_url_raw( admin_url( 'admin-ajax.php' ) ); ?>';
542
543 jQuery.post(
544 ajaxUrl,
545 {
546 action: 'defender_ip_detection_notice_dismiss',
547 prop: $notice.data('prop'),
548 _ajax_nonce: $notice.data('nonce')
549 }
550 ).always(function () {
551 $notice.hide();
552 });
553 });
554 </script>
555 <?php
556 }
557
558 /**
559 * Dismiss notice.
560 *
561 * @return void
562 */
563 public function dismiss_notice(): void {
564 if (
565 ! current_user_can( 'manage_options' ) ||
566 ! check_ajax_referer( 'defender_ip_detection_notice_dismiss' )
567 ) {
568 wp_send_json_error(
569 array( 'message' => esc_html__( 'Invalid request, you are not allowed to do that action.', 'defender-security' ) )
570 );
571 }
572
573 $prop = defender_get_data_from_request( 'prop', 'p' );
574 $notice_type = '' !== trim( $prop ) ? $prop : false;
575 if ( 'notice-for-cf' === $notice_type ) {
576 update_site_option( Firewall::IP_DETECTION_CF_DISMISS_SLUG, true );
577 wp_send_json_success();
578 } elseif ( 'notice-for-xff' === $notice_type ) {
579 update_site_option( Firewall::IP_DETECTION_XFF_DISMISS_SLUG, true );
580 wp_send_json_success();
581 } else {
582 wp_send_json_error(
583 array( 'message' => esc_html__( 'Invalid request, allowed data not provided.', 'defender-security' ) )
584 );
585 }
586 }
587
588 /**
589 * Switch to XFF option.
590 *
591 * @return void
592 */
593 public function switch_to_xff(): void {
594 if (
595 ! current_user_can( 'manage_options' ) ||
596 ! check_ajax_referer( 'defender_ip_detection_notice_dismiss' )
597 ) {
598 wp_send_json_error(
599 array( 'message' => esc_html__( 'Invalid request, you are not allowed to do that action.', 'defender-security' ) )
600 );
601 }
602 // Change model's data.
603 $model_firewall = wd_di()->get( Model\Setting\Firewall::class );
604 $model_firewall->http_ip_header = 'HTTP_X_FORWARDED_FOR';
605 $xff_ip = defender_get_data_from_request( 'HTTP_X_FORWARDED_FOR', 's' );
606 $xff_parts = preg_split( '/\s*,\s*/', $xff_ip );
607 $xff_parts = is_array( $xff_parts ) ? $xff_parts : array();
608 $xff_parts = array_map( 'trim', $xff_parts );
609 $xff_parts = array_filter(
610 $xff_parts,
611 static function ( $ip ) {
612 return false !== filter_var( $ip, FILTER_VALIDATE_IP );
613 }
614 );
615 $separator = "\r\n";
616 $xff_parts = array_unique( $xff_parts );
617 $xff_ip = implode( $separator, $xff_parts );
618 if ( '' === $xff_ip ) {
619 wp_send_json_error(
620 array( 'message' => esc_html__( 'Invalid trusted proxy IP(s) detected in X-Forwarded-For header.', 'defender-security' ) )
621 );
622 }
623 if ( '' === $model_firewall->trusted_proxies_ip ) {
624 $model_firewall->trusted_proxies_ip = $xff_ip;
625 } else {
626 // Todo: improve the code using a separate method. This will be useful when the user switches between different proxy headeres (IP detection options).
627 $model_firewall->trusted_proxies_ip = $model_firewall->trusted_proxies_ip . $separator . $xff_ip;
628 }
629 $model_firewall->save();
630 // Save Dismiss slug.
631 update_site_option( Firewall::IP_DETECTION_XFF_DISMISS_SLUG, true );
632 wp_send_json_success();
633 }
634
635 /**
636 * Load deactivation survey modal.
637 */
638 public function load_deactivation_survey_modal() {
639 $deactivation_survey_template_file = WP_DEFENDER_DIR .
640 'src' . DIRECTORY_SEPARATOR .
641 'view' . DIRECTORY_SEPARATOR .
642 'modal' . DIRECTORY_SEPARATOR .
643 'deactivation-survey.php';
644
645 if ( ! file_exists( $deactivation_survey_template_file ) ) {
646 return;
647 }
648
649 // Data to be passed to the template file.
650 $is_pro = wd_di()->get( WPMUDEV::class )->is_pro();
651 $docs_link = $this->get_link(
652 'support_with_utm',
653 'defender_deactivation_survey_help',
654 '',
655 $is_pro ? 'defender-pro' : 'defender'
656 );
657
658 ob_start();
659 require_once $deactivation_survey_template_file;
660 // Everything escaped in all template files.
661 echo ob_get_clean(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
662 }
663
664 /**
665 * Track deactivation.
666 */
667 public function track_deactivate() {
668 if (
669 ! current_user_can( 'manage_options' ) ||
670 ! check_ajax_referer( 'defender_deactivation_survey_modal' )
671 ) {
672 wp_send_json_error(
673 array( 'message' => esc_html__( 'Invalid request, you are not allowed to do that action.', 'defender-security' ) )
674 );
675 }
676 $posted_data = defender_get_data_from_request( null, 'p' );
677 if ( ! is_array( $posted_data['properties'] ) ) {
678 wp_send_json_error(
679 array( 'message' => esc_html__( 'Invalid request, allowed data not provided.', 'defender-security' ) )
680 );
681 }
682 $properties = $posted_data['properties'];
683 if (
684 ! isset(
685 $properties['Reason'],
686 $properties['Message'],
687 $properties['Modal Action'],
688 $properties['Requested Assistance'],
689 $properties['Tracking Status']
690 )
691 ) {
692 wp_send_json_error(
693 array( 'message' => esc_html__( 'Missing field(s).', 'defender-security' ) )
694 );
695 }
696
697 wd_di()->get( Deactivation_Survey::class )->track_deactivation_survey( $properties );
698
699 wp_send_json_success();
700 }
701 }
702