alibi_api/plugins/two_factor/
otp_storage.rs1use crate::plugins::token_crypto;
2use alibi_core::AuthResult;
3use async_trait::async_trait;
4use std::sync::Arc;
5
6#[async_trait]
8pub trait TwoFactorOtpHasher: Send + Sync {
9 async fn hash(&self, otp: &str) -> AuthResult<String>;
10}
11
12#[async_trait]
14pub trait TwoFactorOtpCipher: Send + Sync {
15 async fn encrypt(&self, otp: &str) -> AuthResult<String>;
16 async fn decrypt(&self, stored: &str) -> AuthResult<String>;
17}
18
19#[derive(Clone, Default)]
21pub enum TwoFactorOtpStorage {
22 #[default]
23 Plain,
24 Hashed,
25 Encrypted,
26 CustomHash(Arc<dyn TwoFactorOtpHasher>),
27 CustomCipher(Arc<dyn TwoFactorOtpCipher>),
28}
29
30impl std::fmt::Debug for TwoFactorOtpStorage {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 f.write_str(match self {
33 Self::Plain => "Plain",
34 Self::Hashed => "Hashed",
35 Self::Encrypted => "Encrypted",
36 Self::CustomHash(_) => "CustomHash",
37 Self::CustomCipher(_) => "CustomCipher",
38 })
39 }
40}
41
42impl TwoFactorOtpStorage {
43 pub(super) async fn store(
47 &self,
48 otp: &str,
49 secret: &alibi_core::AuthConfig,
50 ) -> AuthResult<String> {
51 match self {
52 Self::Plain => Ok(otp.to_owned()),
53 Self::Hashed => Ok(token_crypto::hash_token(otp)),
54 Self::Encrypted => token_crypto::encrypt_with_config(otp, secret),
55 Self::CustomHash(callback) => callback.hash(otp).await,
56 Self::CustomCipher(callback) => callback.encrypt(otp).await,
57 }
58 }
59
60 pub(super) async fn verify(
64 &self,
65 stored: &str,
66 input: &str,
67 secret: &alibi_core::AuthConfig,
68 ) -> AuthResult<bool> {
69 let (left, right) = match self {
70 Self::Plain => (stored.to_owned(), input.to_owned()),
71 Self::Hashed => (stored.to_owned(), token_crypto::hash_token(input)),
72 Self::Encrypted => (
73 token_crypto::decrypt_with_config(stored, secret)?,
74 input.to_owned(),
75 ),
76 Self::CustomHash(callback) => (stored.to_owned(), callback.hash(input).await?),
77 Self::CustomCipher(callback) => (callback.decrypt(stored).await?, input.to_owned()),
78 };
79 Ok(left.len() == right.len()
80 && left
81 .bytes()
82 .zip(right.bytes())
83 .fold(0u8, |difference, (a, b)| difference | (a ^ b))
84 == 0)
85 }
86}