openauth_plugins/username/
options.rs1use std::sync::Arc;
2
3pub type UsernameValidator = Arc<dyn Fn(&str) -> bool + Send + Sync>;
4pub type UsernameNormalizer = Arc<dyn Fn(&str) -> String + Send + Sync>;
5
6#[derive(Clone)]
7pub struct UsernameOptions {
8 pub min_username_length: usize,
9 pub max_username_length: usize,
10 pub username_validator: UsernameValidator,
11 pub display_username_validator: Option<UsernameValidator>,
12 pub username_normalization: Option<UsernameNormalizer>,
13 pub display_username_normalization: Option<UsernameNormalizer>,
14 pub validation_order: ValidationOrder,
15}
16
17impl Default for UsernameOptions {
18 fn default() -> Self {
19 Self {
20 min_username_length: 3,
21 max_username_length: 30,
22 username_validator: Arc::new(default_username_validator),
23 display_username_validator: None,
24 username_normalization: Some(Arc::new(|username| username.to_lowercase())),
25 display_username_normalization: None,
26 validation_order: ValidationOrder::default(),
27 }
28 }
29}
30
31impl UsernameOptions {
32 pub fn normalize_username(&self, username: &str) -> String {
33 self.username_normalization
34 .as_ref()
35 .map(|normalizer| normalizer(username))
36 .unwrap_or_else(|| username.to_owned())
37 }
38
39 pub fn normalize_display_username(&self, display_username: &str) -> String {
40 self.display_username_normalization
41 .as_ref()
42 .map(|normalizer| normalizer(display_username))
43 .unwrap_or_else(|| display_username.to_owned())
44 }
45
46 pub fn username_for_validation(&self, username: &str) -> String {
47 if self.validation_order.username == ValidationPhase::PostNormalization {
48 self.normalize_username(username)
49 } else {
50 username.to_owned()
51 }
52 }
53
54 pub fn display_username_for_validation(&self, display_username: &str) -> String {
55 if self.validation_order.display_username == ValidationPhase::PostNormalization {
56 self.normalize_display_username(display_username)
57 } else {
58 display_username.to_owned()
59 }
60 }
61
62 pub fn validate_username(
63 &self,
64 username: &str,
65 _phase: ValidationPhase,
66 ) -> Result<(), UsernameValidationError> {
67 if username.len() < self.min_username_length {
68 return Err(UsernameValidationError::TooShort);
69 }
70 if username.len() > self.max_username_length {
71 return Err(UsernameValidationError::TooLong);
72 }
73 if !(self.username_validator)(username) {
74 return Err(UsernameValidationError::Invalid);
75 }
76 Ok(())
77 }
78
79 pub fn validate_display_username(
80 &self,
81 display_username: &str,
82 ) -> Result<(), UsernameValidationError> {
83 if let Some(validator) = &self.display_username_validator {
84 if !validator(display_username) {
85 return Err(UsernameValidationError::InvalidDisplay);
86 }
87 }
88 Ok(())
89 }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub struct ValidationOrder {
94 pub username: ValidationPhase,
95 pub display_username: ValidationPhase,
96}
97
98impl Default for ValidationOrder {
99 fn default() -> Self {
100 Self {
101 username: ValidationPhase::PreNormalization,
102 display_username: ValidationPhase::PreNormalization,
103 }
104 }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108pub enum ValidationPhase {
109 PreNormalization,
110 PostNormalization,
111 Endpoint,
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115pub enum UsernameValidationError {
116 TooShort,
117 TooLong,
118 Invalid,
119 InvalidDisplay,
120}
121
122fn default_username_validator(username: &str) -> bool {
123 username
124 .chars()
125 .all(|character| character.is_ascii_alphanumeric() || character == '_' || character == '.')
126}