use actix_web::{ client::ClientRequest, dev::ServiceRequest, http::{ header::{HeaderMap, InvalidHeaderValue, ToStrError}, uri::PathAndQuery, Method, }, HttpRequest, }; use std::{ collections::BTreeMap, error::Error, fmt::{self, Display}, }; pub mod prelude { pub use crate::{verify::Unverified, Config, Sign, Verify, VerifyError}; pub use actix_web::http::header::{InvalidHeaderValue, ToStrError}; } pub mod create; pub mod verify { pub use http_signature_normalization::verify::{ Algorithm, DeprecatedAlgorithm, ParseSignatureError, ParsedHeader, Unvalidated, Unverified, ValidateError, }; } use self::{ create::{Signed, Unsigned}, verify::Unverified, }; pub trait Verify { fn begin_verify(&self, config: &Config) -> Result; } pub trait Sign { fn authorization_signature(self, config: &Config, key_id: K, f: F) -> Result where F: FnOnce(&str) -> Result, E>, E: From + From, K: Display, Self: Sized; fn signature(self, config: &Config, key_id: K, f: F) -> Result where F: FnOnce(&str) -> Result, E>, E: From + From, K: Display, Self: Sized; } #[derive(Clone, Default)] pub struct Config { pub config: http_signature_normalization::Config, } #[derive(Debug)] pub enum VerifyError { Sig(http_signature_normalization::VerifyError), Header(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 Verify for HttpRequest { fn begin_verify(&self, config: &Config) -> Result { config.begin_verify( self.method(), self.uri().path_and_query(), self.headers().clone(), ) } } impl Verify for ServiceRequest { fn begin_verify(&self, config: &Config) -> Result { config.begin_verify( self.method(), self.uri().path_and_query(), self.headers().clone(), ) } } impl Sign for ClientRequest { fn authorization_signature( mut self, config: &Config, key_id: K, f: F, ) -> Result where F: FnOnce(&str) -> Result, E>, E: From + From, K: Display, { let signed = prepare(&self, config, key_id, f)?; signed.authorization_header(self.headers_mut())?; Ok(self) } fn signature(mut self, config: &Config, key_id: K, f: F) -> Result where F: FnOnce(&str) -> Result, E>, E: From + From, K: Display, { let signed = prepare(&self, config, key_id, f)?; signed.signature_header(self.headers_mut())?; Ok(self) } } fn prepare(request: &ClientRequest, config: &Config, key_id: K, f: F) -> Result where F: FnOnce(&str) -> Result, E>, E: From, K: Display, { let unsigned = config.begin_sign( request.get_method(), request.get_uri().path_and_query(), request.headers().clone(), )?; let key_id = key_id.to_string(); let signed = unsigned.sign(key_id, f)?; Ok(signed) } impl fmt::Display for VerifyError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { VerifyError::Sig(ref e) => write!(f, "Sig error, {}", e), VerifyError::Header(ref e) => write!(f, "Header error, {}", e), } } } impl Error for VerifyError { fn description(&self) -> &str { match *self { VerifyError::Sig(ref e) => e.description(), VerifyError::Header(ref e) => e.description(), } } fn source(&self) -> Option<&(dyn Error + 'static)> { match *self { VerifyError::Sig(ref e) => Some(e), VerifyError::Header(ref e) => Some(e), } } } 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) } }