diff --git a/core/src/config.rs b/core/src/config.rs index 2db195b..be8ec27 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -139,6 +139,13 @@ pub struct CompatibilityConfig { #[serde_inline_default(true)] /// compatibility with lemmy: avoid showing images twice pub skip_single_attachment_if_image_is_set: bool, + + #[serde_inline_default(false)] + /// compatibility with most relays: since they send us other server's activities, we must fetch + /// them to verify that they aren't falsified by the relay itself. this is quite expensive, as + /// relays send a lot of activities and we effectively end up fetching again all these, so this + /// defaults to false + pub verify_relayed_activities_by_fetching: bool, } #[serde_inline_default::serde_inline_default] diff --git a/routes/src/activitypub/inbox.rs b/routes/src/activitypub/inbox.rs index 4253d1f..4666203 100644 --- a/routes/src/activitypub/inbox.rs +++ b/routes/src/activitypub/inbox.rs @@ -1,7 +1,7 @@ use apb::{Activity, ActivityType, Base}; use axum::{extract::{Query, State}, http::StatusCode, Json}; use sea_orm::{sea_query::IntoCondition, ActiveValue::{NotSet, Set}, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect}; -use upub::{model::job::JobType, selector::{RichActivity, RichFillable}, Context}; +use upub::{model::job::JobType, selector::{RichActivity, RichFillable}, traits::Fetcher, Context}; use crate::{AuthIdentity, Identity, builders::JsonLD}; @@ -41,7 +41,7 @@ pub async fn page( pub async fn post( State(ctx): State<Context>, AuthIdentity(auth): AuthIdentity, - Json(activity): Json<serde_json::Value> + Json(mut activity): Json<serde_json::Value> ) -> crate::ApiResult<StatusCode> { let Identity::Remote { domain, user: uid, .. } = auth else { if matches!(activity.activity_type(), Ok(ActivityType::Delete)) { @@ -72,7 +72,11 @@ pub async fn post( let server = upub::Context::server(&aid); if activity.actor().id()? != uid { - return Err(crate::ApiError::forbidden()); + if ctx.cfg().compat.verify_relayed_activities_by_fetching { + activity = ctx.pull(&activity.id()?).await?.activity()?; + } else { + return Err(crate::ApiError::forbidden()); + } } if let Some(_internal) = upub::model::activity::Entity::ap_to_internal(&aid, ctx.db()).await? {