diff --git a/crates/api_models/src/events/user.rs b/crates/api_models/src/events/user.rs index a472b3a76e..c41f52a93e 100644 --- a/crates/api_models/src/events/user.rs +++ b/crates/api_models/src/events/user.rs @@ -16,8 +16,9 @@ use crate::user::{ GetUserRoleDetailsResponse, InviteUserRequest, ListUsersResponse, ReInviteUserRequest, RecoveryCodes, ResetPasswordRequest, RotatePasswordRequest, SendVerifyEmailRequest, SignInResponse, SignUpRequest, SignUpWithMerchantIdRequest, SwitchMerchantIdRequest, - TokenOrPayloadResponse, TokenResponse, UpdateUserAccountDetailsRequest, UserFromEmailRequest, - UserMerchantCreate, VerifyEmailRequest, VerifyRecoveryCodeRequest, VerifyTotpRequest, + TokenOrPayloadResponse, TokenResponse, TwoFactorAuthStatusResponse, + UpdateUserAccountDetailsRequest, UserFromEmailRequest, UserMerchantCreate, VerifyEmailRequest, + VerifyRecoveryCodeRequest, VerifyTotpRequest, }; impl ApiEventMetric for DashboardEntryResponse { @@ -73,6 +74,7 @@ common_utils::impl_misc_api_event_type!( GetUserRoleDetailsRequest, GetUserRoleDetailsResponse, TokenResponse, + TwoFactorAuthStatusResponse, UserFromEmailRequest, BeginTotpResponse, VerifyRecoveryCodeRequest, diff --git a/crates/api_models/src/user.rs b/crates/api_models/src/user.rs index 0c8678d2ef..ee9498cfee 100644 --- a/crates/api_models/src/user.rs +++ b/crates/api_models/src/user.rs @@ -235,6 +235,12 @@ pub struct TokenResponse { pub token_type: TokenPurpose, } +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct TwoFactorAuthStatusResponse { + pub totp: bool, + pub recovery_code: bool, +} + #[derive(Debug, serde::Serialize)] #[serde(untagged)] pub enum TokenOrPayloadResponse { diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs index 7b6e8ebd36..0da381bd49 100644 --- a/crates/router/src/core/user.rs +++ b/crates/router/src/core/user.rs @@ -1874,3 +1874,16 @@ pub async fn terminate_two_factor_auth( token, ) } + +pub async fn check_two_factor_auth_status( + state: AppState, + user_token: auth::UserFromToken, +) -> UserResponse { + Ok(ApplicationResponse::Json( + user_api::TwoFactorAuthStatusResponse { + totp: tfa_utils::check_totp_in_redis(&state, &user_token.user_id).await?, + recovery_code: tfa_utils::check_recovery_code_in_redis(&state, &user_token.user_id) + .await?, + }, + )) +} diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index b38479cd2b..141e9f53af 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -1214,6 +1214,7 @@ impl User { // Two factor auth routes route = route.service( web::scope("/2fa") + .service(web::resource("").route(web::get().to(check_two_factor_auth_status))) .service( web::scope("/totp") .service(web::resource("/begin").route(web::get().to(totp_begin))) diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs index 9e53eb3547..417a4360c5 100644 --- a/crates/router/src/routes/lock_utils.rs +++ b/crates/router/src/routes/lock_utils.rs @@ -218,7 +218,8 @@ impl From for ApiIdentifier { | Flow::TotpUpdate | Flow::RecoveryCodeVerify | Flow::RecoveryCodesGenerate - | Flow::TerminateTwoFactorAuth => Self::User, + | Flow::TerminateTwoFactorAuth + | Flow::TwoFactorAuthStatus => Self::User, Flow::ListRoles | Flow::GetRole diff --git a/crates/router/src/routes/user.rs b/crates/router/src/routes/user.rs index 5ba7ec8da2..f22e4aac52 100644 --- a/crates/router/src/routes/user.rs +++ b/crates/router/src/routes/user.rs @@ -735,3 +735,20 @@ pub async fn terminate_two_factor_auth( )) .await } + +pub async fn check_two_factor_auth_status( + state: web::Data, + req: HttpRequest, +) -> HttpResponse { + let flow = Flow::TwoFactorAuthStatus; + Box::pin(api::server_wrap( + flow, + state.clone(), + &req, + (), + |state, user, _, _| user_core::check_two_factor_auth_status(state, user), + &auth::DashboardNoPermissionAuth, + api_locking::LockAction::NotApplicable, + )) + .await +} diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs index 1bfc20ff1c..728f2ed206 100644 --- a/crates/router_env/src/logger/types.rs +++ b/crates/router_env/src/logger/types.rs @@ -414,6 +414,8 @@ pub enum Flow { RecoveryCodesGenerate, // Terminate two factor authentication TerminateTwoFactorAuth, + // Check 2FA status + TwoFactorAuthStatus, /// List initial webhook delivery attempts WebhookEventInitialDeliveryAttemptList, /// List delivery attempts for a webhook event