fix: serve AP JSON for actor URLs without explicit text/html Accept header

Fedify's acceptsJsonLd() returns false for Accept: */* or no Accept header
because it only checks for explicit application/activity+json in the list.
Remote servers fetching actor URLs for HTTP Signature verification (e.g.
tags.pub) often omit Accept or use */*, getting HTML back instead of the
actor JSON and causing "public key not found" failures.

Add middleware to upgrade ambiguous Accept headers to application/activity+json
for GET requests to /users/:id paths. Explicit text/html requests (browsers)
are unaffected.

Also fix followActor() storing inbox: "" for actors where Fedify uses
remoteActor.inboxId?.href (not remoteActor.inbox?.id?.href). The inbox URL
is stored correctly now for all actor types.
This commit is contained in:
Ricardo
2026-03-22 13:22:27 +01:00
committed by svemagie
parent 790c9a0375
commit cb6c1b5bbc
2 changed files with 17 additions and 2 deletions

View File

@@ -239,6 +239,21 @@ export default class ActivityPubEndpoint {
console.info(`[federation-diag] POST ${req.path} from=${ua.slice(0, 60)} bodyParsed=${bodyParsed} readable=${req.readable}`);
}
// Fedify's acceptsJsonLd() treats Accept: */* as NOT accepting JSON-LD
// (it only returns true for explicit application/activity+json etc.).
// Remote servers fetching actor URLs for HTTP Signature verification
// (e.g. tags.pub) often omit Accept or use */* — they get HTML back
// instead of the actor JSON, causing "public key not found" errors.
// Fix: for GET requests to actor paths, upgrade ambiguous Accept headers
// to application/activity+json so Fedify serves JSON-LD. Explicit
// text/html requests (browsers) are unaffected.
if (req.method === "GET" && /^\/users\/[^/]+\/?$/.test(req.path)) {
const accept = req.get("accept") || "";
if (!accept.includes("text/html") && !accept.includes("application/xhtml+xml")) {
req.headers["accept"] = "application/activity+json";
}
}
return self._fedifyMiddleware(req, res, next);
});
@@ -876,7 +891,7 @@ export default class ActivityPubEndpoint {
(remoteActor.icon
? (await remoteActor.icon)?.url?.href || ""
: "");
const inbox = remoteActor.inbox?.id?.href || "";
const inbox = remoteActor.inboxId?.href || "";
const sharedInbox = remoteActor.endpoints?.sharedInbox?.href || "";
await this._collections.ap_following.updateOne(

View File

@@ -1,6 +1,6 @@
{
"name": "@rmdes/indiekit-endpoint-activitypub",
"version": "3.8.1",
"version": "3.8.2",
"description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.",
"keywords": [
"indiekit",