From 07146e8433c9f2a388c500801f9f9d338a1d640b Mon Sep 17 00:00:00 2001 From: Juuso Tuononen Date: Sun, 26 May 2024 13:54:00 +0300 Subject: [PATCH] Improve OAuth related API --- src/client/mod.rs | 14 ++++++++------ src/client/oauth_yup_oauth2.rs | 32 ++++++++++++++++---------------- src/lib.rs | 2 ++ 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/client/mod.rs b/src/client/mod.rs index f9842fd5c..21d39271e 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,6 +1,6 @@ pub(crate) mod response; -pub mod oauth_yup_oauth2; +mod oauth_yup_oauth2; use std::path::{Path, PathBuf}; use std::time::Duration; @@ -11,14 +11,16 @@ use crate::client::response::FcmResponse; use crate::message::{Message, MessageWrapper}; use crate::RetryAfter; -use self::oauth_yup_oauth2::{YupOauth2, YupOauth2Error}; +use self::oauth_yup_oauth2::OauthClient; + +pub use self::oauth_yup_oauth2::OauthError; #[derive(thiserror::Error, Debug)] pub enum FcmClientError { #[error("Reqwest error: {0}")] Reqwest(#[from] reqwest::Error), #[error("OAuth error: {0}")] - Oauth(YupOauth2Error), + Oauth(OauthError), #[error("Dotenvy error: {0}")] Dotenvy(#[from] dotenvy::Error), #[error("Retry-After HTTP header value is not valid string")] @@ -97,7 +99,7 @@ impl FcmClientBuilder { /// An async client for sending the notification payload. pub struct FcmClient { http_client: reqwest::Client, - oauth_client: YupOauth2, + oauth_client: OauthClient, } impl FcmClient { @@ -117,7 +119,7 @@ impl FcmClient { let http_client = builder.build()?; let oauth_client = if let Some(key_json) = fcm_builder.service_account_key_json_string { - YupOauth2::create_with_string_key( + OauthClient::create_with_string_key( key_json, fcm_builder.token_cache_json_path, ) @@ -130,7 +132,7 @@ impl FcmClient { dotenvy::var("GOOGLE_APPLICATION_CREDENTIALS")?.into() }; - YupOauth2::create_with_key_file( + OauthClient::create_with_key_file( service_account_key_path, fcm_builder.token_cache_json_path, ) diff --git a/src/client/oauth_yup_oauth2.rs b/src/client/oauth_yup_oauth2.rs index 33663329a..9161b0309 100644 --- a/src/client/oauth_yup_oauth2.rs +++ b/src/client/oauth_yup_oauth2.rs @@ -8,7 +8,7 @@ use yup_oauth2::ServiceAccountAuthenticator; const FIREBASE_OAUTH_SCOPE: &str = "https://www.googleapis.com/auth/firebase.messaging"; #[derive(thiserror::Error, Debug)] -pub enum YupOauth2Error { +pub enum OauthError { #[error("Service account key reading failed: {0}")] ServiceAccountKeyReadingFailed(std::io::Error), #[error("OAuth error: {0}")] @@ -21,14 +21,14 @@ pub enum YupOauth2Error { ProjectIdIsMissing, } -impl YupOauth2Error { +impl OauthError { /// If this is `true` then most likely current service account /// key is invalid. pub(crate) fn is_access_token_missing_even_if_server_requests_completed(&self) -> bool { matches!( self, - YupOauth2Error::AccessTokenIsMissing | - YupOauth2Error::Oauth( + OauthError::AccessTokenIsMissing | + OauthError::Oauth( yup_oauth2::Error::MissingAccessToken | yup_oauth2::Error::AuthError(_) ) @@ -36,29 +36,29 @@ impl YupOauth2Error { } } -pub(crate) struct YupOauth2 { +pub(crate) struct OauthClient { authenticator: Authenticator>, project_id: String, } -impl YupOauth2 { +impl OauthClient { pub async fn create_with_key_file( service_account_key_path: PathBuf, token_cache_json_path: Option, - ) -> Result { + ) -> Result { let file = tokio::fs::read_to_string(&service_account_key_path).await - .map_err(YupOauth2Error::ServiceAccountKeyReadingFailed)?; + .map_err(OauthError::ServiceAccountKeyReadingFailed)?; Self::create_with_string_key(file, token_cache_json_path).await } pub async fn create_with_string_key( service_account_key_json_string: String, token_cache_json_path: Option, - ) -> Result { + ) -> Result { let key = yup_oauth2::parse_service_account_key(service_account_key_json_string) - .map_err(YupOauth2Error::ServiceAccountKeyReadingFailed)?; + .map_err(OauthError::ServiceAccountKeyReadingFailed)?; let oauth_client = DefaultHyperClient.build_hyper_client() - .map_err(YupOauth2Error::Oauth)?; + .map_err(OauthError::Oauth)?; let builder = ServiceAccountAuthenticator::with_client(key.clone(), oauth_client); let builder = if let Some(path) = token_cache_json_path { builder.persist_tokens_to_disk(path) @@ -67,22 +67,22 @@ impl YupOauth2 { }; let authenticator = builder.build() .await - .map_err(YupOauth2Error::AuthenticatorCreatingFailed)?; + .map_err(OauthError::AuthenticatorCreatingFailed)?; let project_id = key.project_id - .ok_or(YupOauth2Error::ProjectIdIsMissing)?; + .ok_or(OauthError::ProjectIdIsMissing)?; - Ok(YupOauth2 { + Ok(OauthClient { authenticator, project_id, }) } - pub async fn get_access_token(&self) -> Result { + pub async fn get_access_token(&self) -> Result { let scopes = [FIREBASE_OAUTH_SCOPE]; let access_token = self.authenticator.token(&scopes).await?; let access_token = access_token.token() - .ok_or(YupOauth2Error::AccessTokenIsMissing)?; + .ok_or(OauthError::AccessTokenIsMissing)?; Ok(access_token.to_string()) } diff --git a/src/lib.rs b/src/lib.rs index 9c26d5366..be6e5eb4c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,8 @@ //! } //! ``` +pub use yup_oauth2; + pub mod message; pub(crate) mod notification; pub(crate) mod android;