@fedify/fedify 2.4.0-dev.2065 → 2.4.0-dev.2071

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 (93) hide show
  1. package/dist/{builder-CMkrnYbY.mjs → builder-DVQ0yhKJ.mjs} +6 -2
  2. package/dist/compat/mod.d.cts +1 -1
  3. package/dist/compat/mod.d.ts +1 -1
  4. package/dist/compat/transformers.test.mjs +1 -1
  5. package/dist/{compound-proof-Dj3DCsoj.mjs → compound-proof-KmXDfWFp.mjs} +1 -1
  6. package/dist/{context-b36TpPoG.d.cts → context-DijrgHDe.d.cts} +45 -2
  7. package/dist/{context-D_gg4M0n.d.ts → context-DsB9kF6q.d.ts} +45 -2
  8. package/dist/{deno-BuRFI7wk.mjs → deno-B-NtYZVW.mjs} +1 -1
  9. package/dist/{docloader-_aSNLA90.mjs → docloader-C6yOVoaF.mjs} +2 -2
  10. package/dist/federation/builder.test.mjs +1 -1
  11. package/dist/federation/compound-fanout.test.mjs +4 -4
  12. package/dist/federation/handler-compound-proof.test.mjs +3 -3
  13. package/dist/federation/handler.test.mjs +5 -5
  14. package/dist/federation/hashlink-media.test.mjs +2 -2
  15. package/dist/federation/idempotency.test.mjs +2 -2
  16. package/dist/federation/metrics.test.mjs +1 -1
  17. package/dist/federation/middleware.test.mjs +8 -8
  18. package/dist/federation/mod.cjs +1 -1
  19. package/dist/federation/mod.d.cts +3 -3
  20. package/dist/federation/mod.d.ts +3 -3
  21. package/dist/federation/mod.js +1 -1
  22. package/dist/federation/outgoing-proof.test.mjs +6 -6
  23. package/dist/federation/portable-gateway-keys.test.d.mts +2 -0
  24. package/dist/federation/portable-gateway-keys.test.mjs +363 -0
  25. package/dist/federation/portable.test.mjs +3 -3
  26. package/dist/federation/send.test.mjs +3 -3
  27. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  28. package/dist/federation/tasks/tasks.test.mjs +2 -2
  29. package/dist/federation/temporal.test.mjs +1 -1
  30. package/dist/federation/webfinger.test.mjs +1 -1
  31. package/dist/{federation-Coi_bg12.cjs → federation-CUiHc7dP.cjs} +182 -76
  32. package/dist/http-BoWBwC0g.js +5087 -0
  33. package/dist/{http-BGShIsd6.cjs → http-CuLWIJdf.cjs} +2684 -48
  34. package/dist/{http-f1qaBtOh.mjs → http-DKWi8RjI.mjs} +20 -5
  35. package/dist/{http-65PYi9jY.d.ts → http-n2v6DPxu.d.ts} +52 -2
  36. package/dist/{http-CP-7OdSq.d.cts → http-xlG-jRdB.d.cts} +52 -2
  37. package/dist/{key-BxHsA1s9.mjs → key-lfcx_NaE.mjs} +147 -7
  38. package/dist/{kv-cache-Cgj-kpQS.js → kv-cache-BdnmnAVc.js} +1 -1
  39. package/dist/{kv-cache-CY6pDNoS.cjs → kv-cache-DE8kSNQU.cjs} +1 -1
  40. package/dist/{kv-cache-C9IY-FMN.mjs → kv-cache-d8EjO29d.mjs} +1 -1
  41. package/dist/{ld-CqJq5erX.mjs → ld-jyjdrWjG.mjs} +3 -3
  42. package/dist/{metrics-DOqknlZd.mjs → metrics-B5Rei-HC.mjs} +1 -1
  43. package/dist/{middleware-1h_LgwXC.js → middleware-CAObohey.js} +149 -43
  44. package/dist/{middleware-s-AZzx4r.mjs → middleware-CPx4ZWwt.mjs} +155 -53
  45. package/dist/{middleware-VOCZN3SO.mjs → middleware-CdVnCDXD.mjs} +1 -1
  46. package/dist/{mod-Dhm7SqyE.d.ts → mod-C9WSpZWm.d.ts} +1 -1
  47. package/dist/{mod-C0BYc0OU.d.ts → mod-CVZrXSdm.d.ts} +1 -1
  48. package/dist/{mod-BhMvsgdF.d.ts → mod-DMkflQdF.d.ts} +1 -1
  49. package/dist/{mod-Bfenkg_c.d.cts → mod-DTAaBwiY.d.cts} +1 -1
  50. package/dist/{mod-pLbeNwcC.d.cts → mod-HDSvS-ww.d.cts} +1 -1
  51. package/dist/{mod-CyiSjRkk.d.cts → mod-xGFCHqq_.d.cts} +1 -1
  52. package/dist/mod.cjs +18 -18
  53. package/dist/mod.d.cts +7 -7
  54. package/dist/mod.d.ts +7 -7
  55. package/dist/mod.js +5 -5
  56. package/dist/nodeinfo/handler.test.mjs +1 -1
  57. package/dist/owner-1TFakcTF.js +215 -0
  58. package/dist/owner-BXufwAzm.cjs +225 -0
  59. package/dist/{owner-D_F22lfM.mjs → owner-ByqNQVaa.mjs} +45 -2
  60. package/dist/portable-key-Cw_ow5vn.mjs +194 -0
  61. package/dist/{proof-B03JXhrk.mjs → proof-B6gwdhN5.mjs} +5 -5
  62. package/dist/{send-NNkfKtVN.mjs → send-DsK7xevO.mjs} +3 -3
  63. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  64. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  65. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  66. package/dist/sig/compound-proof.test.mjs +3 -3
  67. package/dist/sig/http.test.mjs +2 -2
  68. package/dist/sig/key.test.mjs +1 -1
  69. package/dist/sig/ld.test.mjs +2 -2
  70. package/dist/sig/mod.cjs +16 -16
  71. package/dist/sig/mod.d.cts +2 -2
  72. package/dist/sig/mod.d.ts +2 -2
  73. package/dist/sig/mod.js +3 -3
  74. package/dist/sig/owner.test.mjs +1 -1
  75. package/dist/sig/portable-collection.test.mjs +3 -3
  76. package/dist/sig/portable-key.test.d.mts +2 -0
  77. package/dist/sig/portable-key.test.mjs +275 -0
  78. package/dist/sig/proof.test.mjs +4 -4
  79. package/dist/{sig-Bb20Pyrd.js → sig-BR_Z6mpY.js} +2 -2
  80. package/dist/{sig-B1E2uyhQ.cjs → sig-TTn9wYrE.cjs} +4 -4
  81. package/dist/{temporal-VVVSuruq.mjs → temporal-Bw5jtrBY.mjs} +1 -1
  82. package/dist/testing/kv.test.mjs +1 -1
  83. package/dist/testing/mod.d.mts +43 -0
  84. package/dist/utils/docloader.test.mjs +2 -2
  85. package/dist/utils/kv-cache.test.mjs +1 -1
  86. package/dist/utils/mod.cjs +1 -1
  87. package/dist/utils/mod.d.cts +1 -1
  88. package/dist/utils/mod.d.ts +1 -1
  89. package/dist/utils/mod.js +1 -1
  90. package/package.json +6 -6
  91. package/dist/http-z5n7chWw.js +0 -2647
  92. package/dist/owner-BLBWXCNt.js +0 -2276
  93. package/dist/owner-D8ZpRusc.cjs +0 -2446
