//! 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 #[cfg(feature = "server")] pub mod middleware; #[cfg(feature = "sha-2")] mod sha2; #[cfg(feature = "sha-3")] mod sha3; #[cfg(feature = "client")] mod sign; #[cfg(feature = "client")] pub use self::client::{DigestClient, DigestCreate, SignExt}; #[cfg(feature = "server")] pub use self::server::{DigestPart, DigestVerify}; /// Giving names to Digest implementations pub trait DigestName { /// The name of the digest algorithm const NAME: &'static str; } #[cfg(feature = "client")] mod client { use crate::{Config, PrepareSignError, Sign, Spawn}; use actix_http::header::InvalidHeaderValue; use actix_rt::task::JoinError; use awc::{ClientRequest, SendClientRequest}; use std::{fmt::Display, future::Future, pin::Pin}; use super::DigestName; /// A trait for creating digests of an array of bytes pub trait DigestCreate: DigestName { /// Compute the digest of the input bytes fn compute(&mut self, input: &[u8]) -> String; } /// 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 + From + std::fmt::Debug + Send + 'static, K: Display + 'static, S: Spawn + '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 + From + std::fmt::Debug + Send + 'static, K: Display + 'static, S: Spawn + 'static, D: DigestCreate + Send + 'static, V: AsRef<[u8]> + Send + 'static, Self: Sized; } /// 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]>, { pub(super) 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()) } /// Split the parts of the request /// /// In case the caller needs to interrogate the ClientRequest before sending pub fn split(self) -> (ClientRequest, V) { (self.req, self.body) } } } #[cfg(feature = "server")] mod server { use super::DigestName; /// A trait for verifying digests pub trait DigestVerify: DigestName { /// 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; } /// A parsed digest from the request #[derive(Debug)] pub struct DigestPart { /// The alrogithm used to produce the digest pub algorithm: String, /// The digest itself pub digest: String, } }