buzzrelay/src/fetch.rs

47 lines
1.6 KiB
Rust
Raw Permalink Normal View History

use std::time::SystemTime;
2023-05-14 20:44:26 +00:00
use http::StatusCode;
2022-12-11 00:07:39 +00:00
use serde::de::DeserializeOwned;
2023-05-14 20:44:26 +00:00
use sigh::{PrivateKey, SigningConfig, alg::RsaSha256};
use tokio::task::spawn_blocking;
2023-05-14 20:58:00 +00:00
use crate::{digest, error::Error};
2022-12-11 00:07:39 +00:00
2023-05-14 20:44:26 +00:00
pub async fn authorized_fetch<T>(
client: &reqwest::Client,
uri: &str,
key_id: &str,
private_key: &PrivateKey,
2023-05-14 20:58:00 +00:00
) -> Result<T, Error>
2023-05-14 20:44:26 +00:00
where
T: DeserializeOwned,
{
let url = reqwest::Url::parse(uri)
2023-05-14 20:58:00 +00:00
.map_err(|_| Error::InvalidUri)?;
let host = format!("{}", url.host().ok_or(Error::InvalidUri)?);
2023-05-14 20:44:26 +00:00
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", httpdate::fmt_http_date(SystemTime::now()))
2023-05-14 20:44:26 +00:00
.header("accept", "application/activity+json")
.header("digest", digest_header)
.body(vec![])?;
let private_key = private_key.clone();
let key_id = key_id.to_string();
let req = spawn_blocking(move || {
SigningConfig::new(RsaSha256, &private_key, &key_id).sign(&mut req)?;
Ok(req)
})
.await
.map_err(|e| Error::Response(format!("{e}")))?
.map_err(|e: sigh::Error| Error::Response(format!("{e}")))?;
2023-05-14 20:44:26 +00:00
let req: reqwest::Request = req.try_into()?;
let res = client.execute(req).await?;
2023-05-14 20:44:26 +00:00
if res.status() >= StatusCode::OK && res.status() < StatusCode::MULTIPLE_CHOICES {
Ok(res.json().await?)
} else {
2023-05-14 21:29:36 +00:00
Err(Error::Response(res.text().await?))
2023-05-14 20:44:26 +00:00
}
}