//! 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_http::encoding::Decoder; use actix_web::{ client::{ClientRequest, ClientResponse, SendRequestError}, dev::Payload, error::BlockingError, http::header::InvalidHeaderValue, }; 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 { /// Verify the payload of the request against a slice of digests /// /// The slice of digests should never be empty fn verify(&mut self, digests: &[DigestPart], payload: &[u8]) -> 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, ) -> impl Future>, SendRequestError>> { self.req.send_body(self.body.as_ref().to_vec()) } }