this repo has no description
1pub const MAX_EMAIL_LENGTH: usize = 254; 2pub const MAX_LOCAL_PART_LENGTH: usize = 64; 3pub const MAX_DOMAIN_LENGTH: usize = 253; 4pub const MAX_DOMAIN_LABEL_LENGTH: usize = 63; 5const EMAIL_LOCAL_SPECIAL_CHARS: &str = ".!#$%&'*+/=?^_`{|}~-"; 6 7pub const MIN_HANDLE_LENGTH: usize = 3; 8pub const MAX_HANDLE_LENGTH: usize = 253; 9 10#[derive(Debug, PartialEq)] 11pub enum HandleValidationError { 12 Empty, 13 TooShort, 14 TooLong, 15 InvalidCharacters, 16 StartsWithInvalidChar, 17 EndsWithInvalidChar, 18 ContainsSpaces, 19} 20 21impl std::fmt::Display for HandleValidationError { 22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 23 match self { 24 Self::Empty => write!(f, "Handle cannot be empty"), 25 Self::TooShort => write!(f, "Handle must be at least {} characters", MIN_HANDLE_LENGTH), 26 Self::TooLong => write!(f, "Handle exceeds maximum length of {} characters", MAX_HANDLE_LENGTH), 27 Self::InvalidCharacters => write!(f, "Handle contains invalid characters. Only alphanumeric, hyphens, and underscores are allowed"), 28 Self::StartsWithInvalidChar => write!(f, "Handle cannot start with a hyphen or underscore"), 29 Self::EndsWithInvalidChar => write!(f, "Handle cannot end with a hyphen or underscore"), 30 Self::ContainsSpaces => write!(f, "Handle cannot contain spaces"), 31 } 32 } 33} 34 35pub fn validate_short_handle(handle: &str) -> Result<String, HandleValidationError> { 36 let handle = handle.trim(); 37 38 if handle.is_empty() { 39 return Err(HandleValidationError::Empty); 40 } 41 42 if handle.contains(' ') || handle.contains('\t') || handle.contains('\n') { 43 return Err(HandleValidationError::ContainsSpaces); 44 } 45 46 if handle.len() < MIN_HANDLE_LENGTH { 47 return Err(HandleValidationError::TooShort); 48 } 49 50 if handle.len() > MAX_HANDLE_LENGTH { 51 return Err(HandleValidationError::TooLong); 52 } 53 54 let first_char = handle.chars().next().unwrap(); 55 if first_char == '-' || first_char == '_' { 56 return Err(HandleValidationError::StartsWithInvalidChar); 57 } 58 59 let last_char = handle.chars().last().unwrap(); 60 if last_char == '-' || last_char == '_' { 61 return Err(HandleValidationError::EndsWithInvalidChar); 62 } 63 64 for c in handle.chars() { 65 if !c.is_ascii_alphanumeric() && c != '-' && c != '_' { 66 return Err(HandleValidationError::InvalidCharacters); 67 } 68 } 69 70 Ok(handle.to_lowercase()) 71} 72 73pub fn is_valid_email(email: &str) -> bool { 74 let email = email.trim(); 75 if email.is_empty() || email.len() > MAX_EMAIL_LENGTH { 76 return false; 77 } 78 let parts: Vec<&str> = email.rsplitn(2, '@').collect(); 79 if parts.len() != 2 { 80 return false; 81 } 82 let domain = parts[0]; 83 let local = parts[1]; 84 if local.is_empty() || local.len() > MAX_LOCAL_PART_LENGTH { 85 return false; 86 } 87 if local.starts_with('.') || local.ends_with('.') { 88 return false; 89 } 90 if local.contains("..") { 91 return false; 92 } 93 for c in local.chars() { 94 if !c.is_ascii_alphanumeric() && !EMAIL_LOCAL_SPECIAL_CHARS.contains(c) { 95 return false; 96 } 97 } 98 if domain.is_empty() || domain.len() > MAX_DOMAIN_LENGTH { 99 return false; 100 } 101 if !domain.contains('.') { 102 return false; 103 } 104 for label in domain.split('.') { 105 if label.is_empty() || label.len() > MAX_DOMAIN_LABEL_LENGTH { 106 return false; 107 } 108 if label.starts_with('-') || label.ends_with('-') { 109 return false; 110 } 111 for c in label.chars() { 112 if !c.is_ascii_alphanumeric() && c != '-' { 113 return false; 114 } 115 } 116 } 117 true 118} 119 120#[cfg(test)] 121mod tests { 122 use super::*; 123 124 #[test] 125 fn test_valid_handles() { 126 assert_eq!(validate_short_handle("alice"), Ok("alice".to_string())); 127 assert_eq!(validate_short_handle("bob123"), Ok("bob123".to_string())); 128 assert_eq!(validate_short_handle("user-name"), Ok("user-name".to_string())); 129 assert_eq!(validate_short_handle("user_name"), Ok("user_name".to_string())); 130 assert_eq!(validate_short_handle("UPPERCASE"), Ok("uppercase".to_string())); 131 assert_eq!(validate_short_handle("MixedCase123"), Ok("mixedcase123".to_string())); 132 assert_eq!(validate_short_handle("abc"), Ok("abc".to_string())); 133 } 134 135 #[test] 136 fn test_invalid_handles() { 137 assert_eq!(validate_short_handle(""), Err(HandleValidationError::Empty)); 138 assert_eq!(validate_short_handle(" "), Err(HandleValidationError::Empty)); 139 assert_eq!(validate_short_handle("ab"), Err(HandleValidationError::TooShort)); 140 assert_eq!(validate_short_handle("a"), Err(HandleValidationError::TooShort)); 141 assert_eq!(validate_short_handle("test spaces"), Err(HandleValidationError::ContainsSpaces)); 142 assert_eq!(validate_short_handle("test\ttab"), Err(HandleValidationError::ContainsSpaces)); 143 assert_eq!(validate_short_handle("-starts"), Err(HandleValidationError::StartsWithInvalidChar)); 144 assert_eq!(validate_short_handle("_starts"), Err(HandleValidationError::StartsWithInvalidChar)); 145 assert_eq!(validate_short_handle("ends-"), Err(HandleValidationError::EndsWithInvalidChar)); 146 assert_eq!(validate_short_handle("ends_"), Err(HandleValidationError::EndsWithInvalidChar)); 147 assert_eq!(validate_short_handle("test@user"), Err(HandleValidationError::InvalidCharacters)); 148 assert_eq!(validate_short_handle("test!user"), Err(HandleValidationError::InvalidCharacters)); 149 assert_eq!(validate_short_handle("test.user"), Err(HandleValidationError::InvalidCharacters)); 150 } 151 152 #[test] 153 fn test_handle_trimming() { 154 assert_eq!(validate_short_handle(" alice "), Ok("alice".to_string())); 155 } 156 157 #[test] 158 fn test_valid_emails() { 159 assert!(is_valid_email("user@example.com")); 160 assert!(is_valid_email("user.name@example.com")); 161 assert!(is_valid_email("user+tag@example.com")); 162 assert!(is_valid_email("user@sub.example.com")); 163 assert!(is_valid_email("USER@EXAMPLE.COM")); 164 assert!(is_valid_email("user123@example123.com")); 165 assert!(is_valid_email("a@b.co")); 166 } 167 #[test] 168 fn test_invalid_emails() { 169 assert!(!is_valid_email("")); 170 assert!(!is_valid_email("user")); 171 assert!(!is_valid_email("user@")); 172 assert!(!is_valid_email("@example.com")); 173 assert!(!is_valid_email("user@example")); 174 assert!(!is_valid_email("user@@example.com")); 175 assert!(!is_valid_email("user@.example.com")); 176 assert!(!is_valid_email("user@example..com")); 177 assert!(!is_valid_email(".user@example.com")); 178 assert!(!is_valid_email("user.@example.com")); 179 assert!(!is_valid_email("user..name@example.com")); 180 assert!(!is_valid_email("user@-example.com")); 181 assert!(!is_valid_email("user@example-.com")); 182 } 183 #[test] 184 fn test_trimmed_whitespace() { 185 assert!(is_valid_email(" user@example.com ")); 186 } 187}