diff options
Diffstat (limited to 'plugins/jetpack/jetpack_vendor/automattic/jetpack-connection/src/class-server-sandbox.php')
-rw-r--r-- | plugins/jetpack/jetpack_vendor/automattic/jetpack-connection/src/class-server-sandbox.php | 140 |
1 files changed, 126 insertions, 14 deletions
diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-connection/src/class-server-sandbox.php b/plugins/jetpack/jetpack_vendor/automattic/jetpack-connection/src/class-server-sandbox.php index 619194ad..2d45a0b6 100644 --- a/plugins/jetpack/jetpack_vendor/automattic/jetpack-connection/src/class-server-sandbox.php +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-connection/src/class-server-sandbox.php @@ -26,14 +26,14 @@ class Server_Sandbox { return; } - add_action( 'requests-requests.before_request', array( $this, 'server_sandbox' ), 10, 2 ); + add_action( 'requests-requests.before_request', array( $this, 'server_sandbox' ), 10, 4 ); add_action( 'admin_bar_menu', array( $this, 'admin_bar_add_sandbox_item' ), 999 ); /** * Fires when the server sandbox is initialized. This action is used to ensure that * the server sandbox action hooks are set up only once. * - * @since $$next_version$$ + * @since 1.30.7 */ do_action( 'jetpack_server_sandbox_init' ); } @@ -44,16 +44,20 @@ class Server_Sandbox { * @param string $sandbox Sandbox domain. * @param string $url URL of request about to be made. * @param array $headers Headers of request about to be made. + * @param string $data The body of request about to be made. + * @param string $method The method of request about to be made. * - * @return array [ 'url' => new URL, 'host' => new Host ] + * @return array [ 'url' => new URL, 'host' => new Host, 'new_signature => New signature if url was changed ] */ - public function server_sandbox_request_parameters( $sandbox, $url, $headers ) { - $host = ''; + public function server_sandbox_request_parameters( $sandbox, $url, $headers, $data = null, $method = 'GET' ) { + $host = ''; + $new_signature = ''; if ( ! is_string( $sandbox ) || ! is_string( $url ) ) { return array( - 'url' => $url, - 'host' => $host, + 'url' => $url, + 'host' => $host, + 'new_signature' => $new_signature, ); } @@ -64,16 +68,118 @@ class Server_Sandbox { case 'jetpack.wordpress.com': case 'jetpack.com': case 'dashboard.wordpress.com': - $host = isset( $headers['Host'] ) ? $headers['Host'] : $url_host; - $url = preg_replace( + $host = isset( $headers['Host'] ) ? $headers['Host'] : $url_host; + $original_url = $url; + $url = preg_replace( '@^(https?://)' . preg_quote( $url_host, '@' ) . '(?=[/?#].*|$)@', '${1}' . $sandbox, $url, 1 ); + + /** + * Whether to add the X Debug query parameter to the request made to the Sandbox + * + * @since 1.36.0 + * + * @param bool $add_parameter Whether to add the parameter to the request or not. Default is to false. + * @param string $url The URL of the request being made. + * @param string $host The host of the request being made. + */ + if ( apply_filters( 'jetpack_sandbox_add_profile_parameter', false, $url, $host ) ) { + $url = add_query_arg( 'XDEBUG_PROFILE', 1, $url ); + + // URL has been modified since the signature was created. We'll need a new one. + $original_url = add_query_arg( 'XDEBUG_PROFILE', 1, $original_url ); + $new_signature = $this->get_new_signature( $original_url, $headers, $data, $method ); + + } + } + + return compact( 'url', 'host', 'new_signature' ); + } + + /** + * Gets a new signature for the request + * + * @param string $url The new URL to be signed. + * @param array $headers The headers of the request about to be made. + * @param string $data The body of request about to be made. + * @param string $method The method of the request about to be made. + * @return string|null + */ + private function get_new_signature( $url, $headers, $data, $method ) { + + if ( ! empty( $headers['Authorization'] ) ) { + $a_headers = $this->extract_authorization_headers( $headers ); + if ( ! empty( $a_headers ) ) { + $token_details = explode( ':', $a_headers['token'] ); + + if ( count( $token_details ) === 3 ) { + $user_id = $token_details[2]; + $token = ( new Tokens() )->get_access_token( $user_id ); + $time_diff = (int) \Jetpack_Options::get_option( 'time_diff' ); + $jetpack_signature = new \Jetpack_Signature( $token->secret, $time_diff ); + + $signature = $jetpack_signature->sign_request( + $a_headers['token'], + $a_headers['timestamp'], + $a_headers['nonce'], + $a_headers['body-hash'], + $method, + $url, + $data, + false + ); + + if ( $signature && ! is_wp_error( $signature ) ) { + return $signature; + } elseif ( is_wp_error( $signature ) ) { + $this->log_new_signature_error( $signature->get_error_message() ); + } + } else { + $this->log_new_signature_error( 'Malformed token on Authorization Header' ); + } + } else { + $this->log_new_signature_error( 'Error extracting Authorization Header' ); + } + } else { + $this->log_new_signature_error( 'Empty Authorization Header' ); } - return compact( 'url', 'host' ); + } + + /** + * Logs error if the attempt to create a new signature fails + * + * @param string $message The error message. + * @return void + */ + private function log_new_signature_error( $message ) { + if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { + error_log( sprintf( "SANDBOXING: Error re-signing the request. '%s'", $message ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log + } + } + + /** + * Extract the values in the Authorization header into an array + * + * @param array $headers The headers of the request about to be made. + * @return array|null + */ + public function extract_authorization_headers( $headers ) { + if ( ! empty( $headers['Authorization'] ) && is_string( $headers['Authorization'] ) ) { + $header = str_replace( 'X_JETPACK ', '', $headers['Authorization'] ); + $vars = explode( ' ', $header ); + $result = array(); + foreach ( $vars as $var ) { + $elements = explode( '"', $var ); + if ( count( $elements ) === 3 ) { + $result[ substr( $elements[0], 0, -1 ) ] = $elements[1]; + } + } + return $result; + } } /** @@ -82,24 +188,30 @@ class Server_Sandbox { * * Attached to the `requests-requests.before_request` filter. * - * @param string $url URL of request about to be made. - * @param array $headers Headers of request about to be made. + * @param string $url URL of request about to be made. + * @param array $headers Headers of request about to be made. + * @param array|string $data Data of request about to be made. + * @param string $type Type of request about to be made. * @return void */ - public function server_sandbox( &$url, &$headers ) { + public function server_sandbox( &$url, &$headers, &$data = null, &$type = null ) { if ( ! Constants::get_constant( 'JETPACK__SANDBOX_DOMAIN' ) ) { return; } $original_url = $url; - $request_parameters = $this->server_sandbox_request_parameters( Constants::get_constant( 'JETPACK__SANDBOX_DOMAIN' ), $url, $headers ); + $request_parameters = $this->server_sandbox_request_parameters( Constants::get_constant( 'JETPACK__SANDBOX_DOMAIN' ), $url, $headers, $data, $type ); $url = $request_parameters['url']; if ( $request_parameters['host'] ) { $headers['Host'] = $request_parameters['host']; + if ( $request_parameters['new_signature'] ) { + $headers['Authorization'] = preg_replace( '/signature=\"[^\"]+\"/', 'signature="' . $request_parameters['new_signature'] . '"', $headers['Authorization'] ); + } + if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log( sprintf( "SANDBOXING via '%s': '%s'", Constants::get_constant( 'JETPACK__SANDBOX_DOMAIN' ), $original_url ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log } |