rustauth_plugins/one_time_token/
options.rs1use 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}