@fedify/fedify 2.4.0-dev.2010 → 2.4.0-dev.2030

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.
Files changed (100) hide show
  1. package/dist/{assert-CebeUf0C.mjs → assert-D1Eafmd_.mjs} +1 -1
  2. package/dist/{assert_equals-CBlRfA-_.mjs → assert_equals-Z6IcEbWU.mjs} +2 -28
  3. package/dist/{assert_exists-DtzkXC47.mjs → assert_exists-cffSpJ7X.mjs} +1 -1
  4. package/dist/{assert_false-3pLLLsO4.mjs → assert_false-CPdRnc3E.mjs} +1 -1
  5. package/dist/{assert_greater_or_equal-BApOTh1h.mjs → assert_greater_or_equal-BlafOF4-.mjs} +2 -1
  6. package/dist/{assert_instance_of-g3WcyYNR.mjs → assert_instance_of-mrXWWNY-.mjs} +1 -1
  7. package/dist/{assert_not_equals-BN7yDMWe.mjs → assert_not_equals-CpPK2t89.mjs} +2 -1
  8. package/dist/{assert_rejects-wFbSPn1O.mjs → assert_rejects-CTptdYck.mjs} +2 -2
  9. package/dist/{assert_strict_equals-Bpjl4Psw.mjs → assert_strict_equals-CYvBmkpC.mjs} +2 -1
  10. package/dist/{assert_throws-BJ5wuvR2.mjs → assert_throws-BYITOvPO.mjs} +2 -1
  11. package/dist/assertion_error-B-cx0fFA.mjs +31 -0
  12. package/dist/{builder-asm96yV1.mjs → builder-BYJ5otJa.mjs} +2 -2
  13. package/dist/compat/outgoing-jsonld.test.mjs +71 -3
  14. package/dist/compat/public-audience.test.mjs +3 -3
  15. package/dist/compat/secured-document.test.d.mts +2 -0
  16. package/dist/compat/secured-document.test.mjs +58 -0
  17. package/dist/compat/transformers.test.mjs +4 -4
  18. package/dist/{compound-proof-7UIAueLV.mjs → compound-proof-BIvUoJxm.mjs} +74 -2
  19. package/dist/{deno-Ckq9TwCv.mjs → deno-Vj_9wePq.mjs} +1 -1
  20. package/dist/{docloader-DUKEPG-O.mjs → docloader-qUudHZVH.mjs} +2 -2
  21. package/dist/federation/builder.test.mjs +5 -5
  22. package/dist/federation/circuit-breaker.test.mjs +3 -3
  23. package/dist/federation/collection.test.mjs +2 -2
  24. package/dist/federation/compound-fanout.test.d.mts +2 -0
  25. package/dist/federation/compound-fanout.test.mjs +228 -0
  26. package/dist/federation/handler-compound-proof.test.mjs +5 -5
  27. package/dist/federation/handler.test.mjs +11 -11
  28. package/dist/federation/idempotency.test.mjs +4 -4
  29. package/dist/federation/inbox.test.mjs +2 -2
  30. package/dist/federation/keycache.test.mjs +3 -3
  31. package/dist/federation/kv.test.mjs +2 -2
  32. package/dist/federation/metrics.test.mjs +4 -4
  33. package/dist/federation/middleware.test.mjs +17 -17
  34. package/dist/federation/mod.cjs +1 -1
  35. package/dist/federation/mod.js +1 -1
  36. package/dist/federation/mq.test.mjs +7 -6
  37. package/dist/federation/negotiation.test.mjs +3 -3
  38. package/dist/federation/outgoing-proof.test.d.mts +2 -0
  39. package/dist/federation/outgoing-proof.test.mjs +396 -0
  40. package/dist/federation/retry.test.mjs +3 -2
  41. package/dist/federation/router.test.mjs +5 -5
  42. package/dist/federation/send.test.mjs +11 -11
  43. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  44. package/dist/federation/tasks/tasks.test.mjs +2 -2
  45. package/dist/federation/temporal.test.mjs +4 -4
  46. package/dist/federation/webfinger.test.mjs +4 -4
  47. package/dist/{federation-CgbvMauV.cjs → federation-CTnaljmy.cjs} +203 -37
  48. package/dist/{http-DQBfmkrS.cjs → http-B5F1JMh0.cjs} +1 -1
  49. package/dist/{http-DQA2JOEJ.js → http-By8tnmEr.js} +1 -1
  50. package/dist/{http-DZaAutqg.mjs → http-D4WPcJUe.mjs} +3 -3
  51. package/dist/{key-zxzx01Ec.mjs → key-B_Zc5Jbd.mjs} +2 -2
  52. package/dist/{kv-cache-sy8OMNT8.cjs → kv-cache-8K70pjtX.cjs} +1 -1
  53. package/dist/{kv-cache-CbrUX90H.mjs → kv-cache-BXdT7pJQ.mjs} +1 -1
  54. package/dist/{kv-cache-BBoePTOJ.js → kv-cache-BswMKQjC.js} +1 -1
  55. package/dist/{ld-CD_TN0e8.mjs → ld-B16KUSIQ.mjs} +3 -3
  56. package/dist/{metrics-B47Cm5gK.mjs → metrics-DpQqUAmh.mjs} +1 -1
  57. package/dist/{middleware-U_Gannqi.mjs → middleware-BL5HFFVU.mjs} +1 -1
  58. package/dist/{middleware-pHwDTAnq.mjs → middleware-C7_hqDnl.mjs} +143 -49
  59. package/dist/{middleware-U0OIuqwD.js → middleware-Cxto6Bq2.js} +204 -38
  60. package/dist/{mod-UDwMjuHM.d.ts → mod-CNRAxXEb.d.ts} +1 -5
  61. package/dist/{mod-CbKDOnCt.d.cts → mod-CVQFWefn.d.cts} +1 -5
  62. package/dist/mod.cjs +4 -4
  63. package/dist/mod.d.cts +1 -1
  64. package/dist/mod.d.ts +1 -1
  65. package/dist/mod.js +4 -4
  66. package/dist/nodeinfo/client.test.mjs +2 -2
  67. package/dist/nodeinfo/handler.test.mjs +3 -3
  68. package/dist/nodeinfo/types.test.mjs +3 -3
  69. package/dist/otel/exporter.test.mjs +2 -2
  70. package/dist/{outgoing-jsonld-B5Ne7JoL.mjs → outgoing-jsonld-4IJqPYos.mjs} +11 -9
  71. package/dist/{owner-u3IJRhVx.mjs → owner-BIOIhZoM.mjs} +2 -2
  72. package/dist/{owner-BNKC3s6G.js → owner-D-E0bT2O.js} +127 -35
  73. package/dist/{owner--mNatWct.cjs → owner-WUYke16i.cjs} +126 -34
  74. package/dist/{proof-D3te0SP-.mjs → proof-BVxJu5vv.mjs} +80 -23
  75. package/dist/{public-audience-Cc2YJ3ip.mjs → public-audience--klBIOk1.mjs} +13 -9
  76. package/dist/secured-document-CxzZZ9nL.mjs +35 -0
  77. package/dist/{send-CDr0Zivk.mjs → send-Cr5FJ7iu.mjs} +3 -3
  78. package/dist/sig/compound-proof-discovery.test.mjs +3 -3
  79. package/dist/sig/compound-proof-producer.test.d.mts +2 -0
  80. package/dist/sig/compound-proof-producer.test.mjs +107 -0
  81. package/dist/sig/compound-proof-verification.test.mjs +5 -5
  82. package/dist/sig/compound-proof.test.mjs +145 -58
  83. package/dist/sig/http.test.mjs +11 -10
  84. package/dist/sig/key.test.mjs +6 -6
  85. package/dist/sig/ld.test.mjs +9 -9
  86. package/dist/sig/mod.cjs +2 -2
  87. package/dist/sig/mod.d.cts +1 -1
  88. package/dist/sig/mod.d.ts +1 -1
  89. package/dist/sig/mod.js +2 -2
  90. package/dist/sig/owner.test.mjs +5 -5
  91. package/dist/sig/proof.test.mjs +9 -9
  92. package/dist/std__assert-DvMDRPes.mjs +8 -0
  93. package/dist/{temporal-DKhVF_Uk.mjs → temporal-CCf0lZV3.mjs} +1 -1
  94. package/dist/testing/kv.test.mjs +2 -2
  95. package/dist/utils/docloader.test.mjs +5 -5
  96. package/dist/utils/kv-cache.test.mjs +1 -1
  97. package/dist/utils/mod.cjs +1 -1
  98. package/dist/utils/mod.js +1 -1
  99. package/package.json +6 -6
  100. package/dist/std__assert-CxFT0MNt.mjs +0 -8
