diff --git a/Cargo.lock b/Cargo.lock index c8aa7785..2e782926 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1206,6 +1206,7 @@ dependencies = [ "bincode", "brotli", "bytes", + "chrono", "collab", "collab-entity", "database-entity", diff --git a/libs/app_error/src/lib.rs b/libs/app_error/src/lib.rs index 88e0ae0c..23af6578 100644 --- a/libs/app_error/src/lib.rs +++ b/libs/app_error/src/lib.rs @@ -33,6 +33,12 @@ pub enum AppError { #[error("{0}")] OAuthError(String), + #[error("{0}")] + UserUnAuthorized(String), + + #[error("{0}")] + UserAlreadyRegistered(String), + #[error("Missing Payload:{0}")] MissingPayload(String), @@ -115,8 +121,8 @@ impl AppError { matches!(self, AppError::Connect(_) | AppError::RequestTimeout(_)) } - pub fn is_oauth_error(&self) -> bool { - matches!(self, AppError::OAuthError(_)) + pub fn is_unauthorized(&self) -> bool { + matches!(self, AppError::UserUnAuthorized(_)) } pub fn code(&self) -> ErrorCode { @@ -128,6 +134,8 @@ impl AppError { AppError::InvalidEmail(_) => ErrorCode::InvalidEmail, AppError::InvalidPassword(_) => ErrorCode::InvalidPassword, AppError::OAuthError(_) => ErrorCode::OAuthError, + AppError::UserUnAuthorized(_) => ErrorCode::UserUnAuthorized, + AppError::UserAlreadyRegistered(_) => ErrorCode::RecordAlreadyExists, AppError::MissingPayload(_) => ErrorCode::MissingPayload, AppError::DBError(_) => ErrorCode::DBError, AppError::OpenError(_) => ErrorCode::OpenError, @@ -198,11 +206,13 @@ impl From for AppError { GoTrueError::RequestTimeout(msg) => AppError::RequestTimeout(msg), GoTrueError::InvalidRequest(msg) => AppError::InvalidRequest(msg), GoTrueError::ClientError(err) => AppError::OAuthError(err.to_string()), - GoTrueError::Auth(err) => AppError::OAuthError(err), + GoTrueError::Auth(err) => AppError::UserUnAuthorized(err), GoTrueError::Internal(err) => match (err.code, err.msg.as_str()) { (400, m) if m.starts_with("oauth error") => AppError::OAuthError(err.msg), - (400, m) if m.starts_with("User already registered") => AppError::OAuthError(err.msg), - (401, _) => AppError::OAuthError(err.msg), + (400, m) if m.starts_with("User already registered") => { + AppError::UserAlreadyRegistered(err.msg) + }, + (401, _) => AppError::UserUnAuthorized(err.msg), (422, _) => AppError::InvalidRequest(err.msg), _ => AppError::OAuthError(err.to_string()), }, @@ -252,6 +262,7 @@ pub enum ErrorCode { S3ResponseError = 1021, SerdeError = 1022, NetworkError = 1023, + UserUnAuthorized = 1024, } impl ErrorCode { diff --git a/libs/client-api/Cargo.toml b/libs/client-api/Cargo.toml index a1619cf3..3ba28611 100644 --- a/libs/client-api/Cargo.toml +++ b/libs/client-api/Cargo.toml @@ -31,6 +31,7 @@ url = "2.5.0" mime = "0.3.17" tokio-stream = { version = "0.1.14" } realtime-entity = { workspace = true } +chrono = "0.4" collab = { version = "0.1.0", optional = true } collab-entity = { version = "0.1.0" } diff --git a/libs/client-api/src/http.rs b/libs/client-api/src/http.rs index 3adef375..1aac9112 100644 --- a/libs/client-api/src/http.rs +++ b/libs/client-api/src/http.rs @@ -37,7 +37,7 @@ use shared_entity::dto::workspace_dto::{ use shared_entity::response::{AppResponse, AppResponseError}; use std::sync::atomic::AtomicBool; use std::sync::Arc; -use std::time::{Duration, SystemTime}; +use std::time::Duration; use tracing::{event, instrument, trace, warn}; use url::Url; @@ -1113,10 +1113,7 @@ impl Client { let expires_at = self.token_expires_at()?; // Refresh token if it's about to expire - let time_now_sec = SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap() - .as_secs() as i64; + let time_now_sec = chrono::Local::now().timestamp(); if time_now_sec + 10 > expires_at { // Add 10 seconds buffer self.refresh_token().await?; diff --git a/libs/client-api/src/native/http_native.rs b/libs/client-api/src/native/http_native.rs index 57d9b67c..406f8e11 100644 --- a/libs/client-api/src/native/http_native.rs +++ b/libs/client-api/src/native/http_native.rs @@ -120,7 +120,7 @@ impl Client { } async fn inner_refresh_token(&self) -> Result<(), AppResponseError> { - let retry_strategy = FixedInterval::new(Duration::from_secs(2)).take(4); + let retry_strategy = FixedInterval::new(Duration::from_secs(10)).take(4); let action = RefreshTokenAction::new(self.token.clone(), self.gotrue_client.clone()); match RetryIf::spawn(retry_strategy, action, RefreshTokenRetryCondition).await { Ok(_) => { @@ -132,7 +132,7 @@ impl Client { event!(tracing::Level::ERROR, "refresh token failed: {}", err); // If the error is an OAuth error, unset the token. - if err.is_oauth_error() { + if err.is_unauthorized() { self.token.write().unset(); } Err(err.into()) diff --git a/tests/user/sign_in.rs b/tests/user/sign_in.rs index bcebed65..47dd6557 100644 --- a/tests/user/sign_in.rs +++ b/tests/user/sign_in.rs @@ -92,7 +92,7 @@ async fn sign_in_with_invalid_url() { match c.sign_in_with_url(url_str).await { Ok(_) => panic!("should not be ok"), Err(e) => { - assert_eq!(e.code, ErrorCode::OAuthError); + assert_eq!(e.code, ErrorCode::UserUnAuthorized); assert!(e .message .contains("invalid JWT: unable to parse or verify signature, token is expired by"));