From 7dcdbb455109d1b585e4d53ddd32d57ac8283f3d Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sun, 17 May 2026 11:55:17 +0200 Subject: [PATCH] feat: implement verify() for all stub activity handlers Undo: inner activity actor must match Undo actor Announce/Like/Block: verify_domains_match(activity_id, actor_url) Add: attributedTo must match actor (same as Create/Update) --- .../activitypub-base/src/activities.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/adapters/activitypub-base/src/activities.rs b/crates/adapters/activitypub-base/src/activities.rs index 2c96fde..3ea058d 100644 --- a/crates/adapters/activitypub-base/src/activities.rs +++ b/crates/adapters/activitypub-base/src/activities.rs @@ -4,6 +4,7 @@ use activitypub_federation::{ kinds::activity::{ AcceptType, CreateType, DeleteType, FollowType, RejectType, UndoType, UpdateType, }, + protocol::verification::verify_domains_match, traits::Activity, }; use serde::{Deserialize, Serialize}; @@ -239,6 +240,14 @@ impl Activity for UndoActivity { } async fn verify(&self, _data: &Data) -> Result<(), Self::Error> { + // The actor undoing must be the same as the actor in the wrapped activity. + if let Some(inner_actor) = self.object.get("actor").and_then(|v| v.as_str()) { + if inner_actor != self.actor.inner().as_str() { + return Err(Error::bad_request(anyhow::anyhow!( + "Undo actor does not match inner activity actor" + ))); + } + } Ok(()) } @@ -570,6 +579,7 @@ impl Activity for AnnounceActivity { } async fn verify(&self, _data: &Data) -> Result<(), Self::Error> { + verify_domains_match(&self.id, self.actor.inner())?; Ok(()) } @@ -633,6 +643,7 @@ impl Activity for LikeActivity { } async fn verify(&self, _data: &Data) -> Result<(), Self::Error> { + verify_domains_match(&self.id, self.actor.inner())?; Ok(()) } @@ -692,6 +703,14 @@ impl Activity for AddActivity { } async fn verify(&self, _data: &Data) -> Result<(), Self::Error> { + if let Some(attributed_to) = self.object.get("attributedTo").and_then(|v| v.as_str()) + && let Ok(attributed_url) = Url::parse(attributed_to) + && &attributed_url != self.actor.inner() + { + return Err(Error::bad_request(anyhow::anyhow!( + "Add actor does not match object attributedTo" + ))); + } Ok(()) } @@ -742,6 +761,7 @@ impl Activity for BlockActivity { } async fn verify(&self, _data: &Data) -> Result<(), Self::Error> { + verify_domains_match(&self.id, self.actor.inner())?; Ok(()) }