mirror of
https://git.asonix.dog/asonix/http-signature-normalization.git
synced 2024-11-22 09:21:00 +00:00
Add client digest support
This commit is contained in:
parent
73ee0c51e6
commit
ef2a4e338f
2 changed files with 120 additions and 0 deletions
|
@ -8,10 +8,15 @@ readme = "../README.md"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
digest = ["base64", "futures"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "1.0"
|
actix-web = "1.0"
|
||||||
|
base64 = { version = "0.10", optional = true }
|
||||||
http-signature-normalization = { version = "0.1.0", path = ".." }
|
http-signature-normalization = { version = "0.1.0", path = ".." }
|
||||||
|
futures = { version = "0.1", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix = "0.8"
|
actix = "0.8"
|
||||||
|
|
|
@ -14,9 +14,17 @@ use std::{
|
||||||
fmt::{self, Display},
|
fmt::{self, Display},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
use actix_web::{client::ClientResponse, error::PayloadError, web::Bytes};
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
use futures::{Future, Stream};
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{verify::Unverified, Config, Sign, Verify, VerifyError};
|
pub use crate::{verify::Unverified, Config, Sign, Verify, VerifyError};
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
pub use crate::Digest;
|
||||||
|
|
||||||
pub use actix_web::http::header::{InvalidHeaderValue, ToStrError};
|
pub use actix_web::http::header::{InvalidHeaderValue, ToStrError};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +42,13 @@ use self::{
|
||||||
verify::Unverified,
|
verify::Unverified,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
pub trait Digest {
|
||||||
|
const NAME: &'static str;
|
||||||
|
|
||||||
|
fn compute(input: &[u8]) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Verify {
|
pub trait Verify {
|
||||||
fn begin_verify(&self, config: &Config) -> Result<Unverified, VerifyError>;
|
fn begin_verify(&self, config: &Config) -> Result<Unverified, VerifyError>;
|
||||||
}
|
}
|
||||||
|
@ -52,6 +67,38 @@ pub trait Sign {
|
||||||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
E: From<ToStrError> + From<InvalidHeaderValue>,
|
||||||
K: Display,
|
K: Display,
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
fn authorization_signature_with_digest<F, E, K, D, V>(
|
||||||
|
self,
|
||||||
|
config: &Config,
|
||||||
|
key_id: K,
|
||||||
|
f: F,
|
||||||
|
v: V,
|
||||||
|
) -> Result<DigestClient<V>, E>
|
||||||
|
where
|
||||||
|
F: FnOnce(&str) -> Result<Vec<u8>, E>,
|
||||||
|
E: From<ToStrError> + From<InvalidHeaderValue>,
|
||||||
|
K: Display,
|
||||||
|
D: Digest,
|
||||||
|
V: AsRef<[u8]>,
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
fn signature_with_digest<F, E, K, D, V>(
|
||||||
|
self,
|
||||||
|
config: &Config,
|
||||||
|
key_id: K,
|
||||||
|
f: F,
|
||||||
|
v: V,
|
||||||
|
) -> Result<DigestClient<V>, E>
|
||||||
|
where
|
||||||
|
F: FnOnce(&str) -> Result<Vec<u8>, E>,
|
||||||
|
E: From<ToStrError> + From<InvalidHeaderValue>,
|
||||||
|
K: Display,
|
||||||
|
D: Digest,
|
||||||
|
V: AsRef<[u8]>,
|
||||||
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
|
@ -59,6 +106,28 @@ pub struct Config {
|
||||||
pub config: http_signature_normalization::Config,
|
pub config: http_signature_normalization::Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
pub struct DigestClient<V> {
|
||||||
|
req: ClientRequest,
|
||||||
|
body: V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
impl<V> DigestClient<V>
|
||||||
|
where
|
||||||
|
V: AsRef<[u8]>,
|
||||||
|
{
|
||||||
|
pub fn new(req: ClientRequest, body: V) -> Self {
|
||||||
|
DigestClient { req, body }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(
|
||||||
|
self,
|
||||||
|
) -> impl Future<Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>> {
|
||||||
|
self.req.send_body(self.body.as_ref().to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum VerifyError {
|
pub enum VerifyError {
|
||||||
Sig(http_signature_normalization::VerifyError),
|
Sig(http_signature_normalization::VerifyError),
|
||||||
|
@ -158,6 +227,52 @@ impl Sign for ClientRequest {
|
||||||
signed.signature_header(self.headers_mut())?;
|
signed.signature_header(self.headers_mut())?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
fn authorization_signature_with_digest<F, E, K, D, V>(
|
||||||
|
self,
|
||||||
|
config: &Config,
|
||||||
|
key_id: K,
|
||||||
|
f: F,
|
||||||
|
v: V,
|
||||||
|
) -> Result<DigestClient<V>, E>
|
||||||
|
where
|
||||||
|
F: FnOnce(&str) -> Result<Vec<u8>, E>,
|
||||||
|
E: From<ToStrError> + From<InvalidHeaderValue>,
|
||||||
|
K: Display,
|
||||||
|
D: Digest,
|
||||||
|
V: AsRef<[u8]>,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let digest = base64::encode(D::compute(v.as_ref()).as_slice());
|
||||||
|
|
||||||
|
self.set_header("Digest", format!("{}={}", D::NAME, digest))
|
||||||
|
.authorization_signature(config, key_id, f)
|
||||||
|
.map(|c| DigestClient::new(c, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
fn signature_with_digest<F, E, K, D, V>(
|
||||||
|
self,
|
||||||
|
config: &Config,
|
||||||
|
key_id: K,
|
||||||
|
f: F,
|
||||||
|
v: V,
|
||||||
|
) -> Result<DigestClient<V>, E>
|
||||||
|
where
|
||||||
|
F: FnOnce(&str) -> Result<Vec<u8>, E>,
|
||||||
|
E: From<ToStrError> + From<InvalidHeaderValue>,
|
||||||
|
K: Display,
|
||||||
|
D: Digest,
|
||||||
|
V: AsRef<[u8]>,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let digest = base64::encode(D::compute(v.as_ref()).as_slice());
|
||||||
|
|
||||||
|
self.set_header("Digest", format!("{}={}", D::NAME, digest))
|
||||||
|
.signature(config, key_id, f)
|
||||||
|
.map(|c| DigestClient::new(c, v))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare<F, E, K>(request: &ClientRequest, config: &Config, key_id: K, f: F) -> Result<Signed, E>
|
fn prepare<F, E, K>(request: &ClientRequest, config: &Config, key_id: K, f: F) -> Result<Signed, E>
|
||||||
|
|
Loading…
Reference in a new issue