1
0
Fork 0
forked from alemi/upub

feat: catch dispatcher errors

This commit is contained in:
əlemi 2024-03-26 03:11:59 +01:00
parent 81b6a7183a
commit e6b30975cc
Signed by: alemi
GPG key ID: A4895B84D311642C
2 changed files with 99 additions and 90 deletions

View file

@ -26,6 +26,9 @@ pub enum UpubError {
#[error("missing field: {0}")] #[error("missing field: {0}")]
Field(#[from] FieldError), Field(#[from] FieldError),
#[error("openssl error: {0}")]
OpenSSL(#[from] openssl::error::ErrorStack),
} }
impl From<StatusCode> for UpubError { impl From<StatusCode> for UpubError {

View file

@ -1,16 +1,24 @@
use base64::Engine; use base64::Engine;
use openssl::{hash::MessageDigest, pkey::PKey, sign::Signer}; use openssl::{hash::MessageDigest, pkey::PKey, sign::Signer};
use reqwest::header::USER_AGENT; use reqwest::header::USER_AGENT;
use sea_orm::{ColumnTrait, Condition, DatabaseConnection, DbErr, EntityTrait, Order, QueryFilter, QueryOrder, QuerySelect, SelectColumns}; use sea_orm::{ColumnTrait, Condition, DatabaseConnection, EntityTrait, Order, QueryFilter, QueryOrder, QuerySelect, SelectColumns};
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use crate::{VERSION, activitypub::{activity::ap_activity, object::ap_object}, activitystream::{object::activity::ActivityMut, Node}, model}; use crate::{activitypub::{activity::ap_activity, object::ap_object, user::outbox::UpubError}, activitystream::{object::activity::ActivityMut, Node}, model, VERSION};
pub struct Dispatcher; pub struct Dispatcher;
impl Dispatcher { impl Dispatcher {
pub fn spawn(db: DatabaseConnection, domain: String, poll_interval: u64) -> JoinHandle<Result<(), DbErr>> { pub fn spawn(db: DatabaseConnection, domain: String, poll_interval: u64) -> JoinHandle<()> {
tokio::spawn(async move { tokio::spawn(async move {
if let Err(e) = worker(db, domain, poll_interval).await {
tracing::error!("delivery worker exited with error: {e}");
}
})
}
}
async fn worker(db: DatabaseConnection, domain: String, poll_interval: u64) -> Result<(), UpubError> {
let mut nosleep = true; let mut nosleep = true;
loop { loop {
if nosleep { nosleep = false } else { if nosleep { nosleep = false } else {
@ -74,15 +82,15 @@ impl Dispatcher {
continue; continue;
}; };
let mut signer = Signer::new(MessageDigest::sha256(), &key).unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &key)?;
let without_protocol = delivery.target.replace("https://", "").replace("http://", ""); let without_protocol = delivery.target.replace("https://", "").replace("http://", "");
let host = without_protocol.replace('/', ""); let host = without_protocol.replace('/', "");
let request_target = without_protocol.replace(&host, ""); let request_target = without_protocol.replace(&host, "");
let date = chrono::Utc::now().to_rfc2822(); let date = chrono::Utc::now().to_rfc2822();
let signed_string = format!("(request-target): post {request_target}\nhost: {host}\ndate: {date}"); let signed_string = format!("(request-target): post {request_target}\nhost: {host}\ndate: {date}");
signer.update(signed_string.as_bytes()).unwrap(); signer.update(signed_string.as_bytes())?;
let signature = base64::prelude::BASE64_URL_SAFE.encode(signer.sign_to_vec().unwrap()); let signature = base64::prelude::BASE64_URL_SAFE.encode(signer.sign_to_vec()?);
let signature_header = format!("keyId=\"{}\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date\",signature=\"{signature}\"", delivery.actor); let signature_header = format!("keyId=\"{}\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date\",signature=\"{signature}\"", delivery.actor);
if let Err(e) = deliver(&delivery.target, &payload, host, date, signature_header, &domain).await { if let Err(e) = deliver(&delivery.target, &payload, host, date, signature_header, &domain).await {
@ -99,8 +107,6 @@ impl Dispatcher {
model::delivery::Entity::insert(new_delivery).exec(&db).await?; model::delivery::Entity::insert(new_delivery).exec(&db).await?;
} }
} }
})
}
} }
async fn deliver(target: &str, payload: &serde_json::Value, host: String, date: String, signature_header: String, domain: &str) -> Result<(), reqwest::Error> { async fn deliver(target: &str, payload: &serde_json::Value, host: String, date: String, signature_header: String, domain: &str) -> Result<(), reqwest::Error> {