mirror of
https://git.asonix.dog/asonix/http-signature-normalization.git
synced 2024-06-13 02:39:34 +00:00
171 lines
4.4 KiB
Rust
171 lines
4.4 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_digest_bytes<D>(
|
|
verifier: impl Filter<Extract = (D,), Error = Rejection> + Clone,
|
|
) -> impl Filter<Extract = (Bytes,), Error = Rejection> + Clone
|
|
where
|
|
D: DigestVerify + Send,
|
|
{
|
|
verifier
|
|
.and(parse_digest_header())
|
|
.and(body::bytes())
|
|
.and_then(|mut verifier: D, parts: Vec<DigestPart>, bytes: Bytes| {
|
|
async move {
|
|
if verifier.verify(&parts, &bytes) {
|
|
Ok(bytes)
|
|
} else {
|
|
Err(warp::reject::custom(VerifyError))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
pub fn verify_digest_json<D, T>(
|
|
verifier: impl Filter<Extract = (D,), Error = Rejection> + Clone,
|
|
) -> impl Filter<Extract = (T,), Error = Rejection> + Clone
|
|
where
|
|
D: DigestVerify + Send,
|
|
T: serde::de::DeserializeOwned,
|
|
{
|
|
verify_digest_bytes(verifier).and_then(|bytes: Bytes| {
|
|
async move {
|
|
serde_json::from_slice(&bytes).map_err(|_| warp::reject::custom(ParseBodyError))
|
|
}
|
|
})
|
|
}
|
|
|
|
pub fn verify_digest_form<D, T>(
|
|
verifier: impl Filter<Extract = (D,), Error = Rejection> + Clone,
|
|
) -> impl Filter<Extract = (T,), Error = Rejection> + Clone
|
|
where
|
|
D: DigestVerify + Send,
|
|
T: serde::de::DeserializeOwned,
|
|
{
|
|
verify_digest_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 {}
|