@@ 1,29 1,53 @@
+//! HTTP Signature handling utility.
+//!
+//! More details in the `Signature` struct
+
+#![warn(missing_docs)]
+
+/// Errors that may be produced when parsing a signature header
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
+ /// A parameter pair did not contain `=`
#[error("Parameter pair did not contain =")]
MissingEquals,
+
+ /// Didn't find a signature in the header
#[error("No signature found in parameters")]
MissingSignature,
+
+ /// A parameter contained invalid characters
#[error("Parameter contained invalid characters")]
InvalidCharacters,
+
+ /// Failed to parse a number
#[error("Failed to parse number")]
Number(std::num::ParseIntError),
+
+ /// Signature field was not valid Base64
#[error("Failed to parse signature bytes")]
Base64(base64::DecodeError),
}
+/// Errors that may be produced when creating a signature
#[derive(Debug, thiserror::Error)]
pub enum SignError<T: std::fmt::Debug> {
+ /// An IO error occurred.
#[error("IO error occurred")]
IO(#[from] std::io::Error),
+
+ /// An error was returned from the provided `sign` function.
#[error("Failed in user sign call")]
User(T),
}
+/// Errors that may be produced when verifying a signature
#[derive(Debug, thiserror::Error)]
pub enum VerifyError<T: std::fmt::Debug> {
+ /// An IO error occurred.
#[error("IO error occurred")]
IO(#[from] std::io::Error),
+
+ /// An error was returned from the provided `verify` function.
#[error("Failed in user verify call")]
User(T),
}
@@ 78,6 102,7 @@ fn parse_maybe_quoted<'a>(src: &'a str) -> &'a str {
}
}
+/// A parsed or generated Signature.
pub struct Signature<'a> {
algorithm: Option<http::header::HeaderName>,
created: Option<u64>,
@@ 88,6 113,12 @@ pub struct Signature<'a> {
}
impl<'a> Signature<'a> {
+ /// Construct a signature.
+ ///
+ /// All headers in `headers` will be included, as well as `(request-target)`, `(created)`, and
+ /// `(expires)` (based on `lifetime_secs` parameter)
+ ///
+ /// The passed `sign` will be called with the body to sign.
pub fn create<E: std::fmt::Debug>(
key_id: &'a str,
request_method: &http::method::Method,
@@ 151,6 182,10 @@ impl<'a> Signature<'a> {
})
}
+ /// Create an old-style signature (no (created) and (expires))
+ ///
+ /// # Panics
+ /// Panics if `headers` doesn't contain a Date header
pub fn create_legacy<E: std::fmt::Debug>(
key_id: &'a str,
request_method: &http::method::Method,
@@ 204,6 239,7 @@ impl<'a> Signature<'a> {
})
}
+ /// Parse a Signature header
pub fn parse(value: &'a http::header::HeaderValue) -> Result<Self, ParseError> {
let mut algorithm = None;
let mut created = None;
@@ 260,6 296,7 @@ impl<'a> Signature<'a> {
})
}
+ /// Create a Signature header value for the signature.
pub fn to_header(&self) -> http::header::HeaderValue {
use std::fmt::Write;
let mut params = String::new();
@@ 297,6 334,10 @@ impl<'a> Signature<'a> {
http::header::HeaderValue::from_bytes(params.as_bytes()).unwrap()
}
+ /// Verify the signature for a given request target and HeaderMap.
+ ///
+ /// The passed `verify` function will be called with (body, signature) where body is the body
+ /// that should match the signature.
pub fn verify<E: std::fmt::Debug>(
&self,
request_method: &http::method::Method,