From e8b2b807b2cd55b29d9bf1b25c9cdbaff68d223d Mon Sep 17 00:00:00 2001 From: Astro Date: Sun, 14 May 2023 22:44:26 +0200 Subject: [PATCH] fetch: add authorized_fetch() --- src/digest.rs | 20 ++++++++++++++++++++ src/fetch.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/main.rs | 2 +- src/send.rs | 17 +++-------------- 4 files changed, 63 insertions(+), 15 deletions(-) create mode 100644 src/digest.rs diff --git a/src/digest.rs b/src/digest.rs new file mode 100644 index 0000000..32d6eab --- /dev/null +++ b/src/digest.rs @@ -0,0 +1,20 @@ +use http_digest_headers::{DigestHeader, DigestMethod}; + +pub fn generate_header(body: &[u8]) -> Result { + let mut digest_header = DigestHeader::new() + .with_method(DigestMethod::SHA256, body) + .map(|h| format!("{}", h)) + .map_err(|_| ())?; + + // mastodon expects uppercase algo name + if digest_header.starts_with("sha-") { + digest_header.replace_range(..4, "SHA-"); + } + // mastodon uses base64::alphabet::STANDARD, not base64::alphabet::URL_SAFE + digest_header.replace_range( + 7.., + &digest_header[7..].replace('-', "+").replace('_', "/") + ); + + Ok(digest_header) +} diff --git a/src/fetch.rs b/src/fetch.rs index 3b0d5d2..6e8ee06 100644 --- a/src/fetch.rs +++ b/src/fetch.rs @@ -1,4 +1,8 @@ +use http::StatusCode; use serde::de::DeserializeOwned; +use sigh::{PrivateKey, SigningConfig, alg::RsaSha256}; +use crate::digest; +use crate::send::SendError; pub async fn fetch(client: &reqwest::Client, url: &str) -> Result where @@ -11,3 +15,38 @@ where .json() .await } + +pub async fn authorized_fetch( + client: &reqwest::Client, + uri: &str, + key_id: &str, + private_key: &PrivateKey, +) -> Result +where + T: DeserializeOwned, +{ + let url = reqwest::Url::parse(uri) + .map_err(|_| SendError::InvalidUri)?; + let host = format!("{}", url.host().ok_or(SendError::InvalidUri)?); + let digest_header = digest::generate_header(&[]) + .expect("digest::generate_header"); + let mut req = http::Request::builder() + .uri(uri) + .header("host", &host) + .header("content-type", "application/activity+json") + .header("date", chrono::Utc::now().to_rfc2822() + .replace("+0000", "GMT")) + .header("accept", "application/activity+json") + .header("digest", digest_header) + .body(vec![])?; + SigningConfig::new(RsaSha256, private_key, key_id) + .sign(&mut req)?; + let req: reqwest::Request = req.try_into()?; + let res = client.execute(req) + .await?; + if res.status() >= StatusCode::OK && res.status() < StatusCode::MULTIPLE_CHOICES { + Ok(res.json().await?) + } else { + Err(SendError::Response(format!("{}", res.text().await?))) + } +} diff --git a/src/main.rs b/src/main.rs index eac2e46..2d67dcf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,8 +17,8 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; mod config; mod actor; mod db; +mod digest; mod fetch; -pub use fetch::fetch; mod send; mod stream; mod relay; diff --git a/src/send.rs b/src/send.rs index de817f1..11fb7aa 100644 --- a/src/send.rs +++ b/src/send.rs @@ -47,22 +47,11 @@ pub async fn send_raw( private_key: &PrivateKey, body: Arc>, ) -> Result<(), SendError> { - let mut digest_header = DigestHeader::new() - .with_method(DigestMethod::SHA256, &body) - .map(|h| format!("{}", h)) - .map_err(|_| SendError::Digest)?; - if digest_header.starts_with("sha-") { - digest_header.replace_range(..4, "SHA-"); - } - // mastodon uses base64::alphabet::STANDARD, not base64::alphabet::URL_SAFE - digest_header.replace_range( - 7.., - &digest_header[7..].replace('-', "+").replace('_', "/") - ); - let url = reqwest::Url::parse(uri) - .map_err(|_| SendError::InvalidUri)?; + .map_err(|_| Error::InvalidUri)?; let host = format!("{}", url.host().ok_or(SendError::InvalidUri)?); + let digest_header = digest::generate_header(&body) + .map_err(|()| SendError::Digest)?; let mut req = http::Request::builder() .method("POST") .uri(uri)