From b1fa54efd60bcccd9a565fa27c24dc81ef26cca5 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Fri, 7 Jun 2024 11:57:08 +0200 Subject: [PATCH] Strip trailing slash in `allowed_outbound_hosts` config. Fixes #2545 Signed-off-by: Ryan Levick --- crates/outbound-networking/src/lib.rs | 47 +++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/crates/outbound-networking/src/lib.rs b/crates/outbound-networking/src/lib.rs index 9a5fdfe532..c2c3095b85 100644 --- a/crates/outbound-networking/src/lib.rs +++ b/crates/outbound-networking/src/lib.rs @@ -187,6 +187,9 @@ impl HostConfig { bail!("Invalid allowed host {host}: wildcards are allowed only as subdomains"); } + // Remove trailing slashes + host = host.trim_end_matches('/'); + Ok(Self::List(vec![host.into()])) } @@ -502,6 +505,37 @@ mod test { use super::*; use std::net::{Ipv4Addr, Ipv6Addr}; + #[test] + fn test_allowed_hosts_accepts_url_without_port() { + assert_eq!( + AllowedHostConfig::new( + SchemeConfig::new("http"), + HostConfig::new("spin.fermyon.dev"), + PortConfig::new(80) + ), + AllowedHostConfig::parse("http://spin.fermyon.dev").unwrap() + ); + + assert_eq!( + AllowedHostConfig::new( + SchemeConfig::new("http"), + // Trailing slash is removed + HostConfig::new("spin.fermyon.dev"), + PortConfig::new(80) + ), + AllowedHostConfig::parse("http://spin.fermyon.dev/").unwrap() + ); + + assert_eq!( + AllowedHostConfig::new( + SchemeConfig::new("https"), + HostConfig::new("spin.fermyon.dev"), + PortConfig::new(443) + ), + AllowedHostConfig::parse("https://spin.fermyon.dev").unwrap() + ); + } + #[test] fn test_allowed_hosts_accepts_url_with_port() { assert_eq!( @@ -667,6 +701,9 @@ mod test { #[test] fn test_allowed_hosts_rejects_path() { + // An empty path is allowed + assert!(AllowedHostConfig::parse("http://spin.fermyon.dev/").is_ok()); + // All other paths are not allowed assert!(AllowedHostConfig::parse("http://spin.fermyon.dev/a").is_err()); assert!(AllowedHostConfig::parse("http://spin.fermyon.dev:6666/a/b").is_err()); assert!(AllowedHostConfig::parse("http://*.fermyon.dev/a").is_err()); @@ -700,6 +737,8 @@ mod test { assert!( allowed.allows(&OutboundUrl::parse("http://example.com:8383/foo/bar", "http").unwrap()) ); + // Allow urls with and without a trailing slash + assert!(allowed.allows(&OutboundUrl::parse("https://spin.fermyon.dev", "https").unwrap())); assert!(allowed.allows(&OutboundUrl::parse("https://spin.fermyon.dev/", "https").unwrap())); assert!(!allowed.allows(&OutboundUrl::parse("http://example.com/", "http").unwrap())); assert!(!allowed.allows(&OutboundUrl::parse("http://google.com/", "http").unwrap())); @@ -707,6 +746,14 @@ mod test { assert!(allowed.allows(&OutboundUrl::parse("example.com:8383", "http").unwrap())); } + #[test] + fn test_allowed_hosts_with_trailing_slash() { + let allowed = + AllowedHostsConfig::parse(&["https://my.api.com/"], &dummy_resolver()).unwrap(); + assert!(allowed.allows(&OutboundUrl::parse("https://my.api.com", "https").unwrap())); + assert!(allowed.allows(&OutboundUrl::parse("https://my.api.com/", "https").unwrap())); + } + #[test] fn test_allowed_hosts_can_be_subdomain_wildcards() { let allowed = AllowedHostsConfig::parse(