Skip to main content

alibi_plugins/email_password/
config.rs

1use super::{CustomSyntheticUserCallback, ExistingUserSignupCallback, UsernameConfig};
2use alibi_core::utils::password::PasswordHasher;
3use std::sync::Arc;
4#[derive(Clone)]
5#[expect(
6    clippy::struct_excessive_bools,
7    reason = "Independent configuration switches model distinct upstream behavior, rather than mutually exclusive states"
8)]
9pub struct EmailPasswordConfig {
10    /// Whether email/password authentication is enabled. Routes remain registered.
11    pub enabled: bool,
12    pub enable_signup: bool,
13    /// Whether to enable the username schema, signup hooks, and endpoints.
14    pub enable_username: bool,
15    pub username: UsernameConfig,
16    pub require_email_verification: bool,
17    /// Minimum UTF-16 password length. Zero uses the default of 8.
18    pub password_min_length: usize,
19    /// Maximum UTF-16 password length. Zero uses the default of 128.
20    pub password_max_length: usize,
21    /// Whether to automatically sign in the user after sign-up (default: true).
22    /// When false, sign-up returns the user but doesn't create a session.
23    pub auto_sign_in: bool,
24    /// Custom password hasher. When `None`, the default scrypt hasher is used.
25    pub password_hasher: Option<Arc<dyn PasswordHasher>>,
26    pub on_existing_user_signup: Option<Arc<ExistingUserSignupCallback>>,
27    pub custom_synthetic_user: Option<Arc<CustomSyntheticUserCallback>>,
28}
29
30/// Password length limits in UTF-16 units, shared by every endpoint that
31/// accepts a new password. The email/password plugin is always installed, so
32/// its configuration is the single source; the defaults only apply to contexts
33/// built without it.
34pub(crate) fn password_length_limits(
35    ctx: &alibi_core::AuthContext<impl alibi_core::AuthSchema>,
36) -> (usize, usize) {
37    ctx.extensions
38        .get::<EmailPasswordConfig>()
39        .map_or((8, 128), |config| {
40            (config.effective_min_length(), config.effective_max_length())
41        })
42}
43
44impl EmailPasswordConfig {
45    pub(in crate::email_password) const fn effective_min_length(&self) -> usize {
46        if self.password_min_length == 0 {
47            8
48        } else {
49            self.password_min_length
50        }
51    }
52
53    pub(in crate::email_password) const fn effective_max_length(&self) -> usize {
54        if self.password_max_length == 0 {
55            128
56        } else {
57            self.password_max_length
58        }
59    }
60}
61
62impl std::fmt::Debug for EmailPasswordConfig {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        f.debug_struct("EmailPasswordConfig")
65            .field("enabled", &self.enabled)
66            .field("enable_signup", &self.enable_signup)
67            .field("enable_username", &self.enable_username)
68            .field("username", &self.username)
69            .field(
70                "require_email_verification",
71                &self.require_email_verification,
72            )
73            .field("password_min_length", &self.password_min_length)
74            .field("password_max_length", &self.password_max_length)
75            .field("auto_sign_in", &self.auto_sign_in)
76            .field(
77                "password_hasher",
78                &self.password_hasher.as_ref().map(|_| "custom"),
79            )
80            .field(
81                "on_existing_user_signup",
82                &self.on_existing_user_signup.as_ref().map(|_| "custom"),
83            )
84            .field(
85                "custom_synthetic_user",
86                &self.custom_synthetic_user.as_ref().map(|_| "custom"),
87            )
88            .finish()
89    }
90}
91
92impl Default for EmailPasswordConfig {
93    fn default() -> Self {
94        Self {
95            enabled: true,
96            enable_signup: true,
97            enable_username: true,
98            username: UsernameConfig::default(),
99            require_email_verification: false,
100            password_min_length: 8,
101            password_max_length: 128,
102            auto_sign_in: true,
103            password_hasher: None,
104            on_existing_user_signup: None,
105            custom_synthetic_user: None,
106        }
107    }
108}