Completed
Push — fix/story-image-scaling-in-ema... ( c127bb...4ef3f5 )
by
unknown
299:55 queued 290:12
created

jetpack_xmlrpc_server_event()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 4
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Jetpack XMLRPC Methods.
4
 *
5
 * Registers the Jetpack specific XMLRPC methods
6
 *
7
 * @package jetpack
8
 */
9
10
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
11
use Automattic\Jetpack\Connection\Tokens;
12
13
/**
14
 * XMLRPC Methods registration and callbacks
15
 */
16
class Jetpack_XMLRPC_Methods {
17
18
	/**
19
	 * Initialize the main hooks.
20
	 */
21
	public static function init() {
22
		add_filter( 'jetpack_xmlrpc_unauthenticated_methods', array( __CLASS__, 'xmlrpc_methods' ) );
23
		add_filter( 'jetpack_xmlrpc_test_connection_response', array( __CLASS__, 'test_connection' ) );
24
		add_filter( 'jetpack_remote_xmlrpc_provision_response', array( __CLASS__, 'remote_provision_response' ), 10, 2 );
25
		add_action( 'jetpack_xmlrpc_server_event', array( __CLASS__, 'jetpack_xmlrpc_server_event' ), 10, 4 );
26
		add_action( 'jetpack_remote_connect_end', array( __CLASS__, 'remote_connect_end' ) );
27
		add_filter( 'jetpack_xmlrpc_remote_register_redirect_uri', array( __CLASS__, 'remote_register_redirect_uri' ) );
28
	}
29
30
	/**
31
	 * Adds Jetpack specific methods to the methods added by the Connection package.
32
	 *
33
	 * @param array $methods Methods added by the Connection package.
34
	 */
35
	public static function xmlrpc_methods( $methods ) {
36
37
		$methods['jetpack.featuresAvailable'] = array( __CLASS__, 'features_available' );
38
		$methods['jetpack.featuresEnabled']   = array( __CLASS__, 'features_enabled' );
39
		$methods['jetpack.disconnectBlog']    = array( __CLASS__, 'disconnect_blog' );
40
		$methods['jetpack.jsonAPI']           = array( __CLASS__, 'json_api' );
41
42
		return $methods;
43
	}
44
45
	/**
46
	 * Returns what features are available. Uses the slug of the module files.
47
	 *
48
	 * @return array
49
	 */
50 View Code Duplication
	public static function features_available() {
51
		$raw_modules = Jetpack::get_available_modules();
52
		$modules     = array();
53
		foreach ( $raw_modules as $module ) {
54
			$modules[] = Jetpack::get_module_slug( $module );
55
		}
56
57
		return $modules;
58
	}
59
60
	/**
61
	 * Returns what features are enabled. Uses the slug of the modules files.
62
	 *
63
	 * @return array
64
	 */
65 View Code Duplication
	public static function features_enabled() {
66
		$raw_modules = Jetpack::get_active_modules();
67
		$modules     = array();
68
		foreach ( $raw_modules as $module ) {
69
			$modules[] = Jetpack::get_module_slug( $module );
70
		}
71
72
		return $modules;
73
	}
74
75
	/**
76
	 * Filters the result of test_connection XMLRPC method
77
	 *
78
	 * @return string The current Jetpack version number
79
	 */
80
	public static function test_connection() {
81
		return JETPACK__VERSION;
82
	}
83
84
	/**
85
	 * Disconnect this blog from the connected wordpress.com account
86
	 *
87
	 * @return boolean
88
	 */
89
	public static function disconnect_blog() {
90
91
		/**
92
		 * Fired when we want to log an event to the Jetpack event log.
93
		 *
94
		 * @since 7.7.0
95
		 *
96
		 * @param string $code Unique name for the event.
97
		 * @param string $data Optional data about the event.
98
		 */
99
		do_action( 'jetpack_event_log', 'disconnect' );
100
		Jetpack::disconnect();
101
102
		return true;
103
	}
104
105
	/**
106
	 * Serve a JSON API request.
107
	 *
108
	 * @param array $args request arguments.
109
	 */
110
	public static function json_api( $args = array() ) {
111
		$json_api_args        = $args[0];
112
		$verify_api_user_args = $args[1];
113
114
		$method       = (string) $json_api_args[0];
115
		$url          = (string) $json_api_args[1];
116
		$post_body    = is_null( $json_api_args[2] ) ? null : (string) $json_api_args[2];
117
		$user_details = (array) $json_api_args[4];
118
		$locale       = (string) $json_api_args[5];
119
120
		if ( ! $verify_api_user_args ) {
121
			$user_id = 0;
122
		} elseif ( 'internal' === $verify_api_user_args[0] ) {
123
			$user_id = (int) $verify_api_user_args[1];
124
			if ( $user_id ) {
125
				$user = get_user_by( 'id', $user_id );
126
				if ( ! $user || is_wp_error( $user ) ) {
127
					return false;
128
				}
129
			}
130
		} else {
131
			$user_id = call_user_func( array( new Jetpack_XMLRPC_Server(), 'test_api_user_code' ), $verify_api_user_args );
132
			if ( ! $user_id ) {
133
				return false;
134
			}
135
		}
136
137
		if ( 'en' !== $locale ) {
138
			// .org mo files are named slightly different from .com, and all we have is this the locale -- try to guess them.
139
			$new_locale = $locale;
140
			if ( strpos( $locale, '-' ) !== false ) {
141
				$locale_pieces = explode( '-', $locale );
142
				$new_locale    = $locale_pieces[0];
143
				$new_locale   .= ( ! empty( $locale_pieces[1] ) ) ? '_' . strtoupper( $locale_pieces[1] ) : '';
144
			} else {
145
				// .com might pass 'fr' because thats what our language files are named as, where core seems
146
				// to do fr_FR - so try that if we don't think we can load the file.
147
				if ( ! file_exists( WP_LANG_DIR . '/' . $locale . '.mo' ) ) {
148
					$new_locale = $locale . '_' . strtoupper( $locale );
149
				}
150
			}
151
152
			if ( file_exists( WP_LANG_DIR . '/' . $new_locale . '.mo' ) ) {
153
				unload_textdomain( 'default' );
154
				load_textdomain( 'default', WP_LANG_DIR . '/' . $new_locale . '.mo' );
155
			}
156
		}
157
158
		$old_user = wp_get_current_user();
159
		wp_set_current_user( $user_id );
160
161
		if ( $user_id ) {
162
			$token_key = false;
163
		} else {
164
			$verified  = ( new Connection_Manager() )->verify_xml_rpc_signature();
165
			$token_key = $verified['token_key'];
166
		}
167
168
		$token = ( new Tokens() )->get_access_token( $user_id, $token_key );
169
		if ( ! $token || is_wp_error( $token ) ) {
170
			return false;
171
		}
172
173
		define( 'REST_API_REQUEST', true );
174
		define( 'WPCOM_JSON_API__BASE', 'public-api.wordpress.com/rest/v1' );
175
176
		// needed?
177
		require_once ABSPATH . 'wp-admin/includes/admin.php';
178
179
		require_once JETPACK__PLUGIN_DIR . 'class.json-api.php';
180
		$api                        = WPCOM_JSON_API::init( $method, $url, $post_body );
181
		$api->token_details['user'] = $user_details;
182
		require_once JETPACK__PLUGIN_DIR . 'class.json-api-endpoints.php';
183
184
		$display_errors = ini_set( 'display_errors', 0 ); // phpcs:ignore WordPress.PHP.IniSet
185
		ob_start();
186
		$api->serve( false );
187
		$output = ob_get_clean();
188
		ini_set( 'display_errors', $display_errors ); // phpcs:ignore WordPress.PHP.IniSet
189
190
		$nonce = wp_generate_password( 10, false );
191
		$hmac  = hash_hmac( 'md5', $nonce . $output, $token->secret );
192
193
		wp_set_current_user( isset( $old_user->ID ) ? $old_user->ID : 0 );
194
195
		return array(
196
			(string) $output,
197
			(string) $nonce,
198
			(string) $hmac,
199
		);
200
	}
201
202
	/**
203
	 * Filters the response of the remote_provision XMLRPC method
204
	 *
205
	 * @param array $response The response.
206
	 * @param array $request An array containing at minimum a nonce key and a local_username key.
207
	 *
208
	 * @since 9.8.0
209
	 * @return array
210
	 */
211
	public static function remote_provision_response( $response, $request ) {
212
		if ( ! empty( $request['onboarding'] ) ) {
213
			Jetpack::create_onboarding_token();
214
			$response['onboarding_token'] = Jetpack_Options::get_option( 'onboarding' );
215
		}
216
		return $response;
217
	}
218
219
	/**
220
	 * Runs Jetpack specific action in xmlrpc server events
221
	 *
222
	 * @param String  $action the action name, i.e., 'remote_authorize'.
223
	 * @param String  $stage  the execution stage, can be 'begin', 'success', 'error', etc.
224
	 * @param array   $parameters extra parameters from the event.
225
	 * @param WP_User $user the acting user.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $user not be WP_User|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
226
	 * @return void
227
	 */
228
	public static function jetpack_xmlrpc_server_event( $action, $stage, $parameters = array(), $user = null ) { //phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
229
		if ( 'remote_register' === $action && 'begin' === $stage ) {
230
			Jetpack::maybe_set_version_option();
231
		}
232
	}
233
234
	/**
235
	 * Hooks into the remote_connect XMLRPC endpoint and triggers Jetpack::handle_post_authorization_actions
236
	 *
237
	 * @since 9.8.0
238
	 * @return void
239
	 */
240
	public static function remote_connect_end() {
241
		/** This filter is documented in class.jetpack-cli.php */
242
		$enable_sso = apply_filters( 'jetpack_start_enable_sso', true );
243
		Jetpack::handle_post_authorization_actions( $enable_sso, false, false );
244
	}
245
246
	/**
247
	 * Filters the Redirect URI returned by the remote_register XMLRPC method
248
	 *
249
	 * @since 9.8.0
250
	 *
251
	 * @param string $redirect_uri The Redirect URI.
252
	 * @return string
253
	 */
254
	public static function remote_register_redirect_uri( $redirect_uri ) {
255
		$auto_enable_sso = ( ! ( new Connection_Manager() )->has_connected_owner() || Jetpack::is_module_active( 'sso' ) );
256
257
		/** This filter is documented in class.jetpack-cli.php */
258 View Code Duplication
		if ( apply_filters( 'jetpack_start_enable_sso', $auto_enable_sso ) ) {
259
			$redirect_uri = add_query_arg(
260
				array(
261
					'action'      => 'jetpack-sso',
262
					'redirect_to' => rawurlencode( admin_url() ),
263
				),
264
				wp_login_url() // TODO: come back to Jetpack dashboard?
265
			);
266
		}
267
268
		return $redirect_uri;
269
	}
270
}
271