rustauth_plugins/phone_number/
options.rs1use std::sync::Arc;
2
3use rustauth_core::error::RustAuthError;
4use time::Duration;
5
6pub type PhoneNumberSender =
12 Arc<dyn Fn(&str, &str) -> Result<(), RustAuthError> + Send + Sync + 'static>;
13pub type PhoneNumberVerifier =
18 Arc<dyn Fn(&str, &str) -> Result<bool, RustAuthError> + Send + Sync + 'static>;
19pub type PhoneNumberValidator =
21 Arc<dyn Fn(&str) -> Result<bool, RustAuthError> + Send + Sync + 'static>;
22pub type PhoneNumberCallback =
24 Arc<dyn Fn(&str, &str) -> Result<(), RustAuthError> + Send + Sync + 'static>;
25pub type PhoneNumberTempValue = Arc<dyn Fn(&str) -> String + Send + Sync + 'static>;
27
28#[derive(Clone)]
29pub struct SignUpOnVerification {
30 pub get_temp_email: PhoneNumberTempValue,
31 pub get_temp_name: Option<PhoneNumberTempValue>,
32}
33
34#[derive(Clone)]
35pub struct PhoneNumberOptions {
36 pub otp_length: usize,
37 pub expires_in: Duration,
38 pub allowed_attempts: u32,
39 pub require_verification: bool,
40 pub send_otp: Option<PhoneNumberSender>,
42 pub verify_otp: Option<PhoneNumberVerifier>,
44 pub send_password_reset_otp: Option<PhoneNumberSender>,
46 pub callback_on_verification: Option<PhoneNumberCallback>,
48 pub phone_number_validator: Option<PhoneNumberValidator>,
50 pub sign_up_on_verification: Option<SignUpOnVerification>,
51 pub schema: super::schema::PhoneNumberSchemaOptions,
52}
53
54impl Default for PhoneNumberOptions {
55 fn default() -> Self {
56 Self {
57 otp_length: 6,
58 expires_in: Duration::minutes(5),
59 allowed_attempts: 3,
60 require_verification: false,
61 send_otp: None,
62 verify_otp: None,
63 send_password_reset_otp: None,
64 callback_on_verification: None,
65 phone_number_validator: None,
66 sign_up_on_verification: None,
67 schema: super::schema::PhoneNumberSchemaOptions::default(),
68 }
69 }
70}
71
72impl PhoneNumberOptions {
73 #[must_use]
74 pub fn new<F>(sender: F) -> Self
75 where
76 F: Fn(&str, &str) -> Result<(), RustAuthError> + Send + Sync + 'static,
77 {
78 Self {
79 send_otp: Some(Arc::new(sender)),
80 ..Self::default()
81 }
82 }
83
84 pub(crate) fn with_defaults(mut self) -> Self {
85 if self.otp_length == 0 {
86 self.otp_length = 6;
87 }
88 if self.expires_in == Duration::ZERO {
89 self.expires_in = Duration::minutes(5);
90 }
91 if self.allowed_attempts == 0 {
92 self.allowed_attempts = 3;
93 }
94 self
95 }
96
97 #[must_use]
98 pub fn expires_in(mut self, expires_in: Duration) -> Self {
99 self.expires_in = expires_in;
100 self
101 }
102
103 #[must_use]
104 pub fn send_otp<F>(mut self, sender: F) -> Self
105 where
106 F: Fn(&str, &str) -> Result<(), RustAuthError> + Send + Sync + 'static,
107 {
108 self.send_otp = Some(Arc::new(sender));
109 self
110 }
111
112 #[must_use]
113 pub fn verify_otp<F>(mut self, verifier: F) -> Self
114 where
115 F: Fn(&str, &str) -> Result<bool, RustAuthError> + Send + Sync + 'static,
116 {
117 self.verify_otp = Some(Arc::new(verifier));
118 self
119 }
120
121 #[must_use]
122 pub fn send_password_reset_otp<F>(mut self, sender: F) -> Self
123 where
124 F: Fn(&str, &str) -> Result<(), RustAuthError> + Send + Sync + 'static,
125 {
126 self.send_password_reset_otp = Some(Arc::new(sender));
127 self
128 }
129
130 #[must_use]
131 pub fn phone_number_validator<F>(mut self, validator: F) -> Self
132 where
133 F: Fn(&str) -> Result<bool, RustAuthError> + Send + Sync + 'static,
134 {
135 self.phone_number_validator = Some(Arc::new(validator));
136 self
137 }
138
139 #[must_use]
140 pub fn callback_on_verification<F>(mut self, callback: F) -> Self
141 where
142 F: Fn(&str, &str) -> Result<(), RustAuthError> + Send + Sync + 'static,
143 {
144 self.callback_on_verification = Some(Arc::new(callback));
145 self
146 }
147
148 #[must_use]
149 pub fn sign_up_on_verification(mut self, options: SignUpOnVerification) -> Self {
150 self.sign_up_on_verification = Some(options);
151 self
152 }
153
154 #[must_use]
155 pub fn require_verification(mut self, require_verification: bool) -> Self {
156 self.require_verification = require_verification;
157 self
158 }
159
160 pub fn validate(&self) -> Result<(), RustAuthError> {
161 if self.otp_length == 0 {
162 return Err(RustAuthError::InvalidConfig(
163 "phone-number otp_length must be greater than zero".to_owned(),
164 ));
165 }
166 if self.expires_in.is_zero() {
167 return Err(RustAuthError::InvalidConfig(
168 "phone-number expires_in must be greater than zero".to_owned(),
169 ));
170 }
171 if self.allowed_attempts == 0 {
172 return Err(RustAuthError::InvalidConfig(
173 "phone-number allowed_attempts must be greater than zero".to_owned(),
174 ));
175 }
176 if self.send_otp.is_none() {
177 return Err(RustAuthError::InvalidConfig(
178 "phone-number send_otp callback is required".to_owned(),
179 ));
180 }
181 Ok(())
182 }
183}
184
185#[derive(Clone, Default)]
186pub struct PhoneNumberOptionsBuilder {
187 otp_length: Option<usize>,
188 expires_in: Option<Duration>,
189 allowed_attempts: Option<u32>,
190 require_verification: Option<bool>,
191 send_otp: Option<PhoneNumberSender>,
192 verify_otp: Option<PhoneNumberVerifier>,
193 send_password_reset_otp: Option<PhoneNumberSender>,
194 callback_on_verification: Option<PhoneNumberCallback>,
195 phone_number_validator: Option<PhoneNumberValidator>,
196 sign_up_on_verification: Option<SignUpOnVerification>,
197 schema: Option<super::schema::PhoneNumberSchemaOptions>,
198}
199
200impl PhoneNumberOptionsBuilder {
201 pub fn build(self) -> Result<PhoneNumberOptions, RustAuthError> {
202 let defaults = PhoneNumberOptions::default();
203 let options = PhoneNumberOptions {
204 otp_length: self.otp_length.unwrap_or(defaults.otp_length),
205 expires_in: self.expires_in.unwrap_or(defaults.expires_in),
206 allowed_attempts: self.allowed_attempts.unwrap_or(defaults.allowed_attempts),
207 require_verification: self
208 .require_verification
209 .unwrap_or(defaults.require_verification),
210 send_otp: self.send_otp.or(defaults.send_otp),
211 verify_otp: self.verify_otp.or(defaults.verify_otp),
212 send_password_reset_otp: self
213 .send_password_reset_otp
214 .or(defaults.send_password_reset_otp),
215 callback_on_verification: self
216 .callback_on_verification
217 .or(defaults.callback_on_verification),
218 phone_number_validator: self
219 .phone_number_validator
220 .or(defaults.phone_number_validator),
221 sign_up_on_verification: self
222 .sign_up_on_verification
223 .or(defaults.sign_up_on_verification),
224 schema: self.schema.unwrap_or(defaults.schema),
225 };
226 options.validate()?;
227 Ok(options)
228 }
229}