From bbc376aebc5e1e6f112d722d3e50fc68cfe3733c Mon Sep 17 00:00:00 2001 From: giles Date: Mon, 23 Feb 2026 21:05:50 +0000 Subject: [PATCH] Rewrite all federation-domain URLs in object_data for per-app delivery Mastodon requires object IDs to match the actor's domain. The object_data stored in DB uses federation.rose-ash.com but per-app delivery uses blog.rose-ash.com etc. Now rewrites id and attributedTo in object_data, not just the activity-level fields. Co-Authored-By: Claude Opus 4.6 --- events/handlers/ap_delivery_handler.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/events/handlers/ap_delivery_handler.py b/events/handlers/ap_delivery_handler.py index 89260a7..0ac9299 100644 --- a/events/handlers/ap_delivery_handler.py +++ b/events/handlers/ap_delivery_handler.py @@ -15,6 +15,7 @@ On retry (at-least-once reaper), already-delivered inboxes are skipped. from __future__ import annotations import logging +import os from collections import defaultdict import httpx @@ -44,16 +45,25 @@ def _build_activity_json(activity: APActivity, actor: ActorProfile, domain: str) obj = dict(activity.object_data or {}) - # Rewrite activity ID to match the delivery domain so Mastodon's - # origin check passes (activity ID host must equal actor host). - # The stored activity_id uses the federation domain; we replace - # just the host portion for per-app delivery. + # Rewrite all URLs from the federation domain to the delivery domain + # so Mastodon's origin check passes (all IDs must match actor host). import re - activity_id = re.sub( - r"^https://[^/]+/", f"https://{domain}/", activity.activity_id, - ) + fed_domain = os.getenv("AP_DOMAIN", "federation.rose-ash.com") + + def _rewrite(url: str) -> str: + if isinstance(url, str) and fed_domain in url: + return url.replace(f"https://{fed_domain}", f"https://{domain}") + return url + + activity_id = _rewrite(activity.activity_id) object_id = activity_id + "/object" + # Rewrite any federation-domain URLs in object_data + if "id" in obj: + obj["id"] = _rewrite(obj["id"]) + if "attributedTo" in obj: + obj["attributedTo"] = _rewrite(obj["attributedTo"]) + if activity.activity_type == "Delete": obj.setdefault("id", object_id) obj.setdefault("type", "Tombstone")