PluginProbe
Patchstack – WordPress & Plugins Security / 2.1.6
Patchstack – WordPress & Plugins Security v2.1.6
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
← All changes | includes/admin/ajax.php +119 -64 trunk2.1.6 View file →
@@ -18,97 +18,152 @@
18 18 */
19 19 public function __construct( $core ) {
20 20 parent::__construct( $core );
21 21 if ( isset( $_POST['PatchstackNonce'] ) && current_user_can( 'manage_options' ) && wp_verify_nonce( $_POST['PatchstackNonce'], 'patchstack-nonce' ) ) {
22 + // Log tables actions.
23 + add_action( 'wp_ajax_users_log_table', array( $this, 'users_log_table' ) );
24 + add_action( 'wp_ajax_firewall_log_table', array( $this, 'firewall_log_table' ) );
25 +
22 26 // License related actions.
23 - add_action( 'wp_ajax_patchstack_activate_license', [ $this, 'activate_license' ] );
24 -
25 - // Auto license activator.
26 - add_action( 'wp_ajax_patchstack_activate_auto', [ $this, 'auto_activate' ] );
27 - add_action( 'wp_ajax_patchstack_activation_status', [ $this, 'activation_status' ] );
28 -
29 - // Manual connection re-check (Retry link on the settings card).
30 - add_action( 'wp_ajax_patchstack_check_connection', [ $this, 'check_connection' ] );
27 + add_action( 'wp_ajax_activate_license', array( $this, 'activate_license' ) );
31 28 }
32 29 }
33 30
34 31 /**
35 - * Test and activate a new license.
32 + * Firewall logs pagination.
36 33 *
37 - * @return void
34 + * @return array
38 35 */
39 - public function activate_license() {
40 - if ( ! isset( $_POST['key'] ) || strpos( $_POST['key'], '-' ) === false) {
41 - wp_send_json(
42 - [
43 - 'result' => 'error',
44 - 'error_message' => esc_attr__('An invalid API key was provided.', 'patchstack')
45 - ]
46 - );
36 + public function firewall_log_table() {
37 + if ( ! isset( $_POST['start'], $_POST['length'] ) || !ctype_digit( $_POST['start'] ) || !ctype_digit( $_POST['length'] ) ) {
38 + exit;
47 39 }
48 40
49 - // Since we have the keys combined into one now, split them up here.
50 - $split = explode('-', $_POST['key']);
51 - $secretkey = trim($split[0]);
52 - $clientid = trim($split[1]);
41 + // Pull all entries, given parameters.
42 + global $wpdb;
43 + $entries = $wpdb->get_results(
44 + $wpdb->prepare(
45 + "SELECT a.id, a.ip, a.flag, a.method, a.log_date, case when a.referer IS NULL or a.referer = '' then a.request_uri else a.referer end as referer, a.fid, b.description
46 + FROM " . $wpdb->prefix . 'patchstack_firewall_log AS a
47 + LEFT JOIN ' . $wpdb->prefix . 'patchstack_logic AS b ON b.id = a.fid
48 + ORDER BY a.id DESC
49 + LIMIT %d, %d
50 + ',
51 + array( wp_filter_nohtml_kses( $_POST['start'] ), wp_filter_nohtml_kses( $_POST['length'] ) )
52 + )
53 + );
53 54
54 - // Test the new keys.
55 - update_option( 'patchstack_api_token', '' );
56 - $results = $this->plugin->activation->alter_license( wp_filter_nohtml_kses( $clientid ), wp_filter_nohtml_kses( $secretkey ), 'activate' );
57 - if ( $results ) {
58 - $response = $this->plugin->api->update_license_status();
59 - $results['response'] = $response;
60 - wp_send_json( $results );
55 + // Get total amount of rows.
56 + $count = $wpdb->get_var( 'SELECT COUNT(id) FROM ' . $wpdb->prefix . 'patchstack_firewall_log' );
57 + $firewall_rules = json_decode( get_option( 'patchstack_firewall_rules', '' ), true );
58 +
59 + // Modify data if necessary.
60 + $list = array();
61 + foreach ( $entries as $entry ) {
62 + foreach ( $entry as $key => $value ) {
63 + if ( ! in_array( $key, array( 'referer' ) ) ) {
64 + $entry->$key = sanitize_textarea_field( $value );
65 + }
66 + }
67 +
68 + // Attempt to find the block reason.
69 + $reason = $wpdb->get_var( $wpdb->prepare( 'SELECT cname FROM ' . $wpdb->prefix . 'patchstack_logic WHERE id = %d LIMIT 1', array( $entry->fid ) ) );
70 + if ( $reason ) {
71 + $entry->fid = $reason;
72 + } elseif ( $firewall_rules != '' ) {
73 + foreach ( $firewall_rules as $rule ) {
74 + if ( isset( $rule['title'], $rule['cat'] ) && '55' . $rule['id'] == $entry->fid ) {
75 + $entry->fid = $rule['cat'];
76 + $entry->description = $rule['title'];
77 + }
78 + }
79 + } else {
80 + $entry->fid = 'Unknown';
81 + }
82 +
83 + $list[] = $entry;
61 84 }
85 +
86 + // Return output.
87 + wp_send_json(
88 + array(
89 + 'data' => $list,
90 + 'recordsFiltered' => $count,
91 + 'recordsTotal' => $count
92 + )
93 + );
62 94 }
63 95
64 96 /**
65 - * Attempt to auto activate the license after a plugin activation, if no current license exists.
66 - *
97 + * Activity logs pagination.
98 + *
67 99 * @return void
68 100 */
69 - public function auto_activate() {
70 - $secretToken = get_option( 'patchstack_activation_secret', '' );
101 + public function users_log_table() {
102 + if ( ! isset( $_POST['start'], $_POST['length'] ) || !ctype_digit( $_POST['start'] ) || !ctype_digit( $_POST['length'] ) ) {
103 + exit;
104 + }
71 105
72 - // Only continue if we have a secret token.
73 - $autoActivated = false;
74 - if ( ! empty( $secretToken ) ) {
75 - $autoActivated = $this->plugin->api->send_secret_token( $secretToken );
106 + // Determine if searching?
107 + global $wpdb;
108 + $searching = false;
109 + $likes = array();
110 + if ( isset( $_POST['search'], $_POST['search']['value'] ) && $_POST['search']['value'] != '' ) {
111 + $val = wp_filter_nohtml_kses( $_POST['search']['value'] );
112 + $searching = true;
113 + $columns = array( 'author', 'ip', 'object', 'object_name', 'action' );
114 + $search = 'WHERE 1=2 ';
115 + foreach ( $columns as $column ) {
116 + array_push( $likes, '%' . $wpdb->esc_like( $val ) . '%' );
117 + $search .= 'OR ' . $column . ' LIKE %s';
118 + }
76 119 }
77 120
78 - wp_send_json( [
79 - 'result' => $autoActivated || get_option( 'patchstack_clientid', false ) != false ? 'success' : 'error'
80 - ] );
81 - }
121 + $logs = $wpdb->get_results(
122 + $wpdb->prepare(
123 + 'SELECT *
124 + FROM ' . $wpdb->prefix . 'patchstack_event_log ' . ( $searching ? $search : '' ) . '
125 + ORDER BY id DESC
126 + LIMIT %d, %d
127 + ',
128 + array_merge( $likes, array( wp_filter_nohtml_kses( $_POST['start'] ), wp_filter_nohtml_kses( $_POST['length'] ) ) )
129 + )
130 + );
82 131
83 - /**
84 - * Get the current license activation status.
85 - *
86 - * @return void
87 - */
88 - public function activation_status() {
89 - wp_send_json( [
90 - 'activated' => get_option( 'patchstack_clientid', false ) != false
91 - ] );
132 + $count = $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(id) FROM ' . $wpdb->prefix . 'patchstack_event_log ' . ( $searching ? $search : '' ), $likes ) );
133 +
134 + // Modify data if necessary.
135 + $list = array();
136 + foreach ( $logs as $log ) {
137 + $list[] = $log;
138 + }
139 +
140 + // Return output.
141 + wp_send_json(
142 + array(
143 + 'data' => $list,
144 + 'recordsFiltered' => $count,
145 + 'recordsTotal' => $count
146 + )
147 + );
92 148 }
93 149
94 150 /**
95 - * Run a connection check on demand and return the new state for the settings card row.
96 - * Wraps P_Api::update_license_status() so the existing 422-handling happens for free; a
97 - * successful request stamps patchstack_last_sync, which get_last_sync_time() reads back.
151 + * Test and activate a new license.
98 152 *
99 153 * @return void
100 154 */
101 - public function check_connection() {
102 - $this->plugin->api->update_license_status();
155 + public function activate_license() {
156 + if ( ! isset( $_POST['clientid'], $_POST['secretkey'] ) || !ctype_digit( $_POST['clientid'] ) ) {
157 + return;
158 + }
103 159
104 - $timestamp = $this->get_last_sync_time();
105 -
106 - wp_send_json(
107 - [
108 - 'connected' => $this->is_connected(),
109 - 'timestamp' => $timestamp,
110 - 'label' => $this->format_relative_time( $timestamp ),
111 - ]
112 - );
160 + // Test the new keys.
161 + update_option( 'patchstack_api_token', '' );
162 + $results = $this->plugin->activation->alter_license( wp_filter_nohtml_kses( $_POST['clientid'] ), wp_filter_nohtml_kses( $_POST['secretkey'] ), 'activate' );
163 + if ( $results ) {
164 + $response = $this->plugin->api->update_license_status();
165 + $results['response'] = $response;
166 + wp_send_json( $results );
167 + }
113 168 }
114 169 }