feat(users): Add redis in Begin and Verify TOTP and create a new API that updates TOTP (#4765)

This commit is contained in:
Mani Chandra
2024-05-29 15:39:28 +05:30
committed by GitHub
parent a6570b6a06
commit cd9c9b609c
10 changed files with 209 additions and 100 deletions

View File

@ -1,9 +1,10 @@
use std::collections::HashMap;
use std::{collections::HashMap, sync::Arc};
use api_models::user as user_api;
use common_utils::errors::CustomResult;
use diesel_models::{enums::UserStatus, user_role::UserRole};
use error_stack::ResultExt;
use redis_interface::RedisConnectionPool;
use crate::{
core::errors::{StorageError, UserErrors, UserResult},
@ -191,3 +192,11 @@ pub fn get_token_from_signin_response(resp: &user_api::SignInResponse) -> maskin
user_api::SignInResponse::MerchantSelect(data) => data.token.clone(),
}
}
pub fn get_redis_connection(state: &AppState) -> UserResult<Arc<RedisConnectionPool>> {
state
.store
.get_redis_conn()
.change_context(UserErrors::InternalServerError)
.attach_printable("Failed to get redis connection")
}

View File

@ -1,9 +1,6 @@
use std::sync::Arc;
use common_utils::pii;
use error_stack::ResultExt;
use masking::ExposeInterface;
use redis_interface::RedisConnectionPool;
use masking::{ExposeInterface, PeekInterface};
use totp_rs::{Algorithm, TOTP};
use crate::{
@ -35,8 +32,8 @@ pub fn generate_default_totp(
}
pub async fn check_totp_in_redis(state: &AppState, user_id: &str) -> UserResult<bool> {
let redis_conn = get_redis_connection(state)?;
let key = format!("{}{}", consts::user::TOTP_PREFIX, user_id);
let redis_conn = super::get_redis_connection(state)?;
let key = format!("{}{}", consts::user::REDIS_TOTP_PREFIX, user_id);
redis_conn
.exists::<()>(&key)
.await
@ -44,7 +41,7 @@ pub async fn check_totp_in_redis(state: &AppState, user_id: &str) -> UserResult<
}
pub async fn check_recovery_code_in_redis(state: &AppState, user_id: &str) -> UserResult<bool> {
let redis_conn = get_redis_connection(state)?;
let redis_conn = super::get_redis_connection(state)?;
let key = format!("{}{}", consts::user::REDIS_RECOVERY_CODE_PREFIX, user_id);
redis_conn
.exists::<()>(&key)
@ -52,16 +49,62 @@ pub async fn check_recovery_code_in_redis(state: &AppState, user_id: &str) -> Us
.change_context(UserErrors::InternalServerError)
}
fn get_redis_connection(state: &AppState) -> UserResult<Arc<RedisConnectionPool>> {
state
.store
.get_redis_conn()
pub async fn insert_totp_in_redis(state: &AppState, user_id: &str) -> UserResult<()> {
let redis_conn = super::get_redis_connection(state)?;
let key = format!("{}{}", consts::user::REDIS_TOTP_PREFIX, user_id);
redis_conn
.set_key_with_expiry(
key.as_str(),
common_utils::date_time::now_unix_timestamp(),
state.conf.user.two_factor_auth_expiry_in_secs,
)
.await
.change_context(UserErrors::InternalServerError)
.attach_printable("Failed to get redis connection")
}
pub async fn insert_totp_secret_in_redis(
state: &AppState,
user_id: &str,
secret: &masking::Secret<String>,
) -> UserResult<()> {
let redis_conn = super::get_redis_connection(state)?;
redis_conn
.set_key_with_expiry(
&get_totp_secret_key(user_id),
secret.peek(),
consts::user::REDIS_TOTP_SECRET_TTL_IN_SECS,
)
.await
.change_context(UserErrors::InternalServerError)
}
pub async fn get_totp_secret_from_redis(
state: &AppState,
user_id: &str,
) -> UserResult<Option<masking::Secret<String>>> {
let redis_conn = super::get_redis_connection(state)?;
redis_conn
.get_key::<Option<String>>(&get_totp_secret_key(user_id))
.await
.change_context(UserErrors::InternalServerError)
.map(|secret| secret.map(Into::into))
}
pub async fn delete_totp_secret_from_redis(state: &AppState, user_id: &str) -> UserResult<()> {
let redis_conn = super::get_redis_connection(state)?;
redis_conn
.delete_key(&get_totp_secret_key(user_id))
.await
.change_context(UserErrors::InternalServerError)
.map(|_| ())
}
fn get_totp_secret_key(user_id: &str) -> String {
format!("{}{}", consts::user::REDIS_TOTP_SECRET_PREFIX, user_id)
}
pub async fn insert_recovery_code_in_redis(state: &AppState, user_id: &str) -> UserResult<()> {
let redis_conn = get_redis_connection(state)?;
let redis_conn = super::get_redis_connection(state)?;
let key = format!("{}{}", consts::user::REDIS_RECOVERY_CODE_PREFIX, user_id);
redis_conn
.set_key_with_expiry(