diff --git a/server/svix-server/config.default.toml b/server/svix-server/config.default.toml index 68d0ea9e4..ff2ba5163 100644 --- a/server/svix-server/config.default.toml +++ b/server/svix-server/config.default.toml @@ -90,6 +90,9 @@ cache_type = "memory" # If true, headers are prefixed with `Webhook-`, otherwise with `Svix-` (default). whitelabel_headers = false +# Custom User-Agent header +# user_agent_header = "User Agent" + # If true, only allow https endpoints, otherwise also allow http. endpoint_https_only = false diff --git a/server/svix-server/src/cfg.rs b/server/svix-server/src/cfg.rs index 9d9430a00..f8c44c958 100644 --- a/server/svix-server/src/cfg.rs +++ b/server/svix-server/src/cfg.rs @@ -150,6 +150,9 @@ pub struct ConfigurationInner { /// If true, headers are prefixed with `Webhook-`, otherwise with `Svix-` (default). pub whitelabel_headers: bool, + /// Custom User-Agent header + pub user_agent_header: Option, + /// If true, only allow https endpoints, otherwise also allow http. pub endpoint_https_only: bool, diff --git a/server/svix-server/src/worker.rs b/server/svix-server/src/worker.rs index 8ee64910f..f74f2f6d6 100644 --- a/server/svix-server/src/worker.rs +++ b/server/svix-server/src/worker.rs @@ -189,6 +189,7 @@ fn generate_msg_headers( msg_id: &MessageId, signatures: String, whitelabel_headers: bool, + user_agent_header: Option<&str>, configured_headers: Option<&EndpointHeaders>, _endpoint_url: &str, ) -> Result { @@ -213,10 +214,16 @@ fn generate_msg_headers( headers.insert("svix-timestamp".to_owned(), timestamp); headers.insert("svix-signature".to_owned(), signatures_str); } + + let user_agent_value = HeaderValue::try_from( + user_agent_header.unwrap_or(USER_AGENT) + ).unwrap_or_else(|_| USER_AGENT.to_string().parse().unwrap()); + headers.insert( "user-agent".to_owned(), - USER_AGENT.to_string().parse().unwrap(), + user_agent_value, ); + headers.insert( "content-type".to_owned(), "application/json".parse().unwrap(), @@ -299,6 +306,7 @@ async fn prepare_dispatch( &msg_task.msg_id, signatures, cfg.whitelabel_headers, + cfg.user_agent_header.as_deref(), endp.headers.as_ref(), &endp.url, )? @@ -1035,6 +1043,7 @@ mod tests { signatures, WHITELABEL_HEADERS, None, + None, ENDPOINT_URL, ) .unwrap(), @@ -1065,6 +1074,7 @@ mod tests { &id, signatures, WHITELABEL_HEADERS, + None, Some(&EndpointHeaders(headers)), ENDPOINT_URL, ) @@ -1073,6 +1083,34 @@ mod tests { assert_eq!(expected, actual); } + // Tests asymmetric signing keys + #[test] + fn test_generate_msg_headers_with_user_agent_header() { + let (mut expected, id) = mock_headers(); + let _ = expected.insert("user-agent".to_owned(), "User Agent".parse().unwrap()); + + let signatures = sign_msg( + &Encryption::new_noop(), + TIMESTAMP, + BODY, + &id, + ENDPOINT_SIGNING_KEYS, + ); + + let actual = generate_msg_headers( + TIMESTAMP, + &id, + signatures, + WHITELABEL_HEADERS, + Some("User Agent"), + None, + ENDPOINT_URL, + ) + .unwrap(); + + assert_eq!(expected, actual); + } + // Tests endpoint signing keys -- expected values are fetched from the Svix documentation for a // direct comparison to the current implementation. #[test] @@ -1102,6 +1140,7 @@ mod tests { signatures, WHITELABEL_HEADERS, None, + None, ENDPOINT_URL, ) .unwrap();