//! Types and Traits for creating and verifying Digest headers //! //! Digest headers are commonly used in conjunction with HTTP Signatures to verify the whole //! request when request bodies are present use actix_web::{client::ClientRequest, error::BlockingError, http::header::InvalidHeaderValue}; use awc::SendClientRequest; use std::{fmt::Display, future::Future, pin::Pin}; use crate::{Config, PrepareSignError, Sign}; pub mod middleware; #[cfg(feature = "sha-2")] mod sha2; #[cfg(feature = "sha-3")] mod sha3; mod sign; /// A trait for creating digests of an array of bytes pub trait DigestCreate { /// The name of the digest algorithm const NAME: &'static str; /// Compute the digest of the input bytes fn compute(&mut self, input: &[u8]) -> String; } /// A trait for verifying digests pub trait DigestVerify { /// Update the verifier with bytes from the request body fn update(&mut self, part: &[u8]); /// Verify the request body against the digests from the request headers fn verify(&mut self, digests: &[DigestPart]) -> bool; } /// Extend the Sign trait with support for adding Digest Headers to the request /// /// It generates HTTP Signatures after the Digest header has been added, in order to have /// verification that the body has not been tampered with, or that the request can't be replayed by /// a malicious entity pub trait SignExt: Sign { /// Set the Digest and Authorization headers on the request fn authorization_signature_with_digest( self, config: Config, key_id: K, digest: D, v: V, f: F, ) -> Pin, E>>>> where F: FnOnce(&str) -> Result + Send + 'static, E: From + From + From + std::fmt::Debug + Send + 'static, K: Display + 'static, D: DigestCreate + Send + 'static, V: AsRef<[u8]> + Send + 'static, Self: Sized; /// Set the Digest and Signature headers on the request fn signature_with_digest( self, config: Config, key_id: K, digest: D, v: V, f: F, ) -> Pin, E>>>> where F: FnOnce(&str) -> Result + Send + 'static, E: From + From + From + std::fmt::Debug + Send + 'static, K: Display + 'static, D: DigestCreate + Send + 'static, V: AsRef<[u8]> + Send + 'static, Self: Sized; } /// A parsed digest from the request pub struct DigestPart { /// The alrogithm used to produce the digest pub algorithm: String, /// The digest itself pub digest: String, } /// An intermediate type between setting the Digest and Signature or Authorization headers, and /// actually sending the request /// /// This exists so that the return type for the [`SignExt`] trait can be named pub struct DigestClient { req: ClientRequest, body: V, } impl DigestClient where V: AsRef<[u8]>, { fn new(req: ClientRequest, body: V) -> Self { DigestClient { req, body } } /// Send the request /// /// This is analogous to `ClientRequest::send_body` and uses the body provided when producing /// the digest pub fn send(self) -> SendClientRequest { self.req.send_body(self.body.as_ref().to_vec()) } }