alibi_plugins/two_factor/
otp_storage.rs1use crate::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(
44 &self,
45 otp: &str,
46 secret: &alibi_core::AuthConfig,
47 ) -> AuthResult<String> {
48 match self {
49 Self::Plain => Ok(otp.to_owned()),
50 Self::Hashed => Ok(token_crypto::hash_token(otp)),
51 Self::Encrypted => token_crypto::encrypt_with_config(otp, secret),
52 Self::CustomHash(callback) => callback.hash(otp).await,
53 Self::CustomCipher(callback) => callback.encrypt(otp).await,
54 }
55 }
56
57 pub(super) async fn verify(
58 &self,
59 stored: &str,
60 input: &str,
61 secret: &alibi_core::AuthConfig,
62 ) -> AuthResult<bool> {
63 let (left, right) = match self {
64 Self::Plain => (stored.to_owned(), input.to_owned()),
65 Self::Hashed => (stored.to_owned(), token_crypto::hash_token(input)),
66 Self::Encrypted => (
67 token_crypto::decrypt_with_config(stored, secret)?,
68 input.to_owned(),
69 ),
70 Self::CustomHash(callback) => (stored.to_owned(), callback.hash(input).await?),
71 Self::CustomCipher(callback) => (callback.decrypt(stored).await?, input.to_owned()),
72 };
73 Ok(left.len() == right.len()
74 && left
75 .bytes()
76 .zip(right.bytes())
77 .fold(0u8, |difference, (a, b)| difference | (a ^ b))
78 == 0)
79 }
80}