http-signature-normalization/http-signature-normalization-warp/src/digest/mod.rs
2020-02-17 16:57:07 -06:00

152 lines
3.8 KiB
Rust

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<DigestPart>,
}
#[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<Extract = ((),), Error = Rejection> + 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<DigestPart>, 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<Extract = (Vec<DigestPart>,), Error = Rejection> + Clone {
header::header::<Digest>("Digest").map(|d: Digest| d.parts)
}
impl<T> DigestVerify for Vec<T>
where
T: DigestVerify,
{
fn verify(&mut self, parts: &[DigestPart], payload: &[u8]) -> bool {
self.iter_mut().any(|d| d.verify(parts, payload))
}
}
impl<T> 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<T, U> 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<T, U, V> 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<T, U, V, W> 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<Self, Self::Err> {
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<Self, Self::Err> {
let parts: Result<Vec<DigestPart>, 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 {}