use actix_web::http::{ header::{HeaderMap, InvalidHeaderValue, ToStrError}, uri::PathAndQuery, Method, }; use failure::Fail; use futures::future::IntoFuture; use std::{collections::BTreeMap, fmt::Display}; mod sign; #[cfg(feature = "digest")] pub mod digest; pub mod create; pub mod middleware; pub mod prelude { pub use crate::{ middleware::VerifySignature, verify::Unverified, Config, Sign, SignatureVerify, Verify, VerifyError, }; #[cfg(feature = "digest")] pub use crate::digest::{ middleware::VerifyDigest, DigestClient, DigestCreate, DigestPart, DigestVerify, SignExt, }; pub use actix_web::http::header::{InvalidHeaderValue, ToStrError}; } pub mod verify; use self::{ create::Unsigned, verify::{Algorithm, Unverified}, }; pub trait Verify { fn begin_verify(&self, config: &Config) -> Result; } pub trait SignatureVerify { type Error: actix_web::ResponseError; type Future: IntoFuture; fn signature_verify( &mut self, algorithm: Option, key_id: &str, signature: &str, signing_string: &str, ) -> Self::Future; } pub trait Sign { fn authorization_signature(self, config: &Config, key_id: K, f: F) -> Result where F: FnOnce(&str) -> Result, E: From + From, K: Display, Self: Sized; fn signature(self, config: &Config, key_id: K, f: F) -> Result where F: FnOnce(&str) -> Result, E: From + From, K: Display, Self: Sized; } #[derive(Clone, Debug, Default)] pub struct Config { pub config: http_signature_normalization::Config, } #[derive(Debug, Fail)] pub enum VerifyError { #[fail(display = "Signature error, {}", _0)] Sig(#[cause] http_signature_normalization::VerifyError), #[fail(display = "Failed to read header, {}", _0)] Header(#[cause] ToStrError), } impl Config { pub fn begin_sign( &self, method: &Method, path_and_query: Option<&PathAndQuery>, headers: HeaderMap, ) -> Result { let headers = headers .iter() .map(|(k, v)| v.to_str().map(|v| (k.to_string(), v.to_string()))) .collect::, ToStrError>>()?; let path_and_query = path_and_query .map(|p| p.to_string()) .unwrap_or(String::from("/")); let unsigned = self .config .begin_sign(&method.to_string(), &path_and_query, headers); Ok(Unsigned { unsigned }) } pub fn begin_verify( &self, method: &Method, path_and_query: Option<&PathAndQuery>, headers: HeaderMap, ) -> Result { let headers = headers .iter() .map(|(k, v)| v.to_str().map(|v| (k.to_string(), v.to_string()))) .collect::, ToStrError>>()?; let path_and_query = path_and_query .map(|p| p.to_string()) .unwrap_or(String::from("/")); let unverified = self .config .begin_verify(&method.to_string(), &path_and_query, headers)?; Ok(unverified) } } impl From for VerifyError { fn from(e: http_signature_normalization::VerifyError) -> Self { VerifyError::Sig(e) } } impl From for VerifyError { fn from(e: ToStrError) -> Self { VerifyError::Header(e) } }