@oxy.so/federation 2.2.1 → 2.3.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/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/apUri.js +4 -2
- package/dist/cjs/httpSignature.js +1 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/networkIdentity.js +3 -2
- package/dist/cjs/node/actorResolver.js +24 -20
- package/dist/cjs/node/actorRouter.js +12 -4
- package/dist/cjs/node/delivery.js +7 -4
- package/dist/cjs/node/inboundDispatch.js +4 -3
- package/dist/cjs/node/index.js +7 -1
- package/dist/cjs/node/tcoLinks.js +97 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/apUri.js +4 -2
- package/dist/esm/httpSignature.js +1 -1
- package/dist/esm/index.js +3 -3
- package/dist/esm/networkIdentity.js +3 -2
- package/dist/esm/node/actorResolver.js +24 -20
- package/dist/esm/node/actorRouter.js +12 -4
- package/dist/esm/node/delivery.js +7 -4
- package/dist/esm/node/inboundDispatch.js +4 -3
- package/dist/esm/node/index.js +5 -0
- package/dist/esm/node/tcoLinks.js +94 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/httpSignature.d.ts +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/node/delivery.d.ts +2 -3
- package/dist/types/node/index.d.ts +5 -0
- package/dist/types/node/tcoLinks.d.ts +41 -0
- package/package.json +2 -3
- package/src/__tests__/actorCollectionCounts.test.ts +27 -18
- package/src/__tests__/actorObject.test.ts +27 -7
- package/src/__tests__/actorResolver.test.ts +37 -22
- package/src/__tests__/actorResolverNetworkIdentity.test.ts +73 -36
- package/src/__tests__/apUri.test.ts +9 -5
- package/src/__tests__/delivery.test.ts +56 -24
- package/src/__tests__/federationHost.test.ts +13 -3
- package/src/__tests__/httpSignature.test.ts +1 -3
- package/src/__tests__/inboundDispatch.test.ts +80 -30
- package/src/__tests__/networkIdentity.test.ts +240 -113
- package/src/__tests__/routers.test.ts +87 -27
- package/src/__tests__/tcoLinks.test.ts +21 -0
- package/src/actorObject.ts +8 -3
- package/src/apUri.ts +6 -2
- package/src/httpSignature.ts +1 -1
- package/src/index.ts +8 -3
- package/src/networkIdentity.ts +14 -5
- package/src/node/actorResolver.ts +91 -50
- package/src/node/actorRouter.ts +38 -12
- package/src/node/delivery.ts +55 -21
- package/src/node/identityBridge.ts +38 -18
- package/src/node/inboundDispatch.ts +33 -13
- package/src/node/index.ts +11 -0
- package/src/node/signedFetch.ts +3 -1
- package/src/node/tcoLinks.ts +114 -0
|
@@ -29,21 +29,27 @@ interface StoredActor extends DeliveryActorFields {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/** A capturing test rig: records every delivered/queued activity + enqueue jobs. */
|
|
32
|
-
function makeRig(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
function makeRig(
|
|
33
|
+
overrides: {
|
|
34
|
+
actorsByUri?: Record<string, StoredActor>;
|
|
35
|
+
followerActorUris?: string[];
|
|
36
|
+
followerInboxes?: Record<string, { sharedInboxUrl?: string | null; inboxUrl?: string | null }>;
|
|
37
|
+
enqueueReturns?: boolean;
|
|
38
|
+
federationEnabled?: boolean;
|
|
39
|
+
sharingEnabled?: boolean;
|
|
40
|
+
assertSafeInboxUrl?: DeliveryServiceConfig<StoredActor>['assertSafeInboxUrl'];
|
|
41
|
+
blockedHosts?: string[];
|
|
42
|
+
} = {},
|
|
43
|
+
) {
|
|
42
44
|
const deliveredBodies: Array<{ url: string; body: string }> = [];
|
|
43
45
|
const enqueued: DeliveryQueueJob[] = [];
|
|
44
46
|
const fallbackCreates: Array<DeliveryQueueJob & { nextAttemptAt: Date }> = [];
|
|
45
47
|
const fallbackInserts: Array<DeliveryQueueJob & { nextAttemptAt: Date }> = [];
|
|
46
|
-
const upsertedFollows: Array<{
|
|
48
|
+
const upsertedFollows: Array<{
|
|
49
|
+
localOxyUserId: string;
|
|
50
|
+
remoteActorUri: string;
|
|
51
|
+
activityId: string;
|
|
52
|
+
}> = [];
|
|
47
53
|
const deletedFollowIds: unknown[] = [];
|
|
48
54
|
const refreshedInBackground: string[] = [];
|
|
49
55
|
|
|
@@ -65,7 +71,10 @@ function makeRig(overrides: {
|
|
|
65
71
|
deliverSingleHop: async (url, init): Promise<DeliverSingleHopResult> => {
|
|
66
72
|
deliveredBodies.push({ url, body: init.body });
|
|
67
73
|
// 202 Accepted — success path (response body destroyed, never read).
|
|
68
|
-
return {
|
|
74
|
+
return {
|
|
75
|
+
response: Readable.from([]) as unknown as DeliverSingleHopResult['response'],
|
|
76
|
+
status: 202,
|
|
77
|
+
};
|
|
69
78
|
},
|
|
70
79
|
assertSafeInboxUrl: overrides.assertSafeInboxUrl ?? (async () => ({ ok: true })),
|
|
71
80
|
transport: {
|
|
@@ -89,7 +98,10 @@ function makeRig(overrides: {
|
|
|
89
98
|
findActorInboxesByUris: async (uris) =>
|
|
90
99
|
uris
|
|
91
100
|
.map((u) => overrides.followerInboxes?.[u])
|
|
92
|
-
.filter(
|
|
101
|
+
.filter(
|
|
102
|
+
(a): a is { sharedInboxUrl?: string | null; inboxUrl?: string | null } =>
|
|
103
|
+
a !== undefined,
|
|
104
|
+
),
|
|
93
105
|
},
|
|
94
106
|
follows: {
|
|
95
107
|
listAcceptedInboundFollowerActorUris: async () => overrides.followerActorUris ?? [],
|
|
@@ -98,7 +110,9 @@ function makeRig(overrides: {
|
|
|
98
110
|
},
|
|
99
111
|
findOutbound: async (_localOxyUserId, remoteActorUri) => {
|
|
100
112
|
const actor = overrides.actorsByUri?.[remoteActorUri];
|
|
101
|
-
return actor
|
|
113
|
+
return actor
|
|
114
|
+
? { _id: actor._id, activityId: `${urls.actor('alice')}/follows/${String(actor._id)}` }
|
|
115
|
+
: null;
|
|
102
116
|
},
|
|
103
117
|
deleteById: async (id) => {
|
|
104
118
|
deletedFollowIds.push(id);
|
|
@@ -120,7 +134,11 @@ function makeRig(overrides: {
|
|
|
120
134
|
}),
|
|
121
135
|
},
|
|
122
136
|
profile: { getBanner: async () => 'https://cdn.example/banner.png' },
|
|
123
|
-
buildLocalActorObject: (params) => ({
|
|
137
|
+
buildLocalActorObject: (params) => ({
|
|
138
|
+
id: urls.actor(params.username),
|
|
139
|
+
type: 'Person',
|
|
140
|
+
name: params.displayName,
|
|
141
|
+
}),
|
|
124
142
|
logger: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
|
|
125
143
|
isBlockedDomain: domainPolicy.isBlockedDomain,
|
|
126
144
|
};
|
|
@@ -173,7 +191,11 @@ describe('sendFollow', () => {
|
|
|
173
191
|
expect(result).toEqual({ success: true, pending: false });
|
|
174
192
|
expect(rig.refreshedInBackground).toEqual([remote]);
|
|
175
193
|
expect(rig.upsertedFollows).toEqual([
|
|
176
|
-
{
|
|
194
|
+
{
|
|
195
|
+
localOxyUserId: 'u-alice',
|
|
196
|
+
remoteActorUri: remote,
|
|
197
|
+
activityId: `${urls.actor('alice')}/follows/ACTID`,
|
|
198
|
+
},
|
|
177
199
|
]);
|
|
178
200
|
// Byte-frozen Follow activity — the bare AS2 context (NOT the full AP_CONTEXT).
|
|
179
201
|
expect(rig.deliveredBodies).toHaveLength(1);
|
|
@@ -185,7 +207,11 @@ describe('sendFollow', () => {
|
|
|
185
207
|
|
|
186
208
|
it('short-circuits when federation is disabled', async () => {
|
|
187
209
|
const rig = makeRig({ federationEnabled: false });
|
|
188
|
-
const result = await rig.service.sendFollow(
|
|
210
|
+
const result = await rig.service.sendFollow(
|
|
211
|
+
'u-alice',
|
|
212
|
+
'alice',
|
|
213
|
+
'https://remote.example/users/bob',
|
|
214
|
+
);
|
|
189
215
|
expect(result).toEqual({ success: false, pending: false });
|
|
190
216
|
expect(rig.deliveredBodies).toHaveLength(0);
|
|
191
217
|
expect(rig.upsertedFollows).toHaveLength(0);
|
|
@@ -214,7 +240,9 @@ describe('sendAccept', () => {
|
|
|
214
240
|
it('delivers the exact Accept(Follow) activity with the full AP_CONTEXT', async () => {
|
|
215
241
|
const remote = 'https://remote.example/users/bob';
|
|
216
242
|
const rig = makeRig({
|
|
217
|
-
actorsByUri: {
|
|
243
|
+
actorsByUri: {
|
|
244
|
+
[remote]: { _id: 'A', uri: remote, inboxUrl: 'https://remote.example/inbox' },
|
|
245
|
+
},
|
|
218
246
|
});
|
|
219
247
|
|
|
220
248
|
await rig.service.sendAccept('u-alice', 'alice', 'https://remote.example/follows/1', remote);
|
|
@@ -265,7 +293,9 @@ describe('sendAccept', () => {
|
|
|
265
293
|
const remote = 'https://blocked.example/users/bob';
|
|
266
294
|
const rig = makeRig({
|
|
267
295
|
blockedHosts: ['blocked.example'],
|
|
268
|
-
actorsByUri: {
|
|
296
|
+
actorsByUri: {
|
|
297
|
+
[remote]: { _id: 'A', uri: remote, inboxUrl: 'https://blocked.example/inbox' },
|
|
298
|
+
},
|
|
269
299
|
});
|
|
270
300
|
|
|
271
301
|
await rig.service.sendAccept('u-alice', 'alice', 'https://blocked.example/follows/1', remote);
|
|
@@ -279,7 +309,9 @@ describe('sendUndoFollow', () => {
|
|
|
279
309
|
it('deletes the local follow, then delivers the exact Undo(Follow) with AP_CONTEXT', async () => {
|
|
280
310
|
const remote = 'https://remote.example/users/bob';
|
|
281
311
|
const rig = makeRig({
|
|
282
|
-
actorsByUri: {
|
|
312
|
+
actorsByUri: {
|
|
313
|
+
[remote]: { _id: 'A', uri: remote, inboxUrl: 'https://remote.example/inbox' },
|
|
314
|
+
},
|
|
283
315
|
});
|
|
284
316
|
|
|
285
317
|
const ok = await rig.service.sendUndoFollow('u-alice', 'alice', remote);
|
|
@@ -307,7 +339,9 @@ describe('sendUndoFollow', () => {
|
|
|
307
339
|
const remote = 'https://blocked.example/users/bob';
|
|
308
340
|
const rig = makeRig({
|
|
309
341
|
blockedHosts: ['blocked.example'],
|
|
310
|
-
actorsByUri: {
|
|
342
|
+
actorsByUri: {
|
|
343
|
+
[remote]: { _id: 'A', uri: remote, inboxUrl: 'https://blocked.example/inbox' },
|
|
344
|
+
},
|
|
311
345
|
});
|
|
312
346
|
|
|
313
347
|
const ok = await rig.service.sendUndoFollow('u-alice', 'alice', remote);
|
|
@@ -366,9 +400,7 @@ describe('deliverToFollowers', () => {
|
|
|
366
400
|
|
|
367
401
|
it('skips unsafe inbox URLs instead of enqueueing or falling back', async () => {
|
|
368
402
|
const unsafeGuard = jest.fn(async (url: string) =>
|
|
369
|
-
url.includes('unsafe')
|
|
370
|
-
? { ok: false as const, reason: 'blocked' }
|
|
371
|
-
: { ok: true as const },
|
|
403
|
+
url.includes('unsafe') ? { ok: false as const, reason: 'blocked' } : { ok: true as const },
|
|
372
404
|
);
|
|
373
405
|
const rig = makeRig({
|
|
374
406
|
followerActorUris: ['a', 'b'],
|
|
@@ -49,7 +49,11 @@ const CASES: ReadonlyArray<{
|
|
|
49
49
|
}> = [
|
|
50
50
|
{ name: 'exact host', actorUri: 'https://spam.example/users/bob', expectedBlocked: true },
|
|
51
51
|
{ name: 'uppercase host', actorUri: 'https://SPAM.EXAMPLE/users/bob', expectedBlocked: true },
|
|
52
|
-
{
|
|
52
|
+
{
|
|
53
|
+
name: 'www. on the wire',
|
|
54
|
+
actorUri: 'https://www.spam.example/users/bob',
|
|
55
|
+
expectedBlocked: true,
|
|
56
|
+
},
|
|
53
57
|
{
|
|
54
58
|
name: 'www. on the blocklist entry, bare on the wire',
|
|
55
59
|
actorUri: 'https://spam.example/users/bob',
|
|
@@ -86,7 +90,11 @@ const CASES: ReadonlyArray<{
|
|
|
86
90
|
entry: 'über.example',
|
|
87
91
|
expectedBlocked: false,
|
|
88
92
|
},
|
|
89
|
-
{
|
|
93
|
+
{
|
|
94
|
+
name: 'unrelated host',
|
|
95
|
+
actorUri: 'https://mastodon.social/users/alice',
|
|
96
|
+
expectedBlocked: false,
|
|
97
|
+
},
|
|
90
98
|
{
|
|
91
99
|
name: 'blocked host as a subdomain prefix',
|
|
92
100
|
actorUri: 'https://spam.example.evil.test/users/bob',
|
|
@@ -227,7 +235,9 @@ describe('canonicalFederationHost', () => {
|
|
|
227
235
|
|
|
228
236
|
it('does not convert a unicode host to its punycode wire form', () => {
|
|
229
237
|
expect(canonicalFederationHost('ÜBER.example')).toBe('über.example');
|
|
230
|
-
expect(canonicalFederationHost('über.example')).not.toBe(
|
|
238
|
+
expect(canonicalFederationHost('über.example')).not.toBe(
|
|
239
|
+
new URL('https://über.example').hostname,
|
|
240
|
+
);
|
|
231
241
|
});
|
|
232
242
|
});
|
|
233
243
|
|
|
@@ -117,9 +117,7 @@ const fetchPublicKey = async (keyId: string) =>
|
|
|
117
117
|
|
|
118
118
|
/** Reproduce how Express lowercases req.headers, folding content-type as a real header. */
|
|
119
119
|
function lowerHeaders(headers: Record<string, string>): Record<string, string> {
|
|
120
|
-
const lowered = Object.fromEntries(
|
|
121
|
-
Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]),
|
|
122
|
-
);
|
|
120
|
+
const lowered = Object.fromEntries(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]));
|
|
123
121
|
if (lowered.digest && !lowered['content-type']) {
|
|
124
122
|
lowered['content-type'] = DEFAULT_SIGNED_CONTENT_TYPE;
|
|
125
123
|
}
|
|
@@ -21,21 +21,32 @@ import {
|
|
|
21
21
|
const LOCAL_ACTOR = 'https://mention.earth/ap/users/alice';
|
|
22
22
|
const REMOTE_ACTOR = 'https://remote.example/users/bob';
|
|
23
23
|
|
|
24
|
-
function makeRig(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
function makeRig(
|
|
25
|
+
overrides: {
|
|
26
|
+
localUser?: { _id?: string | null; id?: string | null } | null;
|
|
27
|
+
sharingEnabled?: boolean;
|
|
28
|
+
followerOxyUserId?: string | null;
|
|
29
|
+
inboundFollow?: { _id: unknown; localUserId: string } | null;
|
|
30
|
+
actorOxyUserIdForUndo?: string | null;
|
|
31
|
+
validate?: (activity: Record<string, unknown>) => InboundActivityValidation;
|
|
32
|
+
blockedHosts?: string[];
|
|
33
|
+
withMoveHandler?: boolean;
|
|
34
|
+
} = {},
|
|
35
|
+
) {
|
|
34
36
|
const moves: Array<{ activityId: string; oldActorUri: string; targetActorUri: string }> = [];
|
|
35
37
|
const bridgeFollowCalls: Array<[string, string]> = [];
|
|
36
38
|
const bridgeUnfollowCalls: Array<[string, string]> = [];
|
|
37
|
-
const acceptsSent: Array<{
|
|
38
|
-
|
|
39
|
+
const acceptsSent: Array<{
|
|
40
|
+
localOxyUserId: string;
|
|
41
|
+
localUsername: string;
|
|
42
|
+
followActivityId: string;
|
|
43
|
+
remoteActorUri: string;
|
|
44
|
+
}> = [];
|
|
45
|
+
const inboundAcceptedUpserts: Array<{
|
|
46
|
+
localUserId: string;
|
|
47
|
+
remoteActorUri: string;
|
|
48
|
+
activityId: string;
|
|
49
|
+
}> = [];
|
|
39
50
|
const deletedFollowIds: unknown[] = [];
|
|
40
51
|
const contentActivities: Array<{ type: unknown; verifiedActorUri: string }> = [];
|
|
41
52
|
const outboundAcceptedByActivityId: Array<[string, string]> = [];
|
|
@@ -111,7 +122,11 @@ function makeRig(overrides: {
|
|
|
111
122
|
...(overrides.withMoveHandler === false
|
|
112
123
|
? {}
|
|
113
124
|
: {
|
|
114
|
-
onMove: async (move: {
|
|
125
|
+
onMove: async (move: {
|
|
126
|
+
activityId: string;
|
|
127
|
+
oldActorUri: string;
|
|
128
|
+
targetActorUri: string;
|
|
129
|
+
}) => {
|
|
115
130
|
moves.push(move);
|
|
116
131
|
},
|
|
117
132
|
}),
|
|
@@ -145,9 +160,16 @@ describe('inbound Follow', () => {
|
|
|
145
160
|
);
|
|
146
161
|
|
|
147
162
|
expect(rig.bridgeFollowCalls).toEqual([['u-bob', 'u-alice']]);
|
|
148
|
-
expect(rig.inboundAcceptedUpserts).toEqual([
|
|
163
|
+
expect(rig.inboundAcceptedUpserts).toEqual([
|
|
164
|
+
{ localUserId: 'u-alice', remoteActorUri: REMOTE_ACTOR, activityId: 'f1' },
|
|
165
|
+
]);
|
|
149
166
|
expect(rig.acceptsSent).toEqual([
|
|
150
|
-
{
|
|
167
|
+
{
|
|
168
|
+
localOxyUserId: 'u-alice',
|
|
169
|
+
localUsername: 'alice',
|
|
170
|
+
followActivityId: 'f1',
|
|
171
|
+
remoteActorUri: REMOTE_ACTOR,
|
|
172
|
+
},
|
|
151
173
|
]);
|
|
152
174
|
expect(rig.onInboundFollowAcceptedCalls).toEqual([['u-alice', 'u-bob', REMOTE_ACTOR]]);
|
|
153
175
|
});
|
|
@@ -233,20 +255,32 @@ describe('inbound Accept / Reject', () => {
|
|
|
233
255
|
it('marks the outbound follow accepted by activity id + triggers the outbox backfill', async () => {
|
|
234
256
|
const rig = makeRig();
|
|
235
257
|
await rig.dispatcher.processInboxActivity(
|
|
236
|
-
{
|
|
258
|
+
{
|
|
259
|
+
type: 'Accept',
|
|
260
|
+
actor: REMOTE_ACTOR,
|
|
261
|
+
object: { type: 'Follow', id: 'https://mention.earth/ap/users/alice/follows/1' },
|
|
262
|
+
},
|
|
237
263
|
REMOTE_ACTOR,
|
|
238
264
|
);
|
|
239
|
-
expect(rig.outboundAcceptedByActivityId).toEqual([
|
|
265
|
+
expect(rig.outboundAcceptedByActivityId).toEqual([
|
|
266
|
+
[REMOTE_ACTOR, 'https://mention.earth/ap/users/alice/follows/1'],
|
|
267
|
+
]);
|
|
240
268
|
expect(rig.onOutboundFollowAcceptedCalls).toEqual([REMOTE_ACTOR]);
|
|
241
269
|
});
|
|
242
270
|
|
|
243
271
|
it('marks accepted (string ref, then any-pending fallback)', async () => {
|
|
244
272
|
const rig = makeRig();
|
|
245
273
|
await rig.dispatcher.processInboxActivity(
|
|
246
|
-
{
|
|
274
|
+
{
|
|
275
|
+
type: 'Accept',
|
|
276
|
+
actor: REMOTE_ACTOR,
|
|
277
|
+
object: 'https://mention.earth/ap/users/alice/follows/1',
|
|
278
|
+
},
|
|
247
279
|
REMOTE_ACTOR,
|
|
248
280
|
);
|
|
249
|
-
expect(rig.outboundAcceptedByActivityId).toEqual([
|
|
281
|
+
expect(rig.outboundAcceptedByActivityId).toEqual([
|
|
282
|
+
[REMOTE_ACTOR, 'https://mention.earth/ap/users/alice/follows/1'],
|
|
283
|
+
]);
|
|
250
284
|
});
|
|
251
285
|
|
|
252
286
|
it('marks the outbound follow rejected on Reject(Follow)', async () => {
|
|
@@ -273,13 +307,18 @@ describe('Move → onMove', () => {
|
|
|
273
307
|
it('hands a well-formed self-Move to the app', async () => {
|
|
274
308
|
const rig = makeRig();
|
|
275
309
|
await rig.dispatcher.processInboxActivity(move(), REMOTE_ACTOR);
|
|
276
|
-
expect(rig.moves).toEqual([
|
|
310
|
+
expect(rig.moves).toEqual([
|
|
311
|
+
{ activityId: `${REMOTE_ACTOR}#moves/1`, oldActorUri: REMOTE_ACTOR, targetActorUri: TARGET },
|
|
312
|
+
]);
|
|
277
313
|
expect(rig.contentActivities).toHaveLength(0);
|
|
278
314
|
});
|
|
279
315
|
|
|
280
316
|
it('accepts embedded object/target references', async () => {
|
|
281
317
|
const rig = makeRig();
|
|
282
|
-
await rig.dispatcher.processInboxActivity(
|
|
318
|
+
await rig.dispatcher.processInboxActivity(
|
|
319
|
+
move({ object: { id: REMOTE_ACTOR }, target: { id: TARGET } }),
|
|
320
|
+
REMOTE_ACTOR,
|
|
321
|
+
);
|
|
283
322
|
expect(rig.moves).toHaveLength(1);
|
|
284
323
|
});
|
|
285
324
|
|
|
@@ -304,18 +343,23 @@ describe('Move → onMove', () => {
|
|
|
304
343
|
|
|
305
344
|
it('drops a Move when the app registered no handler', async () => {
|
|
306
345
|
const rig = makeRig({ withMoveHandler: false });
|
|
307
|
-
await expect(
|
|
346
|
+
await expect(
|
|
347
|
+
rig.dispatcher.processInboxActivity(move(), REMOTE_ACTOR),
|
|
348
|
+
).resolves.toBeUndefined();
|
|
308
349
|
expect(rig.contentActivities).toHaveLength(0);
|
|
309
350
|
});
|
|
310
351
|
});
|
|
311
352
|
|
|
312
353
|
describe('content verbs → onContentActivity', () => {
|
|
313
|
-
it.each(['Create', 'Announce', 'Like', 'Delete', 'Update'])(
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
354
|
+
it.each(['Create', 'Announce', 'Like', 'Delete', 'Update'])(
|
|
355
|
+
'routes %s to the app',
|
|
356
|
+
async (type) => {
|
|
357
|
+
const rig = makeRig();
|
|
358
|
+
await rig.dispatcher.processInboxActivity({ type, actor: REMOTE_ACTOR }, REMOTE_ACTOR);
|
|
359
|
+
expect(rig.contentActivities).toEqual([{ type, verifiedActorUri: REMOTE_ACTOR }]);
|
|
360
|
+
expect(rig.bridgeFollowCalls).toHaveLength(0);
|
|
361
|
+
},
|
|
362
|
+
);
|
|
319
363
|
|
|
320
364
|
it('drops a malformed activity without dispatching', async () => {
|
|
321
365
|
const rig = makeRig({ validate: () => ({ ok: false, summary: 'bad shape' }) });
|
|
@@ -402,7 +446,10 @@ describe('blocked-origin domain policy', () => {
|
|
|
402
446
|
|
|
403
447
|
it('refuses the origin BEFORE the payload is parsed', async () => {
|
|
404
448
|
const rig = makeRig({ blockedHosts: ['spam.example'] });
|
|
405
|
-
await rig.dispatcher.processInboxActivity(
|
|
449
|
+
await rig.dispatcher.processInboxActivity(
|
|
450
|
+
{ type: 'Create', actor: BLOCKED_ACTOR },
|
|
451
|
+
BLOCKED_ACTOR,
|
|
452
|
+
);
|
|
406
453
|
expect(rig.validatedActivities).toHaveLength(0);
|
|
407
454
|
});
|
|
408
455
|
|
|
@@ -424,7 +471,10 @@ describe('blocked-origin domain policy', () => {
|
|
|
424
471
|
|
|
425
472
|
it('still dispatches an allowed origin while another host is blocked', async () => {
|
|
426
473
|
const rig = makeRig({ blockedHosts: ['spam.example'] });
|
|
427
|
-
await rig.dispatcher.processInboxActivity(
|
|
474
|
+
await rig.dispatcher.processInboxActivity(
|
|
475
|
+
{ type: 'Create', actor: REMOTE_ACTOR },
|
|
476
|
+
REMOTE_ACTOR,
|
|
477
|
+
);
|
|
428
478
|
expect(rig.contentActivities).toEqual([{ type: 'Create', verifiedActorUri: REMOTE_ACTOR }]);
|
|
429
479
|
});
|
|
430
480
|
|