@@ 108,7 108,7 @@ impl<'a> ComponentId<'a> {
fn serialize_value_into<B>(
&self,
result: &mut String,
- src: &RequestOrResponse<B>,
+ src: &RequestOrResponseRef<B>,
) -> Result<(), crate::CommonError> {
match self {
ComponentId::HttpField(component) => {
@@ 143,20 143,20 @@ impl<'a> ComponentId<'a> {
}
}
ComponentId::Method => match src {
- RequestOrResponse::Request(req) => {
+ RequestOrResponseRef::Request(req) => {
result.push_str(req.method().as_str());
}
_ => return Err(crate::CommonError::MissingComponent),
},
ComponentId::TargetUri => match src {
- RequestOrResponse::Request(req) => {
+ RequestOrResponseRef::Request(req) => {
use std::fmt::Write;
write!(result, "{}", req.uri()).unwrap();
}
_ => return Err(crate::CommonError::MissingComponent),
},
ComponentId::Authority => match src {
- RequestOrResponse::Request(req) => {
+ RequestOrResponseRef::Request(req) => {
if let Some(authority) = req.uri().authority() {
result.push_str(authority.as_str());
} else {
@@ 166,7 166,7 @@ impl<'a> ComponentId<'a> {
_ => return Err(crate::CommonError::MissingComponent),
},
ComponentId::Scheme => match src {
- RequestOrResponse::Request(req) => {
+ RequestOrResponseRef::Request(req) => {
if let Some(scheme) = req.uri().scheme_str() {
result.push_str(scheme);
} else {
@@ 176,7 176,7 @@ impl<'a> ComponentId<'a> {
_ => return Err(crate::CommonError::MissingComponent),
},
ComponentId::RequestTarget => match src {
- RequestOrResponse::Request(req) => {
+ RequestOrResponseRef::Request(req) => {
if let Some(value) = req.uri().path_and_query() {
result.push_str(value.as_str());
} else {
@@ 186,13 186,13 @@ impl<'a> ComponentId<'a> {
_ => return Err(crate::CommonError::MissingComponent),
},
ComponentId::Path => match src {
- RequestOrResponse::Request(req) => {
+ RequestOrResponseRef::Request(req) => {
result.push_str(req.uri().path());
}
_ => return Err(crate::CommonError::MissingComponent),
},
ComponentId::Query => match src {
- RequestOrResponse::Request(req) => {
+ RequestOrResponseRef::Request(req) => {
result.push('?');
result.push_str(req.uri().query().unwrap_or(""));
}
@@ 202,7 202,7 @@ impl<'a> ComponentId<'a> {
return Err(crate::CommonError::Unsupported);
}
ComponentId::Status => match src {
- RequestOrResponse::Response(res) => {
+ RequestOrResponseRef::Response(res) => {
result.push_str(res.status().as_str());
}
_ => return Err(crate::CommonError::MissingComponent),
@@ 363,7 363,7 @@ impl<'a> HttpbisSignature<'a> {
name: Cow<'a, str>,
params: SignatureParams<'a>,
covered_components: Cow<'a, [ComponentId<'a>]>,
- src: RequestOrResponse<B>,
+ src: RequestOrResponseRef<B>,
req: Option<&'a http::Request<B>>,
sign: impl FnOnce(&[u8]) -> Result<Vec<u8>, E>,
) -> Result<Self, crate::SignError<E>> {
@@ 386,14 386,14 @@ impl<'a> HttpbisSignature<'a> {
name: impl Into<Cow<'a, str>>,
params: SignatureParams<'a>,
covered_components: impl Into<Cow<'a, [ComponentId<'a>]>>,
- request: http::Request<B>,
+ request: &http::Request<B>,
sign: impl FnOnce(&[u8]) -> Result<Vec<u8>, E>,
) -> Result<Self, crate::SignError<E>> {
Self::create_inner(
name.into(),
params,
covered_components.into(),
- RequestOrResponse::Request(request),
+ RequestOrResponseRef::Request(request),
None,
sign,
)
@@ 445,7 445,7 @@ impl<'a> HttpbisSignature<'a> {
Ok(())
}
- fn parse_inner<B>(src: RequestOrResponse<B>) -> Result<Vec<Self>, crate::ParseError> {
+ fn parse_inner<B>(src: RequestOrResponseRef<B>) -> Result<Vec<Self>, crate::ParseError> {
let headers = src.headers();
let mut inputs = HashMap::new();
@@ 469,8 469,8 @@ impl<'a> HttpbisSignature<'a> {
for (key, value) in list.params {
params_src.push(';');
- <String as AsRef<str>>::as_ref(&key)
- .serialize_as_bare_item(&mut params_src)?;
+ params_src.push_str(&key);
+ params_src.push('=');
match value {
sfv::BareItem::Integer(value) => {
value.serialize_as_bare_item(&mut params_src)?
@@ 575,13 575,13 @@ impl<'a> HttpbisSignature<'a> {
Ok(result)
}
- pub fn parse_from_request<B>(req: http::Request<B>) -> Result<Vec<Self>, crate::ParseError> {
- Self::parse_inner(RequestOrResponse::Request(req))
+ pub fn parse_from_request<B>(req: &http::Request<B>) -> Result<Vec<Self>, crate::ParseError> {
+ Self::parse_inner(RequestOrResponseRef::Request(req))
}
fn verify_inner<E: std::fmt::Debug, B>(
&self,
- src: RequestOrResponse<B>,
+ src: RequestOrResponseRef<B>,
req: Option<http::Request<B>>,
verify: impl FnOnce(&[u8], &[u8]) -> Result<bool, E>,
) -> Result<bool, crate::VerifyError<E>> {
@@ 608,10 608,10 @@ impl<'a> HttpbisSignature<'a> {
pub fn verify_request<E: std::fmt::Debug, B>(
&self,
- request: http::Request<B>,
+ request: &http::Request<B>,
verify: impl FnOnce(&[u8], &[u8]) -> Result<bool, E>,
) -> Result<bool, crate::VerifyError<E>> {
- self.verify_inner(RequestOrResponse::Request(request), None, verify)
+ self.verify_inner(RequestOrResponseRef::Request(request), None, verify)
}
pub fn params(&self) -> &SignatureParams {
@@ 627,16 627,16 @@ impl<'a> HttpbisSignature<'a> {
}
}
-enum RequestOrResponse<B> {
- Request(http::Request<B>),
- Response(http::Response<B>),
+enum RequestOrResponseRef<'a, B> {
+ Request(&'a http::Request<B>),
+ Response(&'a http::Response<B>),
}
-impl<B> RequestOrResponse<B> {
+impl<'a, B> RequestOrResponseRef<'a, B> {
pub fn headers(&self) -> &http::HeaderMap<http::HeaderValue> {
match self {
- RequestOrResponse::Request(req) => req.headers(),
- RequestOrResponse::Response(res) => res.headers(),
+ RequestOrResponseRef::Request(req) => req.headers(),
+ RequestOrResponseRef::Response(res) => res.headers(),
}
}
}
@@ 730,7 730,7 @@ impl<'a> AsBareItem for i64 {
fn create_signature_base<B>(
params_src: &str,
covered_components: &[ComponentId<'_>],
- src: &RequestOrResponse<B>,
+ src: &RequestOrResponseRef<B>,
req: Option<&http::Request<B>>,
) -> Result<String, crate::CommonError> {
let mut result = String::new();
@@ 765,6 765,23 @@ fn create_signature_base<B>(
mod test {
use super::*;
+ fn get_sample_request() -> http::Request<&'static str> {
+ http::Request::builder()
+ .method(http::Method::POST)
+ .uri("/foo?param=Value&Pet=dog")
+ .header(http::header::HOST, "example.com")
+ .header(http::header::DATE, "Tue, 20 Apr 2021 02:07:55 GMT")
+ .header(http::header::CONTENT_TYPE, "application/json")
+ .header(
+ "Content-Digest",
+ "sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+T\
+ aPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:",
+ )
+ .header(http::header::CONTENT_LENGTH, "18")
+ .body(r#"{"hello": "world"}"#)
+ .unwrap()
+ }
+
#[test]
fn test_params_minimal() {
let res = SignatureParams::default().serialize::<()>();
@@ 789,7 806,7 @@ mod test {
fn test_base_minimal() {
let req = http::Request::new(());
let result =
- create_signature_base("", &[], &RequestOrResponse::Request(req), None).unwrap();
+ create_signature_base("", &[], &RequestOrResponseRef::Request(&req), None).unwrap();
assert_eq!(result, r#""@signature-params": ()"#);
}
@@ 814,7 831,7 @@ mod test {
)),
ComponentId::HttpField(HttpFieldComponentId::new(http::header::CONTENT_LENGTH)),
],
- &RequestOrResponse::Response(res),
+ &RequestOrResponseRef::Response(&res),
None,
)
.unwrap();
@@ 831,21 848,19 @@ mod test {
#[test]
fn test_parse_minimal() {
- let req = http::Request::builder()
- .method(http::Method::POST)
- .uri("/foo?param=Value&Pet=dog")
- .header(http::header::HOST, "example.com")
- .header(http::header::DATE, "Tue, 20 Apr 2021 02:07:55 GMT")
- .header(http::header::CONTENT_TYPE, "application/json")
- .header("Content-Digest", "sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+T\
- aPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:")
- .header(http::header::CONTENT_LENGTH, "18")
- .header(SIGNATURE_INPUT_HEADER, r#"sig-b21=();created=1618884473;keyid="test-key-rsa-pss";nonce="b3k2pp5k7z-50gnwp.yemd""#)
- .header(crate::SIGNATURE_HEADER, "sig-b21=:d2pmTvmbncD3xQm8E9ZV2828BjQWGgiwAaw5bAkgibUopemLJcWDy/lkbbHAve4cRAtx31Iq786U7it++wgGxbtRxf8Udx7zFZsckzXaJMkA7ChG52eSkFxykJeNqsrWH5S+oxNFlD4dzVuwe8DhTSja8xxbR/Z2cOGdCbzR72rgFWhzx2VjBqJzsPLMIQKhO4DGezXehhWwE56YCE+O6c0mKZsfxVrogUvA4HELjVKWmAvtl6UnCh8jYzuVG5WSb/QEVPnP5TmcAnLH1g+s++v6d4s8m0gCw1fV5/SITLq9mhho8K3+7EPYTU8IU1bLhdxO5Nyt8C8ssinQ98Xw9Q==:")
- .body(r#"{"hello": "world"}"#)
- .unwrap();
+ let req = {
+ let mut req = get_sample_request();
+
+ req.headers_mut()
+ .insert(SIGNATURE_INPUT_HEADER, r#"sig-b21=();created=1618884473;keyid="test-key-rsa-pss";nonce="b3k2pp5k7z-50gnwp.yemd""#.try_into().unwrap());
+
+ req.headers_mut()
+ .insert(crate::SIGNATURE_HEADER, "sig-b21=:d2pmTvmbncD3xQm8E9ZV2828BjQWGgiwAaw5bAkgibUopemLJcWDy/lkbbHAve4cRAtx31Iq786U7it++wgGxbtRxf8Udx7zFZsckzXaJMkA7ChG52eSkFxykJeNqsrWH5S+oxNFlD4dzVuwe8DhTSja8xxbR/Z2cOGdCbzR72rgFWhzx2VjBqJzsPLMIQKhO4DGezXehhWwE56YCE+O6c0mKZsfxVrogUvA4HELjVKWmAvtl6UnCh8jYzuVG5WSb/QEVPnP5TmcAnLH1g+s++v6d4s8m0gCw1fV5/SITLq9mhho8K3+7EPYTU8IU1bLhdxO5Nyt8C8ssinQ98Xw9Q==:".try_into().unwrap());
+
+ req
+ };
- let result = HttpbisSignature::parse_from_request(req).unwrap();
+ let result = HttpbisSignature::parse_from_request(&req).unwrap();
assert_eq!(result.len(), 1);
let result = result.into_iter().next().unwrap();
@@ 856,4 871,30 @@ mod test {
assert!(result.covered_components().is_empty());
}
+
+ #[test]
+ fn test_verify_minimal() {
+ let req = {
+ let mut req = get_sample_request();
+
+ req.headers_mut()
+ .insert(SIGNATURE_INPUT_HEADER, r#"sig-b21=();created=1618884473;keyid="test-key-rsa-pss";nonce="b3k2pp5k7z-50gnwp.yemd""#.try_into().unwrap());
+
+ req.headers_mut()
+ .insert(crate::SIGNATURE_HEADER, "sig-b21=:d2pmTvmbncD3xQm8E9ZV2828BjQWGgiwAaw5bAkgibUopemLJcWDy/lkbbHAve4cRAtx31Iq786U7it++wgGxbtRxf8Udx7zFZsckzXaJMkA7ChG52eSkFxykJeNqsrWH5S+oxNFlD4dzVuwe8DhTSja8xxbR/Z2cOGdCbzR72rgFWhzx2VjBqJzsPLMIQKhO4DGezXehhWwE56YCE+O6c0mKZsfxVrogUvA4HELjVKWmAvtl6UnCh8jYzuVG5WSb/QEVPnP5TmcAnLH1g+s++v6d4s8m0gCw1fV5/SITLq9mhho8K3+7EPYTU8IU1bLhdxO5Nyt8C8ssinQ98Xw9Q==:".try_into().unwrap());
+
+ req
+ };
+
+ let sigs = HttpbisSignature::parse_from_request(&req).unwrap();
+ assert_eq!(sigs.len(), 1);
+
+ let sig = sigs.first().unwrap();
+ let result = sig.verify_request(&req, |content, sig| {
+ assert_eq!(content, br#""@signature-params": ();created=1618884473;keyid="test-key-rsa-pss";nonce="b3k2pp5k7z-50gnwp.yemd""#);
+ Result::<_, std::convert::Infallible>::Ok(true)
+ }).unwrap();
+
+ assert!(result);
+ }
}