@@ -0,0 +1,396 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { t as esm_default } from "../esm-BHXXx4Wx.mjs";
5
+ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
6
+ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
7
+ import "../std__assert-DvMDRPes.mjs";
8
+ import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
9
+ import { t as assert } from "../assert-D1Eafmd_.mjs";
10
+ import { t as exportJwk } from "../key-B_Zc5Jbd.mjs";
11
+ import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
12
+ import { n as FederationImpl, o as createFederation } from "../middleware-C7_hqDnl.mjs";
13
+ import { s as detachSignature } from "../ld-B16KUSIQ.mjs";
14
+ import { r as signObject } from "../proof-BVxJu5vv.mjs";
15
+ import { a as verifyCompoundPortableObjectProofs } from "../compound-proof-BIvUoJxm.mjs";
16
+ import { Create, Note, Person } from "@fedify/vocab";
17
+ import { mockDocumentLoader, test } from "@fedify/fixture";
18
+ import { exportDidKey, parseIri } from "@fedify/vocab-runtime";
19
+ //#region src/federation/outgoing-proof.test.ts
20
+ const options = {
21
+ contextLoader: mockDocumentLoader,
22
+ documentLoader: mockDocumentLoader
23
+ };
24
+ const created = Temporal.Instant.from("2023-02-24T23:36:38Z");
25
+ const childContext = [
26
+ "https://www.w3.org/ns/activitystreams",
27
+ "https://w3id.org/security/data-integrity/v1",
28
+ { ex: "https://example.com/ns#" }
29
+ ];
30
+ const limits = {
31
+ maxDepth: 64,
32
+ maxMaps: 1e4,
33
+ maxProofs: 32,
34
+ maxBytes: 10 * 1024 * 1024
35
+ };
36
+ const recipient = {
37
+ id: new URL("https://example.com/users/bob"),
38
+ inboxId: new URL("https://example.com/inbox")
39
+ };
40
+ const rsaKey = {
41
+ keyId: rsaPublicKey2.id,
42
+ privateKey: rsaPrivateKey2
43
+ };
44
+ async function didKey(pair) {
45
+ const { privateKey, publicKey } = pair ?? await crypto.subtle.generateKey("Ed25519", true, ["sign", "verify"]);
46
+ const did = await exportDidKey(publicKey);
47
+ return {
48
+ did,
49
+ keyId: new URL(`${did}#${did.substring(8)}`),
50
+ privateKey,
51
+ publicKey
52
+ };
53
+ }
54
+ function sender(key) {
55
+ return {
56
+ keyId: key.keyId,
57
+ privateKey: key.privateKey
58
+ };
59
+ }
60
+ async function signedChild(owner) {
61
+ return await signObject(new Note({
62
+ id: parseIri(`ap+ef61://${owner.did}/objects/${crypto.randomUUID()}`),
63
+ attribution: parseIri(`ap+ef61://${owner.did}/actor`),
64
+ content: "A portable note"
65
+ }), owner.privateKey, owner.keyId, {
66
+ ...options,
67
+ context: childContext,
68
+ created
69
+ });
70
+ }
71
+ function portableCreate(owner, object) {
72
+ return new Create({
73
+ id: parseIri(`ap+ef61://${owner.did}/activities/${crypto.randomUUID()}`),
74
+ actor: parseIri(`ap+ef61://${owner.did}/actor`),
75
+ object
76
+ });
77
+ }
78
+ function httpCreate(object) {
79
+ return new Create({
80
+ id: new URL(`https://example.com/activities/${crypto.randomUUID()}`),
81
+ actor: new URL("https://example.com/users/alice"),
82
+ object
83
+ });
84
+ }
85
+ function createQueue() {
86
+ const queued = [];
87
+ return {
88
+ queued,
89
+ queue: {
90
+ enqueue(message) {
91
+ queued.push(message);
92
+ return Promise.resolve();
93
+ },
94
+ listen() {
95
+ return Promise.resolve();
96
+ }
97
+ }
98
+ };
99
+ }
100
+ function createTestFederation(queue) {
101
+ const federation = new FederationImpl({
102
+ kv: new MemoryKvStore(),
103
+ queue,
104
+ manuallyStartQueue: true,
105
+ contextLoaderFactory: () => mockDocumentLoader,
106
+ documentLoaderFactory: () => mockDocumentLoader
107
+ });
108
+ federation.setInboxListeners("/users/{identifier}/inbox", "/inbox");
109
+ return federation;
110
+ }
111
+ /**
112
+ * Captures what is POSTed to the recipient's inbox while `run` executes.
113
+ */
114
+ async function capture(run) {
115
+ const bodies = [];
116
+ const requests = [];
117
+ esm_default.spyGlobal();
118
+ try {
119
+ esm_default.post(recipient.inboxId.href, async (cl) => {
120
+ const body = await cl.request.text();
121
+ requests.push(new Request(cl.request.url, {
122
+ method: cl.request.method,
123
+ headers: cl.request.headers,
124
+ body
125
+ }));
126
+ bodies.push(JSON.parse(body));
127
+ return new Response(null, { status: 202 });
128
+ });
129
+ await run();
130
+ } finally {
131
+ esm_default.hardReset();
132
+ }
133
+ return {
134
+ bodies,
135
+ requests
136
+ };
137
+ }
138
+ function proofOf(document) {
139
+ const proof = document.proof;
140
+ assert(proof != null && typeof proof === "object" && !Array.isArray(proof), `expected exactly one direct proof, got ${JSON.stringify(proof)}`);
141
+ return proof;
142
+ }
143
+ async function assertCompoundVerifies(body) {
144
+ const result = await verifyCompoundPortableObjectProofs(detachSignature(body), limits, options);
145
+ assertEquals(result.status, "ok");
146
+ assert(result.status === "ok" && result.verified);
147
+ }
148
+ test("a portable activity with one Ed25519 key gets one direct proof", async () => {
149
+ const owner = await didKey();
150
+ const child = await signedChild(await didKey());
151
+ const ctx = createTestFederation().createContext(new URL("https://example.com/"));
152
+ const { bodies, requests } = await capture(() => ctx.sendActivity([rsaKey, sender(owner)], recipient, portableCreate(owner, child)));
153
+ assertEquals(bodies.length, 1);
154
+ assertEquals(proofOf(bodies[0]).verificationMethod, owner.keyId.href);
155
+ assert(requests[0].headers.has("Signature"));
156
+ assert(bodies[0].signature != null);
157
+ await assertCompoundVerifies(bodies[0]);
158
+ });
159
+ test("a portable activity is signed only by the key matching its DID", async () => {
160
+ const owner = await didKey();
161
+ const other = await didKey();
162
+ const childOwner = await didKey();
163
+ const child = await signedChild(childOwner);
164
+ for (const keys of [[other, owner], [owner, other]]) {
165
+ const ctx = createTestFederation().createContext(new URL("https://example.com/"));
166
+ const { bodies, requests } = await capture(() => ctx.sendActivity([
167
+ rsaKey,
168
+ ...keys.map(sender),
169
+ sender(childOwner)
170
+ ], recipient, portableCreate(owner, child)));
171
+ assertEquals(bodies.length, 1);
172
+ assertEquals(proofOf(bodies[0]).verificationMethod, owner.keyId.href);
173
+ assert(requests[0].headers.has("Signature"));
174
+ const embedded = bodies[0].object;
175
+ assertEquals(embedded["@context"], childContext);
176
+ assertEquals(proofOf(embedded).verificationMethod, childOwner.keyId.href);
177
+ await assertCompoundVerifies(bodies[0]);
178
+ }
179
+ });
180
+ test("a portable activity without exactly one DID-matching key is rejected", async () => {
181
+ const owner = await didKey();
182
+ const child = await signedChild(await didKey());
183
+ const cases = [
184
+ [
185
+ "no key matches",
186
+ [sender(await didKey()), sender(await didKey())],
187
+ "none of its 2 Ed25519 keys"
188
+ ],
189
+ [
190
+ "a same-origin key ID is not a DID URL",
191
+ [{
192
+ keyId: parseIri(`ap+ef61://${owner.did}/actor#main-key`),
193
+ privateKey: owner.privateKey
194
+ }, sender(await didKey())],
195
+ "none of its 2 Ed25519 keys"
196
+ ],
197
+ [
198
+ "several keys match",
199
+ [sender(owner), {
200
+ keyId: new URL(`${owner.did}#second`),
201
+ privateKey: owner.privateKey
202
+ }],
203
+ "2 of its Ed25519 keys"
204
+ ]
205
+ ];
206
+ for (const [name, keys, message] of cases) {
207
+ const ctx = createTestFederation().createContext(new URL("https://example.com/"));
208
+ const { bodies } = await capture(() => assertRejects(() => ctx.sendActivity([rsaKey, ...keys], recipient, portableCreate(owner, child)), TypeError, message));
209
+ assertEquals(bodies.length, 0, name);
210
+ }
211
+ });
212
+ test("a non-portable activity embedding portable objects needs one key", async () => {
213
+ const child = await signedChild(await didKey());
214
+ const ctx = createTestFederation().createContext(new URL("https://example.com/"));
215
+ const keys = [sender(await didKey()), sender(await didKey())];
216
+ assertEquals((await capture(() => assertRejects(() => ctx.sendActivity([rsaKey, ...keys], recipient, httpCreate(child)), TypeError, "exactly one Ed25519 key"))).bodies.length, 0);
217
+ const key = {
218
+ keyId: ed25519PublicKey.id,
219
+ privateKey: ed25519PrivateKey
220
+ };
221
+ const accepted = await capture(() => ctx.sendActivity([rsaKey, key], recipient, httpCreate(child)));
222
+ assertEquals(accepted.bodies.length, 1);
223
+ assertEquals(proofOf(accepted.bodies[0]).verificationMethod, ed25519PublicKey.id.href);
224
+ });
225
+ test("an activity without portable objects is still signed by every key", async () => {
226
+ const ctx = createTestFederation().createContext(new URL("https://example.com/"));
227
+ const keys = [await didKey(), await didKey()];
228
+ const { bodies } = await capture(() => ctx.sendActivity([rsaKey, ...keys.map(sender)], recipient, httpCreate(new Note({ content: "Hello" }))));
229
+ assertEquals(bodies.length, 1);
230
+ const proofs = bodies[0].proof;
231
+ assert(Array.isArray(proofs));
232
+ assertEquals(proofs.map((proof) => proof.verificationMethod), keys.map((key) => key.keyId.href));
233
+ });
234
+ test("a pre-signed portable activity is not re-signed", async () => {
235
+ const owner = await didKey();
236
+ const activity = await signObject(portableCreate(owner, await signedChild(await didKey())), owner.privateKey, owner.keyId, {
237
+ ...options,
238
+ created
239
+ });
240
+ const ctx = createTestFederation().createContext(new URL("https://example.com/"));
241
+ const keys = [sender(await didKey()), sender(await didKey())];
242
+ const { bodies } = await capture(() => ctx.sendActivity([rsaKey, ...keys], recipient, activity));
243
+ assertEquals(bodies.length, 1);
244
+ assertEquals(proofOf(bodies[0]).verificationMethod, owner.keyId.href);
245
+ await assertCompoundVerifies(bodies[0]);
246
+ });
247
+ test("a portable activity carrying a proof set is not delivered", async () => {
248
+ const owner = await didKey();
249
+ const second = {
250
+ ...owner,
251
+ keyId: new URL(`${owner.did}#second`)
252
+ };
253
+ let activity = portableCreate(owner, await signedChild(owner));
254
+ for (const key of [owner, second]) activity = await signObject(activity, key.privateKey, key.keyId, {
255
+ ...options,
256
+ created
257
+ });
258
+ assertEquals((await capture(() => assertRejects(() => createTestFederation().createContext(new URL("https://example.com/")).sendActivity(rsaKey, recipient, activity), TypeError, "JSON Pointer \"/proof\""))).bodies.length, 0);
259
+ const outbox = createQueue();
260
+ await assertRejects(() => createTestFederation(outbox.queue).createContext(new URL("https://example.com/")).sendActivity(rsaKey, recipient, activity, { fanout: "skip" }), TypeError, "JSON Pointer \"/proof\"");
261
+ assertEquals(outbox.queued.length, 0);
262
+ const fanout = createQueue();
263
+ await assertRejects(() => createTestFederation(fanout.queue).createContext(new URL("https://example.com/")).sendActivity(rsaKey, recipient, activity, { fanout: "force" }), TypeError, "JSON Pointer \"/proof\"");
264
+ assertEquals(fanout.queued.length, 0);
265
+ });
266
+ test("a proof set on an embedded map is not delivered either", async () => {
267
+ const owner = await didKey();
268
+ let child = await signedChild(owner);
269
+ child = await signObject(child, owner.privateKey, new URL(`${owner.did}#b`), {
270
+ ...options,
271
+ created
272
+ });
273
+ const ctx = createTestFederation().createContext(new URL("https://example.com/"));
274
+ const { bodies } = await capture(() => assertRejects(() => ctx.sendActivity(rsaKey, recipient, httpCreate(child)), TypeError, "JSON Pointer \"/object/proof\""));
275
+ assertEquals(bodies.length, 0);
276
+ });
277
+ test("forced fanout selects the DID-matching key before enqueueing", async () => {
278
+ const owner = await didKey();
279
+ const childOwner = await didKey();
280
+ const child = await signedChild(childOwner);
281
+ const { queue, queued } = createQueue();
282
+ const federation = createTestFederation(queue);
283
+ const ctx = federation.createContext(new URL("https://example.com/"));
284
+ const { bodies } = await capture(async () => {
285
+ await ctx.sendActivity([
286
+ rsaKey,
287
+ sender(await didKey()),
288
+ sender(owner)
289
+ ], recipient, portableCreate(owner, child), { fanout: "force" });
290
+ assertEquals(queued.length, 1);
291
+ const message = queued[0];
292
+ assertEquals(message.type, "fanout");
293
+ assertEquals(message.keys.length, 3);
294
+ assertEquals(message.keys[0].keyId, rsaKey.keyId.href);
295
+ for (let i = 0; i < queued.length; i++) await federation.processQueuedTask(void 0, queued[i]);
296
+ });
297
+ assertEquals(bodies.length, 1);
298
+ assertEquals(proofOf(bodies[0]).verificationMethod, owner.keyId.href);
299
+ const embedded = bodies[0].object;
300
+ assertEquals(embedded["@context"], childContext);
301
+ assertEquals(proofOf(embedded).verificationMethod, childOwner.keyId.href);
302
+ await assertCompoundVerifies(bodies[0]);
303
+ });
304
+ test("the fanout worker selects one key for an unsigned portable activity", async () => {
305
+ const owner = await didKey();
306
+ const activity = portableCreate(owner, await signedChild(await didKey()));
307
+ const federation = createTestFederation();
308
+ const message = {
309
+ type: "fanout",
310
+ id: crypto.randomUUID(),
311
+ baseUrl: "https://example.com",
312
+ keys: await Promise.all([
313
+ rsaKey,
314
+ sender(await didKey()),
315
+ sender(owner)
316
+ ].map(async (key) => ({
317
+ keyId: key.keyId.href,
318
+ privateKey: await exportJwk(key.privateKey)
319
+ }))),
320
+ inboxes: { [recipient.inboxId.href]: {
321
+ actorIds: [recipient.id.href],
322
+ sharedInbox: false
323
+ } },
324
+ activity: await activity.toJsonLd({
325
+ format: "compact",
326
+ ...options
327
+ }),
328
+ activityId: activity.id.href,
329
+ activityType: "https://www.w3.org/ns/activitystreams#Create",
330
+ traceContext: {}
331
+ };
332
+ const { bodies } = await capture(() => federation.processQueuedTask(void 0, message));
333
+ assertEquals(bodies.length, 1);
334
+ assertEquals(proofOf(bodies[0]).verificationMethod, owner.keyId.href);
335
+ });
336
+ test("actor key pairs follow the compound-proof key selection too", async () => {
337
+ const dispatched = [];
338
+ const federation = createTestFederation();
339
+ federation.setActorDispatcher("/users/{identifier}", (ctx, identifier) => new Person({
340
+ id: ctx.getActorUri(identifier),
341
+ inbox: ctx.getInboxUri(identifier)
342
+ })).setKeyPairsDispatcher(() => dispatched);
343
+ const ctx = federation.createContext(new URL("https://example.com/"));
344
+ const owner = await didKey();
345
+ const child = await signedChild(await didKey());
346
+ const other = await didKey();
347
+ dispatched.push({
348
+ privateKey: rsaPrivateKey2,
349
+ publicKey: rsaPublicKey2.publicKey
350
+ }, {
351
+ privateKey: owner.privateKey,
352
+ publicKey: owner.publicKey
353
+ }, {
354
+ privateKey: other.privateKey,
355
+ publicKey: other.publicKey
356
+ });
357
+ assertEquals((await capture(() => assertRejects(() => ctx.sendActivity({ identifier: "alice" }, recipient, portableCreate(owner, child)), TypeError, "none of its 2 Ed25519 keys"))).bodies.length, 0);
358
+ dispatched.splice(2);
359
+ const presigned = await signObject(portableCreate(owner, child), owner.privateKey, owner.keyId, {
360
+ ...options,
361
+ created
362
+ });
363
+ const kept = await capture(() => ctx.sendActivity({ identifier: "alice" }, recipient, presigned));
364
+ assertEquals(kept.bodies.length, 1);
365
+ assertEquals(proofOf(kept.bodies[0]).verificationMethod, owner.keyId.href);
366
+ const ordinary = await signObject(httpCreate(new Note({ content: "Hello" })), owner.privateKey, owner.keyId, {
367
+ ...options,
368
+ created
369
+ });
370
+ const appended = await capture(() => ctx.sendActivity({ identifier: "alice" }, recipient, ordinary));
371
+ assertEquals(appended.bodies.length, 1);
372
+ const proofs = appended.bodies[0].proof;
373
+ assert(Array.isArray(proofs));
374
+ assertEquals(proofs.map((proof) => proof.verificationMethod), [owner.keyId.href, "https://example.com/users/alice#multikey-2"]);
375
+ });
376
+ test("a Fedify inbox accepts a portable activity Fedify produced", async () => {
377
+ const owner = await didKey();
378
+ const child = await signedChild(await didKey());
379
+ const ctx = createTestFederation().createContext(new URL("https://example.com/"));
380
+ const other = await didKey();
381
+ const { requests } = await capture(() => ctx.sendActivity([sender(other), sender(owner)], recipient, portableCreate(owner, child)));
382
+ assertEquals(requests.length, 1);
383
+ let received = 0;
384
+ const receiving = createFederation({
385
+ kv: new MemoryKvStore(),
386
+ contextLoaderFactory: () => mockDocumentLoader,
387
+ documentLoaderFactory: () => mockDocumentLoader
388
+ });
389
+ receiving.setActorDispatcher("/users/{identifier}", () => null);
390
+ receiving.setInboxListeners("/users/{identifier}/inbox", "/inbox").on(Create, () => {
391
+ received++;
392
+ });
393
+ assertEquals([(await receiving.fetch(requests[0], { contextData: void 0 })).status, received], [202, 1]);
394
+ });
395
+ //#endregion
396
+ export {};
@@ -1,8 +1,9 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { l as AssertionError, t as assertEquals } from "../assert_equals-CBlRfA-_.mjs";
5
- import { t as assertNotEquals } from "../assert_not_equals-BN7yDMWe.mjs";
4
+ import { t as AssertionError } from "../assertion_error-B-cx0fFA.mjs";
5
+ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
6
+ import { t as assertNotEquals } from "../assert_not_equals-CpPK2t89.mjs";
6
7
  import { t as createExponentialBackoffPolicy } from "../retry-zX5xw5e0.mjs";
