summaryrefslogtreecommitdiff
blob: 619194ad62a378d4c5cbea987547812e0a22da63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<?php
/**
 * The Server_Sandbox class.
 *
 * This feature is only useful for Automattic developers.
 * It configures Jetpack to talk to staging/sandbox servers
 * on WordPress.com instead of production servers.
 *
 * @package automattic/jetpack-sandbox
 */

namespace Automattic\Jetpack\Connection;

use Automattic\Jetpack\Constants;

/**
 * The Server_Sandbox class.
 */
class Server_Sandbox {

	/**
	 * Sets up the action hooks for the server sandbox.
	 */
	public function init() {
		if ( did_action( 'jetpack_server_sandbox_init' ) ) {
			return;
		}

		add_action( 'requests-requests.before_request', array( $this, 'server_sandbox' ), 10, 2 );
		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$$
		 */
		do_action( 'jetpack_server_sandbox_init' );
	}

	/**
	 * Returns the new url and host values.
	 *
	 * @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.
	 *
	 * @return array [ 'url' => new URL, 'host' => new Host ]
	 */
	public function server_sandbox_request_parameters( $sandbox, $url, $headers ) {
		$host = '';

		if ( ! is_string( $sandbox ) || ! is_string( $url ) ) {
			return array(
				'url'  => $url,
				'host' => $host,
			);
		}

		$url_host = wp_parse_url( $url, PHP_URL_HOST );

		switch ( $url_host ) {
			case 'public-api.wordpress.com':
			case 'jetpack.wordpress.com':
			case 'jetpack.com':
			case 'dashboard.wordpress.com':
				$host = isset( $headers['Host'] ) ? $headers['Host'] : $url_host;
				$url  = preg_replace(
					'@^(https?://)' . preg_quote( $url_host, '@' ) . '(?=[/?#].*|$)@',
					'${1}' . $sandbox,
					$url,
					1
				);
		}

		return compact( 'url', 'host' );
	}

	/**
	 * Modifies parameters of request in order to send the request to the
	 * server specified by `JETPACK__SANDBOX_DOMAIN`.
	 *
	 * 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.
	 * @return void
	 */
	public function server_sandbox( &$url, &$headers ) {
		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 );

		$url = $request_parameters['url'];

		if ( $request_parameters['host'] ) {
			$headers['Host'] = $request_parameters['host'];

			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
			}
		}
	}

	/**
	 * Adds a "Jetpack API Sandboxed" item to the admin bar if the JETPACK__SANDBOX_DOMAIN
	 * constant is set.
	 *
	 * Attached to the `admin_bar_menu` action.
	 *
	 * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar instance.
	 */
	public function admin_bar_add_sandbox_item( $wp_admin_bar ) {
		if ( ! Constants::get_constant( 'JETPACK__SANDBOX_DOMAIN' ) ) {
			return;
		}

		$node = array(
			'id'    => 'jetpack-connection-api-sandbox',
			'title' => 'Jetpack API Sandboxed',
			'meta'  => array(
				'title' => 'Sandboxing via ' . Constants::get_constant( 'JETPACK__SANDBOX_DOMAIN' ),
			),
		);

		$wp_admin_bar->add_menu( $node );
	}
}