@@ -0,0 +1,363 @@
1
+ import "temporal-polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { t as esm_default } from "../esm-BHXXx4Wx.mjs";
5
+ import { r as createRequestContext, t as createInboxContext } from "../context-DG5QeQ8W.mjs";
6
+ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
7
+ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
8
+ import "../std__assert-DvMDRPes.mjs";
9
+ import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
10
+ import { p as signJsonLd } from "../ld-jyjdrWjG.mjs";
11
+ import { s as signRequest } from "../http-DKWi8RjI.mjs";
12
+ import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
13
+ import { d as handleInbox, n as FederationImpl, o as createFederation } from "../middleware-CPx4ZWwt.mjs";
14
+ import { t as ActivityListenerSet } from "../activity-listener-C-BSbKI7.mjs";
15
+ import { t as KvKeyCache } from "../keycache-BUDHB5rY.mjs";
16
+ import { Create, CryptographicKey, Person } from "@fedify/vocab";
17
+ import { mockDocumentLoader, test } from "@fedify/fixture";
18
+ import { encodeMultibase, exportDidKey, parseIri } from "@fedify/vocab-runtime";
19
+ import serialize from "json-canon";
20
+ //#region src/federation/portable-gateway-keys.test.ts
21
+ const did = await exportDidKey(ed25519PublicKey.publicKey);
22
+ const didKeyId = new URL(`${did}#${did.slice(8)}`);
23
+ const actorId = parseIri(`ap+ef61://${did}/actors/alice`);
24
+ const gateway = "https://example.com";
25
+ const otherGateway = "https://other.example";
26
+ const compatibleActorId = (origin) => `${origin}/.well-known/apgateway/${did}/actors/alice`;
27
+ const gatewayKeyId = new URL(`${compatibleActorId(gateway)}#main-key`);
28
+ const ed25519GatewayKeyPair = await crypto.subtle.generateKey("Ed25519", true, ["sign", "verify"]);
29
+ const rsaGatewayKeyPair = {
30
+ privateKey: rsaPrivateKey2,
31
+ publicKey: rsaPublicKey2.publicKey
32
+ };
33
+ const portableContext = [
34
+ "https://www.w3.org/ns/activitystreams",
35
+ "https://w3id.org/security/data-integrity/v1",
36
+ "https://w3id.org/fep/ef61"
37
+ ];
38
+ const recipient = {
39
+ id: new URL("https://example.com/users/bob"),
40
+ inboxId: new URL("https://example.com/inbox")
41
+ };
42
+ async function sign(document) {
43
+ const proofConfig = {
44
+ "@context": document["@context"],
45
+ type: "DataIntegrityProof",
46
+ cryptosuite: "eddsa-jcs-2022",
47
+ verificationMethod: didKeyId.href,
48
+ proofPurpose: "assertionMethod",
49
+ created: "2023-02-24T23:36:38Z"
50
+ };
51
+ const encoder = new TextEncoder();
52
+ const digest = /* @__PURE__ */ new Uint8Array(64);
53
+ digest.set(new Uint8Array(await crypto.subtle.digest("SHA-256", encoder.encode(serialize(proofConfig)))), 0);
54
+ digest.set(new Uint8Array(await crypto.subtle.digest("SHA-256", encoder.encode(serialize(document)))), 32);
55
+ const signature = await crypto.subtle.sign("Ed25519", ed25519PrivateKey, digest);
56
+ return {
57
+ ...document,
58
+ proof: {
59
+ ...proofConfig,
60
+ proofValue: new TextDecoder().decode(encodeMultibase("base58btc", new Uint8Array(signature)))
61
+ }
62
+ };
63
+ }
64
+ function createTestFederation(mapper) {
65
+ const federation = new FederationImpl({
66
+ kv: new MemoryKvStore(),
67
+ manuallyStartQueue: true,
68
+ contextLoaderFactory: () => mockDocumentLoader,
69
+ documentLoaderFactory: () => mockDocumentLoader
70
+ });
71
+ const setters = federation.setActorDispatcher("/users/{identifier}", () => null).setKeyPairsDispatcher(() => [rsaGatewayKeyPair, ed25519GatewayKeyPair]);
72
+ if (mapper != null) setters.mapPortableActorId((_ctx, id) => mapper(id));
73
+ return federation;
74
+ }
75
+ function portableCreate(id = "1") {
76
+ return new Create({
77
+ id: parseIri(`ap+ef61://${did}/activities/${id}`),
78
+ actor: actorId,
79
+ object: new URL("https://example.com/notes/1")
80
+ });
81
+ }
82
+ async function signedPortableCreate(id = "1") {
83
+ const json = await portableCreate(id).toJsonLd({
84
+ format: "compact",
85
+ context: portableContext,
86
+ contextLoader: mockDocumentLoader
87
+ });
88
+ return await Create.fromJsonLd(await sign(json), {
89
+ contextLoader: mockDocumentLoader,
90
+ documentLoader: mockDocumentLoader
91
+ });
92
+ }
93
+ async function capture(run) {
94
+ const bodies = [];
95
+ const requests = [];
96
+ esm_default.spyGlobal();
97
+ try {
98
+ esm_default.post(recipient.inboxId.href, async (cl) => {
99
+ const body = await cl.request.text();
100
+ requests.push(new Request(cl.request.url, {
101
+ method: cl.request.method,
102
+ headers: cl.request.headers,
103
+ body
104
+ }));
105
+ bodies.push(JSON.parse(body));
106
+ return new Response(null, { status: 202 });
107
+ });
108
+ await run();
109
+ } finally {
110
+ esm_default.hardReset();
111
+ }
112
+ return {
113
+ bodies,
114
+ requests
115
+ };
116
+ }
117
+ function signatureKeyId(request) {
118
+ return request.headers.get("Signature-Input")?.match(/keyid="([^"]+)"/)?.[1] ?? request.headers.get("Signature")?.match(/keyId="([^"]+)"/)?.[1];
119
+ }
120
+ test("Context.getActorKeyPairs() derives gateway keys for portable actors", async () => {
121
+ const ctx = createTestFederation((id) => id === "alice" ? actorId : null).createContext(new URL(gateway));
122
+ const keys = await ctx.getActorKeyPairs("alice");
123
+ assertEquals(keys.map((k) => k.keyId.href), [gatewayKeyId.href, `${compatibleActorId(gateway)}#key-2`]);
124
+ for (const key of keys) {
125
+ assertEquals(key.cryptographicKey.id?.href, key.keyId.href);
126
+ assertEquals(key.cryptographicKey.ownerId?.href, actorId.href);
127
+ assertEquals(key.multikey.id?.href, key.keyId.href);
128
+ assertEquals(key.multikey.controllerId?.href, actorId.href);
129
+ }
130
+ assertEquals((await ctx.getActorKeyPairs("bob")).map((k) => [k.keyId.href, k.multikey.id?.href]), [["https://example.com/users/bob#main-key", "https://example.com/users/bob#multikey-1"], ["https://example.com/users/bob#key-2", "https://example.com/users/bob#multikey-2"]]);
131
+ const json = await new Person({
132
+ id: actorId,
133
+ gateways: [new URL(gateway)],
134
+ publicKey: keys[0].cryptographicKey,
135
+ assertionMethods: keys.map((k) => k.multikey)
136
+ }).toJsonLd({
137
+ format: "compact",
138
+ contextLoader: mockDocumentLoader
139
+ });
140
+ const assertionMethod = json.assertionMethod;
141
+ assertEquals(assertionMethod.map((k) => [k.id, k.controller]), [[gatewayKeyId.href, `ap+ef61://${did}/actors/alice`], [`${compatibleActorId(gateway)}#key-2`, `ap+ef61://${did}/actors/alice`]]);
142
+ assertEquals(json.publicKey.id, gatewayKeyId.href);
143
+ });
144
+ test("Context.getActorKeyPairs() accepts compatible IDs as portable actor IDs", async () => {
145
+ const published = new URL(compatibleActorId(otherGateway));
146
+ const [key] = await createTestFederation(() => published).createContext(new URL(gateway)).getActorKeyPairs("alice");
147
+ assertEquals(key.keyId.href, gatewayKeyId.href);
148
+ assertEquals(key.cryptographicKey.ownerId?.href, published.href);
149
+ });
150
+ test("Context.getActorKeyPairs() propagates portable actor ID mapper errors", async () => {
151
+ for (const id of [new URL(`${actorId.href}#me`), new URL("https://example.com/users/alice")]) {
152
+ const ctx = createTestFederation(() => id).createContext(new URL(gateway));
153
+ await assertRejects(() => ctx.getActorKeyPairs("alice"), TypeError);
154
+ }
155
+ const ctx = createTestFederation(() => {
156
+ throw new RangeError("mapper failed");
157
+ }).createContext(new URL(gateway));
158
+ await assertRejects(() => ctx.getActorKeyPairs("alice"), RangeError);
159
+ const federation = new FederationImpl({ kv: new MemoryKvStore() });
160
+ federation.setActorDispatcher("/users/{identifier}", () => null).setKeyPairsDispatcher(() => {
161
+ throw new Error("dispatcher failed");
162
+ }).mapPortableActorId(() => actorId);
163
+ assertEquals(await federation.createContext(new URL(gateway)).getActorKeyPairs("alice"), []);
164
+ });
165
+ test("Context.sendActivity() signs requests with gateway keys for portable actors", async () => {
166
+ const ctx = createTestFederation(() => actorId).createContext(new URL(gateway));
167
+ const activity = await signedPortableCreate();
168
+ const { bodies, requests } = await capture(() => ctx.sendActivity({ identifier: "alice" }, recipient, activity));
169
+ assertEquals(bodies.length, 1);
170
+ assertEquals(signatureKeyId(requests[0]), gatewayKeyId.href);
171
+ const proof = bodies[0].proof;
172
+ assertEquals(Array.isArray(proof), false);
173
+ assertEquals(proof.verificationMethod, didKeyId.href);
174
+ assertEquals(bodies[0].signature, void 0);
175
+ });
176
+ test("Context.sendActivity() refuses portable activities gateway keys would sign", async () => {
177
+ const ctx = createTestFederation(() => actorId).createContext(new URL(gateway));
178
+ await assertRejects(() => ctx.sendActivity({ identifier: "alice" }, recipient, portableCreate()), TypeError);
179
+ const httpActivity = new Create({
180
+ id: new URL("https://example.com/activities/1"),
181
+ actor: actorId,
182
+ object: new URL("https://example.com/notes/1")
183
+ });
184
+ await assertRejects(() => ctx.sendActivity({ identifier: "alice" }, recipient, httpActivity), TypeError);
185
+ await assertRejects(() => ctx.sendActivity({
186
+ keyId: new URL("https://example.com/key"),
187
+ privateKey: ed25519PrivateKey
188
+ }, recipient, portableCreate()), TypeError);
189
+ const { bodies } = await capture(() => ctx.sendActivity([{
190
+ keyId: gatewayKeyId,
191
+ privateKey: rsaPrivateKey2
192
+ }, {
193
+ keyId: didKeyId,
194
+ privateKey: ed25519PrivateKey
195
+ }], recipient, portableCreate()));
196
+ assertEquals(bodies[0].proof.verificationMethod, didKeyId.href);
197
+ });
198
+ test("Context.sendActivity() never signs documents with gateway keys", async () => {
199
+ const ctx = createTestFederation().createContext(new URL(gateway));
200
+ const keys = [{
201
+ keyId: gatewayKeyId,
202
+ privateKey: rsaPrivateKey2
203
+ }, {
204
+ keyId: new URL(`${compatibleActorId(gateway)}#key-2`),
205
+ privateKey: ed25519GatewayKeyPair.privateKey
206
+ }];
207
+ const activity = new Create({
208
+ id: new URL("https://example.com/activities/1"),
209
+ actor: new URL("https://example.com/users/bob"),
210
+ object: new URL("https://example.com/notes/1")
211
+ });
212
+ const { bodies, requests } = await capture(() => ctx.sendActivity(keys, recipient, activity));
213
+ assertEquals(signatureKeyId(requests[0]), gatewayKeyId.href);
214
+ assertEquals(bodies[0].proof, void 0);
215
+ assertEquals(bodies[0].signature, void 0);
216
+ });
217
+ test("Context.getDocumentLoader() signs requests with gateway keys for portable actors", async () => {
218
+ const documentLoader = await createTestFederation(() => actorId).createContext(new URL(gateway)).getDocumentLoader({ identifier: "alice" });
219
+ let keyId;
220
+ esm_default.spyGlobal();
221
+ try {
222
+ esm_default.get("https://example.com/notes/1", (cl) => {
223
+ keyId = signatureKeyId(cl.request);
224
+ return new Response(JSON.stringify({ id: cl.request.url }), { headers: { "Content-Type": "application/activity+json" } });
225
+ });
226
+ await documentLoader("https://example.com/notes/1");
227
+ } finally {
228
+ esm_default.hardReset();
229
+ }
230
+ assertEquals(keyId, gatewayKeyId.href);
231
+ });
232
+ async function actorDocument(gateways) {
233
+ const keys = await createTestFederation(() => actorId).createContext(new URL(gateway)).getActorKeyPairs("alice");
234
+ const json = await new Person({
235
+ id: actorId,
236
+ inbox: parseIri(`${actorId.href}/inbox`),
237
+ gateways: gateways.map((g) => new URL(g)),
238
+ publicKey: keys[0].cryptographicKey,
239
+ assertionMethods: keys.map((k) => k.multikey)
240
+ }).toJsonLd({
241
+ format: "compact",
242
+ contextLoader: mockDocumentLoader
243
+ });
244
+ json["@context"] = [...json["@context"], "https://w3id.org/security/data-integrity/v1"];
245
+ return await sign(json);
246
+ }
247
+ function createLoader(responses) {
248
+ return (url) => {
249
+ const document = responses[url.replace(/#.*$/, "")];
250
+ if (document == null) return mockDocumentLoader(url);
251
+ return Promise.resolve({
252
+ contextUrl: null,
253
+ documentUrl: url,
254
+ document: structuredClone(document)
255
+ });
256
+ };
257
+ }
258
+ async function deliver(body, gateways, { kv = new MemoryKvStore(), httpSignature = true } = {}) {
259
+ const documentLoader = createLoader({ [compatibleActorId(gateway)]: await actorDocument(gateways) });
260
+ const unsigned = new Request("https://local.example/inbox", {
261
+ method: "POST",
262
+ body: JSON.stringify(body),
263
+ headers: { "Content-Type": "application/activity+json" }
264
+ });
265
+ const request = httpSignature ? await signRequest(unsigned, rsaPrivateKey2, gatewayKeyId) : unsigned;
266
+ const context = createRequestContext({
267
+ federation: createFederation({ kv: new MemoryKvStore() }),
268
+ request,
269
+ url: new URL(request.url),
270
+ data: void 0,
271
+ documentLoader,
272
+ contextLoader: mockDocumentLoader
273
+ });
274
+ let dispatched = 0;
275
+ const inboxListeners = new ActivityListenerSet();
276
+ inboxListeners.add(Create, () => {
277
+ dispatched++;
278
+ });
279
+ const response = await handleInbox(request, {
280
+ recipient: null,
281
+ context,
282
+ inboxContextFactory() {
283
+ return createInboxContext({
284
+ ...context,
285
+ clone: void 0
286
+ });
287
+ },
288
+ kv,
289
+ kvPrefixes: {
290
+ activityIdempotence: ["_fedify", "activityIdempotence"],
291
+ publicKey: ["_fedify", "publicKey"],
292
+ acceptSignatureNonce: ["_fedify", "acceptSignatureNonce"]
293
+ },
294
+ actorDispatcher() {
295
+ return null;
296
+ },
297
+ inboxListeners,
298
+ onNotFound() {
299
+ return new Response("Not found", { status: 404 });
300
+ },
301
+ signatureTimeWindow: { minutes: 5 },
302
+ skipSignatureVerification: false
303
+ });
304
+ lastResponseText = await response.text();
305
+ return {
306
+ status: response.status,
307
+ dispatched
308
+ };
309
+ }
310
+ let lastResponseText = "";
311
+ async function createJson(id) {
312
+ return await portableCreate(id).toJsonLd({
313
+ format: "compact",
314
+ context: portableContext,
315
+ contextLoader: mockDocumentLoader
316
+ });
317
+ }
318
+ test("handleInbox() requires proofs of portable actors despite gateway signatures", async () => {
319
+ assertEquals(await deliver(await createJson("unsigned"), [gateway]), {
320
+ status: 401,
321
+ dispatched: 0
322
+ });
323
+ assertEquals(await deliver({
324
+ ...await sign(await createJson("tampered")),
325
+ object: "https://remote.example/notes/2"
326
+ }, [gateway]), {
327
+ status: 401,
328
+ dispatched: 0
329
+ });
330
+ assertEquals(await deliver(await sign(await createJson("signed")), [gateway]), {
331
+ status: 202,
332
+ dispatched: 1
333
+ });
334
+ });
335
+ test("handleInbox() does not need gateway signatures for portable actors", async () => {
336
+ assertEquals(await deliver(await sign(await createJson("signed")), [otherGateway]), {
337
+ status: 202,
338
+ dispatched: 1
339
+ });
340
+ assertEquals(await deliver(await createJson("unsigned"), [otherGateway]), {
341
+ status: 401,
342
+ dispatched: 0
343
+ });
344
+ });
345
+ test("handleInbox() does not take Linked Data Signatures for portable actors", async () => {
346
+ const kv = new MemoryKvStore();
347
+ await new KvKeyCache(kv, ["_fedify", "publicKey"]).set(rsaPublicKey2.id, new CryptographicKey({
348
+ id: rsaPublicKey2.id,
349
+ owner: actorId,
350
+ publicKey: rsaPublicKey2.publicKey
351
+ }));
352
+ const ldSign = (document) => signJsonLd(document, rsaPrivateKey2, rsaPublicKey2.id, { contextLoader: mockDocumentLoader });
353
+ assertEquals(await deliver(await ldSign(await createJson("ld-only")), [gateway], {
354
+ kv,
355
+ httpSignature: false
356
+ }), {
357
+ status: 401,
358
+ dispatched: 0
359
+ });
360
+ assertEquals(lastResponseText, "Activities of portable actors must have valid Object Integrity Proofs.");
361
+ });
362
+ //#endregion
363
+ export {};
@@ -7,10 +7,10 @@ import { t as assertInstanceOf } from "../assert_instance_of-mrXWWNY-.mjs";
7
7
  import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
8
8
  import "../std__assert-DvMDRPes.mjs";
9
9
  import { t as assertStrictEquals } from "../assert_strict_equals-CYvBmkpC.mjs";
10
- import { s as signRequest } from "../http-f1qaBtOh.mjs";
10
+ import { o as verifyPortableObjectProof, r as signObject } from "../proof-B6gwdhN5.mjs";
11
+ import { s as signRequest } from "../http-DKWi8RjI.mjs";
11
12
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
12
- import { g as PORTABLE_OBJECT_CONTENT_TYPE, o as createFederation } from "../middleware-s-AZzx4r.mjs";
13
- import { o as verifyPortableObjectProof, r as signObject } from "../proof-B03JXhrk.mjs";
13
+ import { g as PORTABLE_OBJECT_CONTENT_TYPE, o as createFederation } from "../middleware-CPx4ZWwt.mjs";
14
14
  import { Collection, Create, Note, Object as Object$1, Person, Tombstone, lookupObject } from "@fedify/vocab";
15
15
  import { mockDocumentLoader, test } from "@fedify/fixture";
16
16
  import { exportDidKey, formatIri, parseIri } from "@fedify/vocab-runtime";
@@ -10,10 +10,10 @@ import { t as assertNotEquals } from "../assert_not_equals-CpPK2t89.mjs";
10
10
  import "../std__assert-DvMDRPes.mjs";
11
11
  import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
12
12
  import { t as assert } from "../assert-D1Eafmd_.mjs";
13
- import { l as verifyRequest } from "../http-f1qaBtOh.mjs";
13
+ import { l as verifyRequest } from "../http-DKWi8RjI.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-D_F22lfM.mjs";
16
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-NNkfKtVN.mjs";
15
+ import { t as doesActorOwnKey } from "../owner-ByqNQVaa.mjs";
16
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-DsK7xevO.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-By1YYsIK.mjs";
7
- import { o as createFederation } from "../../middleware-s-AZzx4r.mjs";
7
+ import { o as createFederation } from "../../middleware-CPx4ZWwt.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-By1YYsIK.mjs";
7
- import { o as createFederation } from "../../middleware-s-AZzx4r.mjs";
8
- import { r as createFederationBuilder } from "../../builder-CMkrnYbY.mjs";
7
+ import { o as createFederation } from "../../middleware-CPx4ZWwt.mjs";
8
+ import { r as createFederationBuilder } from "../../builder-DVQ0yhKJ.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";
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
4
4
  import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
5
5
  import "../std__assert-DvMDRPes.mjs";
6
6
  import { t as assert } from "../assert-D1Eafmd_.mjs";
7
- import { t as hasMalformedKnownTemporalLiteral } from "../temporal-VVVSuruq.mjs";
7
+ import { t as hasMalformedKnownTemporalLiteral } from "../temporal-Bw5jtrBY.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 () => {
@@ -6,7 +6,7 @@ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
6
6
  import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
7
7
  import { t as assertNotEquals } from "../assert_not_equals-CpPK2t89.mjs";
8
8
  import "../std__assert-DvMDRPes.mjs";
9
- import { o as createFederation, s as handleWebFinger } from "../middleware-s-AZzx4r.mjs";
9
+ import { o as createFederation, s as handleWebFinger } from "../middleware-CPx4ZWwt.mjs";
10
10
  import { Image, Link, Person, Tombstone } from "@fedify/vocab";
11
11
  import { createTestMeterProvider, test } from "@fedify/fixture";
12
12
  import { parseIri } from "@fedify/vocab-runtime";