7
8
  import { test } from "@fedify/fixture";
8
9
  //#region src/federation/retry.test.ts
@@ -1,11 +1,11 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { t as assertEquals } from "../assert_equals-CBlRfA-_.mjs";
5
- import { t as assertFalse } from "../assert_false-3pLLLsO4.mjs";
6
- import { t as assertThrows } from "../assert_throws-BJ5wuvR2.mjs";
7
- import "../std__assert-CxFT0MNt.mjs";
8
- import { t as assert } from "../assert-CebeUf0C.mjs";
4
+ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
5
+ import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
6
+ import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
7
+ import "../std__assert-DvMDRPes.mjs";
8
+ import { t as assert } from "../assert-D1Eafmd_.mjs";
9
9
  import { getLogger } from "@logtape/logtape";
10
10
  import { Router, RouterError, assertPath, isPath } from "@fedify/uri-template";
11
11
  import { test } from "@fedify/fixture";
@@ -2,18 +2,18 @@ import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { t as esm_default } from "../esm-BHXXx4Wx.mjs";
5
- import { t as assertEquals } from "../assert_equals-CBlRfA-_.mjs";
6
- import { t as assertFalse } from "../assert_false-3pLLLsO4.mjs";
7
- import { t as assertGreaterOrEqual } from "../assert_greater_or_equal-BApOTh1h.mjs";
8
- import { t as assertInstanceOf } from "../assert_instance_of-g3WcyYNR.mjs";
9
- import { t as assertNotEquals } from "../assert_not_equals-BN7yDMWe.mjs";
10
- import "../std__assert-CxFT0MNt.mjs";
11
- import { t as assertRejects } from "../assert_rejects-wFbSPn1O.mjs";
12
- import { t as assert } from "../assert-CebeUf0C.mjs";
13
- import { l as verifyRequest } from "../http-DZaAutqg.mjs";
5
+ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
6
+ import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
7
+ import { t as assertGreaterOrEqual } from "../assert_greater_or_equal-BlafOF4-.mjs";
8
+ import { t as assertInstanceOf } from "../assert_instance_of-mrXWWNY-.mjs";
9
+ import { t as assertNotEquals } from "../assert_not_equals-CpPK2t89.mjs";
10
+ import "../std__assert-DvMDRPes.mjs";
11
+ import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
12
+ import { t as assert } from "../assert-D1Eafmd_.mjs";
13
+ import { l as verifyRequest } from "../http-D4WPcJUe.mjs";
14
14
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
15
- import { t as doesActorOwnKey } from "../owner-u3IJRhVx.mjs";
16
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-CDr0Zivk.mjs";
15
+ import { t as doesActorOwnKey } from "../owner-BIOIhZoM.mjs";
16
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-Cr5FJ7iu.mjs";
17
17
  import { Activity, Application, Endpoints, Group, Person, Service } from "@fedify/vocab";
