Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 18 additions & 11 deletions validator/src/validation/email.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,21 @@ static EMAIL_LITERAL_RE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"\[([a-fA-F0-9:\.]+)\]\z").unwrap());

/// Checks if the domain is a valid domain and if not, check whether it's an IP
#[must_use]
fn validate_domain_part(domain_part: &str) -> bool {
if EMAIL_DOMAIN_RE.is_match(domain_part) {
return true;
}

// maybe we have an ip as a domain?
match EMAIL_LITERAL_RE.captures(domain_part) {
Some(caps) => match caps.get(1) {
// if it's a domain literal like [127.0.0.1]
if let Some(caps) = EMAIL_LITERAL_RE.captures(domain_part) {
return match caps.get(1) {
Some(c) => c.as_str().validate_ip(),
None => false,
},
None => false,
};
}

// Check if domain matches pattern and contains at least one dot
if EMAIL_DOMAIN_RE.is_match(domain_part) && domain_part.contains('.') {
return true;
}

false
}

/// Validates whether the given string is an email based on the [HTML5 spec](https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address).
Expand Down Expand Up @@ -154,7 +155,7 @@ mod tests {
("", false),
("abc", false),
("abc@", false),
("abc@bar", true),
("abc@bar", false),
("a @x.cz", false),
("[email protected]", false),
("something@@somewhere.com", false),
Expand Down Expand Up @@ -213,4 +214,10 @@ mod tests {
let test = "a@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com";
assert!(!test.validate_email());
}

#[test]
fn test_user_at_com_fails() {
let test = "user@com";
assert!(!test.validate_email(), "user@com should not be valid");
}
}
21 changes: 21 additions & 0 deletions validator_derive_tests/tests/email.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,24 @@ fn can_validate_custom_impl_for_email() {
assert!(valid.validate().is_ok());
assert!(invalid.validate().is_err());
}

#[test]
fn top_level_domain_only_fails_validation() {
#[derive(Debug, Validate)]
struct TestStruct {
#[validate(email)]
val: String,
}

let s = TestStruct { val: "user@com".to_string() };
let res = s.validate();
assert!(res.is_err());

let err = res.unwrap_err();
let errs = err.field_errors();

assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "email");
assert_eq!(errs["val"][0].params["value"], "user@com");
}