PluginProbe
Patchstack – WordPress & Plugins Security / 2.1.25
Patchstack – WordPress & Plugins Security v2.1.25
2.3.7 trunk 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.17 2.1.18 2.1.19 2.1.2 2.1.20 2.1.21 2.1.22 2.1.23 2.1.24 2.1.25 2.1.3 2.1.4 2.1.5 2.1.6 All 49 releases
patchstack / includes / listener.php

listener.php in Patchstack – WordPress & Plugins Security 2.1.25, at includes/listener.php

728 lines 22.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // Do not allow the file to be called directly.
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 /**
9 * This class is used to communicate from the API to the plugin.
10 */
11 class P_Listener extends P_Core {
12
13 /**
14 * Add the actions required to hide the login page.
15 *
16 * @param Patchstack $core
17 * @return void
18 */
19 public function __construct( $core ) {
20 parent::__construct( $core );
21
22 // Only hook into the action if the authentication is set and valid.
23 if ( isset( $_POST['webarx_secret'] ) && $this->verifyToken( $_POST['webarx_secret'] ) ) {
24 add_action( 'init', array( $this, 'handleRequest' ) );
25 }
26
27 // OTT action.
28 if ( isset( $_POST['patchstack_ott_action'] ) ) {
29 $ott = get_option( 'patchstack_ott_action', '' );
30 if ( ! empty( $ott ) && hash_equals( $ott, $_POST['patchstack_ott_action'] ) ) {
31 $this->setIpHeader();
32 }
33 }
34 }
35
36 /**
37 * Handle the incoming request.
38 *
39 * @return void
40 */
41 public function handleRequest() {
42 // Loop through all possible actions.
43 foreach ( array(
44 'webarx_remote_users' => 'listUsers',
45 'webarx_firewall_switch' => 'switchFirewallStatus',
46 'webarx_wordpress_upgrade' => 'wordpressCoreUpgrade',
47 'webarx_theme_upgrade' => 'themeUpgrade',
48 'webarx_plugins_upgrade' => 'pluginsUpgrade',
49 'webarx_plugins_toggle' => 'pluginsToggle',
50 'webarx_plugins_delete' => 'pluginsDelete',
51 'webarx_get_options' => 'getAvailableOptions',
52 'webarx_set_options' => 'saveOptions',
53 'webarx_refresh_rules' => 'refreshRules',
54 'webarx_get_firewall_bans' => 'getFirewallBans',
55 'webarx_firewall_unban_ip' => 'unbanFirewallIp',
56 'webarx_upload_software' => 'uploadSoftware',
57 'webarx_upload_logs' => 'uploadLogs',
58 'webarx_send_ping' => 'sendPing',
59 'webarx_login_bans' => 'getLoginBans',
60 'webarx_unban_login' => 'unbanLogin',
61 'webarx_debug_info' => 'debugInfo',
62 'webarx_set_ip_header' => 'setIpHeader',
63 'webarx_refresh_license' => 'refreshLicense'
64 ) as $key => $action ) {
65 // Special case for Patchstack plugin upgrade.
66 if ( isset( $_POST[ $key ] ) ) {
67 $this->$action();
68 }
69 }
70 }
71
72 /**
73 * Determine if the provided secret hash equals the sha1 of the private id and key.
74 *
75 * @param string $secret Hash that is sent from our API.
76 * @return boolean
77 */
78 public function verifyToken( $secret ) {
79 $id = get_option( 'patchstack_clientid' );
80 $key = $this->get_secret_key();
81
82 if ( empty( $id ) || empty ( $key ) || strlen( $secret ) != 40 ) {
83 return false;
84 }
85
86 return hash_equals( sha1( $id . $key ), $secret );
87 }
88
89 /**
90 * Determine if given action succeded or not, then return the appropriate message.
91 *
92 * @param mixed $thing
93 * @param string $success
94 * @param string $fail
95 * @return void
96 */
97 private function returnResults( $thing, $success = '', $fail = '' ) {
98 if ( ! is_wp_error( $thing ) && $thing !== false ) {
99 wp_send_json( array( 'success' => $success ) );
100 }
101
102 wp_send_json( array( 'error' => $fail ) );
103 }
104
105 /**
106 * Send a ping back to the API.
107 *
108 * @return void
109 */
110 private function sendPing() {
111 do_action( 'patchstack_send_ping' );
112 wp_send_json(
113 array(
114 'firewall' => $this->get_option( 'patchstack_basic_firewall' ) == 1,
115 )
116 );
117 }
118
119 /**
120 * Get list of all users on WordPress
121 *
122 * @return void
123 */
124 private function listUsers() {
125 // Only fetch data we actually need.
126 $users = get_users( array( 'role__in' => array( 'administrator', 'editor', 'author', 'contributor' ) ) );
127 $roles = wp_roles();
128 $roles = $roles->get_names();
129 $data = array();
130
131 // Loop through all users.
132 foreach ( $users as $user ) {
133
134 // Get text friendly version of the role.
135 $text = '';
136 foreach ( $user->roles as $role ) {
137 if ( isset( $roles[ $role ] ) ) {
138 $text .= $roles[ $role ] . ', ';
139 } else {
140 $text .= $role . ', ';
141 }
142 }
143
144 // Push to array that we will eventually output.
145 array_push(
146 $data,
147 array(
148 'id' => $user->data->ID,
149 'username' => $user->data->user_login,
150 'email' => $user->data->user_email,
151 'roles' => substr( $text, 0, -2 ),
152 )
153 );
154 }
155
156 wp_send_json( array( 'users' => $data ) );
157 }
158
159 /**
160 * Switch the firewall status from on to off or off to on.
161 *
162 * @return string
163 */
164 private function switchFirewallStatus() {
165 $state = $this->get_option( 'patchstack_basic_firewall' ) == 1;
166 update_option( 'patchstack_basic_firewall', $state == 1 ? 0 : 1 );
167 $this->returnResults( null, 'Firewall ' . ( $state == 1 ? 'disabled' : 'enabled' ) . '.', null );
168 }
169
170 /**
171 * Upgrade the core of WordPress.
172 *
173 * @return string|void
174 */
175 private function wordpressCoreUpgrade() {
176 @set_time_limit( 180 );
177
178 // Get the core update info.
179 wp_version_check();
180 $core = get_site_transient( 'update_core' );
181
182 // Any updates available?
183 if ( ! isset( $core->updates ) ) {
184 $this->returnResults( false, null, 'No update available at this time.' );
185 }
186
187 // Are we on the latest version already?
188 if ( $core->updates[0]->response == 'latest' ) {
189 $this->returnResults( false, null, 'Site is already running the latest version available.' );
190 }
191
192 // Require some libraries and attempt the upgrade.
193 @include_once ABSPATH . '/wp-admin/includes/admin.php';
194 @include_once ABSPATH . '/wp-admin/includes/class-wp-upgrader.php';
195 $skin = new Automatic_Upgrader_Skin();
196 $upgrader = new Core_Upgrader( $skin );
197 $result = $upgrader->upgrade(
198 $core->updates[0],
199 array(
200 'attempt_rollback' => true,
201 'do_rollback' => true,
202 'allow_relaxed_file_ownership' => true,
203 )
204 );
205 if ( ! $result ) {
206 $this->returnResults( false, null, 'The WordPress core could not be upgraded, most likely because of invalid filesystem connection information.' );
207 }
208
209 // Synchronize again with the API.
210 do_action( 'patchstack_send_software_data' );
211 $this->returnResults( $results, 'WordPress core has been upgraded.' );
212 }
213
214 /**
215 * Upgrade a WordPress theme.
216 *
217 * @return string|void
218 */
219 private function themeUpgrade() {
220 if ( !isset( $_POST['webarx_theme_upgrade'] ) ) {
221 return;
222 }
223
224 @set_time_limit( 180 );
225
226 // Require some files we need to execute the upgrade.
227 $theme = wp_filter_nohtml_kses( $_POST['webarx_theme_upgrade'] );
228 @include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
229 if ( file_exists( ABSPATH . 'wp-admin/includes/class-theme-upgrader.php' ) ) {
230 @include_once ABSPATH . 'wp-admin/includes/class-theme-upgrader.php';
231 }
232 @include_once ABSPATH . 'wp-admin/includes/misc.php';
233 @include_once ABSPATH . 'wp-admin/includes/file.php';
234
235 // Upgrade the theme.
236 $skin = new Automatic_Upgrader_Skin();
237 $upgrader = new Theme_Upgrader( $skin );
238 $result = $upgrader->upgrade( $theme, array( 'allow_relaxed_file_ownership' => true ) );
239 if ( ! $result ) {
240 $this->returnResults( false, null, 'The theme could not be upgraded, most likely because of invalid filesystem connection information.' );
241 }
242
243 // Synchronize again with the API.
244 do_action( 'patchstack_send_software_data' );
245 $this->returnResults( null, 'The theme has been updated successfully.' );
246 }
247
248 /**
249 * Upgrade a batch of plugins at once.
250 *
251 * @return string|void
252 */
253 private function pluginsUpgrade() {
254 if (!isset( $_POST['webarx_plugins_upgrade'] ) ) {
255 return;
256 }
257
258 @set_time_limit( 180 );
259
260 // Must have a valid number of plugins received to upgrade.
261 $plugins = wp_filter_nohtml_kses( $_POST['webarx_plugins_upgrade'] );
262 $plugins = explode( '|', $plugins );
263 if ( count( $plugins ) == 0 ) {
264 $this->returnResults( false, null, 'No valid plugin names have been given.' );
265 }
266
267 // Require some files we need to execute the upgrade.
268 @include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
269 if ( file_exists( ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php' ) ) {
270 @include_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
271 }
272 @include_once ABSPATH . 'wp-admin/class-automatic-upgrader-skin.php';
273
274 @include_once ABSPATH . 'wp-admin/includes/plugin.php';
275 @include_once ABSPATH . 'wp-admin/includes/misc.php';
276 @include_once ABSPATH . 'wp-admin/includes/file.php';
277 @include_once ABSPATH . 'wp-admin/includes/template.php';
278 @wp_update_plugins();
279 $all_plugins = get_plugins();
280
281 // New array with all available plugins and the ones we want to upgrade.
282 $upgrade = array();
283 foreach ( $all_plugins as $path => $data ) {
284 $t = explode( '/', $path );
285 if ( in_array( $t[0], $plugins ) ) {
286 array_push( $upgrade, $path );
287 }
288 }
289
290 // Don't continue if we have no valid plugins to upgrade.
291 if ( count( $upgrade ) == 0 ) {
292 $this->returnResults( false, null, 'No valid plugin names have been given.' );
293 }
294
295 // Upgrade the plugins.
296 $skin = new Automatic_Upgrader_Skin();
297 $upgrader = new Plugin_Upgrader( $skin );
298 $result = $upgrader->bulk_upgrade( $upgrade, array( 'allow_relaxed_file_ownership' => true ) );
299 if ( ! $result ) {
300 $this->returnResults( false, null, 'The plugins could not be upgraded, most likely because of invalid filesystem connection information.' );
301 }
302
303 // Synchronize again with the API.
304 do_action( 'patchstack_send_software_data' );
305 $this->returnResults( null, 'The plugins have been updated successfully.' );
306 }
307
308 /**
309 * Toggle the state of a batch of plugin to activated or de-activated.
310 *
311 * @return string|void
312 */
313 private function pluginsToggle() {
314 if (!isset( $_POST['webarx_plugins'], $_POST['webarx_plugins_toggle'] ) ) {
315 return;
316 }
317
318 @set_time_limit( 180 );
319
320 // Must have a valid number of plugins received to toggle.
321 $plugins = wp_filter_nohtml_kses( $_POST['webarx_plugins'] );
322 $plugins = explode( '|', $plugins );
323 $state = $_POST['webarx_plugins_toggle'] == 'on' ? 'on' : 'off';
324 if ( count( $plugins ) == 0 ) {
325 $this->returnResults( false, null, 'No valid plugin names have been given.' );
326 }
327
328 @include_once ABSPATH . 'wp-admin/includes/plugin.php';
329 $all_plugins = get_plugins();
330
331 // New array with all available plugins and the ones we want to toggle.
332 $toggle = array();
333 foreach ( $all_plugins as $path => $data ) {
334 $t = explode( '/', $path );
335
336 // Don't continue if the plugin does not exist locally.
337 if ( ! in_array( $t[0], $plugins ) ) {
338 continue;
339 }
340
341 // If plugin should be turned on, check if it's already turned on first.
342 if ( $state == 'on' && ! is_plugin_active( $path ) ) {
343 array_push( $toggle, $path );
344 }
345
346 // If plugin should be turned off, check if it's already turned off first.
347 if ( $state == 'off' && is_plugin_active( $path ) ) {
348 array_push( $toggle, $path );
349 }
350 }
351
352 // Don't continue if we have no valid plugins to toggle..
353 if ( count( $toggle ) == 0 ) {
354 $this->returnResults( false, null, 'The plugins are already turned ' . $state . '.' );
355 }
356
357 // Turn the plugins on or off?
358 if ( $state == 'on' ) {
359 activate_plugins( $toggle );
360 }
361
362 if ( $state == 'off' ) {
363 deactivate_plugins( $toggle );
364 }
365
366 // Synchronize again with the API.
367 do_action( 'patchstack_send_software_data' );
368 $this->returnResults( null, 'The ' . ( count( $toggle ) == 1 ? 'plugin has' : 'plugins have' ) . ' been successfully turned ' . $state . '.' );
369 }
370
371 /**
372 * Delete a batch of plugins.
373 *
374 * @return string|void
375 */
376 private function pluginsDelete() {
377 if (!isset( $_POST['webarx_plugins'] ) ) {
378 return;
379 }
380
381 @set_time_limit( 180 );
382
383 // Must have a valid number of plugins received to toggle.
384 $plugins = wp_filter_nohtml_kses( $_POST['webarx_plugins'] );
385 $plugins = explode( '|', $plugins );
386 if ( count( $plugins ) == 0 ) {
387 $this->returnResults( false, null, 'No valid plugin names have been given.' );
388 }
389
390 @include_once ABSPATH . 'wp-admin/includes/file.php';
391 @include_once ABSPATH . 'wp-admin/includes/plugin.php';
392 $all_plugins = get_plugins();
393
394 // New array with all available plugins and the ones we want to toggle.
395 $delete = array();
396 foreach ( $all_plugins as $path => $data ) {
397 $t = explode( '/', $path );
398
399 // Don't continue if the plugin does not exist locally.
400 if ( ! in_array( $t[0], $plugins ) ) {
401 continue;
402 }
403
404 array_push( $delete, $path );
405 }
406
407 // Don't continue if we have no valid plugins to toggle..
408 if ( count( $delete ) == 0 ) {
409 $this->returnResults( false, null, 'No valid plugins to delete.' );
410 }
411
412 @deactivate_plugins( $delete );
413 @delete_plugins( $delete );
414
415 // Synchronize again with the API.
416 do_action( 'patchstack_send_software_data' );
417 $this->returnResults( null, 'The plugins have been successfully deleted.' );
418 }
419
420 /**
421 * Save received options.
422 *
423 * @return void
424 */
425 private function saveOptions() {
426 if ( ! isset( $_POST['webarx_set_options'], $_POST['webarx_secret'] ) ) {
427 exit;
428 }
429
430 // Get the received options.
431 $options = json_decode( base64_decode( $_POST['webarx_set_options'] ), true );
432 if ( ! $options || count( $options ) == 0 ) {
433 exit;
434 }
435
436 // Loop through the options and update their value.
437 $exclude_filter = array( 'patchstack_firewall_custom_rules', 'patchstack_whitelist' );
438 foreach ( $options as $key => $value ) {
439 if ( array_key_exists( $key, $this->plugin->admin_options->options ) ) {
440
441 // Some options should not be filtered and could cause unexpected behavior if they are filtered.
442 if ( ! in_array( $key, $exclude_filter ) ) {
443 $value = map_deep( $value, 'wp_filter_nohtml_kses' );
444 }
445
446 update_option( $key, $value, true );
447 }
448 }
449
450 $this->returnResults( null, 'Plugin options has been updated.' );
451 }
452
453 /**
454 * Return list of keys and values of Patchstack options.
455 *
456 * @return array
457 */
458 private function getAvailableOptions() {
459 // Get all options and filter by the Patchstack prefix.
460 global $wpdb;
461 $options = $wpdb->get_results( "SELECT option_name, option_value FROM " . $wpdb->options . " WHERE option_name LIKE 'patchstack_%'" );
462 $settings = array();
463 $found = array();
464 foreach ( $options as $option ) {
465 array_push( $found, $option->option_name );
466 $settings[] = (array) $option;
467 }
468
469 // Check for potential missing options and add them to the output.
470 foreach( array( 'patchstack_firewall_custom_rules' ) as $slug ) {
471 if ( ! isset ( $found[$slug] ) ) {
472 $settings[] = array(
473 'option_name' => $slug,
474 'option_value' => $this->get_option( $slug, '' )
475 );
476 }
477 }
478
479 // Add custom values which aren't directly available from the options table.
480 // User roles available for whitelisting.
481 $roles = wp_roles();
482 $roles = $roles->get_names();
483 $roles_available = array();
484 foreach ( $roles as $key => $role ) {
485 $roles_available[ $key ] = $role;
486 }
487 $settings[] = array(
488 'option_name' => 'patchstack_basic_firewall_roles_available',
489 'option_value' => serialize( $roles_available ),
490 );
491
492 // Whether or not auto-updates are disabled in the code.
493 $settings[] = array(
494 'option_name' => 'patchstack_auto_updates_disabled',
495 'option_value' => defined( 'AUTOMATIC_UPDATER_DISABLED' ) && AUTOMATIC_UPDATER_DISABLED,
496 );
497
498 wp_send_json( $settings );
499 }
500
501 /**
502 * Pull firewall rules from the API.
503 *
504 * @return void
505 */
506 private function refreshRules() {
507 do_action( 'patchstack_post_dynamic_firewall_rules' );
508 $this->returnResults( null, 'Firewall rules have been refreshed.' );
509 }
510
511 /**
512 * Get a list of IP addresses that are currently banned by the firewall.
513 *
514 * @return void
515 */
516 private function getFirewallBans() {
517 // Calculate block time.
518 $minutes = (int) $this->get_option( 'patchstack_autoblock_minutes', 30 );
519 $timeout = (int) $this->get_option( 'patchstack_autoblock_blocktime', 60 );
520 if ( empty( $minutes ) || empty( $timeout ) ) {
521 $time = 30 + 60;
522 } else {
523 $time = $minutes + $timeout;
524 }
525
526 global $wpdb;
527 $results = $wpdb->get_results(
528 $wpdb->prepare( 'SELECT ip FROM ' . $wpdb->prefix . "patchstack_firewall_log WHERE apply_ban = 1 AND log_date >= ('" . current_time( 'mysql' ) . "' - INTERVAL %d MINUTE) GROUP BY ip", array( $time ) ),
529 OBJECT
530 );
531
532 $out = array();
533 foreach ( $results as $result ) {
534 if ( isset( $result->ip ) ) {
535 array_push( $out, $result->ip );
536 }
537 }
538
539 wp_send_json( $out );
540 }
541
542 /**
543 * Unban a specific IP address from the firewall.
544 *
545 * @return void
546 */
547 private function unbanFirewallIp() {
548 if ( ! isset( $_POST['webarx_ip'] ) || !filter_var( $_POST['webarx_ip'], FILTER_VALIDATE_IP ) ) {
549 return;
550 }
551
552 global $wpdb;
553 $wpdb->query( $wpdb->prepare( 'UPDATE ' . $wpdb->prefix . 'patchstack_firewall_log SET apply_ban = 0 WHERE ip = %s', array( $_POST['webarx_ip'] ) ) );
554 $this->returnResults( null, 'The IP has been unbanned.' );
555 }
556
557 /**
558 * Send all current software on the WordPress site to the API.
559 *
560 * @return void
561 */
562 private function uploadSoftware() {
563 do_action( 'patchstack_send_software_data' );
564 $this->returnResults( null, 'The software data has been sent to the API.' );
565 }
566
567 /**
568 * Upload the firewall and activity logs.
569 *
570 * @return void
571 */
572 private function uploadLogs() {
573 do_action( 'patchstack_send_hacker_logs' );
574 do_action( 'patchstack_send_event_logs' );
575 $this->returnResults( null, 'The logs have been sent to the API.' );
576 }
577
578 /**
579 * Get the currently banned IP addresses from the login page.
580 *
581 * @return void
582 */
583 private function getLoginBans() {
584 // Calculate block time.
585 $minutes = (int) $this->get_option( 'patchstack_anti_bruteforce_minutes', 30 );
586 $timeout = (int) $this->get_option( 'patchstack_anti_bruteforce_blocktime', 60 );
587 if ( empty( $minutes ) || empty( $timeout ) ) {
588 $time = 30 + 60;
589 } else {
590 $time = $minutes + $timeout;
591 }
592
593 // Check if X failed login attempts were made.
594 global $wpdb;
595 $results = $wpdb->get_results(
596 $wpdb->prepare( 'SELECT id, ip, date FROM ' . $wpdb->prefix . "patchstack_event_log WHERE action = 'failed login' AND date >= ('" . current_time( 'mysql' ) . "' - INTERVAL %d MINUTE) GROUP BY ip HAVING COUNT(ip) >= %d ORDER BY date DESC", array( $time, $this->get_option( 'patchstack_anti_bruteforce_attempts', 10 ) ) ),
597 OBJECT
598 );
599
600 // Return the banned IP addresses.
601 wp_send_json( array( 'banned' => $results ) );
602 }
603
604 /**
605 * Unban a banned login IP address.
606 *
607 * @return void
608 */
609 private function unbanLogin() {
610 if ( ! isset( $_POST['id'], $_POST['type'] ) || !ctype_digit( $_POST['id'] ) ) {
611 exit;
612 }
613
614 global $wpdb;
615
616 // Unblock the IP; delete the logs of the IP.
617 if ( $_POST['type'] == 'unblock' ) {
618 // First get the IP address to unblock.
619 $result = $wpdb->get_results(
620 $wpdb->prepare( 'SELECT ip FROM ' . $wpdb->prefix . 'patchstack_event_log WHERE id = %d', array( (int) $_POST['id'] ) )
621 );
622
623 // Unblock the IP address.
624 if ( isset( $result[0], $result[0]->ip ) && filter_var( $result[0]->ip, FILTER_VALIDATE_IP ) ) {
625 $wpdb->query(
626 $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'patchstack_event_log WHERE ip = %s', array( $result[0]->ip ) )
627 );
628 }
629 }
630
631 // Unblock and whitelist the IP.
632 if ( $_POST['type'] == 'unblock_whitelist' ) {
633 // First get the IP address to whitelist.
634 $result = $wpdb->get_results(
635 $wpdb->prepare( 'SELECT ip FROM ' . $wpdb->prefix . 'patchstack_event_log WHERE id = %d', array( (int) $_POST['id'] ) )
636 );
637
638 // Whitelist and unblock the IP address.
639 if ( isset( $result[0], $result[0]->ip ) && filter_var( $result[0]->ip, FILTER_VALIDATE_IP ) ) {
640 update_option( 'patchstack_login_whitelist', $this->get_option( 'patchstack_login_whitelist', '' ) . "\n" . $result[0]->ip );
641 $wpdb->query(
642 $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'patchstack_event_log WHERE ip = %s', array( $result[0]->ip ) )
643 );
644 }
645 }
646
647 $this->returnResults( null, 'The unban has been processed.' );
648 }
649
650 /**
651 * Get information for debugging purposes.
652 *
653 * @return void
654 */
655 private function debugInfo() {
656 $debug = array(
657 'server' => $_SERVER,
658 'php' => phpversion()
659 );
660
661 wp_send_json( $debug );
662 }
663
664 /**
665 * Try to determine the proper IP address headers.
666 *
667 * @return void
668 */
669 private function setIpHeader() {
670 if ( ! isset( $_POST['ip'] ) ) {
671 return;
672 }
673
674 $ips = ! is_array ( $_POST['ip'] ) ? array( $_POST['ip'] ) : $_POST['ip'];
675
676 // REMOTE_ADDR?
677 foreach ( $ips as $ip ) {
678 if ( isset( $_SERVER['REMOTE_ADDR'] ) && $_SERVER['REMOTE_ADDR'] == $ip ) {
679 update_option( 'patchstack_firewall_ip_header', 'REMOTE_ADDR' );
680 update_option( 'patchstack_ip_header_computed', 1 );
681 update_option( 'patchstack_ott_action', '' );
682 wp_send_json( array( 'success' => true, 'header' => 'REMOTE_ADDR' ) );
683 }
684 }
685
686 // IP address headers in order of priority.
687 $priority = array( 'REMOTE_ADDR', 'HTTP_CF_CONNECTING_IP', 'HTTP_X_SUCURI_CLIENTIP', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'SUCURI_RIP' );
688 foreach ( $ips as $ip ) {
689 foreach ( $priority as $header ) {
690 if ( isset( $_SERVER[ $header ] ) && $_SERVER[ $header ] == $ip ) {
691 update_option( 'patchstack_firewall_ip_header', $header );
692 update_option( 'patchstack_ip_header_computed', 1 );
693 update_option( 'patchstack_ott_action', '' );
694 wp_send_json( array( 'success' => true, 'header' => $header ) );
695 }
696 }
697 }
698
699 // Still not found? Iterate over all $_SERVER keys.
700 foreach ( $ips as $ip ) {
701 foreach ( $_SERVER as $key => $value ) {
702 if ( $value == $ip ) {
703 update_option( 'patchstack_firewall_ip_header', $key );
704 update_option( 'patchstack_ip_header_computed', 1 );
705 update_option( 'patchstack_ott_action', '' );
706 wp_send_json( array( 'success' => true, 'header' => $key ) );
707 }
708 }
709 }
710
711 update_option( 'patchstack_ott_action', '' );
712 wp_send_json( array( 'success' => false, 'header' => 'unknown' ) );
713 }
714
715 /**
716 * Refresh the license and subscription information.
717 *
718 * @return void
719 */
720 private function refreshLicense (){
721 do_action( 'update_license_status' );
722 do_action( 'patchstack_send_software_data' );
723 do_action( 'patchstack_post_dynamic_firewall_rules' );
724
725 wp_send_json( array( 'success' => true ) );
726 }
727 }
728