/// Match a domain against a pattern supporting wildcards. /// /// Supported patterns: /// - `*` matches any domain /// - `*.example.com` matches any subdomain of example.com /// - `example.com` exact match /// - `**.example.com` matches any depth of subdomain pub fn domain_matches(pattern: &str, domain: &str) -> bool { let pattern = pattern.trim().to_lowercase(); let domain = domain.trim().to_lowercase(); if pattern == "*" { return true; } if pattern == domain { return true; } // Wildcard patterns if pattern.starts_with("*.") { let suffix = &pattern[2..]; // e.g., "example.com" // Match exact parent or any single-level subdomain if domain == suffix { return true; } if domain.ends_with(&format!(".{}", suffix)) { // Check it's a single level subdomain for `*.` let prefix = &domain[..domain.len() - suffix.len() - 1]; return !prefix.contains('.'); } return false; } if pattern.starts_with("**.") { let suffix = &pattern[3..]; // Match exact parent or any depth of subdomain return domain == suffix || domain.ends_with(&format!(".{}", suffix)); } // Use glob-match for more complex patterns glob_match::glob_match(&pattern, &domain) } /// Check if a domain matches any of the given patterns. pub fn domain_matches_any(patterns: &[&str], domain: &str) -> bool { patterns.iter().any(|p| domain_matches(p, domain)) } #[cfg(test)] mod tests { use super::*; #[test] fn test_exact_match() { assert!(domain_matches("example.com", "example.com")); assert!(!domain_matches("example.com", "other.com")); } #[test] fn test_wildcard_all() { assert!(domain_matches("*", "anything.com")); assert!(domain_matches("*", "sub.domain.example.com")); } #[test] fn test_wildcard_subdomain() { assert!(domain_matches("*.example.com", "www.example.com")); assert!(domain_matches("*.example.com", "api.example.com")); assert!(domain_matches("*.example.com", "example.com")); assert!(!domain_matches("*.example.com", "deep.sub.example.com")); } #[test] fn test_double_wildcard() { assert!(domain_matches("**.example.com", "www.example.com")); assert!(domain_matches("**.example.com", "deep.sub.example.com")); assert!(domain_matches("**.example.com", "example.com")); } #[test] fn test_case_insensitive() { assert!(domain_matches("Example.COM", "example.com")); assert!(domain_matches("*.EXAMPLE.com", "WWW.example.COM")); } }