diff --git a/mu-plugins/utilities/class-meetup-client.php b/mu-plugins/utilities/class-meetup-client.php index 1d99fcb63..57d00f982 100644 --- a/mu-plugins/utilities/class-meetup-client.php +++ b/mu-plugins/utilities/class-meetup-client.php @@ -49,6 +49,9 @@ class Meetup_Client extends API_Client { * } */ public function __construct( array $settings = array() ) { + // Define the OAuth client first, such that it can be used in the parent constructor callbacks. + $this->oauth_client = new Meetup_OAuth2_Client; + parent::__construct( array( /* * Response codes that should break the request loop. @@ -86,13 +89,12 @@ public function __construct( array $settings = array() ) { self::cli_message( 'Meetup Client debug is on. Results will be truncated.' ); } - $this->oauth_client = new Meetup_OAuth2_Client(); + add_action( 'api_client_tenacious_remote_request_attempt', array( $this, 'maybe_reset_oauth_token' ) ); + add_action( 'api_client_handle_error_response', array( $this, 'maybe_reset_oauth_token' ) ); if ( ! empty( $this->oauth_client->error->get_error_messages() ) ) { $this->error = $this->merge_errors( $this->error, $this->oauth_client->error ); } - - add_action( 'api_client_tenacious_remote_request_attempt', array( $this, 'maybe_reset_oauth_token' ) ); } /** @@ -106,6 +108,12 @@ public function __construct( array $settings = array() ) { * @return void */ public function maybe_reset_oauth_token( $response ) { + static $resetting = false; + // Avoid recursive calls. + if ( $resetting ) { + return; + } + $code = wp_remote_retrieve_response_code( $response ); $body = json_decode( wp_remote_retrieve_body( $response ), true ); @@ -115,6 +123,8 @@ public function maybe_reset_oauth_token( $response ) { ( 400 === $code && $parsed_error->get_error_message( 'invalid_grant' ) ) || ( 401 === $code && $parsed_error->get_error_message( 'auth_fail' ) ) ) { + $resetting = true; + $this->oauth_client->reset_oauth_token(); if ( ! empty( $this->oauth_client->error->get_error_messages() ) ) { @@ -123,6 +133,8 @@ public function maybe_reset_oauth_token( $response ) { // Reset the request headers, so that they include the new oauth token. $this->current_request_args = $this->get_request_args(); + + $resetting = false; } } diff --git a/mu-plugins/utilities/class-meetup-oauth2-client.php b/mu-plugins/utilities/class-meetup-oauth2-client.php index 84a7dd24f..9f4f828eb 100644 --- a/mu-plugins/utilities/class-meetup-oauth2-client.php +++ b/mu-plugins/utilities/class-meetup-oauth2-client.php @@ -87,7 +87,7 @@ public function __construct() { * See API_Client::tenacious_remote_request. */ 'breaking_response_codes' => array( - 400, // Bad request. + 400, // Bad request. This happens for invalid_grant during refresh 401, // Unauthorized (invalid key). 429, // Too many requests (rate-limited). 404, // Unable to find group @@ -219,48 +219,49 @@ public function get_oauth_token() { return $this->oauth_token['access_token']; } + // Get cached access token $token = get_site_option( self::SITE_OPTION_KEY_OAUTH, array() ); + $valid = $this->is_valid_token( $token, 'access_token' ); - if ( ! $this->is_valid_token( $token, 'access_token' ) ) { - - // At this point, we need to get a new oAuth done. - if ( empty( $_GET['code'] ) ) { - $_GET['code'] = get_site_option( self::SITE_OPTION_KEY_AUTHORIZATION, false ); - - if ( ! $_GET['code'] ) { - $message = sprintf( - "Meetup.com oAuth expired. Please access the following url while logged into the %s meetup.com account: \n\n%s\n\n" . - "For sites other than WordCamp Central, the ?code=... parameter will need to be stored on this site via wp-cli and this task run again: `wp --url=%s site option update '%s' '...'`", - self::EMAIL, - sprintf( - 'https://secure.meetup.com/oauth2/authorize?client_id=%s&response_type=code&redirect_uri=%s&state=meetup-oauth', - self::CONSUMER_KEY, - self::REDIRECT_URI - ), - network_site_url('/'), - self::SITE_OPTION_KEY_AUTHORIZATION - ); - - if ( admin_url( '/' ) === self::REDIRECT_URI ) { - printf( '

%s

', nl2br( make_clickable( $message ) ) ); - } - - trigger_error( $message, E_USER_WARNING ); - - return false; + // If it's a valid token, but expired, refresh it. + if ( $valid && $this->is_expired_token( $token ) ) { + $token = $this->request_token( 'refresh_token', $token ); + $valid = $this->is_valid_token( $token, 'access_token' ); + } + + // If it's not a valid token, or the refresh token wasn't valid, check to see if we're able to fetch a new one. + if ( ! $valid ) { + $auth_code = $_GET['code'] ?? get_site_option( self::SITE_OPTION_KEY_AUTHORIZATION, false ); + + if ( $auth_code ) { + $token = $this->request_token( 'access_token', array( 'code' => $auth_code ) ); + $valid = $this->is_valid_token( $token, 'access_token' ); + if ( $valid ) { + delete_site_option( self::SITE_OPTION_KEY_AUTHORIZATION, false ); } } + } - $token = $this->request_token( 'access_token', array( 'code' => $_GET['code'] ) ); + // If we're unable to find a valid token, and we're not mid-refresh, throw a Warning & Notice. + if ( ! $valid ) { + $message = sprintf( + "Meetup.com oAuth expired. Please access the following url while logged into the %s meetup.com account: \n\n%s\n\n" . + "For sites other than WordCamp Central, the ?code=... parameter will need to be stored on this site via wp-cli and this task run again: `wp --url=%s site option update '%s' '...'`", + self::EMAIL, + sprintf( + 'https://secure.meetup.com/oauth2/authorize?client_id=%s&response_type=code&redirect_uri=%s&state=meetup-oauth', + self::CONSUMER_KEY, + self::REDIRECT_URI + ), + network_site_url('/'), + self::SITE_OPTION_KEY_AUTHORIZATION + ); - if ( $this->is_valid_token( $token, 'access_token' ) ) { - delete_site_option( self::SITE_OPTION_KEY_AUTHORIZATION, false ); + if ( admin_url( '/' ) === self::REDIRECT_URI ) { + printf( '

%s

', nl2br( make_clickable( $message ) ) ); } - } elseif ( $this->is_expired_token( $token ) ) { - $token = $this->request_token( 'refresh_token', $token ); - } + trigger_error( $message, E_USER_WARNING ); - if ( ! $this->is_valid_token( $token, 'access_token' ) ) { return false; } @@ -283,7 +284,7 @@ public function get_oauth_token() { public function reset_oauth_token() { // NO. JUST NO. Do not delete the oAuth token. // This is temporarily disabled while Meetup.com server-to-server authentication is unavailable. - // delete_site_option( self::SITE_OPTION_KEY_OAUTH ); + delete_site_option( self::SITE_OPTION_KEY_OAUTH ); $this->oauth_token = array(); $this->error = new WP_Error();