PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 3.2.5
Jetpack – WP Security, Backup, Speed, & Growth v3.2.5
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 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / class.jetpack-client.php
class.jetpack-client.php
215 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class Jetpack_Client {
4 /**
5 * Makes an authorized remote request using Jetpack_Signature
6 *
7 * @return array|WP_Error WP HTTP response on success
8 */
9 public static function remote_request( $args, $body = null ) {
10 $defaults = array(
11 'url' => '',
12 'user_id' => 0,
13 'blog_id' => 0,
14 'auth_location' => JETPACK_CLIENT__AUTH_LOCATION,
15 'method' => 'POST',
16 'timeout' => 10,
17 'redirection' => 0,
18 );
19
20 $args = wp_parse_args( $args, $defaults );
21
22 $args['blog_id'] = (int) $args['blog_id'];
23
24 if ( 'header' != $args['auth_location'] ) {
25 $args['auth_location'] = 'query_string';
26 }
27
28 $token = Jetpack_Data::get_access_token( $args['user_id'] );
29 if ( !$token ) {
30 return new Jetpack_Error( 'missing_token' );
31 }
32
33 $method = strtoupper( $args['method'] );
34
35 $timeout = intval( $args['timeout'] );
36
37 $redirection = $args['redirection'];
38
39 $request = compact( 'method', 'body', 'timeout', 'redirection' );
40
41 @list( $token_key, $secret ) = explode( '.', $token->secret );
42 if ( empty( $token ) || empty( $secret ) ) {
43 return new Jetpack_Error( 'malformed_token' );
44 }
45
46 $token_key = sprintf( '%s:%d:%d', $token_key, JETPACK__API_VERSION, $token->external_user_id );
47
48 require_once JETPACK__PLUGIN_DIR . 'class.jetpack-signature.php';
49
50 $time_diff = (int) Jetpack_Options::get_option( 'time_diff' );
51 $jetpack_signature = new Jetpack_Signature( $token->secret, $time_diff );
52
53 $timestamp = time() + $time_diff;
54 $nonce = wp_generate_password( 10, false );
55
56 // Kind of annoying. Maybe refactor Jetpack_Signature to handle body-hashing
57 if ( is_null( $body ) ) {
58 $body_hash = '';
59 } else {
60 if ( !is_string( $body ) ) {
61 return new Jetpack_Error( 'invalid_body', 'Body is malformed.' );
62 }
63 $body_hash = jetpack_sha1_base64( $body );
64 }
65
66 $auth = array(
67 'token' => $token_key,
68 'timestamp' => $timestamp,
69 'nonce' => $nonce,
70 'body-hash' => $body_hash,
71 );
72
73 if ( false !== strpos( $args['url'], 'xmlrpc.php' ) ) {
74 $url_args = array(
75 'for' => 'jetpack',
76 'wpcom_blog_id' => Jetpack_Options::get_option( 'id' ),
77 );
78 } else {
79 $url_args = array();
80 }
81
82 if ( 'header' != $args['auth_location'] ) {
83 $url_args += $auth;
84 }
85
86 $url = add_query_arg( urlencode_deep( $url_args ), $args['url'] );
87 $url = Jetpack::fix_url_for_bad_hosts( $url );
88
89 $signature = $jetpack_signature->sign_request( $token_key, $timestamp, $nonce, $body_hash, $method, $url, $body, false );
90
91 if ( !$signature || is_wp_error( $signature ) ) {
92 return $signature;
93 }
94
95 // Send an Authorization header so various caches/proxies do the right thing
96 $auth['signature'] = $signature;
97 $auth['version'] = JETPACK__VERSION;
98 $header_pieces = array();
99 foreach ( $auth as $key => $value ) {
100 $header_pieces[] = sprintf( '%s="%s"', $key, $value );
101 }
102 $request['headers'] = array(
103 'Authorization' => "X_JETPACK " . join( ' ', $header_pieces ),
104 );
105
106 if ( 'header' != $args['auth_location'] ) {
107 $url = add_query_arg( 'signature', urlencode( $signature ), $url );
108 }
109
110 return Jetpack_Client::_wp_remote_request( $url, $request );
111 }
112
113 /**
114 * Wrapper for wp_remote_request(). Turns off SSL verification for certain SSL errors.
115 * This is lame, but many, many, many hosts have misconfigured SSL.
116 *
117 * When Jetpack is registered, the jetpack_fallback_no_verify_ssl_certs option is set to the current time if:
118 * 1. a certificate error is found AND
119 * 2. not verifying the certificate works around the problem.
120 *
121 * The option is checked on each request.
122 *
123 * @internal
124 * @see Jetpack::fix_url_for_bad_hosts()
125 *
126 * @return array|WP_Error WP HTTP response on success
127 */
128 public static function _wp_remote_request( $url, $args, $set_fallback = false ) {
129 $fallback = Jetpack_Options::get_option( 'fallback_no_verify_ssl_certs' );
130 if ( false === $fallback ) {
131 Jetpack_Options::update_option( 'fallback_no_verify_ssl_certs', 0 );
132 }
133
134 if ( (int) $fallback ) {
135 // We're flagged to fallback
136 $args['sslverify'] = false;
137 }
138
139 $response = wp_remote_request( $url, $args );
140
141 if (
142 !$set_fallback // We're not allowed to set the flag on this request, so whatever happens happens
143 ||
144 isset( $args['sslverify'] ) && !$args['sslverify'] // No verification - no point in doing it again
145 ||
146 !is_wp_error( $response ) // Let it ride
147 ) {
148 Jetpack_Client::set_time_diff( $response, $set_fallback );
149 return $response;
150 }
151
152 // At this point, we're not flagged to fallback and we are allowed to set the flag on this request.
153
154 $message = $response->get_error_message();
155
156 // Is it an SSL Certificate verification error?
157 if (
158 false === strpos( $message, '14090086' ) // OpenSSL SSL3 certificate error
159 &&
160 false === strpos( $message, '1407E086' ) // OpenSSL SSL2 certificate error
161 &&
162 false === strpos( $message, 'error setting certificate verify locations' ) // cURL CA bundle not found
163 &&
164 false === strpos( $message, 'Peer certificate cannot be authenticated with' ) // cURL CURLE_SSL_CACERT: CA bundle found, but not helpful
165 // different versions of curl have different error messages
166 // this string should catch them all
167 &&
168 false === strpos( $message, 'Problem with the SSL CA cert' ) // cURL CURLE_SSL_CACERT_BADFILE: probably access rights
169 ) {
170 // No, it is not.
171 return $response;
172 }
173
174 // Redo the request without SSL certificate verification.
175 $args['sslverify'] = false;
176 $response = wp_remote_request( $url, $args );
177
178 if ( !is_wp_error( $response ) ) {
179 // The request went through this time, flag for future fallbacks
180 Jetpack_Options::update_option( 'fallback_no_verify_ssl_certs', time() );
181 Jetpack_Client::set_time_diff( $response, $set_fallback );
182 }
183
184 return $response;
185 }
186
187 public static function set_time_diff( &$response, $force_set = false ) {
188 $code = wp_remote_retrieve_response_code( $response );
189
190 // Only trust the Date header on some responses
191 if ( 200 != $code && 304 != $code && 400 != $code && 401 != $code ) {
192 return;
193 }
194
195 if ( !$date = wp_remote_retrieve_header( $response, 'date' ) ) {
196 return;
197 }
198
199 if ( 0 >= $time = (int) strtotime( $date ) ) {
200 return;
201 }
202
203 $time_diff = $time - time();
204
205 if ( $force_set ) { // during register
206 Jetpack_Options::update_option( 'time_diff', $time_diff );
207 } else { // otherwise
208 $old_diff = Jetpack_Options::get_option( 'time_diff' );
209 if ( false === $old_diff || abs( $time_diff - (int) $old_diff ) > 10 ) {
210 Jetpack_Options::update_option( 'time_diff', $time_diff );
211 }
212 }
213 }
214 }
215