18
18
  import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
19
19
  import { FetchError, UrlError } from "@fedify/vocab-runtime";
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
4
4
  import { t as MemoryKvStore } from "../../kv-DCHkaJ9-.mjs";
5
5
  import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, t as MockQueue } from "../../tasks-dbCShlCb.mjs";
6
6
  import "../../testing-hbky2gMN.mjs";
7
- import { o as createFederation } from "../../middleware-pHwDTAnq.mjs";
7
+ import { o as createFederation } from "../../middleware-C7_hqDnl.mjs";
8
8
  import { n as ParallelMessageQueue } from "../../mq-Dm1Wmtm-.mjs";
9
9
  import { configure, reset } from "@logtape/logtape";
10
10
  import { delay } from "es-toolkit";
@@ -4,8 +4,8 @@ globalThis.addEventListener = () => {};
4
4
  import { t as MemoryKvStore } from "../../kv-DCHkaJ9-.mjs";
5
5
  import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, t as MockQueue } from "../../tasks-dbCShlCb.mjs";
6
6
  import "../../testing-hbky2gMN.mjs";
7
- import { o as createFederation } from "../../middleware-pHwDTAnq.mjs";
8
- import { r as createFederationBuilder } from "../../builder-asm96yV1.mjs";
7
+ import { o as createFederation } from "../../middleware-C7_hqDnl.mjs";
8
+ import { r as createFederationBuilder } from "../../builder-BYJ5otJa.mjs";
9
9
  import { t as TaskCodec } from "../../codec-C6rTrpIp.mjs";
