mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 17:19:15 +08:00
feat(users): Added blacklist for users (#3469)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -21,7 +21,7 @@ pub mod routes {
|
|||||||
routes::AppState,
|
routes::AppState,
|
||||||
services::{
|
services::{
|
||||||
api,
|
api,
|
||||||
authentication::{self as auth, AuthToken, AuthenticationData},
|
authentication::{self as auth, AuthenticationData},
|
||||||
authorization::permissions::Permission,
|
authorization::permissions::Permission,
|
||||||
ApplicationResponse,
|
ApplicationResponse,
|
||||||
},
|
},
|
||||||
@ -378,23 +378,13 @@ pub mod routes {
|
|||||||
req: actix_web::HttpRequest,
|
req: actix_web::HttpRequest,
|
||||||
json_payload: web::Json<ReportRequest>,
|
json_payload: web::Json<ReportRequest>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let state_ref = &state;
|
|
||||||
let req_headers = &req.headers();
|
|
||||||
|
|
||||||
let flow = AnalyticsFlow::GenerateRefundReport;
|
let flow = AnalyticsFlow::GenerateRefundReport;
|
||||||
Box::pin(api::server_wrap(
|
Box::pin(api::server_wrap(
|
||||||
flow,
|
flow,
|
||||||
state.clone(),
|
state.clone(),
|
||||||
&req,
|
&req,
|
||||||
json_payload.into_inner(),
|
json_payload.into_inner(),
|
||||||
|state, auth: AuthenticationData, payload| async move {
|
|state, (auth, user_id): auth::AuthenticationDataWithUserId, payload| async move {
|
||||||
let jwt_payload =
|
|
||||||
auth::parse_jwt_payload::<AppState, AuthToken>(req_headers, state_ref).await;
|
|
||||||
|
|
||||||
let user_id = jwt_payload
|
|
||||||
.change_context(AnalyticsError::UnknownError)?
|
|
||||||
.user_id;
|
|
||||||
|
|
||||||
let user = UserInterface::find_user_by_id(&*state.store, &user_id)
|
let user = UserInterface::find_user_by_id(&*state.store, &user_id)
|
||||||
.await
|
.await
|
||||||
.change_context(AnalyticsError::UnknownError)?;
|
.change_context(AnalyticsError::UnknownError)?;
|
||||||
@ -430,23 +420,13 @@ pub mod routes {
|
|||||||
req: actix_web::HttpRequest,
|
req: actix_web::HttpRequest,
|
||||||
json_payload: web::Json<ReportRequest>,
|
json_payload: web::Json<ReportRequest>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let state_ref = &state;
|
|
||||||
let req_headers = &req.headers();
|
|
||||||
|
|
||||||
let flow = AnalyticsFlow::GenerateDisputeReport;
|
let flow = AnalyticsFlow::GenerateDisputeReport;
|
||||||
Box::pin(api::server_wrap(
|
Box::pin(api::server_wrap(
|
||||||
flow,
|
flow,
|
||||||
state.clone(),
|
state.clone(),
|
||||||
&req,
|
&req,
|
||||||
json_payload.into_inner(),
|
json_payload.into_inner(),
|
||||||
|state, auth: AuthenticationData, payload| async move {
|
|state, (auth, user_id): auth::AuthenticationDataWithUserId, payload| async move {
|
||||||
let jwt_payload =
|
|
||||||
auth::parse_jwt_payload::<AppState, AuthToken>(req_headers, state_ref).await;
|
|
||||||
|
|
||||||
let user_id = jwt_payload
|
|
||||||
.change_context(AnalyticsError::UnknownError)?
|
|
||||||
.user_id;
|
|
||||||
|
|
||||||
let user = UserInterface::find_user_by_id(&*state.store, &user_id)
|
let user = UserInterface::find_user_by_id(&*state.store, &user_id)
|
||||||
.await
|
.await
|
||||||
.change_context(AnalyticsError::UnknownError)?;
|
.change_context(AnalyticsError::UnknownError)?;
|
||||||
@ -482,23 +462,13 @@ pub mod routes {
|
|||||||
req: actix_web::HttpRequest,
|
req: actix_web::HttpRequest,
|
||||||
json_payload: web::Json<ReportRequest>,
|
json_payload: web::Json<ReportRequest>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let state_ref = &state;
|
|
||||||
let req_headers = &req.headers();
|
|
||||||
|
|
||||||
let flow = AnalyticsFlow::GeneratePaymentReport;
|
let flow = AnalyticsFlow::GeneratePaymentReport;
|
||||||
Box::pin(api::server_wrap(
|
Box::pin(api::server_wrap(
|
||||||
flow,
|
flow,
|
||||||
state.clone(),
|
state.clone(),
|
||||||
&req,
|
&req,
|
||||||
json_payload.into_inner(),
|
json_payload.into_inner(),
|
||||||
|state, auth: AuthenticationData, payload| async move {
|
|state, (auth, user_id): auth::AuthenticationDataWithUserId, payload| async move {
|
||||||
let jwt_payload =
|
|
||||||
auth::parse_jwt_payload::<AppState, AuthToken>(req_headers, state_ref).await;
|
|
||||||
|
|
||||||
let user_id = jwt_payload
|
|
||||||
.change_context(AnalyticsError::UnknownError)?
|
|
||||||
.user_id;
|
|
||||||
|
|
||||||
let user = UserInterface::find_user_by_id(&*state.store, &user_id)
|
let user = UserInterface::find_user_by_id(&*state.store, &user_id)
|
||||||
.await
|
.await
|
||||||
.change_context(AnalyticsError::UnknownError)?;
|
.change_context(AnalyticsError::UnknownError)?;
|
||||||
|
|||||||
@ -66,12 +66,16 @@ pub const ROUTING_CONFIG_ID_LENGTH: usize = 10;
|
|||||||
pub const LOCKER_REDIS_PREFIX: &str = "LOCKER_PM_TOKEN";
|
pub const LOCKER_REDIS_PREFIX: &str = "LOCKER_PM_TOKEN";
|
||||||
pub const LOCKER_REDIS_EXPIRY_SECONDS: u32 = 60 * 15; // 15 minutes
|
pub const LOCKER_REDIS_EXPIRY_SECONDS: u32 = 60 * 15; // 15 minutes
|
||||||
|
|
||||||
#[cfg(any(feature = "olap", feature = "oltp"))]
|
|
||||||
pub const JWT_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24 * 2; // 2 days
|
pub const JWT_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24 * 2; // 2 days
|
||||||
|
|
||||||
|
pub const USER_BLACKLIST_PREFIX: &str = "BU_";
|
||||||
|
|
||||||
#[cfg(feature = "email")]
|
#[cfg(feature = "email")]
|
||||||
pub const EMAIL_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24; // 1 day
|
pub const EMAIL_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24; // 1 day
|
||||||
|
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
pub const EMAIL_TOKEN_BLACKLIST_PREFIX: &str = "BET_";
|
||||||
|
|
||||||
#[cfg(feature = "olap")]
|
#[cfg(feature = "olap")]
|
||||||
pub const VERIFY_CONNECTOR_ID_PREFIX: &str = "conn_verify";
|
pub const VERIFY_CONNECTOR_ID_PREFIX: &str = "conn_verify";
|
||||||
#[cfg(feature = "olap")]
|
#[cfg(feature = "olap")]
|
||||||
|
|||||||
@ -264,6 +264,11 @@ pub async fn connect_account(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn signout(state: AppState, user_from_token: auth::UserFromToken) -> UserResponse<()> {
|
||||||
|
auth::blacklist::insert_user_in_blacklist(&state, &user_from_token.user_id).await?;
|
||||||
|
Ok(ApplicationResponse::StatusOk)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn change_password(
|
pub async fn change_password(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
request: user_api::ChangePasswordRequest,
|
request: user_api::ChangePasswordRequest,
|
||||||
|
|||||||
@ -965,6 +965,7 @@ impl User {
|
|||||||
web::resource("/signin").route(web::post().to(user_signin_without_invite_checks)),
|
web::resource("/signin").route(web::post().to(user_signin_without_invite_checks)),
|
||||||
)
|
)
|
||||||
.service(web::resource("/v2/signin").route(web::post().to(user_signin)))
|
.service(web::resource("/v2/signin").route(web::post().to(user_signin)))
|
||||||
|
.service(web::resource("/signout").route(web::post().to(signout)))
|
||||||
.service(web::resource("/change_password").route(web::post().to(change_password)))
|
.service(web::resource("/change_password").route(web::post().to(change_password)))
|
||||||
.service(web::resource("/internal_signup").route(web::post().to(internal_user_signup)))
|
.service(web::resource("/internal_signup").route(web::post().to(internal_user_signup)))
|
||||||
.service(web::resource("/switch_merchant").route(web::post().to(switch_merchant_id)))
|
.service(web::resource("/switch_merchant").route(web::post().to(switch_merchant_id)))
|
||||||
|
|||||||
@ -164,6 +164,7 @@ impl From<Flow> for ApiIdentifier {
|
|||||||
| Flow::UserSignUp
|
| Flow::UserSignUp
|
||||||
| Flow::UserSignInWithoutInviteChecks
|
| Flow::UserSignInWithoutInviteChecks
|
||||||
| Flow::UserSignIn
|
| Flow::UserSignIn
|
||||||
|
| Flow::Signout
|
||||||
| Flow::ChangePassword
|
| Flow::ChangePassword
|
||||||
| Flow::SetDashboardMetadata
|
| Flow::SetDashboardMetadata
|
||||||
| Flow::GetMutltipleDashboardMetadata
|
| Flow::GetMutltipleDashboardMetadata
|
||||||
|
|||||||
@ -116,6 +116,20 @@ pub async fn user_connect_account(
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn signout(state: web::Data<AppState>, http_req: HttpRequest) -> HttpResponse {
|
||||||
|
let flow = Flow::Signout;
|
||||||
|
Box::pin(api::server_wrap(
|
||||||
|
flow,
|
||||||
|
state.clone(),
|
||||||
|
&http_req,
|
||||||
|
(),
|
||||||
|
|state, user, _| user_core::signout(state, user),
|
||||||
|
&auth::DashboardNoPermissionAuth,
|
||||||
|
api_locking::LockAction::NotApplicable,
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn change_password(
|
pub async fn change_password(
|
||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
http_req: HttpRequest,
|
http_req: HttpRequest,
|
||||||
|
|||||||
@ -36,6 +36,7 @@ use crate::{
|
|||||||
types::domain,
|
types::domain,
|
||||||
utils::OptionExt,
|
utils::OptionExt,
|
||||||
};
|
};
|
||||||
|
pub mod blacklist;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AuthenticationData {
|
pub struct AuthenticationData {
|
||||||
@ -333,6 +334,9 @@ where
|
|||||||
state: &A,
|
state: &A,
|
||||||
) -> RouterResult<(UserWithoutMerchantFromToken, AuthenticationType)> {
|
) -> RouterResult<(UserWithoutMerchantFromToken, AuthenticationType)> {
|
||||||
let payload = parse_jwt_payload::<A, UserAuthToken>(request_headers, state).await?;
|
let payload = parse_jwt_payload::<A, UserAuthToken>(request_headers, state).await?;
|
||||||
|
if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
|
||||||
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
UserWithoutMerchantFromToken {
|
UserWithoutMerchantFromToken {
|
||||||
@ -495,6 +499,9 @@ where
|
|||||||
state: &A,
|
state: &A,
|
||||||
) -> RouterResult<((), AuthenticationType)> {
|
) -> RouterResult<((), AuthenticationType)> {
|
||||||
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||||
|
if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
|
||||||
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
|
||||||
let permissions = authorization::get_permissions(&payload.role_id)?;
|
let permissions = authorization::get_permissions(&payload.role_id)?;
|
||||||
authorization::check_authorization(&self.0, permissions)?;
|
authorization::check_authorization(&self.0, permissions)?;
|
||||||
@ -521,6 +528,9 @@ where
|
|||||||
state: &A,
|
state: &A,
|
||||||
) -> RouterResult<(UserFromToken, AuthenticationType)> {
|
) -> RouterResult<(UserFromToken, AuthenticationType)> {
|
||||||
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||||
|
if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
|
||||||
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
|
||||||
let permissions = authorization::get_permissions(&payload.role_id)?;
|
let permissions = authorization::get_permissions(&payload.role_id)?;
|
||||||
authorization::check_authorization(&self.0, permissions)?;
|
authorization::check_authorization(&self.0, permissions)?;
|
||||||
@ -556,6 +566,9 @@ where
|
|||||||
state: &A,
|
state: &A,
|
||||||
) -> RouterResult<((), AuthenticationType)> {
|
) -> RouterResult<((), AuthenticationType)> {
|
||||||
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||||
|
if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
|
||||||
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
|
||||||
let permissions = authorization::get_permissions(&payload.role_id)?;
|
let permissions = authorization::get_permissions(&payload.role_id)?;
|
||||||
authorization::check_authorization(&self.required_permission, permissions)?;
|
authorization::check_authorization(&self.required_permission, permissions)?;
|
||||||
@ -585,12 +598,6 @@ where
|
|||||||
Ok(payload)
|
Ok(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
|
||||||
struct JwtAuthPayloadFetchMerchantAccount {
|
|
||||||
merchant_id: String,
|
|
||||||
role_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<A> AuthenticateAndFetch<AuthenticationData, A> for JWTAuth
|
impl<A> AuthenticateAndFetch<AuthenticationData, A> for JWTAuth
|
||||||
where
|
where
|
||||||
@ -601,9 +608,10 @@ where
|
|||||||
request_headers: &HeaderMap,
|
request_headers: &HeaderMap,
|
||||||
state: &A,
|
state: &A,
|
||||||
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
|
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
|
||||||
let payload =
|
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||||
parse_jwt_payload::<A, JwtAuthPayloadFetchMerchantAccount>(request_headers, state)
|
if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
|
||||||
.await?;
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
|
||||||
let permissions = authorization::get_permissions(&payload.role_id)?;
|
let permissions = authorization::get_permissions(&payload.role_id)?;
|
||||||
authorization::check_authorization(&self.0, permissions)?;
|
authorization::check_authorization(&self.0, permissions)?;
|
||||||
@ -638,6 +646,56 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type AuthenticationDataWithUserId = (AuthenticationData, String);
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<A> AuthenticateAndFetch<AuthenticationDataWithUserId, A> for JWTAuth
|
||||||
|
where
|
||||||
|
A: AppStateInfo + Sync,
|
||||||
|
{
|
||||||
|
async fn authenticate_and_fetch(
|
||||||
|
&self,
|
||||||
|
request_headers: &HeaderMap,
|
||||||
|
state: &A,
|
||||||
|
) -> RouterResult<(AuthenticationDataWithUserId, AuthenticationType)> {
|
||||||
|
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||||
|
if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
|
||||||
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let permissions = authorization::get_permissions(&payload.role_id)?;
|
||||||
|
authorization::check_authorization(&self.0, permissions)?;
|
||||||
|
|
||||||
|
let key_store = state
|
||||||
|
.store()
|
||||||
|
.get_merchant_key_store_by_merchant_id(
|
||||||
|
&payload.merchant_id,
|
||||||
|
&state.store().get_master_key().to_vec().into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.change_context(errors::ApiErrorResponse::InvalidJwtToken)
|
||||||
|
.attach_printable("Failed to fetch merchant key store for the merchant id")?;
|
||||||
|
|
||||||
|
let merchant = state
|
||||||
|
.store()
|
||||||
|
.find_merchant_account_by_merchant_id(&payload.merchant_id, &key_store)
|
||||||
|
.await
|
||||||
|
.change_context(errors::ApiErrorResponse::InvalidJwtToken)?;
|
||||||
|
|
||||||
|
let auth = AuthenticationData {
|
||||||
|
merchant_account: merchant,
|
||||||
|
key_store,
|
||||||
|
};
|
||||||
|
Ok((
|
||||||
|
(auth.clone(), payload.user_id.clone()),
|
||||||
|
AuthenticationType::MerchantJwt {
|
||||||
|
merchant_id: auth.merchant_account.merchant_id.clone(),
|
||||||
|
user_id: None,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DashboardNoPermissionAuth;
|
pub struct DashboardNoPermissionAuth;
|
||||||
|
|
||||||
#[cfg(feature = "olap")]
|
#[cfg(feature = "olap")]
|
||||||
@ -652,6 +710,9 @@ where
|
|||||||
state: &A,
|
state: &A,
|
||||||
) -> RouterResult<(UserFromToken, AuthenticationType)> {
|
) -> RouterResult<(UserFromToken, AuthenticationType)> {
|
||||||
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||||
|
if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
|
||||||
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
UserFromToken {
|
UserFromToken {
|
||||||
@ -679,7 +740,10 @@ where
|
|||||||
request_headers: &HeaderMap,
|
request_headers: &HeaderMap,
|
||||||
state: &A,
|
state: &A,
|
||||||
) -> RouterResult<((), AuthenticationType)> {
|
) -> RouterResult<((), AuthenticationType)> {
|
||||||
parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||||
|
if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
|
||||||
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
|
||||||
Ok(((), AuthenticationType::NoAuth))
|
Ok(((), AuthenticationType::NoAuth))
|
||||||
}
|
}
|
||||||
|
|||||||
63
crates/router/src/services/authentication/blacklist.rs
Normal file
63
crates/router/src/services/authentication/blacklist.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[cfg(feature = "olap")]
|
||||||
|
use common_utils::date_time;
|
||||||
|
use error_stack::{IntoReport, ResultExt};
|
||||||
|
use redis_interface::RedisConnectionPool;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
consts::{JWT_TOKEN_TIME_IN_SECS, USER_BLACKLIST_PREFIX},
|
||||||
|
core::errors::{ApiErrorResponse, RouterResult},
|
||||||
|
routes::app::AppStateInfo,
|
||||||
|
};
|
||||||
|
#[cfg(feature = "olap")]
|
||||||
|
use crate::{
|
||||||
|
core::errors::{UserErrors, UserResult},
|
||||||
|
routes::AppState,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "olap")]
|
||||||
|
pub async fn insert_user_in_blacklist(state: &AppState, user_id: &str) -> UserResult<()> {
|
||||||
|
let user_blacklist_key = format!("{}{}", USER_BLACKLIST_PREFIX, user_id);
|
||||||
|
let expiry =
|
||||||
|
expiry_to_i64(JWT_TOKEN_TIME_IN_SECS).change_context(UserErrors::InternalServerError)?;
|
||||||
|
let redis_conn = get_redis_connection(state).change_context(UserErrors::InternalServerError)?;
|
||||||
|
redis_conn
|
||||||
|
.set_key_with_expiry(
|
||||||
|
user_blacklist_key.as_str(),
|
||||||
|
date_time::now_unix_timestamp(),
|
||||||
|
expiry,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.change_context(UserErrors::InternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn check_user_in_blacklist<A: AppStateInfo>(
|
||||||
|
state: &A,
|
||||||
|
user_id: &str,
|
||||||
|
token_expiry: u64,
|
||||||
|
) -> RouterResult<bool> {
|
||||||
|
let token = format!("{}{}", USER_BLACKLIST_PREFIX, user_id);
|
||||||
|
let token_issued_at = expiry_to_i64(token_expiry - JWT_TOKEN_TIME_IN_SECS)?;
|
||||||
|
let redis_conn = get_redis_connection(state)?;
|
||||||
|
redis_conn
|
||||||
|
.get_key::<Option<i64>>(token.as_str())
|
||||||
|
.await
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.map(|timestamp| timestamp.map_or(false, |timestamp| timestamp > token_issued_at))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_redis_connection<A: AppStateInfo>(state: &A) -> RouterResult<Arc<RedisConnectionPool>> {
|
||||||
|
state
|
||||||
|
.store()
|
||||||
|
.get_redis_conn()
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to get redis connection")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expiry_to_i64(expiry: u64) -> RouterResult<i64> {
|
||||||
|
expiry
|
||||||
|
.try_into()
|
||||||
|
.into_report()
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
}
|
||||||
@ -285,6 +285,8 @@ pub enum Flow {
|
|||||||
FrmFulfillment,
|
FrmFulfillment,
|
||||||
/// Change password flow
|
/// Change password flow
|
||||||
ChangePassword,
|
ChangePassword,
|
||||||
|
/// Signout flow
|
||||||
|
Signout,
|
||||||
/// Set Dashboard Metadata flow
|
/// Set Dashboard Metadata flow
|
||||||
SetDashboardMetadata,
|
SetDashboardMetadata,
|
||||||
/// Get Multiple Dashboard Metadata flow
|
/// Get Multiple Dashboard Metadata flow
|
||||||
|
|||||||
Reference in New Issue
Block a user