mirror of
https://git.asonix.dog/asonix/http-signature-normalization.git
synced 2024-11-25 10:51:01 +00:00
Update versions and examples
This commit is contained in:
parent
2d13b04199
commit
02b85e55d8
3 changed files with 99 additions and 71 deletions
|
@ -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"
|
||||||
|
|
|
@ -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")]
|
||||||
|
|
|
@ -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
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
Loading…
Reference in a new issue