10
10
  import { t as InProcessMessageQueue } from "../../mq-Dm1Wmtm-.mjs";
11
11
  import { W3CTraceContextPropagator } from "@opentelemetry/core";
@@ -1,10 +1,10 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { t as assertFalse } from "../assert_false-3pLLLsO4.mjs";
5
- import "../std__assert-CxFT0MNt.mjs";
6
- import { t as assert } from "../assert-CebeUf0C.mjs";
7
- import { t as hasMalformedKnownTemporalLiteral } from "../temporal-DKhVF_Uk.mjs";
4
+ import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
5
+ import "../std__assert-DvMDRPes.mjs";
6
+ import { t as assert } from "../assert-D1Eafmd_.mjs";
7
+ import { t as hasMalformedKnownTemporalLiteral } from "../temporal-CCf0lZV3.mjs";
8
8
  import { test } from "@fedify/fixture";
9
9
  //#region src/federation/temporal.test.ts
10
10
  test("hasMalformedKnownTemporalLiteral() detects expanded proof timestamps", async () => {
@@ -3,10 +3,10 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { r as createRequestContext } from "../context-CbS35fLr.mjs";
5
5
  import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
6
- import { t as assertEquals } from "../assert_equals-CBlRfA-_.mjs";
7
- import { t as assertNotEquals } from "../assert_not_equals-BN7yDMWe.mjs";
8
- import "../std__assert-CxFT0MNt.mjs";
9
- import { o as createFederation, s as handleWebFinger } from "../middleware-pHwDTAnq.mjs";
6
+ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
7
+ import { t as assertNotEquals } from "../assert_not_equals-CpPK2t89.mjs";
8
+ import "../std__assert-DvMDRPes.mjs";
9
+ import { o as createFederation, s as handleWebFinger } from "../middleware-C7_hqDnl.mjs";
10
10
  import { Image, Link, Person, Tombstone } from "@fedify/vocab";
11
11
  import { createTestMeterProvider, test } from "@fedify/fixture";
12
12
  //#region src/federation/webfinger.test.ts