use bytes::Bytes; use std::str::FromStr; use warp::{body, header, Filter, Rejection}; #[cfg(feature = "sha-2")] mod sha_2; pub trait DigestVerify { fn verify(&mut self, digests: &[DigestPart], payload: &[u8]) -> bool; } 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_bytes( verifier: impl DigestVerify + Clone + Send, ) -> impl Filter + Clone { parse_digest_header().and(body::bytes()).and_then( move |parts: Vec, bytes: Bytes| { let mut verifier = verifier.clone(); async move { if verifier.verify(&parts, &bytes) { Ok(bytes) } else { Err(warp::reject::custom(VerifyError)) } } }, ) } pub fn verify_json( verifier: impl DigestVerify + Clone + Send, ) -> impl Filter + Clone where T: serde::de::DeserializeOwned, { verify_bytes(verifier).and_then(|bytes: Bytes| { async move { serde_json::from_slice(&bytes).map_err(|_| warp::reject::custom(ParseBodyError)) } }) } pub fn verify_form( verifier: impl DigestVerify + Clone + Send, ) -> impl Filter + Clone where T: serde::de::DeserializeOwned, { verify_bytes(verifier).and_then(|bytes: Bytes| { async move { serde_urlencoded::from_bytes(&bytes).map_err(|_| warp::reject::custom(ParseBodyError)) } }) } 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 {}