rustauth_scim/
validation.rs1use crate::errors::ScimError;
4use crate::mappings::{primary_email, ScimEmail};
5
6pub fn is_valid_email(value: &str) -> bool {
8 let value = value.trim();
9 if value.is_empty() || value.contains(char::is_whitespace) {
10 return false;
11 }
12 let Some((local, domain)) = value.split_once('@') else {
13 return false;
14 };
15 !local.is_empty()
16 && !domain.is_empty()
17 && domain.contains('.')
18 && !domain.starts_with('.')
19 && !domain.ends_with('.')
20 && !domain.contains('@')
21}
22
23pub fn validate_scim_user_identity(
25 user_name: &str,
26 emails: &[ScimEmail],
27) -> Result<String, ScimError> {
28 let user_name = user_name.trim();
29 if user_name.is_empty() {
30 return Err(ScimError::bad_request("userName is required").with_scim_type("invalidValue"));
31 }
32 let email = primary_email(user_name, emails).to_ascii_lowercase();
33 if !is_valid_email(&email) {
34 return Err(ScimError::bad_request(
35 "userName and emails.value must resolve to a valid email address",
36 )
37 .with_scim_type("invalidValue"));
38 }
39 Ok(email)
40}
41
42pub fn validate_emails(emails: &[ScimEmail]) -> Result<(), ScimError> {
44 if emails.iter().filter(|email| email.primary).count() > 1 {
45 return Err(
46 ScimError::bad_request("Only one emails value can be primary")
47 .with_scim_type("invalidValue"),
48 );
49 }
50 for email in emails {
51 if !is_valid_email(&email.value) {
52 return Err(
53 ScimError::bad_request("emails.value must be a valid email address")
54 .with_scim_type("invalidValue"),
55 );
56 }
57 }
58 Ok(())
59}