Stop using the regex crate for parsing addresses (#776)
This commit is contained in:
@@ -20,7 +20,7 @@ maintenance = { status = "actively-developed" }
|
||||
|
||||
[dependencies]
|
||||
idna = "0.2"
|
||||
once_cell = "1"
|
||||
once_cell = { version = "1", optional = true }
|
||||
tracing = { version = "0.1.16", default-features = false, features = ["std"], optional = true } # feature
|
||||
|
||||
# builder
|
||||
@@ -29,7 +29,6 @@ mime = { version = "0.3.4", optional = true }
|
||||
fastrand = { version = "1.4", optional = true }
|
||||
quoted_printable = { version = "0.4", optional = true }
|
||||
base64 = { version = "0.13", optional = true }
|
||||
regex = { version = "1", default-features = false, features = ["std", "unicode-case"] }
|
||||
email-encoding = { git = "https://github.com/lettre/email-encoding.git", rev = "ac7ab8630b8d012ade63869c89b2855e27b3ce7a", optional = true }
|
||||
|
||||
# file transport
|
||||
@@ -67,6 +66,7 @@ tokio1_rustls = { package = "tokio-rustls", version = "0.23", optional = true }
|
||||
sha2 = { version = "0.10", optional = true }
|
||||
rsa = { version = "0.6.0", optional = true }
|
||||
ed25519-dalek = { version = "1.0.1", optional = true }
|
||||
regex = { version = "1", default-features = false, features = ["std"], optional = true }
|
||||
|
||||
# email formats
|
||||
email_address = { version = "0.2.1", default-features = false }
|
||||
@@ -95,7 +95,7 @@ mime03 = ["mime"]
|
||||
file-transport = ["uuid"]
|
||||
file-transport-envelope = ["serde", "serde_json", "file-transport"]
|
||||
sendmail-transport = []
|
||||
smtp-transport = ["base64", "nom", "socket2"]
|
||||
smtp-transport = ["base64", "nom", "socket2", "once_cell"]
|
||||
|
||||
pool = ["futures-util"]
|
||||
|
||||
@@ -109,7 +109,7 @@ tokio1 = ["tokio1_crate", "async-trait", "futures-io", "futures-util"]
|
||||
tokio1-native-tls = ["tokio1", "native-tls", "tokio1_native_tls_crate"]
|
||||
tokio1-rustls-tls = ["tokio1", "rustls-tls", "tokio1_rustls"]
|
||||
|
||||
dkim = ["base64", "sha2", "rsa", "ed25519-dalek"]
|
||||
dkim = ["base64", "sha2", "rsa", "ed25519-dalek", "regex", "once_cell"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
@@ -10,8 +10,6 @@ use std::{
|
||||
|
||||
use email_address::EmailAddress;
|
||||
use idna::domain_to_ascii;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
|
||||
/// Represents an email address with a user and a domain name.
|
||||
///
|
||||
@@ -56,9 +54,6 @@ pub struct Address {
|
||||
at_start: usize,
|
||||
}
|
||||
|
||||
// literal form, ipv4 or ipv6 address (SMTP 4.1.3)
|
||||
static LITERAL_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?i)\[([A-f0-9:\.]+)\]\z").unwrap());
|
||||
|
||||
impl Address {
|
||||
/// Creates a new email address from a user and domain.
|
||||
///
|
||||
@@ -132,16 +127,19 @@ impl Address {
|
||||
}
|
||||
|
||||
fn check_domain_ascii(domain: &str) -> Result<(), AddressError> {
|
||||
// Domain
|
||||
if EmailAddress::is_valid_domain(domain) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(caps) = LITERAL_RE.captures(domain) {
|
||||
if let Some(cap) = caps.get(1) {
|
||||
if cap.as_str().parse::<IpAddr>().is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
// IP
|
||||
let ip = domain
|
||||
.strip_prefix('[')
|
||||
.and_then(|ip| ip.strip_suffix(']'))
|
||||
.unwrap_or(domain);
|
||||
|
||||
if ip.parse::<IpAddr>().is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(AddressError::InvalidDomain)
|
||||
@@ -259,7 +257,7 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_address() {
|
||||
fn ascii_address() {
|
||||
let addr_str = "something@example.com";
|
||||
let addr = Address::from_str(addr_str).unwrap();
|
||||
let addr2 = Address::new("something", "example.com").unwrap();
|
||||
@@ -268,7 +266,34 @@ mod tests {
|
||||
assert_eq!(addr.domain(), "example.com");
|
||||
assert_eq!(addr2.user(), "something");
|
||||
assert_eq!(addr2.domain(), "example.com");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ascii_address_ipv4() {
|
||||
let addr_str = "something@1.1.1.1";
|
||||
let addr = Address::from_str(addr_str).unwrap();
|
||||
let addr2 = Address::new("something", "1.1.1.1").unwrap();
|
||||
assert_eq!(addr, addr2);
|
||||
assert_eq!(addr.user(), "something");
|
||||
assert_eq!(addr.domain(), "1.1.1.1");
|
||||
assert_eq!(addr2.user(), "something");
|
||||
assert_eq!(addr2.domain(), "1.1.1.1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ascii_address_ipv6() {
|
||||
let addr_str = "something@[2606:4700:4700::1111]";
|
||||
let addr = Address::from_str(addr_str).unwrap();
|
||||
let addr2 = Address::new("something", "[2606:4700:4700::1111]").unwrap();
|
||||
assert_eq!(addr, addr2);
|
||||
assert_eq!(addr.user(), "something");
|
||||
assert_eq!(addr.domain(), "[2606:4700:4700::1111]");
|
||||
assert_eq!(addr2.user(), "something");
|
||||
assert_eq!(addr2.domain(), "[2606:4700:4700::1111]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_parts() {
|
||||
assert!(Address::check_user("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").is_err());
|
||||
assert!(
|
||||
Address::check_domain("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com").is_err()
|
||||
|
||||
Reference in New Issue
Block a user