@oxy.so/federation 2.7.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/cjs/actorObject.js +4 -1
- package/dist/cjs/groupCollections.js +61 -0
- package/dist/cjs/index.js +10 -1
- package/dist/cjs/node/actorRouter.js +33 -10
- package/dist/cjs/node/delivery.js +7 -0
- package/dist/cjs/node/goneActor.js +43 -0
- package/dist/cjs/node/index.js +8 -1
- package/dist/cjs/node/webfingerRouter.js +6 -1
- package/dist/esm/actorObject.js +4 -1
- package/dist/esm/groupCollections.js +55 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/node/actorRouter.js +33 -10
- package/dist/esm/node/delivery.js +7 -0
- package/dist/esm/node/goneActor.js +39 -0
- package/dist/esm/node/index.js +5 -0
- package/dist/esm/node/webfingerRouter.js +6 -1
- package/dist/types/groupCollections.d.ts +42 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/node/actorRouter.d.ts +11 -2
- package/dist/types/node/delivery.d.ts +9 -0
- package/dist/types/node/goneActor.d.ts +29 -0
- package/dist/types/node/index.d.ts +5 -0
- package/dist/types/node/webfingerRouter.d.ts +7 -0
- package/package.json +1 -1
- package/src/__tests__/actorObject.test.ts +1 -0
- package/src/__tests__/delivery.test.ts +23 -0
- package/src/__tests__/routers.test.ts +72 -0
- package/src/actorObject.ts +4 -1
- package/src/groupCollections.ts +67 -0
- package/src/index.ts +11 -0
- package/src/node/actorRouter.ts +40 -16
- package/src/node/delivery.ts +20 -0
- package/src/node/goneActor.ts +45 -0
- package/src/node/index.ts +6 -0
- package/src/node/webfingerRouter.ts +14 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A DELETED local actor, as the fediverse is told about it.
|
|
3
|
+
*
|
|
4
|
+
* Two halves, following Mastodon's account deletion:
|
|
5
|
+
*
|
|
6
|
+
* 1. Once, the app sends `Delete{actor}`: the actor deletes itself, signed with
|
|
7
|
+
* its own key, to every follower's (shared) inbox. That is
|
|
8
|
+
* `DeliveryService.federateActorDelete`, built by {@link buildActorDeleteActivity}.
|
|
9
|
+
* 2. From then on the actor's URLs answer `410 Gone` instead of `404`. That is
|
|
10
|
+
* what a server that missed the Delete, or never acts on one, reads as
|
|
11
|
+
* permanent: Mastodon deletes its copy of an account whose WebFinger answers
|
|
12
|
+
* 410, and Lemmy, PieFed and Mbin mark a community or person deleted when a
|
|
13
|
+
* refetch answers 410 or a `Tombstone`. A 404 tells all of them nothing, so
|
|
14
|
+
* they keep the ghost profile and keep delivering to it.
|
|
15
|
+
*
|
|
16
|
+
* The routers ask the app's `isActorGone(username)` only after `resolveUser`
|
|
17
|
+
* found nobody, so a live account is never answered as gone.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { AP_CONTEXT } from '../apContext';
|
|
21
|
+
|
|
22
|
+
/** Does `username` name a local actor that was deleted? Asked only for a username that resolved to nobody. */
|
|
23
|
+
export type IsActorGone = (username: string) => Promise<boolean>;
|
|
24
|
+
|
|
25
|
+
/** The body of a `410 Gone` for a deleted object: a bare `Tombstone` naming it. */
|
|
26
|
+
export function goneTombstone(id: string): Record<string, unknown> {
|
|
27
|
+
return { '@context': AP_CONTEXT, id, type: 'Tombstone' };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The actor's `Delete` of itself. The id is DETERMINISTIC (no timestamp), the
|
|
32
|
+
* shape Mastodon sends (`<actor>#delete`), so a retried run re-sends the same
|
|
33
|
+
* activity and a delivery queue that dedupes on activity id + inbox sends each
|
|
34
|
+
* inbox one copy.
|
|
35
|
+
*/
|
|
36
|
+
export function buildActorDeleteActivity(actorUri: string): Record<string, unknown> {
|
|
37
|
+
return {
|
|
38
|
+
'@context': AP_CONTEXT,
|
|
39
|
+
id: `${actorUri}#delete`,
|
|
40
|
+
type: 'Delete',
|
|
41
|
+
actor: actorUri,
|
|
42
|
+
to: ['https://www.w3.org/ns/activitystreams#Public'],
|
|
43
|
+
object: actorUri,
|
|
44
|
+
};
|
|
45
|
+
}
|
package/src/node/index.ts
CHANGED
|
@@ -141,6 +141,12 @@ export {
|
|
|
141
141
|
* The ActivityPub actor + inbox + follow-graph router (actor GET incl. the
|
|
142
142
|
* `instance` actor, inbox POST with HTTP-sig verify, followers/following pages).
|
|
143
143
|
*/
|
|
144
|
+
/**
|
|
145
|
+
* A deleted local actor: its `Delete` of itself, and the `Tombstone` its URLs
|
|
146
|
+
* answer `410 Gone` with afterwards.
|
|
147
|
+
*/
|
|
148
|
+
export { buildActorDeleteActivity, goneTombstone, type IsActorGone } from './goneActor';
|
|
149
|
+
|
|
144
150
|
export {
|
|
145
151
|
createActorRouter,
|
|
146
152
|
type ActorRouterConfig,
|
|
@@ -17,6 +17,7 @@ import { discoveryCacheControl } from './httpCacheControl';
|
|
|
17
17
|
import { isSameFederationHost } from '../apUri';
|
|
18
18
|
import type { UrlBuilders } from '../urls';
|
|
19
19
|
import { INSTANCE_ACTOR_USERNAME, normalizeActorUsername } from '../urls';
|
|
20
|
+
import type { IsActorGone } from './goneActor';
|
|
20
21
|
|
|
21
22
|
/** Default HTTP response max-age. The injected JRD cache has its own policy. */
|
|
22
23
|
const WEBFINGER_CACHE_TTL = 3600;
|
|
@@ -65,6 +66,12 @@ export interface WebfingerRouterConfig {
|
|
|
65
66
|
get(username: string): Promise<WebfingerJrd | null>;
|
|
66
67
|
set(username: string, jrd: WebfingerJrd): void;
|
|
67
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* Whether a username that resolved to nobody names a DELETED local actor
|
|
71
|
+
* (`goneActor.ts`). True ⇒ `410 Gone` instead of 404, which is what makes
|
|
72
|
+
* Mastodon delete its copy of the account. Omitted ⇒ every miss is a 404.
|
|
73
|
+
*/
|
|
74
|
+
isActorGone?: IsActorGone;
|
|
68
75
|
/** HTTP response TTL in whole seconds, 0..86400. Defaults to 3600; 0 sends no-store. */
|
|
69
76
|
httpCacheTtlSeconds?: number;
|
|
70
77
|
/** Diagnostics sink. */
|
|
@@ -147,7 +154,13 @@ export function createWebfingerRouter(config: WebfingerRouterConfig): Router {
|
|
|
147
154
|
}
|
|
148
155
|
|
|
149
156
|
const user = await config.resolveUser(username);
|
|
150
|
-
if (!user)
|
|
157
|
+
if (!user) {
|
|
158
|
+
if (config.isActorGone && (await config.isActorGone(username))) {
|
|
159
|
+
res.set('Cache-Control', httpCacheControl);
|
|
160
|
+
return res.status(410).json({ error: 'User deleted' });
|
|
161
|
+
}
|
|
162
|
+
return res.status(404).json({ error: 'User not found' });
|
|
163
|
+
}
|
|
151
164
|
|
|
152
165
|
// Sharing OFF must be indistinguishable from a nonexistent user — same 404
|
|
153
166
|
// body, no separate error code. UNLIKE the other user-scoped surfaces,
|