http-signature-normalization/http-signature-normalization-warp/src/digest/mod.rs
2020-01-17 18:35:30 -06:00

171 lines
4.3 KiB
Rust

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<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_bytes(
verifier: impl DigestVerify + Clone + Send,
) -> impl Filter<Extract = (Bytes,), Error = Rejection> + Clone {
parse_digest_header().and(body::bytes()).and_then(
move |parts: Vec<DigestPart>, 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<T>(
verifier: impl DigestVerify + Clone + Send,
) -> impl Filter<Extract = (T,), Error = Rejection> + 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<T>(
verifier: impl DigestVerify + Clone + Send,
) -> impl Filter<Extract = (T,), Error = Rejection> + 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<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 {}