mirror of
https://git.asonix.dog/asonix/http-signature-normalization.git
synced 2024-11-28 04:11:02 +00:00
Remove chrono, thiserror
This commit is contained in:
parent
d42c0464a4
commit
bc34e8e054
9 changed files with 122 additions and 74 deletions
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "http-signature-normalization"
|
name = "http-signature-normalization"
|
||||||
description = "An HTTP Signatures library that leaves the signing to you"
|
description = "An HTTP Signatures library that leaves the signing to you"
|
||||||
version = "0.5.4"
|
version = "0.6.0"
|
||||||
authors = ["asonix <asonix@asonix.dog>"]
|
authors = ["asonix <asonix@asonix.dog>"]
|
||||||
license-file = "LICENSE"
|
license-file = "LICENSE"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -20,5 +20,4 @@ members = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4"
|
httpdate = "1"
|
||||||
thiserror = "1.0"
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "http-signature-normalization-actix"
|
name = "http-signature-normalization-actix"
|
||||||
description = "An HTTP Signatures library that leaves the signing to you"
|
description = "An HTTP Signatures library that leaves the signing to you"
|
||||||
version = "0.5.0-beta.14"
|
version = "0.6.0-beta.0"
|
||||||
authors = ["asonix <asonix@asonix.dog>"]
|
authors = ["asonix <asonix@asonix.dog>"]
|
||||||
license-file = "LICENSE"
|
license-file = "LICENSE"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -27,14 +27,14 @@ name = "client"
|
||||||
required-features = ["client", "sha-2"]
|
required-features = ["client", "sha-2"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-http = { version = "3.0.0-beta.14", default-features = false }
|
actix-http = { version = "=3.0.0-beta.18", default-features = false }
|
||||||
actix-rt = "2.5.0"
|
actix-rt = "2.5.0"
|
||||||
actix-web = { version = "4.0.0-beta.13", default-features = false, optional = true }
|
actix-router = "=0.5.0-beta.4"
|
||||||
|
actix-web = { version = "=4.0.0-beta.19", default-features = false, optional = true }
|
||||||
awc = { version = "3.0.0-beta.12", default-features = false, optional = true }
|
awc = { version = "3.0.0-beta.12", default-features = false, optional = true }
|
||||||
base64 = { version = "0.13", optional = true }
|
base64 = { version = "0.13", optional = true }
|
||||||
chrono = "0.4.6"
|
|
||||||
futures-util = { version = "0.3", default-features = false }
|
futures-util = { version = "0.3", default-features = false }
|
||||||
http-signature-normalization = { version = "0.5.1", path = ".." }
|
http-signature-normalization = { version = "0.6.0", path = ".." }
|
||||||
sha2 = { version = "0.10", optional = true }
|
sha2 = { version = "0.10", optional = true }
|
||||||
sha3 = { version = "0.10", optional = true }
|
sha3 = { version = "0.10", optional = true }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
|
@ -159,7 +159,7 @@
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use chrono::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[cfg(any(feature = "client", feature = "server"))]
|
#[cfg(any(feature = "client", feature = "server"))]
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "http-signature-normalization-http"
|
name = "http-signature-normalization-http"
|
||||||
description = "An HTTP Signatures library that leaves the signing to you"
|
description = "An HTTP Signatures library that leaves the signing to you"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
authors = ["asonix <asonix@asonix.dog>"]
|
authors = ["asonix <asonix@asonix.dog>"]
|
||||||
license-file = "../LICENSE"
|
license-file = "../LICENSE"
|
||||||
readme = "../README.md"
|
readme = "../README.md"
|
||||||
|
@ -13,4 +13,4 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
http = "0.2"
|
http = "0.2"
|
||||||
http-signature-normalization = { version = "0.5.0", path = ".." }
|
http-signature-normalization = { version = "0.6.0", path = ".." }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "http-signature-normalization-reqwest"
|
name = "http-signature-normalization-reqwest"
|
||||||
description = "An HTTP Signatures library that leaves the signing to you"
|
description = "An HTTP Signatures library that leaves the signing to you"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
authors = ["asonix <asonix@asonix.dog>"]
|
authors = ["asonix <asonix@asonix.dog>"]
|
||||||
license-file = "LICENSE"
|
license-file = "LICENSE"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -24,9 +24,8 @@ required-features = ["sha-2"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = { version = "0.13", optional = true }
|
base64 = { version = "0.13", optional = true }
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
chrono = "0.4.10"
|
|
||||||
http = "0.2.0"
|
http = "0.2.0"
|
||||||
http-signature-normalization = { version = "0.5.1", path = ".." }
|
http-signature-normalization = { version = "0.6.0", path = ".." }
|
||||||
reqwest = { version = "0.11", default-features = false, features = ["json"] }
|
reqwest = { version = "0.11", default-features = false, features = ["json"] }
|
||||||
reqwest-middleware = { version = "0.1.2", optional = true }
|
reqwest-middleware = { version = "0.1.2", optional = true }
|
||||||
sha2 = { version = "0.10", optional = true }
|
sha2 = { version = "0.10", optional = true }
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use chrono::Duration;
|
|
||||||
use http_signature_normalization::create::Signed;
|
use http_signature_normalization::create::Signed;
|
||||||
use reqwest::{
|
use reqwest::{
|
||||||
header::{InvalidHeaderValue, ToStrError},
|
header::{InvalidHeaderValue, ToStrError},
|
||||||
Request, RequestBuilder,
|
Request, RequestBuilder,
|
||||||
};
|
};
|
||||||
use std::fmt::Display;
|
use std::{fmt::Display, time::Duration};
|
||||||
|
|
||||||
pub use http_signature_normalization::RequiredError;
|
pub use http_signature_normalization::RequiredError;
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
//! Types and logic for creating signature and authorization headers
|
//! Types and logic for creating signature and authorization headers
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ALGORITHM_FIELD, ALGORITHM_VALUE, CREATED_FIELD, EXPIRES_FIELD, HEADERS_FIELD, KEY_ID_FIELD,
|
unix_timestamp, ALGORITHM_FIELD, ALGORITHM_VALUE, CREATED_FIELD, EXPIRES_FIELD, HEADERS_FIELD,
|
||||||
SIGNATURE_FIELD,
|
KEY_ID_FIELD, SIGNATURE_FIELD,
|
||||||
};
|
};
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// The signed stage of creating a signature
|
/// The signed stage of creating a signature
|
||||||
|
@ -13,8 +12,8 @@ use crate::{
|
||||||
pub struct Signed {
|
pub struct Signed {
|
||||||
signature: String,
|
signature: String,
|
||||||
sig_headers: Vec<String>,
|
sig_headers: Vec<String>,
|
||||||
created: Option<DateTime<Utc>>,
|
created: Option<SystemTime>,
|
||||||
expires: Option<DateTime<Utc>>,
|
expires: Option<SystemTime>,
|
||||||
key_id: String,
|
key_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +25,8 @@ pub struct Signed {
|
||||||
pub struct Unsigned {
|
pub struct Unsigned {
|
||||||
pub(crate) signing_string: String,
|
pub(crate) signing_string: String,
|
||||||
pub(crate) sig_headers: Vec<String>,
|
pub(crate) sig_headers: Vec<String>,
|
||||||
pub(crate) created: Option<DateTime<Utc>>,
|
pub(crate) created: Option<SystemTime>,
|
||||||
pub(crate) expires: Option<DateTime<Utc>>,
|
pub(crate) expires: Option<SystemTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Signed {
|
impl Signed {
|
||||||
|
@ -51,8 +50,8 @@ impl Signed {
|
||||||
vec![
|
vec![
|
||||||
(KEY_ID_FIELD, self.key_id),
|
(KEY_ID_FIELD, self.key_id),
|
||||||
(ALGORITHM_FIELD, ALGORITHM_VALUE.to_owned()),
|
(ALGORITHM_FIELD, ALGORITHM_VALUE.to_owned()),
|
||||||
(CREATED_FIELD, created.timestamp().to_string()),
|
(CREATED_FIELD, unix_timestamp(created).to_string()),
|
||||||
(EXPIRES_FIELD, expires.timestamp().to_string()),
|
(EXPIRES_FIELD, unix_timestamp(expires).to_string()),
|
||||||
(HEADERS_FIELD, self.sig_headers.join(" ")),
|
(HEADERS_FIELD, self.sig_headers.join(" ")),
|
||||||
(SIGNATURE_FIELD, self.signature),
|
(SIGNATURE_FIELD, self.signature),
|
||||||
]
|
]
|
||||||
|
|
93
src/lib.rs
93
src/lib.rs
|
@ -10,12 +10,11 @@
|
||||||
//! Http Signature Normalization is a minimal-dependency crate for producing HTTP Signatures with user-provided signing and verification. The API is simple; there's a series of steps for creation and verification with types that ensure reasonable usage.
|
//! Http Signature Normalization is a minimal-dependency crate for producing HTTP Signatures with user-provided signing and verification. The API is simple; there's a series of steps for creation and verification with types that ensure reasonable usage.
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use chrono::Duration;
|
|
||||||
//! use http_signature_normalization::Config;
|
//! use http_signature_normalization::Config;
|
||||||
//! use std::collections::BTreeMap;
|
//! use std::{collections::BTreeMap, time::Duration};
|
||||||
//!
|
//!
|
||||||
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
|
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
//! let config = Config::default().set_expiration(Duration::seconds(5));
|
//! let config = Config::default().set_expiration(Duration::from_secs(5));
|
||||||
//!
|
//!
|
||||||
//! let headers = BTreeMap::new();
|
//! let headers = BTreeMap::new();
|
||||||
//!
|
//!
|
||||||
|
@ -42,8 +41,11 @@
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use chrono::{DateTime, Duration, Utc};
|
use std::{
|
||||||
use std::collections::{BTreeMap, HashSet};
|
collections::{BTreeMap, HashSet},
|
||||||
|
num::ParseIntError,
|
||||||
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||||
|
};
|
||||||
|
|
||||||
pub mod create;
|
pub mod create;
|
||||||
pub mod verify;
|
pub mod verify;
|
||||||
|
@ -76,29 +78,69 @@ pub struct Config {
|
||||||
required_headers: HashSet<String>,
|
required_headers: HashSet<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug)]
|
||||||
/// Error preparing a header for validation
|
/// Error preparing a header for validation
|
||||||
///
|
///
|
||||||
/// This could be due to a missing header, and unparsable header, or an expired header
|
/// This could be due to a missing header, and unparsable header, or an expired header
|
||||||
pub enum PrepareVerifyError {
|
pub enum PrepareVerifyError {
|
||||||
#[error("{0}")]
|
|
||||||
/// Error validating the header
|
/// Error validating the header
|
||||||
Validate(#[from] ValidateError),
|
Validate(ValidateError),
|
||||||
|
|
||||||
#[error("{0}")]
|
|
||||||
/// Error parsing the header
|
/// Error parsing the header
|
||||||
Parse(#[from] ParseSignatureError),
|
Parse(ParseSignatureError),
|
||||||
|
|
||||||
#[error("{0}")]
|
|
||||||
/// Missing required headers
|
/// Missing required headers
|
||||||
Required(#[from] RequiredError),
|
Required(RequiredError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
impl std::fmt::Display for PrepareVerifyError {
|
||||||
#[error("Missing required headers {0:?}")]
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Validate(ref e) => std::fmt::Display::fmt(e, f),
|
||||||
|
Self::Parse(ref e) => std::fmt::Display::fmt(e, f),
|
||||||
|
Self::Required(ref e) => std::fmt::Display::fmt(e, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for PrepareVerifyError {
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
match self {
|
||||||
|
Self::Validate(ref e) => Some(e),
|
||||||
|
Self::Parse(ref e) => Some(e),
|
||||||
|
Self::Required(ref e) => Some(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ValidateError> for PrepareVerifyError {
|
||||||
|
fn from(e: ValidateError) -> Self {
|
||||||
|
Self::Validate(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<ParseSignatureError> for PrepareVerifyError {
|
||||||
|
fn from(e: ParseSignatureError) -> Self {
|
||||||
|
Self::Parse(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<RequiredError> for PrepareVerifyError {
|
||||||
|
fn from(e: RequiredError) -> Self {
|
||||||
|
Self::Required(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
/// Failed to build a signing string due to missing required headers
|
/// Failed to build a signing string due to missing required headers
|
||||||
pub struct RequiredError(HashSet<String>);
|
pub struct RequiredError(HashSet<String>);
|
||||||
|
|
||||||
|
impl std::fmt::Display for RequiredError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Missing required headers {:?}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for RequiredError {}
|
||||||
|
|
||||||
impl RequiredError {
|
impl RequiredError {
|
||||||
/// Retrieve the missing headers from the error
|
/// Retrieve the missing headers from the error
|
||||||
pub fn headers(&self) -> &HashSet<String> {
|
pub fn headers(&self) -> &HashSet<String> {
|
||||||
|
@ -169,7 +211,7 @@ impl Config {
|
||||||
let sig_headers = self.build_headers_list(&headers);
|
let sig_headers = self.build_headers_list(&headers);
|
||||||
|
|
||||||
let (created, expires) = if self.use_created_field {
|
let (created, expires) = if self.use_created_field {
|
||||||
let created = Utc::now();
|
let created = SystemTime::now();
|
||||||
let expires = created + self.expires_after;
|
let expires = created + self.expires_after;
|
||||||
|
|
||||||
(Some(created), Some(expires))
|
(Some(created), Some(expires))
|
||||||
|
@ -246,8 +288,8 @@ impl Config {
|
||||||
fn build_signing_string(
|
fn build_signing_string(
|
||||||
method: &str,
|
method: &str,
|
||||||
path_and_query: &str,
|
path_and_query: &str,
|
||||||
created: Option<DateTime<Utc>>,
|
created: Option<SystemTime>,
|
||||||
expires: Option<DateTime<Utc>>,
|
expires: Option<SystemTime>,
|
||||||
sig_headers: &[String],
|
sig_headers: &[String],
|
||||||
btm: &mut BTreeMap<String, String>,
|
btm: &mut BTreeMap<String, String>,
|
||||||
mut required_headers: HashSet<String>,
|
mut required_headers: HashSet<String>,
|
||||||
|
@ -256,10 +298,10 @@ fn build_signing_string(
|
||||||
|
|
||||||
btm.insert(REQUEST_TARGET.to_owned(), request_target);
|
btm.insert(REQUEST_TARGET.to_owned(), request_target);
|
||||||
if let Some(created) = created {
|
if let Some(created) = created {
|
||||||
btm.insert(CREATED.to_owned(), created.timestamp().to_string());
|
btm.insert(CREATED.to_owned(), unix_timestamp(created).to_string());
|
||||||
}
|
}
|
||||||
if let Some(expires) = expires {
|
if let Some(expires) = expires {
|
||||||
btm.insert(EXPIRES.to_owned(), expires.timestamp().to_string());
|
btm.insert(EXPIRES.to_owned(), unix_timestamp(expires).to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
let signing_string = sig_headers
|
let signing_string = sig_headers
|
||||||
|
@ -284,13 +326,24 @@ fn build_signing_string(
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Config {
|
Config {
|
||||||
expires_after: Duration::seconds(10),
|
expires_after: Duration::from_secs(10),
|
||||||
use_created_field: true,
|
use_created_field: true,
|
||||||
required_headers: HashSet::new(),
|
required_headers: HashSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unix_timestamp(time: SystemTime) -> u64 {
|
||||||
|
time.duration_since(UNIX_EPOCH)
|
||||||
|
.expect("UNIX_EPOCH is never in the future")
|
||||||
|
.as_secs()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_unix_timestamp(s: &str) -> Result<SystemTime, ParseIntError> {
|
||||||
|
let u: u64 = s.parse()?;
|
||||||
|
Ok(UNIX_EPOCH + Duration::from_secs(u))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::Config;
|
use super::Config;
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
//! Types and methods to verify a signature or authorization header
|
//! Types and methods to verify a signature or authorization header
|
||||||
use chrono::{DateTime, Duration, TimeZone, Utc};
|
use crate::{
|
||||||
|
build_signing_string, parse_unix_timestamp, RequiredError, ALGORITHM_FIELD, CREATED,
|
||||||
|
CREATED_FIELD, EXPIRES_FIELD, HEADERS_FIELD, KEY_ID_FIELD, SIGNATURE_FIELD,
|
||||||
|
};
|
||||||
|
use httpdate::HttpDate;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, HashMap, HashSet},
|
collections::{BTreeMap, HashMap, HashSet},
|
||||||
error::Error,
|
error::Error,
|
||||||
fmt,
|
fmt,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
time::{Duration, SystemTime},
|
||||||
|
|
||||||
use crate::{
|
|
||||||
build_signing_string, RequiredError, ALGORITHM_FIELD, CREATED, CREATED_FIELD, EXPIRES_FIELD,
|
|
||||||
HEADERS_FIELD, KEY_ID_FIELD, SIGNATURE_FIELD,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -33,9 +33,9 @@ pub struct Unvalidated {
|
||||||
pub(crate) key_id: String,
|
pub(crate) key_id: String,
|
||||||
pub(crate) signature: String,
|
pub(crate) signature: String,
|
||||||
pub(crate) algorithm: Option<Algorithm>,
|
pub(crate) algorithm: Option<Algorithm>,
|
||||||
pub(crate) created: Option<DateTime<Utc>>,
|
pub(crate) created: Option<SystemTime>,
|
||||||
pub(crate) expires: Option<DateTime<Utc>>,
|
pub(crate) expires: Option<SystemTime>,
|
||||||
pub(crate) parsed_at: DateTime<Utc>,
|
pub(crate) parsed_at: SystemTime,
|
||||||
pub(crate) date: Option<String>,
|
pub(crate) date: Option<String>,
|
||||||
pub(crate) signing_string: String,
|
pub(crate) signing_string: String,
|
||||||
}
|
}
|
||||||
|
@ -47,9 +47,9 @@ pub struct ParsedHeader {
|
||||||
key_id: String,
|
key_id: String,
|
||||||
headers: Vec<String>,
|
headers: Vec<String>,
|
||||||
algorithm: Option<Algorithm>,
|
algorithm: Option<Algorithm>,
|
||||||
created: Option<DateTime<Utc>>,
|
created: Option<SystemTime>,
|
||||||
expires: Option<DateTime<Utc>>,
|
expires: Option<SystemTime>,
|
||||||
parsed_at: DateTime<Utc>,
|
parsed_at: SystemTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
@ -190,8 +190,9 @@ impl Unvalidated {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(date) = self.date {
|
if let Some(date) = self.date {
|
||||||
if let Ok(datetime) = DateTime::parse_from_rfc2822(&date) {
|
if let Ok(datetime) = date.parse::<HttpDate>() {
|
||||||
let datetime: DateTime<Utc> = datetime.into();
|
let system_time = SystemTime::from(datetime);
|
||||||
|
let datetime: SystemTime = system_time.into();
|
||||||
if datetime + expires_after < self.parsed_at {
|
if datetime + expires_after < self.parsed_at {
|
||||||
return Err(ValidateError::Expired);
|
return Err(ValidateError::Expired);
|
||||||
}
|
}
|
||||||
|
@ -274,7 +275,7 @@ impl FromStr for ParsedHeader {
|
||||||
algorithm: hm.remove(ALGORITHM_FIELD).map(Algorithm::from),
|
algorithm: hm.remove(ALGORITHM_FIELD).map(Algorithm::from),
|
||||||
created: parse_time(&mut hm, CREATED_FIELD)?,
|
created: parse_time(&mut hm, CREATED_FIELD)?,
|
||||||
expires: parse_time(&mut hm, EXPIRES_FIELD)?,
|
expires: parse_time(&mut hm, EXPIRES_FIELD)?,
|
||||||
parsed_at: Utc::now(),
|
parsed_at: SystemTime::now(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,12 +283,10 @@ impl FromStr for ParsedHeader {
|
||||||
fn parse_time(
|
fn parse_time(
|
||||||
hm: &mut HashMap<String, String>,
|
hm: &mut HashMap<String, String>,
|
||||||
key: &'static str,
|
key: &'static str,
|
||||||
) -> Result<Option<DateTime<Utc>>, ParseSignatureError> {
|
) -> Result<Option<SystemTime>, ParseSignatureError> {
|
||||||
let r = hm.remove(key).map(|s| {
|
let r = hm
|
||||||
s.parse()
|
.remove(key)
|
||||||
.map(|timestamp| Utc.timestamp(timestamp, 0))
|
.map(|s| parse_unix_timestamp(&s).map_err(|_| ParseSignatureError(key)));
|
||||||
.map_err(|_| ParseSignatureError(key))
|
|
||||||
});
|
|
||||||
|
|
||||||
match r {
|
match r {
|
||||||
Some(Ok(t)) => Ok(Some(t)),
|
Some(Ok(t)) => Ok(Some(t)),
|
||||||
|
@ -392,14 +391,14 @@ impl Error for ValidateError {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use chrono::Utc;
|
|
||||||
|
|
||||||
use super::ParsedHeader;
|
use super::ParsedHeader;
|
||||||
|
use crate::unix_timestamp;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_header_succesfully_1() {
|
fn parses_header_succesfully_1() {
|
||||||
let time1 = Utc::now().timestamp();
|
let time1 = unix_timestamp(SystemTime::now());
|
||||||
let time2 = Utc::now().timestamp();
|
let time2 = unix_timestamp(SystemTime::now());
|
||||||
|
|
||||||
let h = format!(
|
let h = format!(
|
||||||
r#"Signature keyId="my-key-id",algorithm="hs2019",created="{}",expires="{}",headers="(request-target) (created) (expires) date content-type",signature="blah blah blah""#,
|
r#"Signature keyId="my-key-id",algorithm="hs2019",created="{}",expires="{}",headers="(request-target) (created) (expires) date content-type",signature="blah blah blah""#,
|
||||||
|
@ -411,8 +410,8 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_header_succesfully_2() {
|
fn parses_header_succesfully_2() {
|
||||||
let time1 = Utc::now().timestamp();
|
let time1 = unix_timestamp(SystemTime::now());
|
||||||
let time2 = Utc::now().timestamp();
|
let time2 = unix_timestamp(SystemTime::now());
|
||||||
|
|
||||||
let h = format!(
|
let h = format!(
|
||||||
r#"Signature keyId="my-key-id",algorithm="rsa-sha256",created="{}",expires="{}",signature="blah blah blah""#,
|
r#"Signature keyId="my-key-id",algorithm="rsa-sha256",created="{}",expires="{}",signature="blah blah blah""#,
|
||||||
|
@ -424,7 +423,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_header_succesfully_3() {
|
fn parses_header_succesfully_3() {
|
||||||
let time1 = Utc::now().timestamp();
|
let time1 = unix_timestamp(SystemTime::now());
|
||||||
|
|
||||||
let h = format!(
|
let h = format!(
|
||||||
r#"Signature keyId="my-key-id",algorithm="rsa-sha256",created="{}",headers="(request-target) (created) date content-type",signature="blah blah blah""#,
|
r#"Signature keyId="my-key-id",algorithm="rsa-sha256",created="{}",headers="(request-target) (created) date content-type",signature="blah blah blah""#,
|
||||||
|
|
Loading…
Reference in a new issue