feat(users): Create generate recovery codes API (#4708)

This commit is contained in:
Mani Chandra
2024-05-22 13:58:42 +05:30
committed by GitHub
parent ae601e8e1b
commit 8fa2cd556b
11 changed files with 135 additions and 38 deletions

View File

@ -66,10 +66,12 @@ pub enum UserErrors {
RoleNameParsingError,
#[error("RoleNameAlreadyExists")]
RoleNameAlreadyExists,
#[error("TOTPNotSetup")]
#[error("TotpNotSetup")]
TotpNotSetup,
#[error("InvalidTOTP")]
#[error("InvalidTotp")]
InvalidTotp,
#[error("TotpRequired")]
TotpRequired,
}
impl common_utils::errors::ErrorSwitch<api_models::errors::types::ApiErrorResponse> for UserErrors {
@ -179,6 +181,9 @@ impl common_utils::errors::ErrorSwitch<api_models::errors::types::ApiErrorRespon
Self::InvalidTotp => {
AER::BadRequest(ApiError::new(sub_code, 37, self.get_error_message(), None))
}
Self::TotpRequired => {
AER::BadRequest(ApiError::new(sub_code, 38, self.get_error_message(), None))
}
}
}
}
@ -217,6 +222,7 @@ impl UserErrors {
Self::RoleNameAlreadyExists => "Role name already exists",
Self::TotpNotSetup => "TOTP not setup",
Self::InvalidTotp => "Invalid TOTP",
Self::TotpRequired => "TOTP required",
}
}
}

View File

@ -1631,7 +1631,7 @@ pub async fn begin_totp(
}));
}
let totp = utils::user::generate_default_totp(user_from_db.get_email(), None)?;
let totp = utils::user::two_factor_auth::generate_default_totp(user_from_db.get_email(), None)?;
let recovery_codes = domain::RecoveryCodes::generate_new();
let key_store = user_from_db.get_or_create_key_store(&state).await?;
@ -1693,8 +1693,10 @@ pub async fn verify_totp(
.await?
.ok_or(UserErrors::InternalServerError)?;
let totp =
utils::user::generate_default_totp(user_from_db.get_email(), Some(user_totp_secret))?;
let totp = utils::user::two_factor_auth::generate_default_totp(
user_from_db.get_email(),
Some(user_totp_secret),
)?;
if totp
.generate_current()
@ -1732,3 +1734,35 @@ pub async fn verify_totp(
token,
)
}
pub async fn generate_recovery_codes(
state: AppState,
user_token: auth::UserFromSinglePurposeToken,
) -> UserResponse<user_api::RecoveryCodes> {
if !utils::user::two_factor_auth::check_totp_in_redis(&state, &user_token.user_id).await? {
return Err(UserErrors::TotpRequired.into());
}
let recovery_codes = domain::RecoveryCodes::generate_new();
state
.store
.update_user_by_user_id(
&user_token.user_id,
storage_user::UserUpdate::TotpUpdate {
totp_status: None,
totp_secret: None,
totp_recovery_codes: Some(
recovery_codes
.get_hashed()
.change_context(UserErrors::InternalServerError)?,
),
},
)
.await
.change_context(UserErrors::InternalServerError)?;
Ok(ApplicationResponse::Json(user_api::RecoveryCodes {
recovery_codes: recovery_codes.into_inner(),
}))
}