mirror of
https://git.asonix.dog/asonix/http-signature-normalization.git
synced 2024-11-25 10:51:01 +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"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[features]
|
||||
default = []
|
||||
digest = ["base64", "futures"]
|
||||
|
||||
[dependencies]
|
||||
actix-web = "1.0"
|
||||
base64 = { version = "0.10", optional = true }
|
||||
http-signature-normalization = { version = "0.1.0", path = ".." }
|
||||
futures = { version = "0.1", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
actix = "0.8"
|
||||
|
|
|
@ -14,9 +14,17 @@ use std::{
|
|||
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 use crate::{verify::Unverified, Config, Sign, Verify, VerifyError};
|
||||
|
||||
#[cfg(feature = "digest")]
|
||||
pub use crate::Digest;
|
||||
|
||||
pub use actix_web::http::header::{InvalidHeaderValue, ToStrError};
|
||||
}
|
||||
|
||||
|
@ -34,6 +42,13 @@ use self::{
|
|||
verify::Unverified,
|
||||
};
|
||||
|
||||
#[cfg(feature = "digest")]
|
||||
pub trait Digest {
|
||||
const NAME: &'static str;
|
||||
|
||||
fn compute(input: &[u8]) -> Vec<u8>;
|
||||
}
|
||||
|
||||
pub trait Verify {
|
||||
fn begin_verify(&self, config: &Config) -> Result<Unverified, VerifyError>;
|
||||
}
|
||||
|
@ -52,6 +67,38 @@ pub trait Sign {
|
|||
E: From<ToStrError> + From<InvalidHeaderValue>,
|
||||
K: Display,
|
||||
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)]
|
||||
|
@ -59,6 +106,28 @@ pub struct 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)]
|
||||
pub enum VerifyError {
|
||||
Sig(http_signature_normalization::VerifyError),
|
||||
|
@ -158,6 +227,52 @@ impl Sign for ClientRequest {
|
|||
signed.signature_header(self.headers_mut())?;
|
||||
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>
|
||||
|
|
Loading…
Reference in a new issue