REST_Connector   F
last analyzed

Complexity

Total Complexity 61

Size/Duplication

Total Lines 649
Duplicated Lines 0.46 %

Coupling/Cohesion

Components 2
Dependencies 8

Importance

Changes 0
Metric Value
dl 3
loc 649
rs 3.471
c 0
b 0
f 0
wmc 61
lcom 2
cbo 8

18 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 158 2
A verify_registration() 0 5 1
A remote_authorize() 0 10 2
A connection_status() 0 38 5
A get_connection_plugins() 0 16 2
A activate_plugins_permission_check() 0 7 2
A connection_plugins_permission_check() 0 12 3
B is_request_signed_by_jetpack_debugger() 0 36 6
A jetpack_reconnect_permission_check() 0 7 2
A get_user_permissions_error_msg() 0 3 1
B connection_reconnect() 0 36 7
A jetpack_register_permission_check() 0 7 2
B connection_register() 3 49 9
A connection_authorize_url() 0 19 4
B update_user_token() 0 41 7
A update_user_token_permission_check() 0 5 2
A set_connection_owner() 0 15 2
A set_connection_owner_permission_check() 0 7 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like REST_Connector often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use REST_Connector, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Sets up the Connection REST API endpoints.
4
 *
5
 * @package automattic/jetpack-connection
6
 */
7
8
namespace Automattic\Jetpack\Connection;
9
10
use Automattic\Jetpack\Redirect;
11
use Automattic\Jetpack\Status;
12
use Jetpack_XMLRPC_Server;
13
use WP_Error;
14
use WP_REST_Request;
15
use WP_REST_Response;
16
use WP_REST_Server;
17
18
/**
19
 * Registers the REST routes for Connections.
20
 */
