1use std::fmt;
2use std::sync::Arc;
3
4#[cfg(feature = "oauth")]
5use rustauth_oauth::oauth2::SocialOAuthProvider;
6
7use super::storage::SecondaryStorage;
8use crate::crypto::SecretEntry;
9use crate::plugin::AuthPlugin;
10
11use super::account::AccountOptions;
12use super::advanced::AdvancedOptions;
13use super::api_error::OnApiErrorOptions;
14use super::email_password::EmailPasswordOptions;
15use super::email_verification::EmailVerificationOptions;
16use super::hooks::GlobalHooksOptions;
17use super::init_database_hooks::InitDatabaseHooksOptions;
18use super::origins::TrustedOriginOptions;
19use super::password::PasswordOptions;
20use super::rate_limit::RateLimitOptions;
21use super::session::SessionOptions;
22use super::user::UserOptions;
23use super::verification::VerificationOptions;
24use crate::env::{is_production, logger::LoggerOptions};
25use crate::plugin::PluginDatabaseHook;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
44pub enum DeploymentMode {
45 #[default]
47 Auto,
48 Production,
50 Development,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Default)]
56pub struct TelemetryOptions {
57 pub enabled: Option<bool>,
59 pub debug: bool,
60}
61
62impl TelemetryOptions {
63 pub fn new() -> Self {
64 Self::default()
65 }
66
67 #[must_use]
68 pub fn enabled(mut self, enabled: bool) -> Self {
69 self.enabled = Some(enabled);
70 self
71 }
72
73 #[must_use]
74 pub fn debug(mut self, debug: bool) -> Self {
75 self.debug = debug;
76 self
77 }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq)]
82pub struct ExperimentalOptions {
83 pub joins: bool,
84}
85
86impl Default for ExperimentalOptions {
87 fn default() -> Self {
88 Self { joins: true }
89 }
90}
91
92impl ExperimentalOptions {
93 pub fn new() -> Self {
94 Self::default()
95 }
96
97 #[must_use]
98 pub fn joins(mut self, enabled: bool) -> Self {
99 self.joins = enabled;
100 self
101 }
102}
103
104#[derive(Clone, Default)]
124pub struct RustAuthOptions {
125 pub app_name: Option<String>,
126 pub base_url: Option<String>,
127 pub base_path: Option<String>,
128 pub secret: Option<String>,
129 pub secrets: Vec<SecretEntry>,
130 pub trusted_origins: TrustedOriginOptions,
131 pub disabled_paths: Vec<String>,
132 pub session: SessionOptions,
133 pub user: UserOptions,
134 pub email_password: EmailPasswordOptions,
135 pub email_verification: EmailVerificationOptions,
136 pub password: PasswordOptions,
137 pub account: AccountOptions,
138 pub verification: VerificationOptions,
139 pub hooks: GlobalHooksOptions,
140 pub on_api_error: OnApiErrorOptions,
141 pub init_database_hooks: InitDatabaseHooksOptions,
142 pub database_hooks: Vec<PluginDatabaseHook>,
143 pub logger: LoggerOptions,
144 pub advanced: AdvancedOptions,
145 pub rate_limit: RateLimitOptions,
146 pub secondary_storage: Option<Arc<dyn SecondaryStorage>>,
147 pub plugins: Vec<AuthPlugin>,
148 #[cfg(feature = "oauth")]
149 pub social_providers: Vec<Arc<dyn SocialOAuthProvider>>,
150 pub mode: DeploymentMode,
151 pub telemetry: TelemetryOptions,
152 pub experimental: ExperimentalOptions,
153}
154
155impl RustAuthOptions {
156 pub fn new() -> Self {
157 Self::default()
158 }
159
160 #[must_use]
161 pub fn app_name(mut self, app_name: impl Into<String>) -> Self {
162 self.app_name = Some(app_name.into());
163 self
164 }
165
166 #[must_use]
167 pub fn base_url(mut self, base_url: impl Into<String>) -> Self {
168 self.base_url = Some(base_url.into());
169 self
170 }
171
172 #[must_use]
173 pub fn base_path(mut self, base_path: impl Into<String>) -> Self {
174 self.base_path = Some(base_path.into());
175 self
176 }
177
178 #[must_use]
179 pub fn secret(mut self, secret: impl Into<String>) -> Self {
180 self.secret = Some(secret.into());
181 self
182 }
183
184 #[must_use]
185 pub fn secrets(mut self, secrets: Vec<SecretEntry>) -> Self {
186 self.secrets = secrets;
187 self
188 }
189
190 #[must_use]
191 pub fn trusted_origins(mut self, trusted_origins: TrustedOriginOptions) -> Self {
192 self.trusted_origins = trusted_origins;
193 self
194 }
195
196 #[must_use]
197 pub fn disabled_path(mut self, path: impl Into<String>) -> Self {
199 self.disabled_paths.push(path.into());
200 self
201 }
202
203 #[must_use]
204 pub fn push_disabled_path(self, path: impl Into<String>) -> Self {
206 self.disabled_path(path)
207 }
208
209 #[must_use]
210 pub fn disabled_paths<I, S>(mut self, paths: I) -> Self
212 where
213 I: IntoIterator<Item = S>,
214 S: Into<String>,
215 {
216 self.disabled_paths = paths.into_iter().map(Into::into).collect();
217 self
218 }
219
220 #[must_use]
221 pub fn set_disabled_paths<I, S>(self, paths: I) -> Self
223 where
224 I: IntoIterator<Item = S>,
225 S: Into<String>,
226 {
227 self.disabled_paths(paths)
228 }
229
230 #[must_use]
231 pub fn session(mut self, session: SessionOptions) -> Self {
232 self.session = session;
233 self
234 }
235
236 #[must_use]
237 pub fn user(mut self, user: UserOptions) -> Self {
238 self.user = user;
239 self
240 }
241
242 #[must_use]
243 pub fn email_password(mut self, email_password: EmailPasswordOptions) -> Self {
244 self.email_password = email_password;
245 self
246 }
247
248 #[must_use]
249 pub fn email_verification(mut self, email_verification: EmailVerificationOptions) -> Self {
250 self.email_verification = email_verification;
251 self
252 }
253
254 #[must_use]
255 pub fn password(mut self, password: PasswordOptions) -> Self {
256 self.password = password;
257 self
258 }
259
260 #[must_use]
261 pub fn account(mut self, account: AccountOptions) -> Self {
262 self.account = account;
263 self
264 }
265
266 #[must_use]
267 pub fn verification(mut self, verification: VerificationOptions) -> Self {
268 self.verification = verification;
269 self
270 }
271
272 #[must_use]
273 pub fn advanced(mut self, advanced: AdvancedOptions) -> Self {
274 self.advanced = advanced;
275 self
276 }
277
278 #[must_use]
279 pub fn rate_limit(mut self, rate_limit: RateLimitOptions) -> Self {
280 self.rate_limit = rate_limit;
281 self
282 }
283
284 #[must_use]
285 pub fn hooks(mut self, hooks: GlobalHooksOptions) -> Self {
286 self.hooks = hooks;
287 self
288 }
289
290 #[must_use]
291 pub fn on_api_error(mut self, on_api_error: OnApiErrorOptions) -> Self {
292 self.on_api_error = on_api_error;
293 self
294 }
295
296 #[must_use]
299 pub fn init_database_hooks(mut self, hooks: InitDatabaseHooksOptions) -> Self {
300 self.init_database_hooks = hooks;
301 self
302 }
303
304 #[must_use]
307 pub fn database_hook(mut self, hook: PluginDatabaseHook) -> Self {
308 self.database_hooks.push(hook);
309 self
310 }
311
312 #[must_use]
313 pub fn logger(mut self, logger: LoggerOptions) -> Self {
314 self.logger = logger;
315 self
316 }
317
318 #[must_use]
319 pub fn secondary_storage(mut self, storage: Arc<dyn SecondaryStorage>) -> Self {
321 self.secondary_storage = Some(storage);
322 self
323 }
324
325 #[must_use]
326 pub fn secondary_storage_arc(self, storage: Arc<dyn SecondaryStorage>) -> Self {
328 self.secondary_storage(storage)
329 }
330
331 #[must_use]
332 pub fn plugin(mut self, plugin: AuthPlugin) -> Self {
334 self.plugins.push(plugin);
335 self
336 }
337
338 #[must_use]
339 pub fn push_plugin(self, plugin: AuthPlugin) -> Self {
341 self.plugin(plugin)
342 }
343
344 #[must_use]
345 pub fn plugins(mut self, plugins: Vec<AuthPlugin>) -> Self {
350 self.plugins.extend(plugins);
351 self
352 }
353
354 #[must_use]
355 pub fn extend_plugins(self, plugins: Vec<AuthPlugin>) -> Self {
357 self.plugins(plugins)
358 }
359
360 #[must_use]
361 pub fn set_plugins(mut self, plugins: Vec<AuthPlugin>) -> Self {
363 self.plugins = plugins;
364 self
365 }
366
367 #[cfg(feature = "oauth")]
368 #[must_use]
369 pub fn social_provider<P>(mut self, provider: P) -> Self
370 where
371 P: SocialOAuthProvider,
372 {
373 self.social_providers.push(Arc::new(provider));
374 self
375 }
376
377 #[cfg(feature = "oauth")]
378 #[must_use]
379 pub fn social_provider_arc(mut self, provider: Arc<dyn SocialOAuthProvider>) -> Self {
380 self.social_providers.push(provider);
381 self
382 }
383
384 #[cfg(feature = "oauth")]
385 #[must_use]
386 pub fn social_providers<I, P>(mut self, providers: I) -> Self
388 where
389 I: IntoIterator<Item = P>,
390 P: SocialOAuthProvider + 'static,
391 {
392 self.social_providers.extend(
393 providers
394 .into_iter()
395 .map(|provider| Arc::new(provider) as Arc<dyn SocialOAuthProvider>),
396 );
397 self
398 }
399
400 #[cfg(feature = "oauth")]
401 pub fn try_social_providers<I, P, E>(mut self, iter: I) -> Result<Self, E>
403 where
404 I: IntoIterator<Item = Result<P, E>>,
405 P: SocialOAuthProvider + 'static,
406 E: std::error::Error,
407 {
408 for provider in iter {
409 self.social_providers
410 .push(Arc::new(provider?) as Arc<dyn SocialOAuthProvider>);
411 }
412 Ok(self)
413 }
414
415 #[must_use]
416 pub fn deployment_mode(mut self, mode: DeploymentMode) -> Self {
418 self.mode = mode;
419 self
420 }
421
422 #[must_use]
423 pub fn production(mut self, production: bool) -> Self {
425 self.mode = if production {
426 DeploymentMode::Production
427 } else if self.mode == DeploymentMode::Production {
428 DeploymentMode::Auto
429 } else {
430 self.mode
431 };
432 self
433 }
434
435 #[must_use]
436 pub fn development(mut self, development: bool) -> Self {
438 self.mode = if development {
439 DeploymentMode::Development
440 } else if self.mode == DeploymentMode::Development {
441 DeploymentMode::Auto
442 } else {
443 self.mode
444 };
445 self
446 }
447
448 pub fn explicit_production(&self) -> bool {
450 matches!(self.mode, DeploymentMode::Production)
451 }
452
453 pub fn production_error_posture(&self) -> bool {
456 match self.mode {
457 DeploymentMode::Production => true,
458 DeploymentMode::Development => false,
459 DeploymentMode::Auto => is_production(),
460 }
461 }
462
463 #[must_use]
464 pub fn telemetry(mut self, telemetry: TelemetryOptions) -> Self {
465 self.telemetry = telemetry;
466 self
467 }
468
469 #[must_use]
470 pub fn experimental(mut self, experimental: ExperimentalOptions) -> Self {
471 self.experimental = experimental;
472 self
473 }
474}
475
476impl fmt::Debug for RustAuthOptions {
477 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
478 formatter
479 .debug_struct("RustAuthOptions")
480 .field("app_name", &self.app_name)
481 .field("base_url", &self.base_url)
482 .field("base_path", &self.base_path)
483 .field("secret", &self.secret.as_ref().map(|_| "<redacted>"))
484 .field(
485 "secrets",
486 &format_args!("{} secret(s) redacted", self.secrets.len()),
487 )
488 .field("trusted_origins", &self.trusted_origins)
489 .field("disabled_paths", &self.disabled_paths)
490 .field("session", &self.session)
491 .field("user", &self.user)
492 .field("email_password", &self.email_password)
493 .field("email_verification", &self.email_verification)
494 .field("password", &self.password)
495 .field("account", &self.account)
496 .field("verification", &self.verification)
497 .field("hooks", &self.hooks)
498 .field("on_api_error", &self.on_api_error)
499 .field("init_database_hooks", &self.init_database_hooks)
500 .field("database_hooks", &self.database_hooks)
501 .field("logger", &"<logger-options>")
502 .field("advanced", &self.advanced)
503 .field("rate_limit", &self.rate_limit)
504 .field(
505 "secondary_storage",
506 &self
507 .secondary_storage
508 .as_ref()
509 .map(|_| "<secondary-storage>"),
510 )
511 .field("plugins", &self.plugins)
512 .field("social_providers", &debug_social_providers(self))
513 .field("mode", &self.mode)
514 .field("telemetry", &self.telemetry)
515 .field("experimental", &self.experimental)
516 .finish()
517 }
518}
519
520#[cfg(feature = "oauth")]
521fn debug_social_providers(options: &RustAuthOptions) -> Vec<&str> {
522 options
523 .social_providers
524 .iter()
525 .map(|provider| provider.id())
526 .collect()
527}
528
529#[cfg(not(feature = "oauth"))]
530fn debug_social_providers(_options: &RustAuthOptions) -> Vec<&'static str> {
531 Vec::new()
532}