PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.3-beta
16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 All 507 releases
← All changes | jetpack_vendor/automattic/jetpack-connection/src/class-tracking.php +32 -19 13.7.2 → 16.3-beta View file →
@@ -6,8 +6,10 @@
6 6 */
7 7
8 8 namespace Automattic\Jetpack;
9 9
10 +use Automattic\Jetpack\IP\Utils as IP_Utils;
11 +
10 12 /**
11 13 * The Tracking class, used to record events in wpcom
12 14 */
13 15 class Tracking {
@@ -37,9 +39,9 @@
37 39
38 40 /**
39 41 * Creates the Tracking object.
40 42 *
41 - * @param String $product_name the slug of the product that we are tracking.
43 + * @param string $product_name the slug of the product that we are tracking.
42 44 * @param \Automattic\Jetpack\Connection\Manager $connection the connection manager object.
43 45 */
44 46 public function __construct( $product_name = 'jetpack', $connection = null ) {
45 47 $this->product_name = $product_name;
@@ -75,9 +77,10 @@
75 77 || ! wp_verify_nonce( $_REQUEST['tracksNonce'], 'jp-tracks-ajax-nonce' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- WP core doesn't pre-sanitize nonces either.
76 78 ) {
77 79 wp_send_json_error(
78 80 __( 'You aren’t authorized to do that.', 'jetpack-connection' ),
79 - 403
81 + 403,
82 + JSON_UNESCAPED_SLASHES
80 83 );
81 84 }
82 85
83 86 if ( ! isset( $_REQUEST['tracksEventName'] ) || ! isset( $_REQUEST['tracksEventType'] ) ) {
@@ -82,24 +85,30 @@
82 85
83 86 if ( ! isset( $_REQUEST['tracksEventName'] ) || ! isset( $_REQUEST['tracksEventType'] ) ) {
84 87 wp_send_json_error(
85 88 __( 'No valid event name or type.', 'jetpack-connection' ),
86 - 403
89 + 403,
90 + JSON_UNESCAPED_SLASHES
87 91 );
92 + exit; // @phan-suppress-current-line PhanPluginUnreachableCode -- @todo Remove when WP 7.1 is the minimum version.
88 93 }
89 94
90 95 $tracks_data = array();
91 96 if ( 'click' === $_REQUEST['tracksEventType'] && isset( $_REQUEST['tracksEventProp'] ) ) {
92 97 if ( is_array( $_REQUEST['tracksEventProp'] ) ) {
93 - $tracks_data = array_map( 'filter_var', wp_unslash( $_REQUEST['tracksEventProp'] ) );
98 + // map_deep() rather than array_map(): the request is client-supplied and may nest,
99 + // and sanitize_text_field() returns an empty string when handed an array.
100 + $tracks_data = map_deep( wp_unslash( $_REQUEST['tracksEventProp'] ), 'sanitize_text_field' );
94 101 } else {
95 - $tracks_data = array( 'clicked' => filter_var( wp_unslash( $_REQUEST['tracksEventProp'] ) ) );
102 + $tracks_data = array( 'clicked' => sanitize_text_field( wp_unslash( $_REQUEST['tracksEventProp'] ) ) );
96 103 }
97 104 }
98 105
99 - $this->record_user_event( filter_var( wp_unslash( $_REQUEST['tracksEventName'] ) ), $tracks_data, null, false );
106 + // Tracks only accepts lowercase alphanumerics and underscores in an event name
107 + // (see Jetpack_Tracks_Event::EVENT_NAME_REGEX), which is what sanitize_key() permits.
108 + $this->record_user_event( sanitize_key( wp_unslash( $_REQUEST['tracksEventName'] ) ), $tracks_data, null, false );
100 109
101 - wp_send_json_success();
110 + wp_send_json_success( null, null, JSON_UNESCAPED_SLASHES );
102 111 }
103 112
104 113 /**
105 114 * Register script necessary for tracking.
@@ -168,11 +177,11 @@
168 177 $user = wp_get_current_user();
169 178 }
170 179 $site_url = get_option( 'siteurl' );
171 180
172 - $data['_via_ua'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? filter_var( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
173 - $data['_via_ip'] = isset( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
174 - $data['_lg'] = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? filter_var( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) : '';
181 + $data['_via_ua'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
182 + $data['_via_ip'] = isset( $_SERVER['REMOTE_ADDR'] ) ? (string) IP_Utils::clean_ip( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- clean_ip() validates the address.
183 + $data['_lg'] = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) : '';
175 184 $data['blog_url'] = $site_url;
176 185 $data['blog_id'] = \Jetpack_Options::get_option( 'id' );
177 186
178 187 // Top level events should not be namespaced.
@@ -250,9 +259,9 @@
250 259
251 260 $properties['user_lang'] = $user->get( 'WPLANG' );
252 261
253 262 $blog_details = array(
254 - 'blog_lang' => isset( $properties['blog_lang'] ) ? $properties['blog_lang'] : get_bloginfo( 'language' ),
263 + 'blog_lang' => $properties['blog_lang'] ?? get_bloginfo( 'language' ),
255 264 'blog_id' => \Jetpack_Options::get_option( 'id' ),
256 265 );
257 266
258 267 $timestamp = ( false !== $event_timestamp_millis ) ? $event_timestamp_millis : round( microtime( true ) * 1000 );
@@ -279,11 +288,11 @@
279 288 * @return array $identity
280 289 */
281 290 public function tracks_get_identity( $user_id ) {
282 291
283 - // Meta is set, and user is still connected. Use WPCOM ID.
292 + // Meta is set, and user is still connected. Use WPCOM ID.
284 293 $wpcom_id = get_user_meta( $user_id, 'jetpack_tracks_wpcom_id', true );
285 - if ( $wpcom_id && $this->connection->is_user_connected( $user_id ) ) {
294 + if ( $wpcom_id && is_string( $wpcom_id ) && $this->connection->is_user_connected( $user_id ) ) {
286 295 return array(
287 296 '_ut' => 'wpcom:user_id',
288 297 '_ui' => $wpcom_id,
289 298 );
@@ -288,17 +297,21 @@
288 297 '_ui' => $wpcom_id,
289 298 );
290 299 }
291 300
292 - // User is connected, but no meta is set yet. Use WPCOM ID and set meta.
301 + // User is connected, but no meta is set yet. Use WPCOM ID and set meta.
293 302 if ( $this->connection->is_user_connected( $user_id ) ) {
294 303 $wpcom_user_data = $this->connection->get_connected_user_data( $user_id );
295 - update_user_meta( $user_id, 'jetpack_tracks_wpcom_id', $wpcom_user_data['ID'] );
304 + $wpcom_id = $wpcom_user_data['ID'] ?? null;
296 305
297 - return array(
298 - '_ut' => 'wpcom:user_id',
299 - '_ui' => $wpcom_user_data['ID'],
300 - );
306 + if ( is_string( $wpcom_id ) ) {
307 + update_user_meta( $user_id, 'jetpack_tracks_wpcom_id', $wpcom_id );
308 +
309 + return array(
310 + '_ut' => 'wpcom:user_id',
311 + '_ui' => $wpcom_id,
312 + );
313 + }
301 314 }
302 315
303 316 // User isn't linked at all. Fall back to anonymous ID.
304 317 $anon_id = get_user_meta( $user_id, 'jetpack_tracks_anon_id', true );