Update reqwest to automatically set Date header in masto compat

This commit is contained in:
asonix 2022-11-22 18:12:41 -06:00
parent 68e55bee28
commit 82b59317cb
3 changed files with 33 additions and 11 deletions

View file

@ -24,6 +24,7 @@ required-features = ["sha-2"]
[dependencies] [dependencies]
base64 = { version = "0.13", optional = true } base64 = { version = "0.13", optional = true }
http-signature-normalization = { version = "0.6.0", path = ".." } http-signature-normalization = { version = "0.6.0", path = ".." }
httpdate = "1.0.2"
reqwest = { version = "0.11", default-features = false, features = ["json"] } reqwest = { version = "0.11", default-features = false, features = ["json"] }
reqwest-middleware = { version = "0.2.0", optional = true } reqwest-middleware = { version = "0.2.0", optional = true }
sha2 = { version = "0.10", optional = true } sha2 = { version = "0.10", optional = true }
@ -34,7 +35,6 @@ tokio = { version = "1", default-features = false, features = [
], optional = true } ], optional = true }
[dev-dependencies] [dev-dependencies]
httpdate = "1.0.2"
pretty_env_logger = "0.4" pretty_env_logger = "0.4"
tokio = { version = "1", default-features = false, features = [ tokio = { version = "1", default-features = false, features = [
"rt-multi-thread", "rt-multi-thread",

View file

@ -1,11 +1,9 @@
use http_signature_normalization_reqwest::prelude::*; use http_signature_normalization_reqwest::prelude::*;
use httpdate::HttpDate;
use reqwest::{ use reqwest::{
header::{ACCEPT, DATE, USER_AGENT}, header::{ACCEPT, USER_AGENT},
Client, Client,
}; };
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::time::SystemTime;
async fn request(config: Config) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { async fn request(config: Config) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let digest = Sha256::new(); let digest = Sha256::new();
@ -16,7 +14,6 @@ async fn request(config: Config) -> Result<(), Box<dyn std::error::Error + Send
.post("http://127.0.0.1:8010/") .post("http://127.0.0.1:8010/")
.header(USER_AGENT, "Reqwest") .header(USER_AGENT, "Reqwest")
.header(ACCEPT, "text/plain") .header(ACCEPT, "text/plain")
.header(DATE, HttpDate::from(SystemTime::now()).to_string())
.signature_with_digest(config, "my-key-id", digest, "Hewwo-owo", |s| { .signature_with_digest(config, "my-key-id", digest, "Hewwo-owo", |s| {
println!("Signing String\n{}", s); println!("Signing String\n{}", s);
Ok(base64::encode(s)) as Result<_, MyError> Ok(base64::encode(s)) as Result<_, MyError>

View file

@ -1,9 +1,14 @@
use http_signature_normalization::create::Signed; use http_signature_normalization::create::Signed;
use httpdate::HttpDate;
use reqwest::{ use reqwest::{
header::{InvalidHeaderValue, ToStrError}, header::{InvalidHeaderValue, ToStrError},
Request, RequestBuilder, Request, RequestBuilder,
}; };
use std::{fmt::Display, time::Duration}; use std::{
convert::TryInto,
fmt::Display,
time::{Duration, SystemTime},
};
pub use http_signature_normalization::RequiredError; pub use http_signature_normalization::RequiredError;
@ -28,6 +33,9 @@ pub struct Config {
/// Whether to set the Host header /// Whether to set the Host header
set_host: bool, set_host: bool,
/// Whether to set the Date header
set_date: bool,
} }
/// A trait implemented by the reqwest RequestBuilder type to add an HTTP Signature to the request /// A trait implemented by the reqwest RequestBuilder type to add an HTTP Signature to the request
@ -90,6 +98,7 @@ impl Config {
Config { Config {
config: self.config, config: self.config,
set_host: true, set_host: true,
set_date: self.set_date,
} }
} }
@ -101,6 +110,7 @@ impl Config {
Config { Config {
config: self.config.mastodon_compat(), config: self.config.mastodon_compat(),
set_host: true, set_host: true,
set_date: true,
} }
} }
@ -111,6 +121,7 @@ impl Config {
Config { Config {
config: self.config.require_digest(), config: self.config.require_digest(),
set_host: self.set_host, set_host: self.set_host,
set_date: self.set_date,
} }
} }
@ -122,6 +133,7 @@ impl Config {
Config { Config {
config: self.config.dont_use_created_field(), config: self.config.dont_use_created_field(),
set_host: self.set_host, set_host: self.set_host,
set_date: self.set_date,
} }
} }
@ -130,6 +142,7 @@ impl Config {
Config { Config {
config: self.config.set_expiration(expiries_after), config: self.config.set_expiration(expiries_after),
set_host: self.set_host, set_host: self.set_host,
set_date: self.set_date,
} }
} }
@ -138,6 +151,7 @@ impl Config {
Config { Config {
config: self.config.require_header(header), config: self.config.require_header(header),
set_host: self.set_host, set_host: self.set_host,
set_date: self.set_date,
} }
} }
} }
@ -155,7 +169,7 @@ impl Sign for RequestBuilder {
K: Display, K: Display,
{ {
let mut request = self.build()?; let mut request = self.build()?;
let signed = prepare(&request, config, key_id, f)?; let signed = prepare(&mut request, config, key_id, f)?;
let auth_header = signed.authorization_header(); let auth_header = signed.authorization_header();
request.headers_mut().insert( request.headers_mut().insert(
@ -173,7 +187,7 @@ impl Sign for RequestBuilder {
K: Display, K: Display,
{ {
let mut request = self.build()?; let mut request = self.build()?;
let signed = prepare(&request, config, key_id, f)?; let signed = prepare(&mut request, config, key_id, f)?;
let sig_header = signed.signature_header(); let sig_header = signed.signature_header();
@ -186,12 +200,23 @@ impl Sign for RequestBuilder {
} }
} }
fn prepare<F, E, K>(req: &Request, config: &Config, key_id: K, f: F) -> Result<Signed, E> fn prepare<F, E, K>(req: &mut Request, config: &Config, key_id: K, f: F) -> Result<Signed, E>
where where
F: FnOnce(&str) -> Result<String, E>, F: FnOnce(&str) -> Result<String, E>,
E: From<SignError>, E: From<SignError>,
K: Display, K: Display,
{ {
if config.set_date {
if !req.headers().contains_key("date") {
req.headers_mut().insert(
"date",
HttpDate::from(SystemTime::now())
.to_string()
.try_into()
.map_err(SignError::from)?,
);
}
}
let mut bt = std::collections::BTreeMap::new(); let mut bt = std::collections::BTreeMap::new();
for (k, v) in req.headers().iter() { for (k, v) in req.headers().iter() {
bt.insert( bt.insert(
@ -247,7 +272,7 @@ mod middleware {
K: Display, K: Display,
{ {
let mut request = self.build()?; let mut request = self.build()?;
let signed = prepare(&request, config, key_id, f)?; let signed = prepare(&mut request, config, key_id, f)?;
let auth_header = signed.authorization_header(); let auth_header = signed.authorization_header();
request.headers_mut().insert( request.headers_mut().insert(
@ -265,7 +290,7 @@ mod middleware {
K: Display, K: Display,
{ {
let mut request = self.build()?; let mut request = self.build()?;
let signed = prepare(&request, config, key_id, f)?; let signed = prepare(&mut request, config, key_id, f)?;
let sig_header = signed.signature_header(); let sig_header = signed.signature_header();