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-server-sandbox.php +243 -0 16.2-beta → 16.3-beta View file →
@@ -1,0 +1,243 @@
1 +<?php
2 +/**
3 + * The Server_Sandbox class.
4 + *
5 + * This feature is only useful for Automattic developers.
6 + * It configures Jetpack to talk to staging/sandbox servers
7 + * on WordPress.com instead of production servers.
8 + *
9 + * @package automattic/jetpack-sandbox
10 + */
11 +
12 +namespace Automattic\Jetpack\Connection;
13 +
14 +use Automattic\Jetpack\Constants;
15 +
16 +/**
17 + * The Server_Sandbox class.
18 + */
19 +class Server_Sandbox {
20 +
21 + /**
22 + * Sets up the action hooks for the server sandbox.
23 + */
24 + public function init() {
25 + if ( did_action( 'jetpack_server_sandbox_init' ) ) {
26 + return;
27 + }
28 +
29 + add_action( 'requests-requests.before_request', array( $this, 'server_sandbox' ), 10, 4 );
30 + add_action( 'admin_bar_menu', array( $this, 'admin_bar_add_sandbox_item' ), 999 );
31 +
32 + /**
33 + * Fires when the server sandbox is initialized. This action is used to ensure that
34 + * the server sandbox action hooks are set up only once.
35 + *
36 + * @since 1.30.7
37 + */
38 + do_action( 'jetpack_server_sandbox_init' );
39 + }
40 +
41 + /**
42 + * Returns the new url and host values.
43 + *
44 + * @param string $sandbox Sandbox domain.
45 + * @param string $url URL of request about to be made.
46 + * @param array $headers Headers of request about to be made.
47 + * @param string $data The body of request about to be made.
48 + * @param string $method The method of request about to be made.
49 + *
50 + * @return array [ 'url' => new URL, 'host' => new Host, 'new_signature => New signature if url was changed ]
51 + */
52 + public function server_sandbox_request_parameters( $sandbox, $url, $headers, $data = null, $method = 'GET' ) {
53 + $host = '';
54 + $new_signature = '';
55 +
56 + if ( ! is_string( $sandbox ) || ! is_string( $url ) ) {
57 + return array(
58 + 'url' => $url,
59 + 'host' => $host,
60 + 'new_signature' => $new_signature,
61 + );
62 + }
63 +
64 + $url_host = wp_parse_url( $url, PHP_URL_HOST );
65 +
66 + switch ( $url_host ) {
67 + case 'public-api.wordpress.com':
68 + case 'jetpack.wordpress.com':
69 + case 'jetpack.com':
70 + case 'dashboard.wordpress.com':
71 + $host = $headers['Host'] ?? $url_host;
72 + $original_url = $url;
73 + $url = preg_replace(
74 + '@^(https?://)' . preg_quote( $url_host, '@' ) . '(?=[/?#].*|$)@',
75 + '${1}' . $sandbox,
76 + $url,
77 + 1
78 + );
79 +
80 + /**
81 + * Whether to add the X Debug query parameter to the request made to the Sandbox
82 + *
83 + * @since 1.36.0
84 + *
85 + * @param bool $add_parameter Whether to add the parameter to the request or not. Default is to false.
86 + * @param string $url The URL of the request being made.
87 + * @param string $host The host of the request being made.
88 + */
89 + if ( apply_filters( 'jetpack_sandbox_add_profile_parameter', false, $url, $host ) ) {
90 + $url = add_query_arg( 'XDEBUG_PROFILE', 1, $url );
91 +
92 + // URL has been modified since the signature was created. We'll need a new one.
93 + $original_url = add_query_arg( 'XDEBUG_PROFILE', 1, $original_url );
94 + $new_signature = $this->get_new_signature( $original_url, $headers, $data, $method );
95 +
96 + }
97 + }
98 +
99 + return compact( 'url', 'host', 'new_signature' );
100 + }
101 +
102 + /**
103 + * Gets a new signature for the request
104 + *
105 + * @param string $url The new URL to be signed.
106 + * @param array $headers The headers of the request about to be made.
107 + * @param string $data The body of request about to be made.
108 + * @param string $method The method of the request about to be made.
109 + * @return string|null
110 + */
111 + private function get_new_signature( $url, $headers, $data, $method ) {
112 +
113 + if ( ! empty( $headers['Authorization'] ) ) {
114 + $a_headers = $this->extract_authorization_headers( $headers );
115 + if ( ! empty( $a_headers ) ) {
116 + $token_details = explode( ':', $a_headers['token'] );
117 +
118 + if ( count( $token_details ) === 3 ) {
119 + $user_id = $token_details[2];
120 + $token = ( new Tokens() )->get_access_token( $user_id );
121 + $time_diff = (int) \Jetpack_Options::get_option( 'time_diff' );
122 + $jetpack_signature = new \Jetpack_Signature( $token->secret, $time_diff );
123 +
124 + $signature = $jetpack_signature->sign_request(
125 + $a_headers['token'],
126 + $a_headers['timestamp'],
127 + $a_headers['nonce'],
128 + $a_headers['body-hash'],
129 + $method,
130 + $url,
131 + $data,
132 + false
133 + );
134 +
135 + if ( $signature && ! is_wp_error( $signature ) ) {
136 + return $signature;
137 + } elseif ( is_wp_error( $signature ) ) {
138 + $this->log_new_signature_error( $signature->get_error_message() );
139 + }
140 + } else {
141 + $this->log_new_signature_error( 'Malformed token on Authorization Header' );
142 + }
143 + } else {
144 + $this->log_new_signature_error( 'Error extracting Authorization Header' );
145 + }
146 + } else {
147 + $this->log_new_signature_error( 'Empty Authorization Header' );
148 + }
149 + }
150 +
151 + /**
152 + * Logs error if the attempt to create a new signature fails
153 + *
154 + * @param string $message The error message.
155 + * @return void
156 + */
157 + private function log_new_signature_error( $message ) {
158 + if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
159 + error_log( sprintf( "SANDBOXING: Error re-signing the request. '%s'", $message ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
160 + }
161 + }
162 +
163 + /**
164 + * Extract the values in the Authorization header into an array
165 + *
166 + * @param array $headers The headers of the request about to be made.
167 + * @return array|null
168 + */
169 + public function extract_authorization_headers( $headers ) {
170 + if ( ! empty( $headers['Authorization'] ) && is_string( $headers['Authorization'] ) ) {
171 + $header = str_replace( 'X_JETPACK ', '', $headers['Authorization'] );
172 + $vars = explode( ' ', $header );
173 + $result = array();
174 + foreach ( $vars as $var ) {
175 + $elements = explode( '"', $var );
176 + if ( count( $elements ) === 3 ) {
177 + $result[ substr( $elements[0], 0, -1 ) ] = $elements[1];
178 + }
179 + }
180 + return $result;
181 + }
182 + }
183 +
184 + /**
185 + * Modifies parameters of request in order to send the request to the
186 + * server specified by `JETPACK__SANDBOX_DOMAIN`.
187 + *
188 + * Attached to the `requests-requests.before_request` filter.
189 + *
190 + * @param string $url URL of request about to be made.
191 + * @param array $headers Headers of request about to be made.
192 + * @param array|string $data Data of request about to be made.
193 + * @param string $type Type of request about to be made.
194 + * @return void
195 + */
196 + public function server_sandbox( &$url, &$headers, &$data = null, &$type = null ) {
197 + if ( ! Constants::get_constant( 'JETPACK__SANDBOX_DOMAIN' ) ) {
198 + return;
199 + }
200 +
201 + $original_url = $url;
202 +
203 + $request_parameters = $this->server_sandbox_request_parameters( Constants::get_constant( 'JETPACK__SANDBOX_DOMAIN' ), $url, $headers, $data, $type );
204 +
205 + $url = $request_parameters['url'];
206 +
207 + if ( $request_parameters['host'] ) {
208 + $headers['Host'] = $request_parameters['host'];
209 +
210 + if ( $request_parameters['new_signature'] ) {
211 + $headers['Authorization'] = preg_replace( '/signature=\"[^\"]+\"/', 'signature="' . $request_parameters['new_signature'] . '"', $headers['Authorization'] );
212 + }
213 +
214 + if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
215 + error_log( sprintf( "SANDBOXING via '%s': '%s'", Constants::get_constant( 'JETPACK__SANDBOX_DOMAIN' ), $original_url ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
216 + }
217 + }
218 + }
219 +
220 + /**
221 + * Adds a "Jetpack API Sandboxed" item to the admin bar if the JETPACK__SANDBOX_DOMAIN
222 + * constant is set.
223 + *
224 + * Attached to the `admin_bar_menu` action.
225 + *
226 + * @param \WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar instance.
227 + */
228 + public function admin_bar_add_sandbox_item( $wp_admin_bar ) {
229 + if ( ! Constants::get_constant( 'JETPACK__SANDBOX_DOMAIN' ) ) {
230 + return;
231 + }
232 +
233 + $node = array(
234 + 'id' => 'jetpack-connection-api-sandbox',
235 + 'title' => 'Jetpack API Sandboxed',
236 + 'meta' => array(
237 + 'title' => 'Sandboxing via ' . Constants::get_constant( 'JETPACK__SANDBOX_DOMAIN' ),
238 + ),
239 + );
240 +
241 + $wp_admin_bar->add_menu( $node );
242 + }
243 +}