PluginProbe
Patchstack – WordPress & Plugins Security / 2.2.2
Patchstack – WordPress & Plugins Security v2.2.2
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 +136 -53 trunk2.2.2 View file →
@@ -18,21 +18,142 @@
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_patchstack_users_log_table', [ $this, 'users_log_table' ] );
24 + add_action( 'wp_ajax_patchstack_firewall_log_table', [ $this, 'firewall_log_table' ] );
25 +
22 26 // License related actions.
23 27 add_action( 'wp_ajax_patchstack_activate_license', [ $this, 'activate_license' ] );
24 28
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' ] );
29 + // Hide login related actions.
30 + add_action( 'wp_ajax_patchstack_send_new_url_email', [ $this, 'send_new_url_email' ] );
31 + }
32 + }
28 33
29 - // Manual connection re-check (Retry link on the settings card).
30 - add_action( 'wp_ajax_patchstack_check_connection', [ $this, 'check_connection' ] );
34 + /**
35 + * Firewall logs pagination.
36 + *
37 + * @return array
38 + */
39 + public function firewall_log_table() {
40 + if ( ! isset( $_POST['start'], $_POST['length'] ) || !ctype_digit( $_POST['start'] ) || !ctype_digit( $_POST['length'] ) ) {
41 + exit;
31 42 }
43 +
44 + // Pull all entries, given parameters.
45 + global $wpdb;
46 + $entries = $wpdb->get_results(
47 + $wpdb->prepare(
48 + "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
49 + FROM " . $wpdb->prefix . 'patchstack_firewall_log AS a
50 + LEFT JOIN ' . $wpdb->prefix . 'patchstack_logic AS b ON b.id = a.fid
51 + ORDER BY a.id DESC
52 + LIMIT %d, %d
53 + ',
54 + [ wp_filter_nohtml_kses( $_POST['start'] ), wp_filter_nohtml_kses( $_POST['length'] ) ]
55 + )
56 + );
57 +
58 + // Get total amount of rows.
59 + $count = $wpdb->get_var( 'SELECT COUNT(id) FROM ' . $wpdb->prefix . 'patchstack_firewall_log' );
60 + $firewall_rules = json_decode( get_option( 'patchstack_firewall_rules', '' ), true );
61 + $firewall_rules_v3 = json_decode( get_option( 'patchstack_firewall_rules_v3', [] ), true );
62 + $firewall_rules = array_merge($firewall_rules, $firewall_rules_v3);
63 +
64 + // Modify data if necessary.
65 + $list = [];
66 + foreach ( $entries as $entry ) {
67 + foreach ( $entry as $key => $value ) {
68 + if ( ! in_array( $key, [ 'referer' ] ) ) {
69 + $entry->$key = sanitize_textarea_field( $value );
70 + }
71 + }
72 +
73 + // Attempt to find the block reason.
74 + $reason = $wpdb->get_var( $wpdb->prepare( 'SELECT cname FROM ' . $wpdb->prefix . 'patchstack_logic WHERE id = %d LIMIT 1', [ $entry->fid ] ) );
75 + if ( $reason ) {
76 + $entry->fid = $reason;
77 + } elseif ( $firewall_rules != '' ) {
78 + foreach ( $firewall_rules as $rule ) {
79 + if ( isset( $rule['title'], $rule['cat'] ) && '55' . $rule['id'] == $entry->fid ) {
80 + $entry->fid = $rule['cat'];
81 + $entry->description = $rule['title'];
82 + }
83 + }
84 + } else {
85 + $entry->fid = 'Unknown';
86 + }
87 +
88 + $list[] = $entry;
89 + }
90 +
91 + // Return output.
92 + wp_send_json(
93 + [
94 + 'data' => $list,
95 + 'recordsFiltered' => $count,
96 + 'recordsTotal' => $count
97 + ]
98 + );
32 99 }
33 100
34 101 /**
102 + * Activity logs pagination.
103 + *
104 + * @return void
105 + */
106 + public function users_log_table() {
107 + if ( ! isset( $_POST['start'], $_POST['length'] ) || !ctype_digit( $_POST['start'] ) || !ctype_digit( $_POST['length'] ) ) {
108 + exit;
109 + }
110 +
111 + // Determine if searching?
112 + global $wpdb;
113 + $searching = false;
114 + $likes = [];
115 + if ( isset( $_POST['search'], $_POST['search']['value'] ) && $_POST['search']['value'] != '' ) {
116 + $val = wp_filter_nohtml_kses( $_POST['search']['value'] );
117 + $searching = true;
118 + $columns = [ 'author', 'ip', 'object', 'object_name', 'action' ];
119 + $search = 'WHERE 1=2 ';
120 + foreach ( $columns as $column ) {
121 + array_push( $likes, '%' . $wpdb->esc_like( $val ) . '%' );
122 + $search .= 'OR ' . $column . ' LIKE %s';
123 + }
124 + }
125 +
126 + $logs = $wpdb->get_results(
127 + $wpdb->prepare(
128 + 'SELECT *
129 + FROM ' . $wpdb->prefix . 'patchstack_event_log ' . ( $searching ? $search : '' ) . '
130 + ORDER BY id DESC
131 + LIMIT %d, %d
132 + ',
133 + array_merge( $likes, [ wp_filter_nohtml_kses( $_POST['start'] ), wp_filter_nohtml_kses( $_POST['length'] ) ] )
134 + )
135 + );
136 +
137 + $count = $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(id) FROM ' . $wpdb->prefix . 'patchstack_event_log ' . ( $searching ? $search : '' ), $likes ) );
138 +
139 + // Modify data if necessary.
140 + $list = [];
141 + foreach ( $logs as $log ) {
142 + $list[] = $log;
143 + }
144 +
145 + // Return output.
146 + wp_send_json(
147 + [
148 + 'data' => $list,
149 + 'recordsFiltered' => $count,
150 + 'recordsTotal' => $count
151 + ]
152 + );
153 + }
154 +
155 + /**
35 156 * Test and activate a new license.
36 157 *
37 158 * @return void
38 159 */
@@ -40,9 +161,9 @@
40 161 if ( ! isset( $_POST['key'] ) || strpos( $_POST['key'], '-' ) === false) {
41 162 wp_send_json(
42 163 [
43 164 'result' => 'error',
44 - 'error_message' => esc_attr__('An invalid API key was provided.', 'patchstack')
165 + 'error_message' => 'An invalid API key was provided.'
45 166 ]
46 167 );
47 168 }
48 169
@@ -47,10 +168,10 @@
47 168 }
48 169
49 170 // Since we have the keys combined into one now, split them up here.
50 171 $split = explode('-', $_POST['key']);
51 - $secretkey = trim($split[0]);
52 - $clientid = trim($split[1]);
172 + $secretkey = $split[0];
173 + $clientid = $split[1];
53 174
54 175 // Test the new keys.
55 176 update_option( 'patchstack_api_token', '' );
56 177 $results = $this->plugin->activation->alter_license( wp_filter_nohtml_kses( $clientid ), wp_filter_nohtml_kses( $secretkey ), 'activate' );
@@ -61,54 +182,16 @@
61 182 }
62 183 }
63 184
64 185 /**
65 - * Attempt to auto activate the license after a plugin activation, if no current license exists.
66 - *
67 - * @return void
68 - */
69 - public function auto_activate() {
70 - $secretToken = get_option( 'patchstack_activation_secret', '' );
71 -
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 );
76 - }
77 -
78 - wp_send_json( [
79 - 'result' => $autoActivated || get_option( 'patchstack_clientid', false ) != false ? 'success' : 'error'
80 - ] );
81 - }
82 -
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 - ] );
92 - }
93 -
94 - /**
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.
186 + * Send an email to the current logged in user that contains the new admin page URL.
98 187 *
99 188 * @return void
100 189 */
101 - public function check_connection() {
102 - $this->plugin->api->update_license_status();
103 -
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 - );
190 + public function send_new_url_email() {
191 + global $current_user;
192 + $subject = __( 'New Login URL', 'patchstack' );
193 + $message = '<br /><br />Your login page is now here: <strong> <a href="' . get_site_url() . '/' . get_site_option( 'patchstack_rename_wp_login' ) . '">' . get_site_url() . '/' . get_site_option( 'patchstack_rename_wp_login' ) . '</strong></a>';
194 + $email_sent = wp_mail( $current_user->user_email, $subject, $message );
195 + die( $email_sent ? 'success' : 'fail' );
113 196 }
114 197 }