-
-
Notifications
You must be signed in to change notification settings - Fork 96
Description
Problem
The actor dispatcher currently returns Actor | null, which makes it impossible to represent a deleted or suspended account properly. When null is returned, Fedify passes the request to the next middleware without responding—so there is no way to return an HTTP 410 Gone with a Tombstone object, which is what ActivityPub §6.2 expects for deleted actors.
Applications that need to handle this case today are forced to work around Fedify by registering a separate route that catches requests Fedify declines and manually returns the 410 response. This is workable, but it means the application has to duplicate logic and manage two separate code paths for what should be a single concern.
The same problem applies to WebFinger: when a remote server looks up a deleted account, it should receive 410 Gone there too, not a 200 with a stale resource descriptor or a 404.
Proposed solution
Extend the actor dispatcher return type from Actor | null to Actor | Tombstone | null. When the dispatcher returns a Tombstone, Fedify should:
- respond to the actor endpoint with
HTTP 410 Goneand the serializedTombstoneas the body - respond to the corresponding WebFinger lookup with
HTTP 410 Gone
Returning null continues to mean “not handled” (pass through to the next middleware), so there is no change to existing behavior.
API design
The only change is to the dispatcher callback signature:
federation.setActorDispatcher("/users/{identifier}", async (ctx, identifier) => {
const account = await db.getAccount(identifier);
if (account == null) return null;
if (account.deletedAt != null) {
return new Tombstone({
id: ctx.getActorUri(identifier),
deleted: account.deletedAt,
});
}
return new Person({
id: ctx.getActorUri(identifier),
// ...
});
});No new methods or options are needed. The Tombstone type is already part of @fedify/vocab.
Response format
When the dispatcher returns a Tombstone, the actor endpoint should respond with:
HTTP/1.1 410 Gone
Content-Type: application/activity+json
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.com/users/alice",
"type": "Tombstone",
"deleted": "2024-01-15T00:00:00Z"
}The deleted field is not required by the spec, but it is widely expected by implementations like Mastodon for cache invalidation.
For WebFinger, a 410 Gone with an empty body (or no body) is appropriate.
Considerations
The change is purely additive. Existing dispatcher implementations that return Actor | null are unaffected, and Tombstone in the return type is opt-in.
Fedify already logs a warning when the returned actor's id does not match the expected actor URI, without blocking the response. The same behavior should apply to Tombstone: warn if the id is mismatched, but still respond with 410 Gone.