Completed
Push — update/business-hours-block-ph... ( 3401d5...d076d1 )
by
unknown
09:58 queued 10s
created

update_user_token_permission_check()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
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
192
	/**
193
	 * Handles verification that a site is registered.
194
	 *
195
	 * @since 5.4.0
196
	 *
197
	 * @param WP_REST_Request $request The request sent to the WP REST API.
198
	 *
199
	 * @return string|WP_Error
200
	 */
201
	public function verify_registration( WP_REST_Request $request ) {
202
		$registration_data = array( $request['secret_1'], $request['state'] );
203
204
		return $this->connection->handle_registration( $registration_data );
205
	}
206
207
	/**
208
	 * Handles verification that a site is registered
209
	 *
210
	 * @since 5.4.0
211
	 *
212
	 * @param WP_REST_Request $request The request sent to the WP REST API.
213
	 *
214
	 * @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...
215
	 */
216
	public static function remote_authorize( $request ) {
217
		$xmlrpc_server = new Jetpack_XMLRPC_Server();
218
		$result        = $xmlrpc_server->remote_authorize( $request );
219
220
		if ( is_a( $result, 'IXR_Error' ) ) {
221
			$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...
222
		}
223
224
		return $result;
225
	}
226
227
	/**
228
	 * Get connection status for this Jetpack site.
229
	 *
230
	 * @since 4.3.0
231
	 *
232
	 * @param bool $rest_response Should we return a rest response or a simple array. Default to rest response.
233
	 *
234
	 * @return WP_REST_Response|array Connection information.
235
	 */
236
	public static function connection_status( $rest_response = true ) {
237
		$status     = new Status();
238
		$connection = new Manager();
239
240
		$connection_status = array(
241
			'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...
242
			'isStaging'         => $status->is_staging_site(),
243
			'isRegistered'      => $connection->is_connected(),
244
			'isUserConnected'   => $connection->is_user_connected(),
245
			'hasConnectedOwner' => $connection->has_connected_owner(),
246
			'offlineMode'       => array(
247
				'isActive'        => $status->is_offline_mode(),
248
				'constant'        => defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG,
249
				'url'             => $status->is_local_site(),
250
				/** This filter is documented in packages/status/src/class-status.php */
251
				'filter'          => ( apply_filters( 'jetpack_development_mode', false ) || apply_filters( 'jetpack_offline_mode', false ) ), // jetpack_development_mode is deprecated.
252
				'wpLocalConstant' => defined( 'WP_LOCAL_DEV' ) && WP_LOCAL_DEV,
253
			),
254
			'isPublic'          => '1' == get_option( 'blog_public' ), // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
255
		);
256
257
		/**
258
		 * Filters the connection status data.
259
		 *
260
		 * @since 9.6.0
261
		 *
262
		 * @param array An array containing the connection status data.
263
		 */
264
		$connection_status = apply_filters( 'jetpack_connection_status', $connection_status );
265
266
		if ( $rest_response ) {
267
			return rest_ensure_response(
268
				$connection_status
269
			);
270
		} else {
271
			return $connection_status;
272
		}
273
	}
274
275
	/**
276
	 * Get plugins connected to the Jetpack.
277
	 *
278
	 * @since 8.6.0
279
	 *
280
	 * @return WP_REST_Response|WP_Error Response or error object, depending on the request result.
281
	 */
282
	public function get_connection_plugins() {
283
		$plugins = $this->connection->get_connected_plugins();
284
285
		if ( is_wp_error( $plugins ) ) {
286
			return $plugins;
287
		}
288
289
		array_walk(
290
			$plugins,
291
			function ( &$data, $slug ) {
292
				$data['slug'] = $slug;
293
			}
294
		);
295
296
		return rest_ensure_response( array_values( $plugins ) );
297
	}
298
299
	/**
300
	 * Verify that user can view Jetpack admin page and can activate plugins.
301
	 *
302
	 * @since 8.8.0
303
	 *
304
	 * @return bool|WP_Error Whether user has the capability 'activate_plugins'.
305
	 */
306
	public static function activate_plugins_permission_check() {
307
		if ( current_user_can( 'activate_plugins' ) ) {
308
			return true;
309
		}
310
311
		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...
312
	}
313
314
	/**
315
	 * Permission check for the connection_plugins endpoint
316
	 *
317
	 * @return bool|WP_Error
318
	 */
319
	public static function connection_plugins_permission_check() {
320
		if ( true === static::activate_plugins_permission_check() ) {
321
			return true;
322
		}
323
324
		if ( true === static::is_request_signed_by_jetpack_debugger() ) {
325
			return true;
326
		}
327
328
		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...
329
330
	}
