relay/src/requests.rs

167 lines
5.1 KiB
Rust
Raw Normal View History

2020-03-23 22:17:53 +00:00
use crate::error::MyError;
use activitystreams::primitives::XsdAnyUri;
2020-03-18 04:35:20 +00:00
use actix_web::client::Client;
use bytes::Bytes;
2020-03-18 04:35:20 +00:00
use http_signature_normalization_actix::prelude::*;
use log::{error, info};
2020-03-18 04:35:20 +00:00
use rsa::{hash::Hashes, padding::PaddingScheme, RSAPrivateKey};
use sha2::{Digest, Sha256};
#[derive(Clone)]
pub struct Requests {
client: Client,
key_id: String,
private_key: RSAPrivateKey,
config: Config,
2020-03-19 19:05:16 +00:00
user_agent: String,
2020-03-18 04:35:20 +00:00
}
2020-03-18 04:35:20 +00:00
impl Requests {
2020-03-23 22:17:53 +00:00
pub fn new(key_id: String, private_key: RSAPrivateKey, user_agent: String) -> Self {
2020-03-18 04:35:20 +00:00
Requests {
client: Client::default(),
key_id,
private_key,
config: Config::default().dont_use_created_field(),
2020-03-19 19:05:16 +00:00
user_agent,
2020-03-18 04:35:20 +00:00
}
}
2020-03-18 04:35:20 +00:00
pub async fn fetch<T>(&self, url: &str) -> Result<T, MyError>
where
T: serde::de::DeserializeOwned,
{
let mut res = self
.client
.get(url)
.header("Accept", "application/activity+json")
2020-03-19 19:05:16 +00:00
.header("User-Agent", self.user_agent.as_str())
2020-03-18 04:35:20 +00:00
.signature(&self.config, &self.key_id, |signing_string| {
self.sign(signing_string)
})?
.send()
.await
.map_err(|e| {
error!("Couldn't send request to {}, {}", url, e);
MyError::SendRequest
})?;
if !res.status().is_success() {
if let Ok(bytes) = res.body().await {
if let Ok(s) = String::from_utf8(bytes.as_ref().to_vec()) {
if !s.is_empty() {
error!("Response, {}", s);
}
2020-03-18 04:35:20 +00:00
}
}
2020-03-18 04:35:20 +00:00
return Err(MyError::Status(res.status()));
}
2020-03-18 04:35:20 +00:00
res.json().await.map_err(|e| {
error!("Coudn't fetch json from {}, {}", url, e);
MyError::ReceiveResponse
})
}
pub async fn fetch_bytes(&self, url: &str) -> Result<(String, Bytes), MyError> {
info!("Fetching bytes for {}", url);
let mut res = self
.client
.get(url)
.header("Accept", "application/activity+json")
.header("User-Agent", self.user_agent.as_str())
.signature(&self.config, &self.key_id, |signing_string| {
self.sign(signing_string)
})?
.send()
.await
.map_err(|e| {
error!("Couldn't send request to {}, {}", url, e);
MyError::SendRequest
})?;
let content_type = if let Some(content_type) = res.headers().get("content-type") {
if let Ok(s) = content_type.to_str() {
s.to_owned()
} else {
return Err(MyError::ContentType);
}
} else {
return Err(MyError::ContentType);
};
if !res.status().is_success() {
if let Ok(bytes) = res.body().await {
if let Ok(s) = String::from_utf8(bytes.as_ref().to_vec()) {
if !s.is_empty() {
error!("Response, {}", s);
}
}
}
return Err(MyError::Status(res.status()));
}
let bytes = match res.body().limit(1024 * 1024 * 4).await {
Err(e) => {
error!("Coudn't fetch json from {}, {}", url, e);
return Err(MyError::ReceiveResponse);
}
Ok(bytes) => bytes,
};
Ok((content_type, bytes))
}
2020-03-18 04:35:20 +00:00
pub async fn deliver<T>(&self, inbox: XsdAnyUri, item: &T) -> Result<(), MyError>
where
T: serde::ser::Serialize,
{
let mut digest = Sha256::new();
let item_string = serde_json::to_string(item)?;
let mut res = self
.client
.post(inbox.as_str())
.header("Accept", "application/activity+json")
.header("Content-Type", "application/activity+json")
2020-03-19 19:05:16 +00:00
.header("User-Agent", self.user_agent.as_str())
2020-03-18 04:35:20 +00:00
.signature_with_digest(
&self.config,
&self.key_id,
&mut digest,
item_string,
|signing_string| self.sign(signing_string),
)?
.send()
.await
.map_err(|e| {
error!("Couldn't send deliver request to {}, {}", inbox, e);
MyError::SendRequest
})?;
if !res.status().is_success() {
if let Ok(bytes) = res.body().await {
if let Ok(s) = String::from_utf8(bytes.as_ref().to_vec()) {
if !s.is_empty() {
error!("Response, {}", s);
}
2020-03-18 04:35:20 +00:00
}
}
return Err(MyError::Status(res.status()));
2020-03-18 04:35:20 +00:00
}
2020-03-18 04:35:20 +00:00
Ok(())
}
fn sign(&self, signing_string: &str) -> Result<String, MyError> {
2020-03-18 04:35:20 +00:00
let hashed = Sha256::digest(signing_string.as_bytes());
let bytes =
self.private_key
.sign(PaddingScheme::PKCS1v15, Some(&Hashes::SHA2_256), &hashed)?;
Ok(base64::encode(bytes))
}
}