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-client.php +46 -6 13.6.2 → 16.3-beta View file →
@@ -38,10 +38,36 @@
38 38 */
39 39 $args['url'] = apply_filters( 'jetpack_remote_request_url', $args['url'] );
40 40 }
41 41
42 + // Feed failures into the outgoing-request error flow of Error_Handler: any known
43 + // connection error is stored and surfaced to the user. See the Error_Handler
44 + // class docblock for the full picture of both error-handling flows.
45 + // Outgoing XML-RPC calls (Jetpack_IXR_Client) are funneled through this method too;
46 + // tell the transports apart by the endpoint the request targets.
47 + // The literals match Error_Handler::ERROR_TYPE_XMLRPC / ERROR_TYPE_REST. The constants
48 + // themselves must not be referenced from this class: during a plugin update, a stale
49 + // Error_Handler that predates them can already be loaded, and resolving them against
50 + // it would fatal the request.
51 + $request_path = (string) wp_parse_url( empty( $args['url'] ) ? '' : $args['url'], PHP_URL_PATH );
52 + $error_type = '/xmlrpc.php' === substr( $request_path, -strlen( '/xmlrpc.php' ) ) ? 'xmlrpc' : 'rest';
53 +
42 54 $result = self::build_signed_request( $args, $body );
43 55 if ( is_wp_error( $result ) ) {
56 + // The request was never made, so it has no response to check. Report the signing
57 + // failure; attribution comes from the error itself — see
58 + // `Error_Handler::check_signed_request_for_errors()`.
59 + // Reporting is best-effort and must never fatal a request running mid-plugin-update:
60 + // skip it when the already-loaded Error_Handler is a stale version predating this method.
61 + if ( method_exists( Error_Handler::class, 'check_signed_request_for_errors' ) ) {
62 + Error_Handler::get_instance()->check_signed_request_for_errors(
63 + $result,
64 + empty( $args['url'] ) ? '' : $args['url'],
65 + empty( $args['method'] ) ? 'POST' : $args['method'],
66 + $error_type
67 + );
68 + }
69 +
44 70 return $result;
45 71 }
46 72
47 73 $response = self::_wp_remote_request( $result['url'], $result['request'] );
@@ -50,9 +76,9 @@
50 76 $response,
51 77 $result['auth'],
52 78 empty( $args['url'] ) ? '' : $args['url'],
53 79 empty( $args['method'] ) ? 'POST' : $args['method'],
54 - 'rest'
80 + $error_type
55 81 );
56 82
57 83 /**
58 84 * Fired when the remote request response has been received.
@@ -109,11 +135,22 @@
109 135 if ( 'header' !== $args['auth_location'] ) {
110 136 $args['auth_location'] = 'query_string';
111 137 }
112 138
113 - $token = ( new Tokens() )->get_access_token( $args['user_id'] );
139 + // Return the specific reason the token could not be loaded instead of a bare `false`.
140 + // Note the returned `WP_Error` is truthy, so this must not be tested with `! $token`.
141 + $token = ( new Tokens() )->get_access_token(
142 + $args['user_id'],
143 + false, // token_key
144 + false // suppress_errors
145 + );
146 + if ( is_wp_error( $token ) ) {
147 + return $token;
148 + }
114 149 if ( ! $token ) {
115 - return new WP_Error( 'missing_token' );
150 + // `get_access_token()` explains itself for every case but one: it returns a bare
151 + // `false` when the tokens are locked. That lock is one-shot and self-healing.
152 + return new WP_Error( 'tokens_locked' );
116 153 }
117 154
118 155 $method = strtoupper( $args['method'] );
119 156
@@ -163,9 +200,12 @@
163 200 if ( is_array( $body_to_hash ) ) {
164 201 // We cast this to a new variable, because the array form of $body needs to be
165 202 // maintained so it can be passed into the request later on in the code.
166 203 if ( array() !== $body_to_hash ) {
167 - $body_to_hash = wp_json_encode( self::_stringify_data( $body_to_hash ) );
204 + $body_to_hash = wp_json_encode(
205 + self::_stringify_data( $body_to_hash ),
206 + 0 // phpcs:ignore Jetpack.Functions.JsonEncodeFlags.ZeroFound -- No `json_encode()` flags because this needs to match whatever is calculating the hash on the other end.
207 + );
168 208 } else {
169 209 $body_to_hash = '';
170 210 }
171 211 }
@@ -416,9 +456,9 @@
416 456 *
417 457 * @param string $path REST API path.
418 458 * @param string $version REST API version. Default is `2`.
419 459 * @param array $args Arguments to {@see WP_Http}. Default is `array()`.
420 - * @param null|string|array $body Body passed to {@see WP_Http}. Default is `null`.
460 + * @param null|string|array $body Body passed to {@see WP_Http}. Default is `null`.
421 461 * @param string $base_api_path REST API root. Default is `wpcom`.
422 462 *
423 463 * @return array|WP_Error $response Response data, else {@see WP_Error} on failure.
424 464 * @phan-return _WP_Remote_Response_Array|WP_Error
@@ -437,9 +477,9 @@
437 477 $args['headers'] = array( 'Content-Type' => 'application/json' );
438 478 }
439 479
440 480 if ( isset( $body ) && ! is_string( $body ) ) {
441 - $body = wp_json_encode( $body );
481 + $body = wp_json_encode( $body, JSON_UNESCAPED_SLASHES );
442 482 }
443 483
444 484 return self::remote_request( $args, $body );
445 485 }