diff --git a/src/attested_get.rs b/src/attested_get.rs index 27e7ad3..008cb1c 100644 --- a/src/attested_get.rs +++ b/src/attested_get.rs @@ -2,6 +2,25 @@ use crate::{AttestationGenerator, AttestationVerifier, ProxyClient, ProxyError}; use tokio_rustls::rustls::pki_types::CertificateDer; +/// Split an `attested-get` target into a proxy target and an optional request path. +/// +/// This lets users write `127.0.0.1:3000/some/path` and still keep the proxy +/// connection target separate from the HTTP request path. +pub fn split_target_and_path(target: &str) -> (String, Option) { + let Some((target_addr, url_path)) = target.split_once('/') else { + return (target.to_string(), None); + }; + + let url_path = url_path.trim_start_matches('/').to_string(); + let url_path = if url_path.is_empty() { + None + } else { + Some(url_path) + }; + + (target_addr.to_string(), url_path) +} + /// Start a proxy-client, send a single HTTP GET request to the given path and return the /// [reqwest::Response] pub async fn attested_get( @@ -138,4 +157,18 @@ mod tests { assert_eq!(content_type, "text/plain"); assert_eq!(&body.to_vec(), b"bar"); } + + #[test] + fn split_target_and_path_handles_embedded_path() { + let (target, path) = split_target_and_path("127.0.0.1:3000/some/path"); + assert_eq!(target, "127.0.0.1:3000"); + assert_eq!(path.as_deref(), Some("some/path")); + } + + #[test] + fn split_target_and_path_leaves_bare_target_alone() { + let (target, path) = split_target_and_path("127.0.0.1:3000"); + assert_eq!(target, "127.0.0.1:3000"); + assert_eq!(path, None); + } } diff --git a/src/main.rs b/src/main.rs index d929778..bb5fee9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use tracing::level_filters::LevelFilter; use attested_tls_proxy::{ AttestationGenerator, ProxyClient, ProxyServer, - attested_get::attested_get, + attested_get::{attested_get, split_target_and_path}, attested_tls::{ TlsCertAndKey, attestation::{AttestationType, AttestationVerifier, measurements::MeasurementPolicy}, @@ -156,17 +156,19 @@ enum CliCommand { /// Start a proxy-client, send a single HTTP GET request to the given path and print the /// response to standard output AttestedGet { - /// The hostname:port or ip:port of the proxy server (port defaults to 443) + /// The hostname:port or ip:port of the proxy server (port defaults to 443) together + /// with the URL path to GET from the target service, eg: 127.0.0.1:3000/foobar target_addr: String, - #[arg(long)] - /// path to GET (defaults to '/') - url_path: Option, /// Additional CA certificate to verify against (PEM) Defaults to no additional TLS certs. #[arg(long)] tls_ca_certificate: Option, /// Enables verification of self-signed TLS certificates #[arg(long)] allow_self_signed: bool, + /// Optional path to GET (defaults to '/') - this takes precedence over giving the path + /// as part of the target address. + #[arg(long)] + url_path: Option, }, } @@ -429,9 +431,12 @@ async fn main() -> anyhow::Result<()> { None => None, }; + let (target_addr, embedded_url_path) = split_target_and_path(&target_addr); + let url_path = url_path.or(embedded_url_path); + let mut response = attested_get( target_addr, - &url_path.unwrap_or_default(), + url_path.as_deref().unwrap_or("/"), attestation_verifier, remote_tls_cert, allow_self_signed,