Update versions and examples

This commit is contained in:
Aode (Lion) 2022-03-08 12:00:17 -06:00
parent 2d13b04199
commit 02b85e55d8
3 changed files with 99 additions and 71 deletions

View file

@ -1,7 +1,7 @@
[package] [package]
name = "http-signature-normalization-actix" name = "http-signature-normalization-actix"
description = "An HTTP Signatures library that leaves the signing to you" description = "An HTTP Signatures library that leaves the signing to you"
version = "0.6.0" version = "0.6.1"
authors = ["asonix <asonix@asonix.dog>"] authors = ["asonix <asonix@asonix.dog>"]
license-file = "LICENSE" license-file = "LICENSE"
readme = "README.md" readme = "README.md"

View file

@ -13,72 +13,49 @@ This crate provides extensions the ClientRequest type from Actix Web, and provid
#### First, add this crate to your dependencies #### First, add this crate to your dependencies
```toml ```toml
actix-rt = "2.0.2" actix-rt = "2.6.0"
actix-web = "4.0.0-beta.3" actix-web = "4.0.0"
thiserror = "0.1" 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" sha2 = "0.9"
``` ```
#### Then, use it in your client #### Then, use it in your client
```rust ```rust
use actix_web::client::Client; async fn request(config: Config) -> Result<(), Box<dyn std::error::Error>> {
use http_signature_normalization_actix::prelude::*; let digest = Sha256::new();
use sha2::{Digest, Sha256};
#[actix_rt::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = Config::default();
let mut digest = Sha256::new();
let mut response = Client::default() let mut response = Client::default()
.post("http://127.0.0.1:8010/") .post("http://127.0.0.1:8010/")
.header("User-Agent", "Actix Web") .append_header(("User-Agent", "Actix Web"))
.authorization_signature_with_digest(&config, "my-key-id", &mut digest, "My request body", |s| { .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> Ok(base64::encode(s)) as Result<_, MyError>
})? })
.await? .await?
.send() .send()
.await .await
.map_err(|e| { .map_err(|e| {
eprintln!("Error, {}", e); error!("Error, {}", e);
MyError::SendRequest MyError::SendRequest
})?; })?;
let body = response.body().await.map_err(|e| { let body = response.body().await.map_err(|e| {
eprintln!("Error, {}", e); error!("Error, {}", e);
MyError::Body MyError::Body
})?; })?;
println!("{:?}", body); info!("{:?}", body);
Ok(()) 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 #### Or, use it in your server
```rust ```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)] #[derive(Clone, Debug)]
struct MyVerify; struct MyVerify;
@ -95,39 +72,52 @@ impl SignatureVerify for MyVerify {
) -> Self::Future { ) -> Self::Future {
match algorithm { match algorithm {
Some(Algorithm::Hs2019) => (), Some(Algorithm::Hs2019) => (),
_ => return err(MyError::Algorithm), _ => return ready(Err(MyError::Algorithm)),
}; };
if key_id != "my-key-id" { if key_id != "my-key-id" {
return err(MyError::Key); return ready(Err(MyError::Key));
} }
let decoded = match base64::decode(&signature) { let decoded = match base64::decode(&signature) {
Ok(decoded) => decoded, 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 { async fn index(
println!("Signature verified for {}", sig_verified.key_id()); (_, sig_verified): (DigestVerified, SignatureVerified),
req: HttpRequest,
_body: web::Bytes,
) -> &'static str {
info!("Verified request for {}", sig_verified.key_id());
info!("{:?}", req);
"Eyyyyup" "Eyyyyup"
} }
#[actix_rt::main] #[actix_rt::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
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 || { HttpServer::new(move || {
App::new() App::new()
.wrap(VerifyDigest::new(Sha256::new()).optional()) .wrap(VerifyDigest::new(Sha256::new()).optional())
.wrap( .wrap(VerifySignature::new(MyVerify, config.clone()).optional())
VerifySignature::new(MyVerify, config.clone()) .wrap(TracingLogger::default())
.authorization()
.optional(),
)
.route("/", web::post().to(index)) .route("/", web::post().to(index))
}) })
.bind("127.0.0.1:8010")? .bind("127.0.0.1:8010")?
@ -139,7 +129,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
enum MyError { enum MyError {
#[error("Failed to verify, {}", _0)] #[error("Failed to verify, {0}")]
Verify(#[from] PrepareVerifyError), Verify(#[from] PrepareVerifyError),
#[error("Unsupported algorithm")] #[error("Unsupported algorithm")]

View file

@ -8,10 +8,14 @@
//! //!
//! ### Use it in a server //! ### Use it in a server
//! ```rust,ignore //! ```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 http_signature_normalization_actix::prelude::*;
//! use sha2::{Digest, Sha256}; //! use sha2::{Digest, Sha256};
//! use std::future::{ready, Ready}; //! 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)] //! #[derive(Clone, Debug)]
//! struct MyVerify; //! struct MyVerify;
@ -41,27 +45,40 @@
//! Err(_) => return ready(Err(MyError::Decode)), //! Err(_) => return ready(Err(MyError::Decode)),
//! }; //! };
//! //!
//! info!("Signing String\n{}", signing_string);
//!
//! ready(Ok(decoded == signing_string.as_bytes())) //! ready(Ok(decoded == signing_string.as_bytes()))
//! } //! }
//! } //! }
//! //!
//! async fn index((_, sig_verified): (DigestVerified, SignatureVerified)) -> &'static str { //! async fn index(
//! println!("Signature verified for {}", sig_verified.key_id()); //! (_, sig_verified): (DigestVerified, SignatureVerified),
//! req: HttpRequest,
//! _body: web::Bytes,
//! ) -> &'static str {
//! info!("Verified request for {}", sig_verified.key_id());
//! info!("{:?}", req);
//! "Eyyyyup" //! "Eyyyyup"
//! } //! }
//! //!
//! #[actix_rt::main] //! #[actix_rt::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> { //! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! 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 || { //! HttpServer::new(move || {
//! App::new() //! App::new()
//! .wrap(VerifyDigest::new(Sha256::new()).optional()) //! .wrap(VerifyDigest::new(Sha256::new()).optional())
//! .wrap( //! .wrap(VerifySignature::new(MyVerify, config.clone()).optional())
//! VerifySignature::new(MyVerify, config.clone()) //! .wrap(TracingLogger::default())
//! .authorization()
//! .optional(),
//! )
//! .route("/", web::post().to(index)) //! .route("/", web::post().to(index))
//! }) //! })
//! .bind("127.0.0.1:8010")? //! .bind("127.0.0.1:8010")?
@ -73,7 +90,7 @@
//! //!
//! #[derive(Debug, thiserror::Error)] //! #[derive(Debug, thiserror::Error)]
//! enum MyError { //! enum MyError {
//! #[error("Failed to verify, {}", _0)] //! #[error("Failed to verify, {0}")]
//! Verify(#[from] PrepareVerifyError), //! Verify(#[from] PrepareVerifyError),
//! //!
//! #[error("Unsupported algorithm")] //! #[error("Unsupported algorithm")]
@ -103,34 +120,55 @@
//! use awc::Client; //! use awc::Client;
//! use http_signature_normalization_actix::prelude::*; //! use http_signature_normalization_actix::prelude::*;
//! use sha2::{Digest, Sha256}; //! 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 request(config: Config) -> Result<(), Box<dyn std::error::Error>> {
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let config = Config::default();
//! let digest = Sha256::new(); //! let digest = Sha256::new();
//! //!
//! let mut response = Client::default() //! let mut response = Client::default()
//! .post("http://127.0.0.1:8010/") //! .post("http://127.0.0.1:8010/")
//! .header("User-Agent", "Actix Web") //! .append_header(("User-Agent", "Actix Web"))
//! .set(actix_web::http::header::Date(SystemTime::now().into())) //! .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| { //! .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> //! Ok(base64::encode(s)) as Result<_, MyError>
//! }) //! })
//! .await? //! .await?
//! .send() //! .send()
//! .await //! .await
//! .map_err(|e| { //! .map_err(|e| {
//! eprintln!("Error, {}", e); //! error!("Error, {}", e);
//! MyError::SendRequest //! MyError::SendRequest
//! })?; //! })?;
//! //!
//! let body = response.body().await.map_err(|e| { //! let body = response.body().await.map_err(|e| {
//! eprintln!("Error, {}", e); //! error!("Error, {}", e);
//! MyError::Body //! MyError::Body
//! })?; //! })?;
//! //!
//! println!("{:?}", body); //! info!("{:?}", body);
//! Ok(())
//! }
//!
//! #[actix_rt::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! 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(()) //! Ok(())
//! } //! }
//! //!
@ -154,7 +192,7 @@
//! //!
//! impl From<JoinError> for MyError { //! impl From<JoinError> for MyError {
//! fn from(_: JoinError) -> Self { //! fn from(_: JoinError) -> Self {
//! MyError::Canceled, //! MyError::Canceled
//! } //! }
//! } //! }
//! ``` //! ```