mirror of
https://git.asonix.dog/asonix/http-signature-normalization.git
synced 2024-11-25 02:41:00 +00:00
Fix header strings
This commit is contained in:
parent
1202b7ff43
commit
421eb3520e
8 changed files with 122 additions and 15 deletions
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "http-signature-normalization"
|
||||
description = "An HTTP Signatures library that leaves the signing to you"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
authors = ["asonix <asonix@asonix.dog>"]
|
||||
license-file = "LICENSE"
|
||||
readme = "README.md"
|
||||
|
@ -15,6 +15,7 @@ edition = "2018"
|
|||
members = [
|
||||
"http-signature-normalization-actix",
|
||||
"http-signature-normalization-http",
|
||||
"http-signature-normalization-reqwest",
|
||||
"http-signature-normalization-warp",
|
||||
]
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "http-signature-normalization-actix"
|
||||
description = "An HTTP Signatures library that leaves the signing to you"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["asonix <asonix@asonix.dog>"]
|
||||
license-file = "LICENSE"
|
||||
readme = "README.md"
|
||||
|
@ -29,7 +29,7 @@ actix-web = "1.0"
|
|||
base64 = { version = "0.10", optional = true }
|
||||
failure = "0.1"
|
||||
futures = "0.1"
|
||||
http-signature-normalization = { version = "0.1.0", path = ".." }
|
||||
http-signature-normalization = { version = "0.2.0", path = ".." }
|
||||
sha2 = { version = "0.8", optional = true }
|
||||
sha3 = { version = "0.8", optional = true }
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "http-signature-normalization-http"
|
||||
description = "An HTTP Signatures library that leaves the signing to you"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
authors = ["asonix <asonix@asonix.dog>"]
|
||||
license-file = "../LICENSE"
|
||||
readme = "../README.md"
|
||||
|
@ -13,4 +13,4 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
http = "0.2"
|
||||
http-signature-normalization = { version = "0.1.0", path = ".." }
|
||||
http-signature-normalization = { version = "0.2.0", path = ".." }
|
||||
|
|
13
http-signature-normalization-reqwest/Cargo.toml
Normal file
13
http-signature-normalization-reqwest/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "http-signature-normalization-reqwest"
|
||||
version = "0.1.0"
|
||||
authors = ["asonix <asonix@asonix.dog>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.10"
|
||||
http = "0.2.0"
|
||||
http-signature-normalization = { version = "0.2.0", path = ".." }
|
||||
reqwest = "0.10.1"
|
88
http-signature-normalization-reqwest/src/lib.rs
Normal file
88
http-signature-normalization-reqwest/src/lib.rs
Normal file
|
@ -0,0 +1,88 @@
|
|||
use chrono::Duration;
|
||||
use http_signature_normalization::create::Signed;
|
||||
use reqwest::{
|
||||
header::{InvalidHeaderValue, ToStrError},
|
||||
Request,
|
||||
};
|
||||
use std::fmt::Display;
|
||||
|
||||
pub struct Config(http_signature_normalization::Config);
|
||||
|
||||
pub trait Sign {
|
||||
fn authorization_signature<F, E, K>(self, config: &Config, key_id: K, f: F) -> Result<Self, E>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnOnce(&str) -> Result<String, E>,
|
||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
||||
K: Display;
|
||||
|
||||
fn signature<F, E, K>(self, config: &Config, key_id: K, f: F) -> Result<Self, E>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnOnce(&str) -> Result<String, E>,
|
||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
||||
K: Display;
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(expires_after: Duration) -> Self {
|
||||
Config(http_signature_normalization::Config { expires_after })
|
||||
}
|
||||
}
|
||||
|
||||
impl Sign for Request {
|
||||
fn authorization_signature<F, E, K>(
|
||||
mut self,
|
||||
config: &Config,
|
||||
key_id: K,
|
||||
f: F,
|
||||
) -> Result<Self, E>
|
||||
where
|
||||
F: FnOnce(&str) -> Result<String, E>,
|
||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
||||
K: Display,
|
||||
{
|
||||
let signed = prepare(&self, config, key_id, f)?;
|
||||
|
||||
let auth_header = signed.authorization_header();
|
||||
self.headers_mut()
|
||||
.insert("Authorization", auth_header.parse()?);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn signature<F, E, K>(mut self, config: &Config, key_id: K, f: F) -> Result<Self, E>
|
||||
where
|
||||
F: FnOnce(&str) -> Result<String, E>,
|
||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
||||
K: Display,
|
||||
{
|
||||
let signed = prepare(&self, config, key_id, f)?;
|
||||
|
||||
let sig_header = signed.signature_header();
|
||||
self.headers_mut().insert("Signature", sig_header.parse()?);
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare<F, E, K>(req: &Request, config: &Config, key_id: K, f: F) -> Result<Signed, E>
|
||||
where
|
||||
F: FnOnce(&str) -> Result<String, E>,
|
||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
||||
K: Display,
|
||||
{
|
||||
let mut bt = std::collections::BTreeMap::new();
|
||||
for (k, v) in req.headers().iter() {
|
||||
bt.insert(k.as_str().to_owned(), v.to_str()?.to_owned());
|
||||
}
|
||||
let path_and_query = if let Some(query) = req.url().query() {
|
||||
format!("{}?{}", req.url().path(), query)
|
||||
} else {
|
||||
req.url().path().to_string()
|
||||
};
|
||||
let unsigned = config
|
||||
.0
|
||||
.begin_sign(req.method().as_str(), &path_and_query, bt);
|
||||
|
||||
let signed = unsigned.sign(key_id.to_string(), f)?;
|
||||
Ok(signed)
|
||||
}
|
|
@ -15,7 +15,7 @@ base64 = { version = "0.11.0", optional = true }
|
|||
bytes = "0.5.3"
|
||||
futures = "0.3.1"
|
||||
http = "0.2.0"
|
||||
http-signature-normalization-http = { version = "0.2.0", path = "../http-signature-normalization-http" }
|
||||
http-signature-normalization-http = { version = "0.3.0", path = "../http-signature-normalization-http" }
|
||||
serde = { version = "1.0.104", features = ["derive"], optional = true }
|
||||
serde_json = { version = "1.0.44", optional = true }
|
||||
serde_urlencoded = { version = "0.6.1", optional = true }
|
||||
|
|
|
@ -38,9 +38,8 @@ pub struct ParseBodyError;
|
|||
pub fn verify_bytes(
|
||||
verifier: impl DigestVerify + Clone + Send,
|
||||
) -> impl Filter<Extract = (Bytes,), Error = Rejection> + Clone {
|
||||
parse_digest_header()
|
||||
.and(body::bytes())
|
||||
.and_then(move |parts: Vec<DigestPart>, bytes: Bytes| {
|
||||
parse_digest_header().and(body::bytes()).and_then(
|
||||
move |parts: Vec<DigestPart>, bytes: Bytes| {
|
||||
let mut verifier = verifier.clone();
|
||||
async move {
|
||||
if verifier.verify(&parts, &bytes) {
|
||||
|
@ -49,11 +48,12 @@ pub fn verify_bytes(
|
|||
Err(warp::reject::custom(VerifyError))
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn verify_json<T>(
|
||||
verifier: impl DigestVerify + Clone + Send
|
||||
verifier: impl DigestVerify + Clone + Send,
|
||||
) -> impl Filter<Extract = (T,), Error = Rejection> + Clone
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
|
@ -117,7 +117,9 @@ where
|
|||
V: DigestVerify,
|
||||
{
|
||||
fn verify(&mut self, parts: &[DigestPart], payload: &[u8]) -> bool {
|
||||
self.0.verify(parts, payload) || self.1.verify(parts, payload) || self.2.verify(parts, payload)
|
||||
self.0.verify(parts, payload)
|
||||
|| self.1.verify(parts, payload)
|
||||
|| self.2.verify(parts, payload)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,7 +131,10 @@ where
|
|||
W: DigestVerify,
|
||||
{
|
||||
fn verify(&mut self, parts: &[DigestPart], payload: &[u8]) -> bool {
|
||||
self.0.verify(parts, payload) || self.1.verify(parts, payload) || self.2.verify(parts, payload) || self.3.verify(parts, payload)
|
||||
self.0.verify(parts, payload)
|
||||
|| self.1.verify(parts, payload)
|
||||
|| self.2.verify(parts, payload)
|
||||
|| self.3.verify(parts, payload)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,14 +35,14 @@ impl Signed {
|
|||
///
|
||||
/// Done manually, it would look like `format!("Signature: {}", signed.signature_header())`
|
||||
pub fn signature_header(self) -> String {
|
||||
format!("Signature {}", self.into_header())
|
||||
self.into_header()
|
||||
}
|
||||
|
||||
/// Turn the Signed type into a String that can be used as the Authorization Header
|
||||
///
|
||||
/// Done manually, it would look like `format!("Authorization: {}", signed.authorization_header())`
|
||||
pub fn authorization_header(self) -> String {
|
||||
self.into_header()
|
||||
format!("Signature {}", self.into_header())
|
||||
}
|
||||
|
||||
fn into_header(self) -> String {
|
||||
|
|
Loading…
Reference in a new issue