webex_message_handler/
url_validation.rs1const ALLOWED_DOMAIN_SUFFIXES: &[&str] = &[".webex.com", ".wbx2.com", ".ciscospark.com"];
4
5pub fn validate_webex_url(raw_url: &str, required_scheme: &str) -> Result<(), String> {
15 let scheme_end = raw_url.find("://").ok_or_else(|| "URL missing scheme".to_string())?;
17 let scheme = &raw_url[..scheme_end];
18
19 if scheme != required_scheme {
20 return Err(format!(
21 "URL scheme must be {required_scheme}, got {scheme}"
22 ));
23 }
24
25 let after_scheme = &raw_url[scheme_end + 3..];
27 let host = after_scheme.split('/').next().unwrap_or("");
28 let host_lower = host.to_lowercase();
29
30 let host_without_port = host_lower.split(':').next().unwrap_or(&host_lower);
32
33 let is_allowed = ALLOWED_DOMAIN_SUFFIXES
36 .iter()
37 .any(|suffix| host_without_port.ends_with(suffix) || host_without_port == &suffix[1..]);
38
39 if !is_allowed {
40 return Err(format!(
41 "URL host {host_without_port} is not a recognized Webex domain"
42 ));
43 }
44
45 Ok(())
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn test_valid_webex_com_https() {
54 assert!(validate_webex_url("https://webex.com/api/v1", "https").is_ok());
55 }
56
57 #[test]
58 fn test_valid_wbx2_com_https() {
59 assert!(validate_webex_url("https://wdm-a.wbx2.com/wdm/api", "https").is_ok());
60 }
61
62 #[test]
63 fn test_valid_ciscospark_com_https() {
64 assert!(validate_webex_url("https://api.ciscospark.com/v1", "https").is_ok());
65 }
66
67 #[test]
68 fn test_valid_wss_scheme() {
69 assert!(validate_webex_url("wss://mercury.webex.com/socket", "wss").is_ok());
70 }
71
72 #[test]
73 fn test_invalid_scheme() {
74 let result = validate_webex_url("http://webex.com/api", "https");
75 assert!(result.is_err());
76 assert!(result.unwrap_err().contains("scheme must be https"));
77 }
78
79 #[test]
80 fn test_invalid_domain() {
81 let result = validate_webex_url("https://evil.com/api", "https");
82 assert!(result.is_err());
83 assert!(result.unwrap_err().contains("not a recognized Webex domain"));
84 }
85
86 #[test]
87 fn test_url_with_port() {
88 assert!(validate_webex_url("https://webex.com:443/api", "https").is_ok());
89 }
90
91 #[test]
92 fn test_missing_scheme() {
93 let result = validate_webex_url("webex.com/api", "https");
94 assert!(result.is_err());
95 }
96}