rustauth_plugins/two_factor/
options.rs1use std::future::Future;
2use std::pin::Pin;
3use std::sync::Arc;
4
5use rustauth_core::api::ApiRequest;
6use rustauth_core::db::User;
7use rustauth_core::error::RustAuthError;
8use time::Duration;
9
10pub type SendOtpFuture = Pin<Box<dyn Future<Output = Result<(), RustAuthError>> + Send>>;
11pub type SendOtp = Arc<dyn Fn(TwoFactorOtpMessage) -> SendOtpFuture + Send + Sync>;
12
13#[derive(Clone)]
14pub struct TwoFactorOtpMessage {
15 pub user: User,
16 pub otp: String,
17 pub request: ApiRequest,
18}
19
20#[derive(Clone)]
21pub struct TwoFactorOptions {
22 pub issuer: Option<String>,
23 pub two_factor_table: String,
25 pub totp: TotpOptions,
26 pub otp: OtpOptions,
27 pub backup_codes: BackupCodeOptions,
28 pub skip_verification_on_enable: bool,
29 pub allow_passwordless: bool,
30 pub two_factor_cookie_max_age: Duration,
31 pub trust_device_max_age: Duration,
32}
33
34impl Default for TwoFactorOptions {
35 fn default() -> Self {
36 Self {
37 issuer: None,
38 two_factor_table: "two_factors".to_owned(),
39 totp: TotpOptions::default(),
40 otp: OtpOptions::default(),
41 backup_codes: BackupCodeOptions::default(),
42 skip_verification_on_enable: false,
43 allow_passwordless: false,
44 two_factor_cookie_max_age: Duration::minutes(10),
45 trust_device_max_age: Duration::days(30),
46 }
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct TotpOptions {
52 pub digits: u32,
53 pub period: Duration,
54 pub disabled: bool,
55}
56
57impl Default for TotpOptions {
58 fn default() -> Self {
59 Self {
60 digits: 6,
61 period: Duration::seconds(30),
62 disabled: false,
63 }
64 }
65}
66
67#[derive(Clone)]
68pub struct OtpOptions {
69 pub period: Duration,
70 pub digits: usize,
71 pub allowed_attempts: u32,
72 pub storage: OtpStorage,
73 pub send_otp: Option<SendOtp>,
74}
75
76impl Default for OtpOptions {
77 fn default() -> Self {
78 Self {
79 period: Duration::minutes(3),
80 digits: 6,
81 allowed_attempts: 5,
82 storage: OtpStorage::Plain,
83 send_otp: None,
84 }
85 }
86}
87
88pub use super::otp_storage::{OtpDecryptFn, OtpEncryptFn, OtpHashFn, OtpStorage};
89
90#[derive(Debug, Clone, PartialEq, Eq)]
91pub struct BackupCodeOptions {
92 pub amount: usize,
93 pub length: usize,
94 pub storage: BackupCodeStorage,
95}
96
97impl Default for BackupCodeOptions {
98 fn default() -> Self {
99 Self {
100 amount: 10,
101 length: 10,
102 storage: BackupCodeStorage::Encrypted,
103 }
104 }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108pub enum BackupCodeStorage {
109 Plain,
110 Encrypted,
111}
112
113#[derive(Clone, Default)]
114pub struct TwoFactorOptionsBuilder {
115 issuer: Option<Option<String>>,
116 two_factor_table: Option<String>,
117 totp: Option<TotpOptions>,
118 otp: Option<OtpOptions>,
119 backup_codes: Option<BackupCodeOptions>,
120 skip_verification_on_enable: Option<bool>,
121 allow_passwordless: Option<bool>,
122 two_factor_cookie_max_age: Option<Duration>,
123 trust_device_max_age: Option<Duration>,
124}
125
126impl TwoFactorOptionsBuilder {
127 pub fn build(self) -> TwoFactorOptions {
128 let defaults = TwoFactorOptions::default();
129 TwoFactorOptions {
130 issuer: self.issuer.unwrap_or(defaults.issuer),
131 two_factor_table: self.two_factor_table.unwrap_or(defaults.two_factor_table),
132 totp: self.totp.unwrap_or(defaults.totp),
133 otp: self.otp.unwrap_or(defaults.otp),
134 backup_codes: self.backup_codes.unwrap_or(defaults.backup_codes),
135 skip_verification_on_enable: self
136 .skip_verification_on_enable
137 .unwrap_or(defaults.skip_verification_on_enable),
138 allow_passwordless: self
139 .allow_passwordless
140 .unwrap_or(defaults.allow_passwordless),
141 two_factor_cookie_max_age: self
142 .two_factor_cookie_max_age
143 .unwrap_or(defaults.two_factor_cookie_max_age),
144 trust_device_max_age: self
145 .trust_device_max_age
146 .unwrap_or(defaults.trust_device_max_age),
147 }
148 }
149}
150
151impl TwoFactorOptions {
152 #[must_use]
153 pub fn builder() -> TwoFactorOptionsBuilder {
154 TwoFactorOptionsBuilder::default()
155 }
156}