From a9dbe5dd9c61d8be7b217dc9eddb0ec97fad9439 Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 31 Dec 2024 17:11:06 +0100 Subject: [PATCH] feat: add fetch rejection policy --- upub/core/src/config.rs | 4 ++++ upub/core/src/traits/fetch.rs | 12 +++++++++++- upub/routes/src/activitypub/application.rs | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/upub/core/src/config.rs b/upub/core/src/config.rs index ef30d52..b76c795 100644 --- a/upub/core/src/config.rs +++ b/upub/core/src/config.rs @@ -154,6 +154,10 @@ pub struct RejectConfig { /// discard incoming activities from these instances pub incoming: Vec, + #[serde(default)] + /// prevent fetching content from these instances + pub fetch: Vec, + #[serde(default)] /// prevent content from these instances from being displayed publicly /// this effectively removes the public (aka NULL) addressing: only other addressees (followers, diff --git a/upub/core/src/traits/fetch.rs b/upub/core/src/traits/fetch.rs index 93a9a47..4def445 100644 --- a/upub/core/src/traits/fetch.rs +++ b/upub/core/src/traits/fetch.rs @@ -42,6 +42,9 @@ pub enum RequestError { #[error("resource no longer exists")] Tombstone, + #[error("request aborted due to configured policies")] + AbortedForPolicy, + #[error("error constructing http signature: {0:?}")] HttpSignature(#[from] httpsign::HttpSignatureError), } @@ -131,7 +134,7 @@ pub trait Fetcher { let mut signer = HttpSignature::new( format!("{from}#main-key"), // TODO don't hardcode #main-key - //"hs2019".to_string(), // pixelfeed/iceshrimp made me go back + //"hs2019".to_string(), // TODO could we switch to this now? "rsa-sha256".to_string(), &headers, ); @@ -168,6 +171,10 @@ pub trait Fetcher { #[async_trait::async_trait] impl Fetcher for crate::Context { async fn pull_r(&self, id: &str, depth: u32) -> Result, RequestError> { + if crate::ext::is_blacklisted(id, &self.cfg().reject.fetch) { + return Err(RequestError::AbortedForPolicy); + } + tracing::debug!("fetching {id}"); // let _domain = self.fetch_domain(&crate::Context::server(id)).await?; @@ -526,6 +533,9 @@ impl Dereferenceable for apb::Node { match self { apb::Node::Link(uri) => { let href = uri.href()?; + if crate::ext::is_blacklisted(&href, &ctx.cfg().reject.fetch) { + return Err(RequestError::AbortedForPolicy); + } tracing::info!("dereferencing {href}"); let res = crate::Context::request(Method::GET, &href, None, ctx.base(), ctx.pkey(), ctx.domain()) .await? diff --git a/upub/routes/src/activitypub/application.rs b/upub/routes/src/activitypub/application.rs index 9934fbc..eb93ba5 100644 --- a/upub/routes/src/activitypub/application.rs +++ b/upub/routes/src/activitypub/application.rs @@ -117,6 +117,10 @@ pub async fn ap_fetch( }, }; + if upub::ext::is_blacklisted(&query.uri, &ctx.cfg().reject.fetch) { + return Err(crate::ApiError::FetchError(upub::traits::fetch::RequestError::AbortedForPolicy)); + } + let resp = Context::request( Method::GET, &query.uri,