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