use bytes::BytesMut; use std::str::FromStr; use warp::{header, Filter, Rejection}; #[cfg(feature = "sha-2")] mod sha_2; pub trait DigestVerify { fn verify(&mut self, digests: &[DigestPart], payload: &[u8]) -> bool; } #[derive(Clone, Debug)] pub struct DigestPart { pub algorithm: String, pub digest: String, } struct Digest { parts: Vec, } #[derive(Clone, Debug, thiserror::Error)] #[error("Could not verify digest")] pub struct VerifyError; #[derive(Clone, Debug, thiserror::Error)] pub enum ParseDigestError { #[error("Missing algorithm")] Algorithm, #[error("Missing digest")] Digest, } #[derive(Clone, Debug, thiserror::Error)] #[error("Could not parse request body")] pub struct ParseBodyError; pub fn verify( verifier: impl DigestVerify + Clone + Send + Sync + 'static, ) -> impl Filter + Clone { parse_digest_header() .and(warp::body::inspect_request_body( BytesMut::new(), move |mut acc, bytes| { acc.extend_from_slice(bytes); async move { acc } }, )) .and_then(move |parts: Vec, bytes_mut: BytesMut| { let mut verifier = verifier.clone(); async move { if verifier.verify(&parts, &bytes_mut.freeze()) { Ok(()) } else { Err(warp::reject::custom(VerifyError)) } } }) } fn parse_digest_header() -> impl Filter,), Error = Rejection> + Clone { header::header::("Digest").map(|d: Digest| d.parts) } impl DigestVerify for Vec where T: DigestVerify, { fn verify(&mut self, parts: &[DigestPart], payload: &[u8]) -> bool { self.iter_mut().any(|d| d.verify(parts, payload)) } } impl DigestVerify for &mut [T] where T: DigestVerify, { fn verify(&mut self, parts: &[DigestPart], payload: &[u8]) -> bool { self.iter_mut().any(|d| d.verify(parts, payload)) } } impl DigestVerify for (T, U) where T: DigestVerify, U: DigestVerify, { fn verify(&mut self, parts: &[DigestPart], payload: &[u8]) -> bool { self.0.verify(parts, payload) || self.1.verify(parts, payload) } } impl DigestVerify for (T, U, V) where T: DigestVerify, U: DigestVerify, V: DigestVerify, { fn verify(&mut self, parts: &[DigestPart], payload: &[u8]) -> bool { self.0.verify(parts, payload) || self.1.verify(parts, payload) || self.2.verify(parts, payload) } } impl DigestVerify for (T, U, V, W) where T: DigestVerify, U: DigestVerify, V: DigestVerify, W: DigestVerify, { fn verify(&mut self, parts: &[DigestPart], payload: &[u8]) -> bool { self.0.verify(parts, payload) || self.1.verify(parts, payload) || self.2.verify(parts, payload) || self.3.verify(parts, payload) } } impl FromStr for DigestPart { type Err = ParseDigestError; fn from_str(s: &str) -> Result { let mut iter = s.splitn(2, "="); let algorithm = iter.next().ok_or(ParseDigestError::Algorithm)?; let digest = iter.next().ok_or(ParseDigestError::Digest)?; Ok(DigestPart { algorithm: algorithm.to_owned(), digest: digest.to_owned(), }) } } impl FromStr for Digest { type Err = ParseDigestError; fn from_str(s: &str) -> Result { let parts: Result, Self::Err> = s .split(",") .map(|s: &str| DigestPart::from_str(s)) .collect(); Ok(Digest { parts: parts? }) } } impl warp::reject::Reject for VerifyError {} impl warp::reject::Reject for ParseBodyError {}