331
332
	/**
333
	 * Verifies if the request was signed with the Jetpack Debugger key
334
	 *
335
	 * @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.
336
	 *
337
	 * @return bool
338
	 */
339
	public static function is_request_signed_by_jetpack_debugger( $pub_key = null ) {
340
		 // phpcs:disable WordPress.Security.NonceVerification.Recommended
341
		if ( ! isset( $_GET['signature'], $_GET['timestamp'], $_GET['url'], $_GET['rest_route'] ) ) {
342
			return false;
343
		}
344
345
		// signature timestamp must be within 5min of current time.
346
		if ( abs( time() - (int) $_GET['timestamp'] ) > 300 ) {
347
			return false;
348
		}
349
350
		$signature = base64_decode( $_GET['signature'] ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
351
352
		$signature_data = wp_json_encode(
353
			array(
354
				'rest_route' => $_GET['rest_route'],
355
				'timestamp'  => (int) $_GET['timestamp'],
356
				'url'        => wp_unslash( $_GET['url'] ),
357
			)
358
		);
359
360
		if (
361
			! function_exists( 'openssl_verify' )
362
			|| 1 !== openssl_verify(
363
				$signature_data,
364
				$signature,
365
				$pub_key ? $pub_key : static::JETPACK__DEBUGGER_PUBLIC_KEY
366
			)
367
		) {
368
			return false;
369
		}
370
371
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
372
373
		return true;
374
	}
375
376
	/**
377
	 * Verify that user is allowed to disconnect Jetpack.
378
	 *
379
	 * @since 8.8.0
380
	 *
381
	 * @return bool|WP_Error Whether user has the capability 'jetpack_disconnect'.
382
	 */
383
	public static function jetpack_reconnect_permission_check() {
384
		if ( current_user_can( 'jetpack_reconnect' ) ) {
385
			return true;
386
		}
387
388
		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...
389
	}
390
391
	/**
392
	 * Returns generic error message when user is not allowed to perform an action.
393
	 *
394
	 * @return string The error message.
395
	 */
396
	public static function get_user_permissions_error_msg() {
397
		return self::$user_permissions_error_msg;
398
	}
399
400
	/**
401
	 * The endpoint tried to partially or fully reconnect the website to WP.com.
402
	 *
403
	 * @since 8.8.0
404
	 *
405
	 * @return \WP_REST_Response|WP_Error
406
	 */
407
	public function connection_reconnect() {
408
		$response = array();
409
410
		$next = null;
411
412
		$result = $this->connection->restore();
413
414
		if ( is_wp_error( $result ) ) {
415
			$response = $result;
416
		} elseif ( is_string( $result ) ) {
417
			$next = $result;
418
		} else {
419
			$next = true === $result ? 'completed' : 'failed';
420
		}
421
422
		switch ( $next ) {
423
			case 'authorize':
424
				$response['status']       = 'in_progress';
425
				$response['authorizeUrl'] = $this->connection->get_authorization_url();
426
				break;
427
			case 'completed':
428
				$response['status'] = 'completed';
429
				/**
430
				 * Action fired when reconnection has completed successfully.
431
				 *
432
				 * @since 9.0.0
433
				 */
434
				do_action( 'jetpack_reconnection_completed' );
435
				break;
436
			case 'failed':
437
				$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...
438
				break;
439
		}
440
441
		return rest_ensure_response( $response );
442
	}
443
444
	/**
445
	 * Verify that user is allowed to connect Jetpack.
446
	 *
447
	 * @since 9.7.0
448
	 *
449
	 * @return bool|WP_Error Whether user has the capability 'jetpack_connect'.
450
	 */
451
	public static function jetpack_register_permission_check() {
452
		if ( current_user_can( 'jetpack_connect' ) ) {
453
			return true;
454
		}
455
456
		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...
457
	}
458
459
	/**
460
	 * The endpoint tried to partially or fully reconnect the website to WP.com.
461
	 *
462
	 * @since 7.7.0
463
	 *
464
	 * @param \WP_REST_Request $request The request sent to the WP REST API.
465
	 *
466
	 * @return \WP_REST_Response|WP_Error
467
	 */
468
	public function connection_register( $request ) {
469 View Code Duplication
		if ( ! wp_verify_nonce( $request->get_param( 'registration_nonce' ), 'jetpack-registration-nonce' ) ) {
470
			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...
471
		}
472
473
		if ( isset( $request['from'] ) ) {
474
			$this->connection->add_register_request_param( 'from', (string) $request['from'] );
475
		}
476
		$result = $this->connection->try_registration();
477
478
		if ( is_wp_error( $result ) ) {
479
			return $result;
480
		}
481
482
		$redirect_uri = $request->get_param( 'redirect_uri' ) ? admin_url( $request->get_param( 'redirect_uri' ) ) : null;
483
484
		if ( class_exists( 'Jetpack' ) ) {
485
			$authorize_url = \Jetpack::build_authorize_url( $redirect_uri, ! $request->get_param( 'no_iframe' ) );
486
		} else {
487
			if ( ! $request->get_param( 'no_iframe' ) ) {
488
				add_filter( 'jetpack_use_iframe_authorization_flow', '__return_true' );
489
			}
490
491
			$authorize_url = $this->connection->get_authorization_url( null, $redirect_uri );
492
493
			if ( ! $request->get_param( 'no_iframe' ) ) {
494
				remove_filter( 'jetpack_use_iframe_authorization_flow', '__return_true' );
495
			}
496
		}
497
498
		/**
499
		 * Filters the response of jetpack/v4/connection/register endpoint
500
		 *
501
		 * @param array $response Array response
502
		 * @since 9.8.0
503
		 */
504
		$response_body = apply_filters(
505
			'jetpack_register_site_rest_response',
506
			array()
507
		);
508
509
		// We manipulate the alternate URLs after the filter is applied, so they can not be overwritten.
510
		$response_body['authorizeUrl'] = $authorize_url;
511
		if ( ! empty( $response_body['alternateAuthorizeUrl'] ) ) {
512
			$response_body['alternateAuthorizeUrl'] = Redirect::get_url( $response_body['alternateAuthorizeUrl'] );
513
		}
514
515
		return rest_ensure_response( $response_body );
516
	}
517
518
	/**
519
	 * Get the authorization URL.
520
	 *
521
	 * @since 9.8.0
522
	 *
523
	 * @param \WP_REST_Request $request The request sent to the WP REST API.
524
	 *
525
	 * @return \WP_REST_Response|WP_Error
526
	 */
527
	public function connection_authorize_url( $request ) {
528
		$redirect_uri = $request->get_param( 'redirect_uri' ) ? admin_url( $request->get_param( 'redirect_uri' ) ) : null;
529
530
		if ( ! $request->get_param( 'no_iframe' ) ) {
531
			add_filter( 'jetpack_use_iframe_authorization_flow', '__return_true' );
532
		}
533
534
		$authorize_url = $this->connection->get_authorization_url( null, $redirect_uri );
535
536
		if ( ! $request->get_param( 'no_iframe' ) ) {
537
			remove_filter( 'jetpack_use_iframe_authorization_flow', '__return_true' );
538
		}
539
540
		return rest_ensure_response(
541
			array(
542
				'authorizeUrl' => $authorize_url,
543
			)
544
		);
545
	}
546
547
	/**
548
	 * The endpoint tried to partially or fully reconnect the website to WP.com.
549
	 *
550
	 * @since 9.9.0
551
	 *
552
	 * @param \WP_REST_Request $request The request sent to the WP REST API.
553
	 *
554
	 * @return \WP_REST_Response|WP_Error
555
	 */
556
	public static function update_user_token( $request ) {
557
		$token_parts = explode( '.', $request['user_token'] );
558
559
		if ( count( $token_parts ) !== 3 || ! (int) $token_parts[2] || ! ctype_digit( $token_parts[2] ) ) {
560
			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...
561
		}
562
563
		$user_id = (int) $token_parts[2];
564
565
		if ( false === get_userdata( $user_id ) ) {
566
			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...
567
		}
568
569
		$connection = new Manager();
570
571
		if ( ! $connection->is_connected() ) {
572
			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...
573
		}
574
575
		$is_connection_owner = isset( $request['is_connection_owner'] )
576
			? (bool) $request['is_connection_owner']
577
			: ( new Manager() )->get_connection_owner_id() === $user_id;
578
579
		( new Tokens() )->update_user_token( $user_id, $request['user_token'], $is_connection_owner );
580
581
		/**
582
		 * Fires when the user token gets successfully replaced.
583
		 *
584
		 * @since 9.9.0
585
		 *
586
		 * @param int $user_id User ID.
587
		 * @param string $token New user token.
588
		 */
589
		do_action( 'jetpack_updated_user_token', $user_id, $request['user_token'] );
590
591
		return rest_ensure_response(
592
			array(
593
				'success' => true,
594
			)
595
		);
596
	}
597
598
	/**
599
	 * Verify that the API client is allowed to replace user token.
600
	 *
601
	 * @since 9.9.0
602
	 *
603
	 * @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...
604
	 */
605
	public static function update_user_token_permission_check() {
606
		return Rest_Authentication::is_signed_with_blog_token()
607
			? true
608
			: 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...
609
	}
610
}
611