2019-09-21 16:26:11 +00:00
|
|
|
#![deny(missing_docs)]
|
|
|
|
|
|
|
|
//! # Integration of Http Signature Normalization with Actix Web
|
|
|
|
//!
|
|
|
|
//! This library provides middlewares for verifying HTTP Signature headers and, optionally, Digest
|
2021-03-10 02:04:56 +00:00
|
|
|
//! headers with the `digest` feature enabled. It also extends awc's ClientRequest type to
|
2019-09-21 16:26:11 +00:00
|
|
|
//! add signatures and digests to the request
|
|
|
|
//!
|
|
|
|
//! ### Use it in a server
|
|
|
|
//! ```rust,ignore
|
2020-03-16 00:29:47 +00:00
|
|
|
//! use actix_web::{http::StatusCode, web, App, HttpResponse, HttpServer, ResponseError};
|
|
|
|
//! use http_signature_normalization_actix::prelude::*;
|
2019-09-21 16:26:11 +00:00
|
|
|
//! use sha2::{Digest, Sha256};
|
2021-09-18 00:34:16 +00:00
|
|
|
//! use std::future::{ready, Ready};
|
2019-09-21 16:26:11 +00:00
|
|
|
//!
|
|
|
|
//! #[derive(Clone, Debug)]
|
|
|
|
//! struct MyVerify;
|
|
|
|
//!
|
|
|
|
//! impl SignatureVerify for MyVerify {
|
|
|
|
//! type Error = MyError;
|
2020-03-16 00:29:47 +00:00
|
|
|
//! type Future = Ready<Result<bool, Self::Error>>;
|
2019-09-21 16:26:11 +00:00
|
|
|
//!
|
|
|
|
//! fn signature_verify(
|
|
|
|
//! &mut self,
|
|
|
|
//! algorithm: Option<Algorithm>,
|
2020-04-22 22:15:32 +00:00
|
|
|
//! key_id: String,
|
|
|
|
//! signature: String,
|
|
|
|
//! signing_string: String,
|
2019-09-21 16:26:11 +00:00
|
|
|
//! ) -> Self::Future {
|
|
|
|
//! match algorithm {
|
|
|
|
//! Some(Algorithm::Hs2019) => (),
|
2021-09-18 00:34:16 +00:00
|
|
|
//! _ => return ready(Err(MyError::Algorithm)),
|
2019-09-21 16:26:11 +00:00
|
|
|
//! };
|
|
|
|
//!
|
|
|
|
//! if key_id != "my-key-id" {
|
2021-09-18 00:34:16 +00:00
|
|
|
//! return ready(Err(MyError::Key));
|
2019-09-21 16:26:11 +00:00
|
|
|
//! }
|
|
|
|
//!
|
2020-04-22 22:15:32 +00:00
|
|
|
//! let decoded = match base64::decode(&signature) {
|
2020-03-16 00:29:47 +00:00
|
|
|
//! Ok(decoded) => decoded,
|
2021-09-18 00:34:16 +00:00
|
|
|
//! Err(_) => return ready(Err(MyError::Decode)),
|
2020-03-16 00:29:47 +00:00
|
|
|
//! };
|
2019-09-21 16:26:11 +00:00
|
|
|
//!
|
2021-09-18 00:34:16 +00:00
|
|
|
//! ready(Ok(decoded == signing_string.as_bytes()))
|
2019-09-21 16:26:11 +00:00
|
|
|
//! }
|
|
|
|
//! }
|
|
|
|
//!
|
2020-03-17 19:47:00 +00:00
|
|
|
//! async fn index((_, sig_verified): (DigestVerified, SignatureVerified)) -> &'static str {
|
|
|
|
//! println!("Signature verified for {}", sig_verified.key_id());
|
2019-09-21 16:26:11 +00:00
|
|
|
//! "Eyyyyup"
|
|
|
|
//! }
|
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! #[actix_rt::main]
|
|
|
|
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
2019-09-21 16:26:11 +00:00
|
|
|
//! let config = Config::default();
|
|
|
|
//!
|
|
|
|
//! HttpServer::new(move || {
|
|
|
|
//! App::new()
|
|
|
|
//! .wrap(VerifyDigest::new(Sha256::new()).optional())
|
|
|
|
//! .wrap(
|
|
|
|
//! VerifySignature::new(MyVerify, config.clone())
|
|
|
|
//! .authorization()
|
|
|
|
//! .optional(),
|
|
|
|
//! )
|
|
|
|
//! .route("/", web::post().to(index))
|
|
|
|
//! })
|
|
|
|
//! .bind("127.0.0.1:8010")?
|
2020-03-16 00:29:47 +00:00
|
|
|
//! .run()
|
|
|
|
//! .await?;
|
2019-09-21 16:26:11 +00:00
|
|
|
//!
|
|
|
|
//! Ok(())
|
|
|
|
//! }
|
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! #[derive(Debug, thiserror::Error)]
|
2019-09-21 16:26:11 +00:00
|
|
|
//! enum MyError {
|
2020-03-16 00:29:47 +00:00
|
|
|
//! #[error("Failed to verify, {}", _0)]
|
|
|
|
//! Verify(#[from] PrepareVerifyError),
|
2019-09-21 16:26:11 +00:00
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! #[error("Unsupported algorithm")]
|
2019-09-21 16:26:11 +00:00
|
|
|
//! Algorithm,
|
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! #[error("Couldn't decode signature")]
|
2019-09-21 16:26:11 +00:00
|
|
|
//! Decode,
|
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! #[error("Invalid key")]
|
2019-09-21 16:26:11 +00:00
|
|
|
//! Key,
|
|
|
|
//! }
|
|
|
|
//!
|
|
|
|
//! impl ResponseError for MyError {
|
2020-03-16 00:29:47 +00:00
|
|
|
//! fn status_code(&self) -> StatusCode {
|
|
|
|
//! StatusCode::BAD_REQUEST
|
2019-09-21 16:26:11 +00:00
|
|
|
//! }
|
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! fn error_response(&self) -> HttpResponse {
|
|
|
|
//! HttpResponse::BadRequest().finish()
|
2019-09-21 16:26:11 +00:00
|
|
|
//! }
|
|
|
|
//! }
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! ### Use it in a client
|
|
|
|
//! ```rust,ignore
|
2021-03-10 02:04:56 +00:00
|
|
|
//! use actix_web::error::BlockingError;
|
|
|
|
//! use awc::Client;
|
2019-09-21 16:26:11 +00:00
|
|
|
//! use http_signature_normalization_actix::prelude::*;
|
|
|
|
//! use sha2::{Digest, Sha256};
|
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! #[actix_rt::main]
|
|
|
|
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
|
//! let config = Config::default();
|
2020-03-30 05:53:45 +00:00
|
|
|
//! let digest = Sha256::new();
|
2020-03-16 00:29:47 +00:00
|
|
|
//!
|
|
|
|
//! let mut response = Client::default()
|
|
|
|
//! .post("http://127.0.0.1:8010/")
|
|
|
|
//! .header("User-Agent", "Actix Web")
|
2020-03-30 05:53:45 +00:00
|
|
|
//! .set(actix_web::http::header::Date(SystemTime::now().into()))
|
|
|
|
//! .signature_with_digest(config, "my-key-id", digest, "Hewwo-owo", |s| {
|
|
|
|
//! println!("Signing String\n{}", s);
|
2020-03-16 00:29:47 +00:00
|
|
|
//! Ok(base64::encode(s)) as Result<_, MyError>
|
2020-03-30 05:53:45 +00:00
|
|
|
//! })
|
|
|
|
//! .await?
|
2020-03-16 00:29:47 +00:00
|
|
|
//! .send()
|
|
|
|
//! .await
|
|
|
|
//! .map_err(|e| {
|
|
|
|
//! eprintln!("Error, {}", e);
|
|
|
|
//! MyError::SendRequest
|
|
|
|
//! })?;
|
2019-09-21 16:26:11 +00:00
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! let body = response.body().await.map_err(|e| {
|
|
|
|
//! eprintln!("Error, {}", e);
|
|
|
|
//! MyError::Body
|
|
|
|
//! })?;
|
|
|
|
//!
|
|
|
|
//! println!("{:?}", body);
|
|
|
|
//! Ok(())
|
2019-09-21 16:26:11 +00:00
|
|
|
//! }
|
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! #[derive(Debug, thiserror::Error)]
|
2019-09-21 16:26:11 +00:00
|
|
|
//! pub enum MyError {
|
2020-04-23 17:54:56 +00:00
|
|
|
//! #[error("Failed to create signing string, {0}")]
|
|
|
|
//! Convert(#[from] PrepareSignError),
|
2019-09-21 16:26:11 +00:00
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! #[error("Failed to create header, {0}")]
|
|
|
|
//! Header(#[from] InvalidHeaderValue),
|
2019-09-21 16:26:11 +00:00
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! #[error("Failed to send request")]
|
|
|
|
//! SendRequest,
|
2019-09-21 16:26:11 +00:00
|
|
|
//!
|
2020-03-16 00:29:47 +00:00
|
|
|
//! #[error("Failed to retrieve request body")]
|
|
|
|
//! Body,
|
2020-03-30 05:53:45 +00:00
|
|
|
//!
|
|
|
|
//! #[error("Blocking operation was canceled")]
|
|
|
|
//! Canceled,
|
|
|
|
//! }
|
|
|
|
//!
|
2021-02-10 21:45:51 +00:00
|
|
|
//! impl From<BlockingError> for MyError {
|
|
|
|
//! fn from(_: BlockingError) -> Self {
|
|
|
|
//! MyError::Canceled,
|
2020-03-30 05:53:45 +00:00
|
|
|
//! }
|
2019-09-21 16:26:11 +00:00
|
|
|
//! }
|
|
|
|
//! ```
|
|
|
|
|
2020-03-17 23:54:00 +00:00
|
|
|
use chrono::Duration;
|
2019-09-11 22:05:58 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[cfg(any(feature = "client", feature = "server"))]
|
|
|
|
use actix_http::http::{
|
|
|
|
header::{HeaderMap, ToStrError},
|
|
|
|
uri::PathAndQuery,
|
|
|
|
Method,
|
|
|
|
};
|
|
|
|
#[cfg(any(feature = "client", feature = "server"))]
|
|
|
|
use std::collections::BTreeMap;
|
|
|
|
|
|
|
|
#[cfg(feature = "client")]
|
2019-09-13 01:12:35 +00:00
|
|
|
mod sign;
|
|
|
|
|
2019-09-11 23:49:18 +00:00
|
|
|
#[cfg(feature = "digest")]
|
2019-09-13 01:12:35 +00:00
|
|
|
pub mod digest;
|
2019-09-11 23:49:18 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[cfg(feature = "client")]
|
2019-09-13 22:55:51 +00:00
|
|
|
pub mod create;
|
2021-09-23 22:05:11 +00:00
|
|
|
#[cfg(feature = "server")]
|
2019-09-13 22:55:51 +00:00
|
|
|
pub mod middleware;
|
2019-09-21 16:26:11 +00:00
|
|
|
|
2020-04-23 17:54:56 +00:00
|
|
|
pub use http_signature_normalization::RequiredError;
|
|
|
|
|
2019-09-21 16:26:11 +00:00
|
|
|
/// Useful types and traits for using this library in Actix Web
|
2019-09-11 22:05:58 +00:00
|
|
|
pub mod prelude {
|
2021-09-23 22:05:11 +00:00
|
|
|
pub use crate::{Config, RequiredError};
|
|
|
|
|
|
|
|
#[cfg(feature = "client")]
|
|
|
|
pub use crate::{PrepareSignError, Sign};
|
|
|
|
|
|
|
|
#[cfg(feature = "server")]
|
2019-09-13 22:55:51 +00:00
|
|
|
pub use crate::{
|
2019-09-13 23:27:04 +00:00
|
|
|
middleware::{SignatureVerified, VerifySignature},
|
2020-03-17 23:54:00 +00:00
|
|
|
verify::{Algorithm, DeprecatedAlgorithm, Unverified},
|
2021-09-23 22:05:11 +00:00
|
|
|
PrepareVerifyError, SignatureVerify,
|
2019-09-13 22:55:51 +00:00
|
|
|
};
|
2019-09-11 22:05:58 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[cfg(all(feature = "digest", feature = "client"))]
|
|
|
|
pub use crate::digest::{DigestClient, DigestCreate, SignExt};
|
|
|
|
|
|
|
|
#[cfg(all(feature = "digest", feature = "server"))]
|
2019-09-13 01:12:35 +00:00
|
|
|
pub use crate::digest::{
|
2019-09-13 23:27:04 +00:00
|
|
|
middleware::{DigestVerified, VerifyDigest},
|
2021-09-23 22:05:11 +00:00
|
|
|
DigestPart, DigestVerify,
|
2019-09-13 01:12:35 +00:00
|
|
|
};
|
2019-09-11 23:49:18 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
pub use actix_http::http::header::{InvalidHeaderValue, ToStrError};
|
2019-09-11 22:05:58 +00:00
|
|
|
}
|
2019-09-21 16:26:11 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[cfg(feature = "server")]
|
2019-09-21 16:26:11 +00:00
|
|
|
/// Types for Verifying an HTTP Signature
|
2019-09-13 23:33:54 +00:00
|
|
|
pub mod verify {
|
|
|
|
pub use http_signature_normalization::verify::{
|
|
|
|
Algorithm, DeprecatedAlgorithm, ParseSignatureError, ParsedHeader, Unvalidated, Unverified,
|
|
|
|
ValidateError,
|
|
|
|
};
|
|
|
|
}
|
2019-09-11 22:05:58 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[cfg(feature = "client")]
|
|
|
|
pub use self::client::{PrepareSignError, Sign};
|
2019-09-11 23:49:18 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[cfg(feature = "server")]
|
|
|
|
pub use self::server::{PrepareVerifyError, SignatureVerify};
|
2019-09-11 22:05:58 +00:00
|
|
|
|
2019-09-13 22:55:51 +00:00
|
|
|
#[derive(Clone, Debug, Default)]
|
2020-03-17 23:54:00 +00:00
|
|
|
/// Configuration for signing and verifying signatures
|
|
|
|
///
|
|
|
|
/// By default, the config is set up to create and verify signatures that expire after 10
|
|
|
|
/// seconds, and use the `(created)` and `(expires)` fields that were introduced in draft 11
|
2019-09-11 22:05:58 +00:00
|
|
|
pub struct Config {
|
2019-09-21 16:26:11 +00:00
|
|
|
/// The inner config type
|
2020-03-17 23:54:00 +00:00
|
|
|
config: http_signature_normalization::Config,
|
2020-09-07 21:42:06 +00:00
|
|
|
|
|
|
|
/// Whether to set the Host header
|
|
|
|
set_host: bool,
|
2019-09-11 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[cfg(feature = "client")]
|
|
|
|
mod client {
|
|
|
|
use super::{Config, RequiredError};
|
|
|
|
use actix_http::{
|
|
|
|
error::BlockingError,
|
|
|
|
http::header::{InvalidHeaderValue, ToStrError},
|
|
|
|
};
|
|
|
|
use std::{fmt::Display, future::Future, pin::Pin};
|
|
|
|
|
|
|
|
/// A trait implemented by the awc ClientRequest type to add an HTTP signature to the request
|
|
|
|
pub trait Sign {
|
|
|
|
/// Add an Authorization Signature to the request
|
|
|
|
fn authorization_signature<F, E, K>(
|
|
|
|
self,
|
|
|
|
config: Config,
|
|
|
|
key_id: K,
|
|
|
|
f: F,
|
|
|
|
) -> Pin<Box<dyn Future<Output = Result<Self, E>>>>
|
|
|
|
where
|
|
|
|
F: FnOnce(&str) -> Result<String, E> + Send + 'static,
|
|
|
|
E: From<BlockingError>
|
|
|
|
+ From<PrepareSignError>
|
|
|
|
+ From<InvalidHeaderValue>
|
|
|
|
+ std::fmt::Debug
|
|
|
|
+ Send
|
|
|
|
+ 'static,
|
|
|
|
K: Display + 'static,
|
|
|
|
Self: Sized;
|
|
|
|
|
|
|
|
/// Add a Signature to the request
|
|
|
|
fn signature<F, E, K>(
|
|
|
|
self,
|
|
|
|
config: Config,
|
|
|
|
key_id: K,
|
|
|
|
f: F,
|
|
|
|
) -> Pin<Box<dyn Future<Output = Result<Self, E>>>>
|
|
|
|
where
|
|
|
|
F: FnOnce(&str) -> Result<String, E> + Send + 'static,
|
|
|
|
E: From<BlockingError>
|
|
|
|
+ From<PrepareSignError>
|
|
|
|
+ From<InvalidHeaderValue>
|
|
|
|
+ std::fmt::Debug
|
|
|
|
+ Send
|
|
|
|
+ 'static,
|
|
|
|
K: Display + 'static,
|
|
|
|
Self: Sized;
|
|
|
|
}
|
2020-03-20 02:36:10 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
/// An error when preparing to sign a request
|
|
|
|
pub enum PrepareSignError {
|
|
|
|
#[error("Failed to read header, {0}")]
|
|
|
|
/// An error occurred when reading the request's headers
|
|
|
|
Header(#[from] ToStrError),
|
2019-09-13 01:29:24 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[error("{0}")]
|
|
|
|
/// Some headers were marked as required, but are missing
|
|
|
|
RequiredError(#[from] RequiredError),
|
2020-04-23 17:54:56 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[error("No host provided for URL, {0}")]
|
|
|
|
/// Missing host
|
|
|
|
Host(String),
|
|
|
|
}
|
2020-04-23 17:54:56 +00:00
|
|
|
}
|
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[cfg(feature = "server")]
|
|
|
|
mod server {
|
|
|
|
use super::RequiredError;
|
|
|
|
use actix_http::http::header::ToStrError;
|
|
|
|
use std::future::Future;
|
|
|
|
|
|
|
|
/// A trait for verifying signatures
|
|
|
|
pub trait SignatureVerify {
|
|
|
|
/// An error produced while attempting to verify the signature. This can be anything
|
|
|
|
/// implementing ResponseError
|
|
|
|
type Error: actix_web::ResponseError;
|
|
|
|
|
|
|
|
/// The future that resolves to the verification state of the signature
|
|
|
|
type Future: Future<Output = Result<bool, Self::Error>>;
|
|
|
|
|
|
|
|
/// Given the algorithm, key_id, signature, and signing_string, produce a future that resulves
|
|
|
|
/// to a the verification status
|
|
|
|
fn signature_verify(
|
|
|
|
&mut self,
|
|
|
|
algorithm: Option<super::verify::Algorithm>,
|
|
|
|
key_id: String,
|
|
|
|
signature: String,
|
|
|
|
signing_string: String,
|
|
|
|
) -> Self::Future;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
/// An error when preparing to verify a request
|
|
|
|
pub enum PrepareVerifyError {
|
|
|
|
#[error("Header is missing")]
|
|
|
|
/// Header is missing
|
|
|
|
Missing,
|
2020-04-23 17:54:56 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[error("Header is expired")]
|
|
|
|
/// Header is expired
|
|
|
|
Expired,
|
2020-09-07 21:42:06 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[error("Couldn't parse required field, {0}")]
|
|
|
|
/// Couldn't parse required field
|
|
|
|
ParseField(&'static str),
|
2019-09-11 22:05:58 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[error("Failed to read header, {0}")]
|
|
|
|
/// An error converting the header to a string for validation
|
|
|
|
Header(#[from] ToStrError),
|
2020-03-20 02:36:10 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[error("{0}")]
|
|
|
|
/// Required headers were missing from request
|
|
|
|
Required(#[from] RequiredError),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<http_signature_normalization::PrepareVerifyError> for PrepareVerifyError {
|
|
|
|
fn from(e: http_signature_normalization::PrepareVerifyError) -> Self {
|
|
|
|
use http_signature_normalization as hsn;
|
|
|
|
|
|
|
|
match e {
|
|
|
|
hsn::PrepareVerifyError::Parse(parse_error) => {
|
|
|
|
PrepareVerifyError::ParseField(parse_error.missing_field())
|
|
|
|
}
|
|
|
|
hsn::PrepareVerifyError::Validate(validate_error) => match validate_error {
|
|
|
|
hsn::verify::ValidateError::Missing => PrepareVerifyError::Missing,
|
|
|
|
hsn::verify::ValidateError::Expired => PrepareVerifyError::Expired,
|
|
|
|
},
|
|
|
|
hsn::PrepareVerifyError::Required(required_error) => {
|
|
|
|
PrepareVerifyError::Required(required_error)
|
|
|
|
}
|
2020-04-23 17:54:56 +00:00
|
|
|
}
|
2020-03-20 02:36:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-11 22:05:58 +00:00
|
|
|
impl Config {
|
2020-03-17 23:54:00 +00:00
|
|
|
/// Create a new Config with a default expiration of 10 seconds
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Config::default()
|
|
|
|
}
|
|
|
|
|
2020-09-07 21:42:06 +00:00
|
|
|
/// Since manually setting the Host header doesn't work so well in AWC, you can use this method
|
|
|
|
/// to enable setting the Host header for signing requests without breaking client
|
|
|
|
/// functionality
|
|
|
|
pub fn set_host_header(self) -> Self {
|
|
|
|
Config {
|
|
|
|
config: self.config,
|
|
|
|
set_host: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:57:59 +00:00
|
|
|
/// Enable mastodon compatibility
|
|
|
|
///
|
|
|
|
/// This is the same as disabling the use of `(created)` and `(expires)` signature fields,
|
|
|
|
/// requiring the Date header, and requiring the Host header
|
|
|
|
pub fn mastodon_compat(self) -> Self {
|
|
|
|
Config {
|
|
|
|
config: self.config.mastodon_compat(),
|
|
|
|
set_host: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Require the Digest header be set
|
2020-03-17 23:54:00 +00:00
|
|
|
///
|
2020-09-29 23:57:59 +00:00
|
|
|
/// This is useful for POST, PUT, and PATCH requests, but doesn't make sense for GET or DELETE.
|
|
|
|
pub fn require_digest(self) -> Self {
|
|
|
|
Config {
|
|
|
|
config: self.config.require_digest(),
|
|
|
|
set_host: self.set_host,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Opt out of using the (created) and (expires) fields introduced in draft 11
|
2020-04-23 18:52:57 +00:00
|
|
|
///
|
|
|
|
/// Note that by enabling this, the Date header becomes required on requests. This is to
|
|
|
|
/// prevent replay attacks
|
2020-03-17 23:54:00 +00:00
|
|
|
pub fn dont_use_created_field(self) -> Self {
|
|
|
|
Config {
|
|
|
|
config: self.config.dont_use_created_field(),
|
2020-09-07 21:42:06 +00:00
|
|
|
set_host: self.set_host,
|
2020-03-17 23:54:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the expiration to a custom duration
|
|
|
|
pub fn set_expiration(self, expires_after: Duration) -> Self {
|
|
|
|
Config {
|
|
|
|
config: self.config.set_expiration(expires_after),
|
2020-09-07 21:42:06 +00:00
|
|
|
set_host: self.set_host,
|
2020-03-17 23:54:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-23 17:54:56 +00:00
|
|
|
/// Require a header on signed and verified requests
|
|
|
|
pub fn require_header(self, header: &str) -> Self {
|
|
|
|
Config {
|
|
|
|
config: self.config.require_header(header),
|
2020-09-07 21:42:06 +00:00
|
|
|
set_host: self.set_host,
|
2020-04-23 17:54:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[cfg(feature = "client")]
|
2019-09-21 16:26:11 +00:00
|
|
|
/// Begin the process of singing a request
|
2019-09-11 22:05:58 +00:00
|
|
|
pub fn begin_sign(
|
|
|
|
&self,
|
|
|
|
method: &Method,
|
|
|
|
path_and_query: Option<&PathAndQuery>,
|
|
|
|
headers: HeaderMap,
|
2021-09-23 22:05:11 +00:00
|
|
|
) -> Result<self::create::Unsigned, PrepareSignError> {
|
2019-09-11 22:05:58 +00:00
|
|
|
let headers = headers
|
|
|
|
.iter()
|
|
|
|
.map(|(k, v)| v.to_str().map(|v| (k.to_string(), v.to_string())))
|
|
|
|
.collect::<Result<BTreeMap<_, _>, ToStrError>>()?;
|
|
|
|
|
|
|
|
let path_and_query = path_and_query
|
|
|
|
.map(|p| p.to_string())
|
2020-04-26 01:41:21 +00:00
|
|
|
.unwrap_or_else(|| "/".to_string());
|
2019-09-11 22:05:58 +00:00
|
|
|
|
|
|
|
let unsigned = self
|
|
|
|
.config
|
2020-04-23 17:54:56 +00:00
|
|
|
.begin_sign(&method.to_string(), &path_and_query, headers)?;
|
2019-09-11 22:05:58 +00:00
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
Ok(self::create::Unsigned { unsigned })
|
2019-09-11 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
2021-09-23 22:05:11 +00:00
|
|
|
#[cfg(feature = "server")]
|
2019-09-21 16:26:11 +00:00
|
|
|
/// Begin the proess of verifying a request
|
2019-09-11 22:05:58 +00:00
|
|
|
pub fn begin_verify(
|
|
|
|
&self,
|
|
|
|
method: &Method,
|
|
|
|
path_and_query: Option<&PathAndQuery>,
|
|
|
|
headers: HeaderMap,
|
2021-09-23 22:05:11 +00:00
|
|
|
) -> Result<self::verify::Unverified, PrepareVerifyError> {
|
2019-09-11 22:05:58 +00:00
|
|
|
let headers = headers
|
|
|
|
.iter()
|
|
|
|
.map(|(k, v)| v.to_str().map(|v| (k.to_string(), v.to_string())))
|
|
|
|
.collect::<Result<BTreeMap<_, _>, ToStrError>>()?;
|
|
|
|
|
|
|
|
let path_and_query = path_and_query
|
|
|
|
.map(|p| p.to_string())
|
2020-04-26 01:41:21 +00:00
|
|
|
.unwrap_or_else(|| "/".to_string());
|
2019-09-11 22:05:58 +00:00
|
|
|
|
|
|
|
let unverified = self
|
|
|
|
.config
|
|
|
|
.begin_verify(&method.to_string(), &path_and_query, headers)?;
|
|
|
|
|
|
|
|
Ok(unverified)
|
|
|
|
}
|
|
|
|
}
|