diff --git a/http-signature-normalization-actix/Cargo.toml b/http-signature-normalization-actix/Cargo.toml index 8646e5d..4bded05 100644 --- a/http-signature-normalization-actix/Cargo.toml +++ b/http-signature-normalization-actix/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "http-signature-normalization-actix" description = "An HTTP Signatures library that leaves the signing to you" -version = "0.6.0" +version = "0.6.1" authors = ["asonix "] license-file = "LICENSE" readme = "README.md" diff --git a/http-signature-normalization-actix/README.md b/http-signature-normalization-actix/README.md index 673870e..82a7ca6 100644 --- a/http-signature-normalization-actix/README.md +++ b/http-signature-normalization-actix/README.md @@ -13,72 +13,49 @@ This crate provides extensions the ClientRequest type from Actix Web, and provid #### First, add this crate to your dependencies ```toml -actix-rt = "2.0.2" -actix-web = "4.0.0-beta.3" +actix-rt = "2.6.0" +actix-web = "4.0.0" thiserror = "0.1" -http-signature-normalization-actix = { version = "0.5.0-beta.2", default-features = false, features = ["sha-2"] } +http-signature-normalization-actix = { version = "0.6.0", default-features = false, features = ["sha-2"] } sha2 = "0.9" ``` #### Then, use it in your client ```rust -use actix_web::client::Client; -use http_signature_normalization_actix::prelude::*; -use sha2::{Digest, Sha256}; - -#[actix_rt::main] -async fn main() -> Result<(), Box> { - let config = Config::default(); - let mut digest = Sha256::new(); +async fn request(config: Config) -> Result<(), Box> { + let digest = Sha256::new(); let mut response = Client::default() .post("http://127.0.0.1:8010/") - .header("User-Agent", "Actix Web") - .authorization_signature_with_digest(&config, "my-key-id", &mut digest, "My request body", |s| { + .append_header(("User-Agent", "Actix Web")) + .append_header(("Accept", "text/plain")) + .insert_header(actix_web::http::header::Date(SystemTime::now().into())) + .signature_with_digest(config, "my-key-id", digest, "Hewwo-owo", |s| { + info!("Signing String\n{}", s); Ok(base64::encode(s)) as Result<_, MyError> - })? + }) .await? .send() .await .map_err(|e| { - eprintln!("Error, {}", e); + error!("Error, {}", e); MyError::SendRequest })?; let body = response.body().await.map_err(|e| { - eprintln!("Error, {}", e); + error!("Error, {}", e); MyError::Body })?; - println!("{:?}", body); + info!("{:?}", body); Ok(()) } - -#[derive(Debug, thiserror::Error)] -pub enum MyError { - #[error("Failed to read header, {0}")] - Convert(#[from] ToStrError), - - #[error("Failed to create header, {0}")] - Header(#[from] InvalidHeaderValue), - - #[error("Failed to send request")] - SendRequest, - - #[error("Failed to retrieve request body")] - Body, -} ``` #### Or, use it in your server ```rust -use actix_web::{http::StatusCode, web, App, HttpResponse, HttpServer, ResponseError}; -use futures::future::{err, ok, Ready}; -use http_signature_normalization_actix::prelude::*; -use sha2::{Digest, Sha256}; - #[derive(Clone, Debug)] struct MyVerify; @@ -95,39 +72,52 @@ impl SignatureVerify for MyVerify { ) -> Self::Future { match algorithm { Some(Algorithm::Hs2019) => (), - _ => return err(MyError::Algorithm), + _ => return ready(Err(MyError::Algorithm)), }; if key_id != "my-key-id" { - return err(MyError::Key); + return ready(Err(MyError::Key)); } let decoded = match base64::decode(&signature) { Ok(decoded) => decoded, - Err(_) => return err(MyError::Decode), + Err(_) => return ready(Err(MyError::Decode)), }; - ok(decoded == signing_string.as_bytes()) + info!("Signing String\n{}", signing_string); + + ready(Ok(decoded == signing_string.as_bytes())) } } -async fn index((_, sig_verified): (DigestVerified, SignatureVerified)) -> &'static str { - println!("Signature verified for {}", sig_verified.key_id()); +async fn index( + (_, sig_verified): (DigestVerified, SignatureVerified), + req: HttpRequest, + _body: web::Bytes, +) -> &'static str { + info!("Verified request for {}", sig_verified.key_id()); + info!("{:?}", req); "Eyyyyup" } #[actix_rt::main] async fn main() -> Result<(), Box> { - let config = Config::default(); + let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); + + let subscriber = tracing_subscriber::Registry::default() + .with(env_filter) + .with(ErrorLayer::default()) + .with(tracing_subscriber::fmt::layer()); + + tracing::subscriber::set_global_default(subscriber)?; + + let config = Config::default().require_header("accept").require_digest(); HttpServer::new(move || { App::new() .wrap(VerifyDigest::new(Sha256::new()).optional()) - .wrap( - VerifySignature::new(MyVerify, config.clone()) - .authorization() - .optional(), - ) + .wrap(VerifySignature::new(MyVerify, config.clone()).optional()) + .wrap(TracingLogger::default()) .route("/", web::post().to(index)) }) .bind("127.0.0.1:8010")? @@ -139,7 +129,7 @@ async fn main() -> Result<(), Box> { #[derive(Debug, thiserror::Error)] enum MyError { - #[error("Failed to verify, {}", _0)] + #[error("Failed to verify, {0}")] Verify(#[from] PrepareVerifyError), #[error("Unsupported algorithm")] diff --git a/http-signature-normalization-actix/src/lib.rs b/http-signature-normalization-actix/src/lib.rs index 6a7694f..05c9dd2 100644 --- a/http-signature-normalization-actix/src/lib.rs +++ b/http-signature-normalization-actix/src/lib.rs @@ -8,10 +8,14 @@ //! //! ### Use it in a server //! ```rust,ignore -//! use actix_web::{http::StatusCode, web, App, HttpResponse, HttpServer, ResponseError}; +//! use actix_web::{http::StatusCode, web, App, HttpRequest, HttpResponse, HttpServer, ResponseError}; //! use http_signature_normalization_actix::prelude::*; //! use sha2::{Digest, Sha256}; //! use std::future::{ready, Ready}; +//! use tracing::info; +//! use tracing_actix_web::TracingLogger; +//! use tracing_error::ErrorLayer; +//! use tracing_subscriber::{layer::SubscriberExt, EnvFilter}; //! //! #[derive(Clone, Debug)] //! struct MyVerify; @@ -41,27 +45,40 @@ //! Err(_) => return ready(Err(MyError::Decode)), //! }; //! +//! info!("Signing String\n{}", signing_string); +//! //! ready(Ok(decoded == signing_string.as_bytes())) //! } //! } //! -//! async fn index((_, sig_verified): (DigestVerified, SignatureVerified)) -> &'static str { -//! println!("Signature verified for {}", sig_verified.key_id()); +//! async fn index( +//! (_, sig_verified): (DigestVerified, SignatureVerified), +//! req: HttpRequest, +//! _body: web::Bytes, +//! ) -> &'static str { +//! info!("Verified request for {}", sig_verified.key_id()); +//! info!("{:?}", req); //! "Eyyyyup" //! } //! //! #[actix_rt::main] //! async fn main() -> Result<(), Box> { -//! let config = Config::default(); +//! let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); +//! +//! let subscriber = tracing_subscriber::Registry::default() +//! .with(env_filter) +//! .with(ErrorLayer::default()) +//! .with(tracing_subscriber::fmt::layer()); +//! +//! tracing::subscriber::set_global_default(subscriber)?; +//! +//! let config = Config::default().require_header("accept").require_digest(); //! //! HttpServer::new(move || { //! App::new() //! .wrap(VerifyDigest::new(Sha256::new()).optional()) -//! .wrap( -//! VerifySignature::new(MyVerify, config.clone()) -//! .authorization() -//! .optional(), -//! ) +//! .wrap(VerifySignature::new(MyVerify, config.clone()).optional()) +//! .wrap(TracingLogger::default()) //! .route("/", web::post().to(index)) //! }) //! .bind("127.0.0.1:8010")? @@ -73,7 +90,7 @@ //! //! #[derive(Debug, thiserror::Error)] //! enum MyError { -//! #[error("Failed to verify, {}", _0)] +//! #[error("Failed to verify, {0}")] //! Verify(#[from] PrepareVerifyError), //! //! #[error("Unsupported algorithm")] @@ -103,34 +120,55 @@ //! use awc::Client; //! use http_signature_normalization_actix::prelude::*; //! use sha2::{Digest, Sha256}; +//! use std::time::SystemTime; +//! use tracing::{error, info}; +//! use tracing_error::ErrorLayer; +//! use tracing_subscriber::{layer::SubscriberExt, EnvFilter}; //! -//! #[actix_rt::main] -//! async fn main() -> Result<(), Box> { -//! let config = Config::default(); +//! async fn request(config: Config) -> Result<(), Box> { //! let digest = Sha256::new(); //! //! let mut response = Client::default() //! .post("http://127.0.0.1:8010/") -//! .header("User-Agent", "Actix Web") -//! .set(actix_web::http::header::Date(SystemTime::now().into())) +//! .append_header(("User-Agent", "Actix Web")) +//! .append_header(("Accept", "text/plain")) +//! .insert_header(actix_web::http::header::Date(SystemTime::now().into())) //! .signature_with_digest(config, "my-key-id", digest, "Hewwo-owo", |s| { -//! println!("Signing String\n{}", s); +//! info!("Signing String\n{}", s); //! Ok(base64::encode(s)) as Result<_, MyError> //! }) //! .await? //! .send() //! .await //! .map_err(|e| { -//! eprintln!("Error, {}", e); +//! error!("Error, {}", e); //! MyError::SendRequest //! })?; //! //! let body = response.body().await.map_err(|e| { -//! eprintln!("Error, {}", e); +//! error!("Error, {}", e); //! MyError::Body //! })?; //! -//! println!("{:?}", body); +//! info!("{:?}", body); +//! Ok(()) +//! } +//! +//! #[actix_rt::main] +//! async fn main() -> Result<(), Box> { +//! let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); +//! +//! let subscriber = tracing_subscriber::Registry::default() +//! .with(env_filter) +//! .with(ErrorLayer::default()) +//! .with(tracing_subscriber::fmt::layer()); +//! +//! tracing::subscriber::set_global_default(subscriber)?; +//! +//! let config = Config::default().require_header("accept").require_digest(); +//! +//! request(config.clone()).await?; +//! request(config.mastodon_compat()).await?; //! Ok(()) //! } //! @@ -154,7 +192,7 @@ //! //! impl From for MyError { //! fn from(_: JoinError) -> Self { -//! MyError::Canceled, +//! MyError::Canceled //! } //! } //! ```