Skip to main content

rustauth_plugins/one_time_token/
options.rs

1use std::sync::Arc;
2
3use rustauth_core::context::AuthContext;
4use rustauth_core::db::{Session, User};
5use rustauth_core::error::RustAuthError;
6use time::Duration;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct OneTimeTokenSession {
10    pub session: Session,
11    pub user: User,
12}
13
14pub type GenerateToken =
15    Arc<dyn Fn(&OneTimeTokenSession, &AuthContext) -> Result<String, RustAuthError> + Send + Sync>;
16pub type HashToken = Arc<dyn Fn(&str) -> Result<String, RustAuthError> + Send + Sync>;
17
18#[derive(Clone)]
19pub enum StoreToken {
20    Plain,
21    Hashed,
22    Custom(HashToken),
23}
24
25impl StoreToken {
26    pub fn custom<F>(hash: F) -> Self
27    where
28        F: Fn(&str) -> Result<String, RustAuthError> + Send + Sync + 'static,
29    {
30        Self::Custom(Arc::new(hash))
31    }
32}
33
34#[derive(Clone)]
35pub struct OneTimeTokenOptions {
36    pub expires_in: Duration,
37    pub disable_client_request: bool,
38    pub generate_token: Option<GenerateToken>,
39    pub disable_set_session_cookie: bool,
40    pub store_token: StoreToken,
41    pub set_ott_header_on_new_session: bool,
42}
43
44impl Default for OneTimeTokenOptions {
45    fn default() -> Self {
46        Self {
47            expires_in: Duration::minutes(3),
48            disable_client_request: false,
49            generate_token: None,
50            disable_set_session_cookie: false,
51            store_token: StoreToken::Plain,
52            set_ott_header_on_new_session: false,
53        }
54    }
55}
56
57impl OneTimeTokenOptions {
58    #[must_use]
59    pub fn expires_in(mut self, expires_in: Duration) -> Self {
60        self.expires_in = expires_in;
61        self
62    }
63
64    #[must_use]
65    pub fn disable_client_request(mut self, disable: bool) -> Self {
66        self.disable_client_request = disable;
67        self
68    }
69
70    #[must_use]
71    pub fn generate_token<F>(mut self, generate: F) -> Self
72    where
73        F: Fn(&OneTimeTokenSession, &AuthContext) -> Result<String, RustAuthError>
74            + Send
75            + Sync
76            + 'static,
77    {
78        self.generate_token = Some(Arc::new(generate));
79        self
80    }
81
82    #[must_use]
83    pub fn disable_set_session_cookie(mut self, disable: bool) -> Self {
84        self.disable_set_session_cookie = disable;
85        self
86    }
87
88    #[must_use]
89    pub fn store_token(mut self, store_token: StoreToken) -> Self {
90        self.store_token = store_token;
91        self
92    }
93
94    #[must_use]
95    pub fn set_ott_header_on_new_session(mut self, set_header: bool) -> Self {
96        self.set_ott_header_on_new_session = set_header;
97        self
98    }
99
100    #[must_use]
101    pub fn builder() -> OneTimeTokenOptionsBuilder {
102        OneTimeTokenOptionsBuilder::default()
103    }
104
105    pub(crate) fn to_value(&self) -> serde_json::Value {
106        serde_json::json!({
107            "expiresIn": self.expires_in.whole_minutes(),
108            "disableClientRequest": self.disable_client_request,
109            "disableSetSessionCookie": self.disable_set_session_cookie,
110            "storeToken": self.store_token.as_metadata_value(),
111            "setOttHeaderOnNewSession": self.set_ott_header_on_new_session,
112        })
113    }
114}
115
116#[derive(Clone, Default)]
117pub struct OneTimeTokenOptionsBuilder {
118    expires_in: Option<Duration>,
119    disable_client_request: Option<bool>,
120    generate_token: Option<GenerateToken>,
121    disable_set_session_cookie: Option<bool>,
122    store_token: Option<StoreToken>,
123    set_ott_header_on_new_session: Option<bool>,
124}
125
126impl OneTimeTokenOptionsBuilder {
127    pub fn build(self) -> OneTimeTokenOptions {
128        let defaults = OneTimeTokenOptions::default();
129        OneTimeTokenOptions {
130            expires_in: self.expires_in.unwrap_or(defaults.expires_in),
131            disable_client_request: self
132                .disable_client_request
133                .unwrap_or(defaults.disable_client_request),
134            generate_token: self.generate_token.or(defaults.generate_token),
135            disable_set_session_cookie: self
136                .disable_set_session_cookie
137                .unwrap_or(defaults.disable_set_session_cookie),
138            store_token: self.store_token.unwrap_or(defaults.store_token),
139            set_ott_header_on_new_session: self
140                .set_ott_header_on_new_session
141                .unwrap_or(defaults.set_ott_header_on_new_session),
142        }
143    }
144}
145
146impl StoreToken {
147    fn as_metadata_value(&self) -> &'static str {
148        match self {
149            Self::Plain => "plain",
150            Self::Hashed => "hashed",
151            Self::Custom(_) => "custom-hasher",
152        }
153    }
154}