21
class REST_Connector {
22
	/**
23
	 * The Connection Manager.
24
	 *
25
	 * @var Manager
26
	 */
27
	private $connection;
28
29
	/**
30
	 * This property stores the localized "Insufficient Permissions" error message.
31
	 *
32
	 * @var string Generic error message when user is not allowed to perform an action.
33
	 */
34
	private static $user_permissions_error_msg;
35
36
	const JETPACK__DEBUGGER_PUBLIC_KEY = "\r\n" . '-----BEGIN PUBLIC KEY-----' . "\r\n"
37
	. 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm+uLLVoxGCY71LS6KFc6' . "\r\n"
38
	. '1UnF6QGBAsi5XF8ty9kR3/voqfOkpW+gRerM2Kyjy6DPCOmzhZj7BFGtxSV2ZoMX' . "\r\n"
39
	. '9ZwWxzXhl/Q/6k8jg8BoY1QL6L2K76icXJu80b+RDIqvOfJruaAeBg1Q9NyeYqLY' . "\r\n"
40
	. 'lEVzN2vIwcFYl+MrP/g6Bc2co7Jcbli+tpNIxg4Z+Hnhbs7OJ3STQLmEryLpAxQO' . "\r\n"
41
	. 'q8cbhQkMx+FyQhxzSwtXYI/ClCUmTnzcKk7SgGvEjoKGAmngILiVuEJ4bm7Q1yok' . "\r\n"
42
	. 'xl9+wcfW6JAituNhml9dlHCWnn9D3+j8pxStHihKy2gVMwiFRjLEeD8K/7JVGkb/' . "\r\n"
43
	. 'EwIDAQAB' . "\r\n"
44
	. '-----END PUBLIC KEY-----' . "\r\n";
45
46
	/**
47
	 * Constructor.
48
	 *
49
	 * @param Manager $connection The Connection Manager.
50
	 */
51
	public function __construct( Manager $connection ) {
52
		$this->connection = $connection;
53
54
		self::$user_permissions_error_msg = esc_html__(
55
			'You do not have the correct user permissions to perform this action.
56
			Please contact your site admin if you think this is a mistake.',
57
			'jetpack'
58
		);
59
60
		if ( ! $this->connection->has_connected_owner() ) {
61
			// Register a site.
62
			register_rest_route(
63
				'jetpack/v4',
64
				'/verify_registration',
65
				array(
66
					'methods'             => WP_REST_Server::EDITABLE,
67
					'callback'            => array( $this, 'verify_registration' ),
68
					'permission_callback' => '__return_true',
69
				)
70
			);
71
		}
72
73
		// Authorize a remote user.
74
		register_rest_route(
75
			'jetpack/v4',
76
			'/remote_authorize',
77
			array(
78
				'methods'             => WP_REST_Server::EDITABLE,
79
				'callback'            => __CLASS__ . '::remote_authorize',
80
				'permission_callback' => '__return_true',
81
			)
82
		);
83
84
		// Get current connection status of Jetpack.
85
		register_rest_route(
86
			'jetpack/v4',
87
			'/connection',
88
			array(
89
				'methods'             => WP_REST_Server::READABLE,
90
				'callback'            => __CLASS__ . '::connection_status',
91
				'permission_callback' => '__return_true',
92
			)
93
		);
94
95
		// Get list of plugins that use the Jetpack connection.
96
		register_rest_route(
97
			'jetpack/v4',
98
			'/connection/plugins',
99
			array(
100
				'methods'             => WP_REST_Server::READABLE,
101
				'callback'            => array( $this, 'get_connection_plugins' ),
102
				'permission_callback' => __CLASS__ . '::connection_plugins_permission_check',
103
			)
104
		);
105
106
		// Full or partial reconnect in case of connection issues.
107
		register_rest_route(
108
			'jetpack/v4',
109
			'/connection/reconnect',
110
			array(
111
				'methods'             => WP_REST_Server::EDITABLE,
112
				'callback'            => array( $this, 'connection_reconnect' ),
113
				'permission_callback' => __CLASS__ . '::jetpack_reconnect_permission_check',
114
			)
115
		);
116
117
		// Register the site (get `blog_token`).
118
		register_rest_route(
119
			'jetpack/v4',
120
			'/connection/register',
121
			array(
122
				'methods'             => WP_REST_Server::EDITABLE,
123
				'callback'            => array( $this, 'connection_register' ),
124
				'permission_callback' => __CLASS__ . '::jetpack_register_permission_check',
125
				'args'                => array(
126
					'from'               => array(
127
						'description' => __( 'Indicates where the registration action was triggered for tracking/segmentation purposes', 'jetpack' ),
128
						'type'        => 'string',
129
					),
130
					'registration_nonce' => array(
131
						'description' => __( 'The registration nonce', 'jetpack' ),
132
						'type'        => 'string',
133
						'required'    => true,
134
					),
135
					'no_iframe'          => array(
136
						'description' => __( 'Disable In-Place connection flow and go straight to Calypso', 'jetpack' ),
137
						'type'        => 'boolean',
138
					),
139
					'redirect_uri'       => array(
140
						'description' => __( 'URI of the admin page where the user should be redirected after connection flow', 'jetpack' ),
141
						'type'        => 'string',
142
					),
143
				),
144
			)
145
		);
146
147
		// Get authorization URL.
148
		register_rest_route(
149
			'jetpack/v4',
150
			'/connection/authorize_url',
151
			array(
152
				'methods'             => WP_REST_Server::READABLE,
153
				'callback'            => array( $this, 'connection_authorize_url' ),
154
				'permission_callback' => __CLASS__ . '::jetpack_register_permission_check',
155
				'args'                => array(
156
					'no_iframe'    => array(
157
						'description' => __( 'Disable In-Place connection flow and go straight to Calypso', 'jetpack' ),
158
						'type'        => 'boolean',
159
					),
160
					'redirect_uri' => array(
161
						'description' => __( 'URI of the admin page where the user should be redirected after connection flow', 'jetpack' ),
162
						'type'        => 'string',
163
					),
164
				),
165
			)
166
		);
167
168
		register_rest_route(
169
			'jetpack/v4',
170
			'/user-token',
171
			array(
172
				array(
173
					'methods'             => WP_REST_Server::EDITABLE,
174
					'callback'            => array( static::class, 'update_user_token' ),
175
					'permission_callback' => array( static::class, 'update_user_token_permission_check' ),
176
					'args'                => array(
177
						'user_token'          => array(
178
							'description' => __( 'New user token', 'jetpack' ),
179
							'type'        => 'string',
180
							'required'    => true,
181
						),
182
						'is_connection_owner' => array(
183
							'description' => __( 'Is connection owner', 'jetpack' ),
184
							'type'        => 'boolean',
185
						),
186
					),
187
				),
188
			)
189
		);
190
191
		// Set the connection owner.
192
		register_rest_route(
193
			'jetpack/v4',
194
			'/connection/owner',
195
			array(
196
				'methods'             => WP_REST_Server::EDITABLE,
197
				'callback'            => array( static::class, 'set_connection_owner' ),
198
				'permission_callback' => array( static::class, 'set_connection_owner_permission_check' ),
199
				'args'                => array(
200
					'owner' => array(
201
						'description' => __( 'New owner', 'jetpack' ),
202
						'type'        => 'integer',
203
						'required'    => true,
204
					),
205
				),
206
			)
207
		);
208
	}
209
210
	/**
211
	 * Handles verification that a site is registered.
212
	 *
213
	 * @since 5.4.0
214
	 *
215
	 * @param WP_REST_Request $request The request sent to the WP REST API.
216
	 *
217
	 * @return string|WP_Error
218
	 */
219
	public function verify_registration( WP_REST_Request $request ) {
220
		$registration_data = array( $request['secret_1'], $request['state'] );
221
222
		return $this->connection->handle_registration( $registration_data );
223
	}
224
225
	/**
226
	 * Handles verification that a site is registered
227
	 *
228
	 * @since 5.4.0
229
	 *
230
	 * @param WP_REST_Request $request The request sent to the WP REST API.
231
	 *
232
	 * @return array|wp-error
0 ignored issues
show
Documentation introduced by
The doc-type array|wp-error could not be parsed: Unknown type name "wp-error" at position 6. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
233
	 */
234
	public static function remote_authorize( $request ) {
235
		$xmlrpc_server = new Jetpack_XMLRPC_Server();
236
		$result        = $xmlrpc_server->remote_authorize( $request );
237
238
		if ( is_a( $result, 'IXR_Error' ) ) {
239
			$result = new WP_Error( $result->code, $result->message );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with $result->code.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
240
		}
241
242
		return $result;
243
	}
244
245
	/**
246
	 * Get connection status for this Jetpack site.
247
	 *
248
	 * @since 4.3.0
249
	 *
250
	 * @param bool $rest_response Should we return a rest response or a simple array. Default to rest response.
251
	 *
252
	 * @return WP_REST_Response|array Connection information.
253
	 */
254
	public static function connection_status( $rest_response = true ) {
255
		$status     = new Status();
256
		$connection = new Manager();
257
258
		$connection_status = array(
259
			'isActive'          => $connection->is_active(), // TODO deprecate this.
0 ignored issues
show
Deprecated Code introduced by
The method Automattic\Jetpack\Connection\Manager::is_active() has been deprecated with message: 9.6.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
260
			'isStaging'         => $status->is_staging_site(),
261
			'isRegistered'      => $connection->is_connected(),
262
			'isUserConnected'   => $connection->is_user_connected(),
263
			'hasConnectedOwner' => $connection->has_connected_owner(),
264
			'offlineMode'       => array(
265
				'isActive'        => $status->is_offline_mode(),
266
				'constant'        => defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG,
267
				'url'             => $status->is_local_site(),
268
				/** This filter is documented in packages/status/src/class-status.php */
269
				'filter'          => ( apply_filters( 'jetpack_development_mode', false ) || apply_filters( 'jetpack_offline_mode', false ) ), // jetpack_development_mode is deprecated.
270
				'wpLocalConstant' => defined( 'WP_LOCAL_DEV' ) && WP_LOCAL_DEV,
271
			),
272
			'isPublic'          => '1' == get_option( 'blog_public' ), // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
273
		);
274
275
		/**
276
		 * Filters the connection status data.
277
		 *
278
		 * @since 9.6.0
279
		 *
280
		 * @param array An array containing the connection status data.
281
		 */
282
		$connection_status = apply_filters( 'jetpack_connection_status', $connection_status );
283
284
		if ( $rest_response ) {
285
			return rest_ensure_response(
286
				$connection_status
287
			);
288
		} else {
289
			return $connection_status;
290
		}
291
	}
292
293
	/**
294
	 * Get plugins connected to the Jetpack.
295
	 *
296
	 * @since 8.6.0
297
	 *
298
	 * @return WP_REST_Response|WP_Error Response or error object, depending on the request result.
299
	 */
300
	public function get_connection_plugins() {
301
		$plugins = $this->connection->get_connected_plugins();
302
303
		if ( is_wp_error( $plugins ) ) {
304
			return $plugins;
305
		}
306
307
		array_walk(
308
			$plugins,
309
			function ( &$data, $slug ) {
310
				$data['slug'] = $slug;
311
			}
312
		);
313
314
		return rest_ensure_response( array_values( $plugins ) );
315
	}
316
317
	/**
318
	 * Verify that user can view Jetpack admin page and can activate plugins.
319
	 *
320
	 * @since 8.8.0
321
	 *
322
	 * @return bool|WP_Error Whether user has the capability 'activate_plugins'.
323
	 */
324
	public static function activate_plugins_permission_check() {
325
		if ( current_user_can( 'activate_plugins' ) ) {
326
			return true;
327
		}
328
329
		return new WP_Error( 'invalid_user_permission_activate_plugins', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_user_permission_activate_plugins'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
330
	}
331
332
	/**
333
	 * Permission check for the connection_plugins endpoint
334
	 *
335
	 * @return bool|WP_Error
336
	 */
337
	public static function connection_plugins_permission_check() {
338
		if ( true === static::activate_plugins_permission_check() ) {
339
			return true;
340
		}
341
342
		if ( true === static::is_request_signed_by_jetpack_debugger() ) {
343
			return true;
344
		}
345
346
		return new WP_Error( 'invalid_user_permission_activate_plugins', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_user_permission_activate_plugins'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
347
348
	}
349
350
	/**
351
	 * Verifies if the request was signed with the Jetpack Debugger key
352
	 *
353
	 * @param string|null $pub_key The public key used to verify the signature. Default is the Jetpack Debugger key. This is used for testing purposes.
354
	 *
355
	 * @return bool
356
	 */
357
	public static function is_request_signed_by_jetpack_debugger( $pub_key = null ) {
358
		 // phpcs:disable WordPress.Security.NonceVerification.Recommended
359
		if ( ! isset( $_GET['signature'], $_GET['timestamp'], $_GET['url'], $_GET['rest_route'] ) ) {
360
			return false;
361
		}
362
363
		// signature timestamp must be within 5min of current time.
364
		if ( abs( time() - (int) $_GET['timestamp'] ) > 300 ) {
365
			return false;
366
		}
367
368
		$signature = base64_decode( $_GET['signature'] ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
369
370
		$signature_data = wp_json_encode(
371
			array(
372
				'rest_route' => $_GET['rest_route'],
373
				'timestamp'  => (int) $_GET['timestamp'],
374
				'url'        => wp_unslash( $_GET['url'] ),
375
			)
376
		);
377
378
		if (
379
			! function_exists( 'openssl_verify' )
380
			|| 1 !== openssl_verify(
381
				$signature_data,
382
				$signature,
383
				$pub_key ? $pub_key : static::JETPACK__DEBUGGER_PUBLIC_KEY
384
			)
385
		) {
386
			return false;
387
		}
388
389
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
390
391
		return true;
392
	}
393
394
	/**
395
	 * Verify that user is allowed to disconnect Jetpack.
396
	 *
397
	 * @since 8.8.0
398
	 *
399
	 * @return bool|WP_Error Whether user has the capability 'jetpack_disconnect'.
400
	 */
401
	public static function jetpack_reconnect_permission_check() {
402
		if ( current_user_can( 'jetpack_reconnect' ) ) {
403
			return true;
404
		}
405
406
		return new WP_Error( 'invalid_user_permission_jetpack_disconnect', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_user_permission_jetpack_disconnect'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
407
	}
408
409
	/**
410
	 * Returns generic error message when user is not allowed to perform an action.
411
	 *
412
	 * @return string The error message.
413
	 */
414
	public static function get_user_permissions_error_msg() {
415
		return self::$user_permissions_error_msg;
416
	}
417
418
	/**
419
	 * The endpoint tried to partially or fully reconnect the website to WP.com.
420
	 *
421
	 * @since 8.8.0
422
	 *
423
	 * @return \WP_REST_Response|WP_Error
424
	 */
425
	public function connection_reconnect() {
426
		$response = array();
427
428
		$next = null;
429
430
		$result = $this->connection->restore();
431
432
		if ( is_wp_error( $result ) ) {
433
			$response = $result;
434
		} elseif ( is_string( $result ) ) {
435
			$next = $result;
436
		} else {
437
			$next = true === $result ? 'completed' : 'failed';
438
		}
439
440
		switch ( $next ) {
441
			case 'authorize':
442
				$response['status']       = 'in_progress';
443
				$response['authorizeUrl'] = $this->connection->get_authorization_url();
444
				break;
445
			case 'completed':
446
				$response['status'] = 'completed';
447
				/**
448
				 * Action fired when reconnection has completed successfully.
449
				 *
450
				 * @since 9.0.0
451
				 */
452
				do_action( 'jetpack_reconnection_completed' );
453
				break;
454
			case 'failed':
455
				$response = new WP_Error( 'Reconnect failed' );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'Reconnect failed'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
456
				break;
457
		}
458
459
		return rest_ensure_response( $response );
460
	}
461
462
	/**
463
	 * Verify that user is allowed to connect Jetpack.
464
	 *
465
	 * @since 9.7.0
466
	 *
467
	 * @return bool|WP_Error Whether user has the capability 'jetpack_connect'.
468
	 */
469
	public static function jetpack_register_permission_check() {
470
		if ( current_user_can( 'jetpack_connect' ) ) {
471
			return true;
472
		}
473
474
		return new WP_Error( 'invalid_user_permission_jetpack_connect', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_user_permission_jetpack_connect'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
475
	}
476
477
	/**
478
	 * The endpoint tried to partially or fully reconnect the website to WP.com.
479
	 *
480
	 * @since 7.7.0
481
	 *
482
	 * @param \WP_REST_Request $request The request sent to the WP REST API.
483
	 *
484
	 * @return \WP_REST_Response|WP_Error
485
	 */
486
	public function connection_register( $request ) {
487 View Code Duplication
		if ( ! wp_verify_nonce( $request->get_param( 'registration_nonce' ), 'jetpack-registration-nonce' ) ) {
488
			return new WP_Error( 'invalid_nonce', __( 'Unable to verify your request.', 'jetpack' ), array( 'status' => 403 ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_nonce'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
489
		}
490
491
		if ( isset( $request['from'] ) ) {
492
			$this->connection->add_register_request_param( 'from', (string) $request['from'] );
493
		}
494
		$result = $this->connection->try_registration();
495
496
		if ( is_wp_error( $result ) ) {
497
			return $result;
498
		}
499
500
		$redirect_uri = $request->get_param( 'redirect_uri' ) ? admin_url( $request->get_param( 'redirect_uri' ) ) : null;
501
502
		if ( class_exists( 'Jetpack' ) ) {
503
			$authorize_url = \Jetpack::build_authorize_url( $redirect_uri, ! $request->get_param( 'no_iframe' ) );
504
		} else {
505
			if ( ! $request->get_param( 'no_iframe' ) ) {
506
				add_filter( 'jetpack_use_iframe_authorization_flow', '__return_true' );
507
			}
508
509
			$authorize_url = $this->connection->get_authorization_url( null, $redirect_uri );
510
511
			if ( ! $request->get_param( 'no_iframe' ) ) {
512
				remove_filter( 'jetpack_use_iframe_authorization_flow', '__return_true' );
513
			}
514
		}
515
516
		/**
517
		 * Filters the response of jetpack/v4/connection/register endpoint
518
		 *
519
		 * @param array $response Array response
520
		 * @since 9.8.0
521
		 */
522
		$response_body = apply_filters(
523
			'jetpack_register_site_rest_response',
524
			array()
525
		);
526
527
		// We manipulate the alternate URLs after the filter is applied, so they can not be overwritten.
528
		$response_body['authorizeUrl'] = $authorize_url;
529
		if ( ! empty( $response_body['alternateAuthorizeUrl'] ) ) {
530
			$response_body['alternateAuthorizeUrl'] = Redirect::get_url( $response_body['alternateAuthorizeUrl'] );
531
		}
532
533
		return rest_ensure_response( $response_body );
534
	}
535
536
	/**
537
	 * Get the authorization URL.
538
	 *
539
	 * @since 9.8.0
540
	 *
541
	 * @param \WP_REST_Request $request The request sent to the WP REST API.
542
	 *
543
	 * @return \WP_REST_Response|WP_Error
544
	 */
545
	public function connection_authorize_url( $request ) {
546
		$redirect_uri = $request->get_param( 'redirect_uri' ) ? admin_url( $request->get_param( 'redirect_uri' ) ) : null;
547
548
		if ( ! $request->get_param( 'no_iframe' ) ) {
549
			add_filter( 'jetpack_use_iframe_authorization_flow', '__return_true' );
550
		}
551
552
		$authorize_url = $this->connection->get_authorization_url( null, $redirect_uri );
553
554
		if ( ! $request->get_param( 'no_iframe' ) ) {
555
			remove_filter( 'jetpack_use_iframe_authorization_flow', '__return_true' );
556
		}
557
558
		return rest_ensure_response(
559
			array(
560
				'authorizeUrl' => $authorize_url,
561
			)
562
		);
563
	}
564
565
	/**
566
	 * The endpoint tried to partially or fully reconnect the website to WP.com.
567
	 *
568
	 * @since 9.9.0
569
	 *
570
	 * @param \WP_REST_Request $request The request sent to the WP REST API.
571
	 *
572
	 * @return \WP_REST_Response|WP_Error
573
	 */
574
	public static function update_user_token( $request ) {
575
		$token_parts = explode( '.', $request['user_token'] );
576
577
		if ( count( $token_parts ) !== 3 || ! (int) $token_parts[2] || ! ctype_digit( $token_parts[2] ) ) {
578
			return new WP_Error( 'invalid_argument_user_token', esc_html__( 'Invalid user token is provided', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_argument_user_token'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
579
		}
580
581
		$user_id = (int) $token_parts[2];
582
583
		if ( false === get_userdata( $user_id ) ) {
584
			return new WP_Error( 'invalid_argument_user_id', esc_html__( 'Invalid user id is provided', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_argument_user_id'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
585
		}
586
587
		$connection = new Manager();
588
589
		if ( ! $connection->is_connected() ) {
590
			return new WP_Error( 'site_not_connected', esc_html__( 'Site is not connected', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'site_not_connected'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
591
		}
592
593
		$is_connection_owner = isset( $request['is_connection_owner'] )
594
			? (bool) $request['is_connection_owner']
595
			: ( new Manager() )->get_connection_owner_id() === $user_id;
596
597
		( new Tokens() )->update_user_token( $user_id, $request['user_token'], $is_connection_owner );
598
599
		/**
600
		 * Fires when the user token gets successfully replaced.
601
		 *
602
		 * @since 9.9.0
603
		 *
604
		 * @param int $user_id User ID.
605
		 * @param string $token New user token.
606
		 */
607
		do_action( 'jetpack_updated_user_token', $user_id, $request['user_token'] );
608
609
		return rest_ensure_response(
610
			array(
611
				'success' => true,
612
			)
613
		);
614
	}
615
616
	/**
617
	 * Verify that the API client is allowed to replace user token.
618
	 *
619
	 * @since 9.9.0
620
	 *
621
	 * @return bool|WP_Error.
0 ignored issues
show
Documentation introduced by
The doc-type bool|WP_Error. could not be parsed: Unknown type name "WP_Error." at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
622
	 */
623
	public static function update_user_token_permission_check() {
624
		return Rest_Authentication::is_signed_with_blog_token()
625
			? true
626
			: new WP_Error( 'invalid_permission_update_user_token', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_permission_update_user_token'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
627
	}
628
629
	/**
630
	 * Change the connection owner.
631
	 *
632
	 * @since 9.9.0
633
	 *
634
	 * @param WP_REST_Request $request The request sent to the WP REST API.
635
	 *
636
	 * @return \WP_REST_Response|WP_Error
637
	 */
638
	public static function set_connection_owner( $request ) {
639
		$new_owner_id = $request['owner'];
640
641
		$owner_set = ( new Manager() )->update_connection_owner( $new_owner_id );
642
643
		if ( is_wp_error( $owner_set ) ) {
644
			return $owner_set;
645
		}
646
647
		return rest_ensure_response(
648
			array(
649
				'code' => 'success',
650
			)
651
		);
652
	}
653
654
	/**
655
	 * Check that user has permission to change the master user.
656
	 *
657
	 * @since 6.2.0
658
	 * @since 7.7.0 Update so that any user with jetpack_disconnect privs can set owner.
659
	 *
660
	 * @return bool|WP_Error True if user is able to change master user.
661
	 */
662
	public static function set_connection_owner_permission_check() {
663
		if ( current_user_can( 'jetpack_disconnect' ) ) {
664
			return true;
665
		}
666
667
		return new WP_Error( 'invalid_user_permission_set_connection_owner', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_user_permission_set_connection_owner'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
668
	}
669
}
670