PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
← All changes | jetpack_vendor/automattic/jetpack-connection/src/class-tokens.php +49 -15 12.3.2 → 16.3 View file →
@@ -39,8 +39,19 @@
39 39 )
40 40 );
41 41
42 42 $this->remove_lock();
43 +
44 + /**
45 + * Fires after all connection tokens have been deleted from the local site.
46 + *
47 + * `Jetpack_Options::delete_option()` fires no action of its own, so this is the only
48 + * signal that the tokens backing the connection are gone. Anything holding derived
49 + * state — a memoized connection status, a cached credential — must recompute from here.
50 + *
51 + * @since 9.1.1
52 + */
53 + do_action( 'jetpack_connection_tokens_deleted' );
43 54 }
44 55
45 56 /**
46 57 * Perform the API request to validate the blog and user tokens.
@@ -88,8 +99,10 @@
88 99
89 100 /**
90 101 * Perform the API request to validate only the blog.
91 102 *
103 + * @since 9.8.0 Returns a WP_Error, not false, when the request fails.
104 + *
92 105 * @return bool|WP_Error Boolean with the test result. WP_Error if test cannot be performed.
93 106 */
94 107 public function validate_blog_token() {
95 108 $blog_id = Jetpack_Options::get_option( 'id' );
@@ -95,8 +108,14 @@
95 108 $blog_id = Jetpack_Options::get_option( 'id' );
96 109 if ( ! $blog_id ) {
97 110 return new WP_Error( 'site_not_registered', 'Site not registered.' );
98 111 }
112 +
113 + // A missing blog token is broken, not unverifiable: the signed request would fail before it is sent.
114 + if ( ! $this->get_access_token() ) {
115 + return false;
116 + }
117 +
99 118 $url = sprintf(
100 119 '%s/%s/v%s/%s',
101 120 Constants::get_constant( 'JETPACK__WPCOM_JSON_API_BASE' ),
102 121 'wpcom',
@@ -106,12 +125,16 @@
106 125
107 126 $method = 'GET';
108 127 $response = Client::remote_request( compact( 'url', 'method' ) );
109 128
110 - if ( is_wp_error( $response ) || ! wp_remote_retrieve_body( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
111 - return false;
129 + if ( is_wp_error( $response ) ) {
130 + return $response;
112 131 }
113 132
133 + if ( ! wp_remote_retrieve_body( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
134 + return new WP_Error( 'blog_token_check_failed', 'The blog token health check could not be performed.' );
135 + }
136 +
114 137 $body = json_decode( wp_remote_retrieve_body( $response ), true );
115 138
116 139 return is_array( $body ) && isset( $body['is_healthy'] ) && true === $body['is_healthy'];
117 140 }
@@ -282,9 +305,22 @@
282 305 $options = compact( 'user_tokens', 'master_user' );
283 306 } else {
284 307 $options = compact( 'user_tokens' );
285 308 }
286 - return Jetpack_Options::update_options( $options );
309 + $updated = Jetpack_Options::update_options( $options );
310 +
311 + /**
312 + * Fires when the user token gets replaced.
313 + *
314 + * @since 1.29.0
315 + * @since 9.8.1 Fired from Tokens::update_user_token() so every write path (authorize, provisioning, CLI) clears stale connection errors, not just the REST endpoint.
316 + *
317 + * @param int $user_id User ID.
318 + * @param string $token New user token.
319 + */
320 + do_action( 'jetpack_updated_user_token', $user_id, $token );
321 +
322 + return $updated;
287 323 }
288 324
289 325 /**
290 326 * Sign a user role with the master access token.
@@ -376,29 +412,31 @@
376 412 $possible_normal_tokens = array();
377 413 $user_tokens = $this->get_user_tokens();
378 414
379 415 if ( $user_id ) {
416 + $resolved_user_id = true === $user_id ? (int) Jetpack_Options::get_option( 'master_user' ) : (int) $user_id;
417 +
380 418 if ( ! $user_tokens ) {
381 - return $suppress_errors ? false : new WP_Error( 'no_user_tokens', __( 'No user tokens found', 'jetpack-connection' ) );
419 + return $suppress_errors ? false : new WP_Error( 'no_user_tokens', __( 'No user tokens found', 'jetpack-connection' ), array( 'user_id' => $resolved_user_id ) );
382 420 }
383 421 if ( true === $user_id ) { // connection owner.
384 - $user_id = Jetpack_Options::get_option( 'master_user' );
385 - if ( ! $user_id ) {
422 + if ( ! $resolved_user_id ) {
386 423 return $suppress_errors ? false : new WP_Error( 'empty_master_user_option', __( 'No primary user defined', 'jetpack-connection' ) );
387 424 }
425 + $user_id = $resolved_user_id;
388 426 }
389 427 if ( ! isset( $user_tokens[ $user_id ] ) || ! $user_tokens[ $user_id ] ) {
390 428 // translators: %s is the user ID.
391 - return $suppress_errors ? false : new WP_Error( 'no_token_for_user', sprintf( __( 'No token for user %d', 'jetpack-connection' ), $user_id ) );
429 + return $suppress_errors ? false : new WP_Error( 'no_token_for_user', sprintf( __( 'No token for user %d', 'jetpack-connection' ), $user_id ), array( 'user_id' => (int) $user_id ) );
392 430 }
393 431 $user_token_chunks = explode( '.', $user_tokens[ $user_id ] );
394 432 if ( empty( $user_token_chunks[1] ) || empty( $user_token_chunks[2] ) ) {
395 433 // translators: %s is the user ID.
396 - return $suppress_errors ? false : new WP_Error( 'token_malformed', sprintf( __( 'Token for user %d is malformed', 'jetpack-connection' ), $user_id ) );
434 + return $suppress_errors ? false : new WP_Error( 'token_malformed', sprintf( __( 'Token for user %d is malformed', 'jetpack-connection' ), $user_id ), array( 'user_id' => (int) $user_id ) );
397 435 }
398 436 if ( $user_token_chunks[2] !== (string) $user_id ) {
399 437 // translators: %1$d is the ID of the requested user. %2$d is the user ID found in the token.
400 - return $suppress_errors ? false : new WP_Error( 'user_id_mismatch', sprintf( __( 'Requesting user_id %1$d does not match token user_id %2$d', 'jetpack-connection' ), $user_id, $user_token_chunks[2] ) );
438 + return $suppress_errors ? false : new WP_Error( 'user_id_mismatch', sprintf( __( 'Requesting user_id %1$d does not match token user_id %2$d', 'jetpack-connection' ), $user_id, $user_token_chunks[2] ), array( 'user_id' => (int) $user_id ) );
401 439 }
402 440 $possible_normal_tokens[] = "{$user_token_chunks[0]}.{$user_token_chunks[1]}";
403 441 } else {
404 442 $stored_blog_token = Jetpack_Options::get_option( 'blog_token' );
@@ -454,9 +492,9 @@
454 492
455 493 if ( ! $valid_token ) {
456 494 if ( $user_id ) {
457 495 // translators: %d is the user ID.
458 - return $suppress_errors ? false : new WP_Error( 'no_valid_user_token', sprintf( __( 'Invalid token for user %d', 'jetpack-connection' ), $user_id ) );
496 + return $suppress_errors ? false : new WP_Error( 'no_valid_user_token', sprintf( __( 'Invalid token for user %d', 'jetpack-connection' ), $user_id ), array( 'user_id' => (int) $user_id ) );
459 497 } else {
460 498 return $suppress_errors ? false : new WP_Error( 'no_valid_blog_token', __( 'Invalid blog token', 'jetpack-connection' ) );
461 499 }
462 500 }
@@ -548,9 +586,9 @@
548 586
549 587 if ( function_exists( 'wp_generate_password' ) ) {
550 588 $nonce = wp_generate_password( 10, false );
551 589 } else {
552 - $nonce = substr( sha1( wp_rand( 0, 1000000 ) ), 0, 10 );
590 + $nonce = substr( sha1( (string) wp_rand( 0, 1000000 ) ), 0, 10 );
553 591 }
554 592
555 593 $normalized_request_string = implode(
556 594 "\n",
@@ -614,12 +652,8 @@
614 652 public function set_lock( $timespan = HOUR_IN_SECONDS ) {
615 653 try {
616 654 $expires = ( new DateTime() )->add( DateInterval::createFromDateString( (int) $timespan . ' seconds' ) );
617 655 } catch ( Exception $e ) {
618 - return false;
619 - }
620 -
621 - if ( false === $expires ) {
622 656 return false;
623 657 }
624 658
625 659 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode