@fedify/fedify 2.2.3-dev.1098 → 2.2.4

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 (60) hide show
  1. package/dist/{builder-mqtih91o.mjs → builder-Dg2hGWk5.mjs} +2 -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/{context-BPMgyX7m.d.ts → context-BU-1O90h.d.ts} +48 -6
  6. package/dist/{context-DwkhwUX9.d.cts → context-DVA8wHZ0.d.cts} +48 -6
  7. package/dist/{deno-CziVFvS6.mjs → deno-_3m2phl-.mjs} +1 -1
  8. package/dist/{docloader-fI9DeYyB.mjs → docloader-Cq_3E56G.mjs} +2 -2
  9. package/dist/federation/builder.test.mjs +1 -1
  10. package/dist/federation/handler.test.mjs +1363 -43
  11. package/dist/federation/idempotency.test.mjs +2 -2
  12. package/dist/federation/middleware.test.mjs +1584 -80
  13. package/dist/federation/mod.cjs +1 -1
  14. package/dist/federation/mod.d.cts +2 -2
  15. package/dist/federation/mod.d.ts +2 -2
  16. package/dist/federation/mod.js +1 -1
  17. package/dist/federation/retry.test.mjs +1 -1
  18. package/dist/federation/send.test.mjs +3 -3
  19. package/dist/federation/temporal.test.d.mts +2 -0
  20. package/dist/federation/temporal.test.mjs +71 -0
  21. package/dist/federation/webfinger.test.mjs +1 -1
  22. package/dist/{http-D8qsXrUS.js → http-BauEA3uU.js} +1 -1
  23. package/dist/{http-BDCGf4Ac.mjs → http-C6206Ne5.mjs} +2 -2
  24. package/dist/{http-kPc328Pc.cjs → http-CzvQu1wC.cjs} +1 -1
  25. package/dist/{key-D3TgMhcs.mjs → key-ckqyhgo3.mjs} +1 -1
  26. package/dist/{kv-cache-zxW74Wfd.cjs → kv-cache-10y07lRd.cjs} +1 -1
  27. package/dist/{kv-cache-D_eVhctK.js → kv-cache-DLwx2oCr.js} +1 -1
  28. package/dist/ld-B3BrUVFK.mjs +573 -0
  29. package/dist/{middleware-2gmMVy8b.mjs → middleware-Bn8hcuAb.mjs} +314 -78
  30. package/dist/{middleware-BuOXw_hM.cjs → middleware-CBNvWoWG.cjs} +1 -1
  31. package/dist/{middleware-xR9KxICq.cjs → middleware-Cppn0oGi.cjs} +399 -73
  32. package/dist/{middleware-gXlDLkok.js → middleware-DkSEt8CX.js} +396 -71
  33. package/dist/{middleware-CfaiRKQ9.mjs → middleware-_5uCEul-.mjs} +1 -1
  34. package/dist/{mod-CNAHY39V.d.ts → mod-BVt6iTmH.d.ts} +1 -1
  35. package/dist/{mod-Bi6WOdti.d.cts → mod-q-NFLW6B.d.cts} +1 -1
  36. package/dist/mod.cjs +4 -4
  37. package/dist/mod.d.cts +2 -2
  38. package/dist/mod.d.ts +2 -2
  39. package/dist/mod.js +4 -4
  40. package/dist/nodeinfo/handler.test.mjs +1 -1
  41. package/dist/{owner-DBSV2TSl.mjs → owner-BIrHaRRj.mjs} +2 -2
  42. package/dist/{proof-tz91vdtN.mjs → proof-B9P5A7RZ.mjs} +2 -2
  43. package/dist/{proof-CZDkoeWG.cjs → proof-Bxo0UtfN.cjs} +351 -3
  44. package/dist/{proof-z93OkIov.js → proof-erB_wSQi.js} +298 -4
  45. package/dist/{send-CNjG31rJ.mjs → send-7FY-qDY3.mjs} +2 -2
  46. package/dist/sig/http.test.mjs +2 -2
  47. package/dist/sig/key.test.mjs +1 -1
  48. package/dist/sig/ld.test.mjs +558 -2
  49. package/dist/sig/mod.cjs +2 -2
  50. package/dist/sig/mod.js +2 -2
  51. package/dist/sig/owner.test.mjs +1 -1
  52. package/dist/sig/proof.test.mjs +1 -1
  53. package/dist/temporal-CuaJdDfw.mjs +95 -0
  54. package/dist/testing/mod.d.mts +48 -6
  55. package/dist/utils/docloader.test.mjs +2 -2
  56. package/dist/utils/mod.cjs +1 -1
  57. package/dist/utils/mod.js +1 -1
  58. package/package.json +5 -5
  59. package/dist/ld-D_u8mdpv.mjs +0 -279
  60. /package/dist/{retry-bMXBL97A.mjs → retry-v_sGLH1d.mjs} +0 -0
@@ -5,13 +5,21 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
6
6
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
7
7
  import { t as assert } from "../assert-DikXweDx.mjs";
8
- import { i as generateCryptoKeyPair } from "../key-D3TgMhcs.mjs";
8
+ import { i as generateCryptoKeyPair } from "../key-ckqyhgo3.mjs";
9
9
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DGu1NFwu.mjs";
10
- import { a as signJsonLd, i as hasSignatureLike, n as createSignature, o as verifyJsonLd, r as detachSignature, s as verifySignature, t as attachSignature } from "../ld-D_u8mdpv.mjs";
10
+ import { a as compactJsonLd, f as isInvalidUrlTypeError, g as verifySignature, h as verifyJsonLd, i as attachSignature, n as UnsafeJsonLdError, o as createSignature, p as signJsonLd, s as detachSignature, u as hasSignatureLike } from "../ld-B3BrUVFK.mjs";
11
11
  import { mockDocumentLoader, test } from "@fedify/fixture";
12
12
  import { CryptographicKey } from "@fedify/vocab";
13
13
  import { encodeBase64 } from "byte-encodings/base64";
14
14
  //#region src/sig/ld.test.ts
15
+ test("isInvalidUrlTypeError()", () => {
16
+ assert(isInvalidUrlTypeError(/* @__PURE__ */ new TypeError("Invalid URL: http://[")));
17
+ assert(isInvalidUrlTypeError(/* @__PURE__ */ new TypeError("\"http://[\" cannot be parsed as a URL.")));
18
+ const error = /* @__PURE__ */ new TypeError("Failed to parse URL");
19
+ error.code = "ERR_INVALID_URL";
20
+ assert(isInvalidUrlTypeError(error));
21
+ assertFalse(isInvalidUrlTypeError(/* @__PURE__ */ new TypeError("Failed to fetch")));
22
+ });
15
23
  test("attachSignature()", () => {
16
24
  const sig = {
17
25
  "@context": "https://w3id.org/identity/v1",
@@ -249,5 +257,553 @@ test("verifyJsonLd()", async () => {
249
257
  contextLoader: mockDocumentLoader
250
258
  }));
251
259
  });
260
+ test("compactJsonLd() with restrictive context loader", async () => {
261
+ const restrictiveContextLoader = async (resource) => {
262
+ const url = new URL(resource).href;
263
+ if (url === "https://www.w3.org/ns/activitystreams" || url === "https://w3id.org/identity/v1") return await mockDocumentLoader(url);
264
+ throw new Error(`Unexpected context: ${url}`);
265
+ };
266
+ const signed = await signJsonLd({
267
+ "@context": [
268
+ "https://www.w3.org/ns/activitystreams",
269
+ "https://w3id.org/identity/v1",
270
+ "https://w3id.org/security/v1",
271
+ "https://w3id.org/security/data-integrity/v1"
272
+ ],
273
+ id: "https://example.com/1",
274
+ type: "Create",
275
+ actor: "https://example.com/person2"
276
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader });
277
+ assertEquals(await compactJsonLd(signed, restrictiveContextLoader), {
278
+ "@context": [
279
+ "https://w3id.org/identity/v1",
280
+ "https://www.w3.org/ns/activitystreams",
281
+ "https://w3id.org/security/v1",
282
+ "https://w3id.org/security/data-integrity/v1"
283
+ ],
284
+ id: "https://example.com/1",
285
+ type: "Create",
286
+ actor: "https://example.com/person2",
287
+ signature: signed.signature
288
+ });
289
+ });
290
+ test("compactJsonLd() caches repeated remote contexts across graph scan and compaction", async () => {
291
+ const remoteUrl = "https://example.com/context";
292
+ let calls = 0;
293
+ const countingLoader = async (resource) => {
294
+ const url = new URL(resource).href;
295
+ if (url === remoteUrl) {
296
+ calls++;
297
+ return {
298
+ contextUrl: null,
299
+ documentUrl: url,
300
+ document: { "@context": { extra: "https://example.com/extra" } }
301
+ };
302
+ }
303
+ return await mockDocumentLoader(url);
304
+ };
305
+ await compactJsonLd({
306
+ "@context": "https://www.w3.org/ns/activitystreams",
307
+ id: "https://example.com/activities/remote-contexts",
308
+ type: "Create",
309
+ actor: "https://example.com/person2",
310
+ object: [
311
+ {
312
+ "@context": ["https://www.w3.org/ns/activitystreams", remoteUrl],
313
+ type: "Note",
314
+ content: "one"
315
+ },
316
+ {
317
+ "@context": ["https://www.w3.org/ns/activitystreams", remoteUrl],
318
+ type: "Note",
319
+ content: "two"
320
+ },
321
+ {
322
+ "@context": ["https://www.w3.org/ns/activitystreams", remoteUrl],
323
+ type: "Note",
324
+ content: "three"
325
+ }
326
+ ]
327
+ }, countingLoader);
328
+ assertEquals(calls, 1);
329
+ });
330
+ test("compactJsonLd() reuses the same remote context response for graph scan and compaction", async () => {
331
+ const remoteUrl = "https://example.com/context";
332
+ let calls = 0;
333
+ const compacted = await compactJsonLd({
334
+ "@context": [remoteUrl, "https://www.w3.org/ns/activitystreams"],
335
+ id: "https://example.com/activities/memoized-remote-context",
336
+ type: "Create",
337
+ actor: "https://example.com/person2",
338
+ graph: "https://example.com/custom-graph",
339
+ object: "https://example.com/notes/1"
340
+ }, async (resource) => {
341
+ const url = new URL(resource).href;
342
+ if (url === remoteUrl) {
343
+ calls++;
344
+ if (calls > 1) throw new Error(`Remote context should not be fetched twice: ${url}`);
345
+ return {
346
+ contextUrl: null,
347
+ documentUrl: url,
348
+ document: { "@context": { graph: "https://example.com/graph" } }
349
+ };
350
+ }
351
+ return await mockDocumentLoader(url);
352
+ });
353
+ assertEquals(calls, 1);
354
+ assertEquals(compacted, {
355
+ "@context": [
356
+ "https://w3id.org/identity/v1",
357
+ "https://www.w3.org/ns/activitystreams",
358
+ "https://w3id.org/security/v1",
359
+ "https://w3id.org/security/data-integrity/v1"
360
+ ],
361
+ id: "https://example.com/activities/memoized-remote-context",
362
+ type: "Create",
363
+ actor: "https://example.com/person2",
364
+ "https://example.com/graph": "https://example.com/custom-graph",
365
+ object: "https://example.com/notes/1"
366
+ });
367
+ });
368
+ test("compactJsonLd() preserves opaque top-level ids and resolves relative remote contexts against documentUrl during graph scan", async () => {
369
+ const rootContextId = "opaque-root";
370
+ const rootContextUrl = "https://example.com/contexts/root";
371
+ const childContextUrl = "https://example.com/contexts/child";
372
+ const calls = [];
373
+ const customLoader = async (resource) => {
374
+ calls.push(resource);
375
+ if (resource === rootContextId) return {
376
+ contextUrl: null,
377
+ documentUrl: rootContextUrl,
378
+ document: { "@context": {
379
+ "@import": "./child",
380
+ ext: "https://example.com/ext"
381
+ } }
382
+ };
383
+ if (resource === childContextUrl || resource === "child") return {
384
+ contextUrl: null,
385
+ documentUrl: childContextUrl,
386
+ document: { "@context": { child: "https://example.com/child" } }
387
+ };
388
+ return await mockDocumentLoader(resource);
389
+ };
390
+ assertEquals(await compactJsonLd({
391
+ "@context": [rootContextId, "https://www.w3.org/ns/activitystreams"],
392
+ id: "https://example.com/activities/custom-loader-contexts",
393
+ type: "Create",
394
+ actor: "https://example.com/person2",
395
+ ext: "preserve-me",
396
+ object: {
397
+ type: "Note",
398
+ content: "Hello"
399
+ }
400
+ }, customLoader), {
401
+ "@context": [
402
+ "https://w3id.org/identity/v1",
403
+ "https://www.w3.org/ns/activitystreams",
404
+ "https://w3id.org/security/v1",
405
+ "https://w3id.org/security/data-integrity/v1"
406
+ ],
407
+ id: "https://example.com/activities/custom-loader-contexts",
408
+ type: "Create",
409
+ actor: "https://example.com/person2",
410
+ "https://example.com/ext": "preserve-me",
411
+ object: {
412
+ type: "Note",
413
+ content: "Hello"
414
+ }
415
+ });
416
+ assert(calls.includes(rootContextId));
417
+ assert(calls.includes(childContextUrl));
418
+ assertFalse(calls.includes("./child"));
419
+ });
420
+ test("compactJsonLd() preserves base URLs for property-scoped remote contexts", async () => {
421
+ const rootContextId = "opaque-root";
422
+ const rootContextUrl = "https://example.com/contexts/root";
423
+ const childContextUrl = "https://example.com/contexts/child";
424
+ const calls = [];
425
+ const customLoader = async (resource) => {
426
+ calls.push(resource);
427
+ if (resource === rootContextId) return {
428
+ contextUrl: null,
429
+ documentUrl: rootContextUrl,
430
+ document: { "@context": { p: {
431
+ "@id": "https://example.com/p",
432
+ "@context": "./child"
433
+ } } }
434
+ };
435
+ if (resource === childContextUrl) return {
436
+ contextUrl: null,
437
+ documentUrl: childContextUrl,
438
+ document: { "@context": { nested: "https://example.com/nested" } }
439
+ };
440
+ return await mockDocumentLoader(resource);
441
+ };
442
+ assertEquals(await compactJsonLd({
443
+ "@context": [rootContextId, "https://www.w3.org/ns/activitystreams"],
444
+ id: "https://example.com/activities/property-scoped-contexts",
445
+ type: "Create",
446
+ actor: "https://example.com/person2",
447
+ p: { nested: "value" },
448
+ object: "https://example.com/notes/1"
449
+ }, customLoader), {
450
+ "@context": [
451
+ "https://w3id.org/identity/v1",
452
+ "https://www.w3.org/ns/activitystreams",
453
+ "https://w3id.org/security/v1",
454
+ "https://w3id.org/security/data-integrity/v1"
455
+ ],
456
+ id: "https://example.com/activities/property-scoped-contexts",
457
+ type: "Create",
458
+ actor: "https://example.com/person2",
459
+ "https://example.com/p": { "https://example.com/nested": "value" },
460
+ object: "https://example.com/notes/1"
461
+ });
462
+ assert(calls.includes(rootContextId));
463
+ assert(calls.includes(childContextUrl));
464
+ assertFalse(calls.includes("./child"));
465
+ });
466
+ test("compactJsonLd() ignores unsafe-looking keys inside @json values", async () => {
467
+ const remoteContextUrl = "https://example.com/contexts/json";
468
+ assertEquals(await compactJsonLd({
469
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
470
+ id: "https://example.com/activities/json-blob",
471
+ type: "Create",
472
+ actor: "https://example.com/person2",
473
+ blob: {
474
+ graph: { nested: true },
475
+ "@reverse": { nope: true },
476
+ "@included": [{ still: "raw-json" }]
477
+ },
478
+ object: "https://example.com/notes/1"
479
+ }, async (resource) => {
480
+ const url = new URL(resource).href;
481
+ if (url === remoteContextUrl) return {
482
+ contextUrl: null,
483
+ documentUrl: url,
484
+ document: { "@context": {
485
+ blob: {
486
+ "@id": "https://example.com/blob",
487
+ "@type": "@json"
488
+ },
489
+ graph: "@graph"
490
+ } }
491
+ };
492
+ return await mockDocumentLoader(url);
493
+ }), {
494
+ "@context": [
495
+ "https://w3id.org/identity/v1",
496
+ "https://www.w3.org/ns/activitystreams",
497
+ "https://w3id.org/security/v1",
498
+ "https://w3id.org/security/data-integrity/v1"
499
+ ],
500
+ id: "https://example.com/activities/json-blob",
501
+ type: "Create",
502
+ "https://example.com/blob": {
503
+ type: "@json",
504
+ "@value": {
505
+ graph: { nested: true },
506
+ "@reverse": { nope: true },
507
+ "@included": [{ still: "raw-json" }]
508
+ }
509
+ },
510
+ actor: "https://example.com/person2",
511
+ object: "https://example.com/notes/1"
512
+ });
513
+ });
514
+ test("compactJsonLd() ignores unsafe-looking keys inside inline @json value wrappers", async () => {
515
+ const remoteContextUrl = "https://example.com/contexts/inline-json";
516
+ assertEquals(await compactJsonLd({
517
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
518
+ id: "https://example.com/activities/inline-json-blob",
519
+ type: "Create",
520
+ actor: "https://example.com/person2",
521
+ blob: {
522
+ "@value": {
523
+ graph: { nested: true },
524
+ "@reverse": { nope: true },
525
+ "@included": [{ still: "raw-json" }]
526
+ },
527
+ "@type": "@json"
528
+ },
529
+ object: "https://example.com/notes/1"
530
+ }, async (resource) => {
531
+ const url = new URL(resource).href;
532
+ if (url === remoteContextUrl) return {
533
+ contextUrl: null,
534
+ documentUrl: url,
535
+ document: { "@context": {
536
+ blob: "https://example.com/blob",
537
+ graph: "@graph"
538
+ } }
539
+ };
540
+ return await mockDocumentLoader(url);
541
+ }), {
542
+ "@context": [
543
+ "https://w3id.org/identity/v1",
544
+ "https://www.w3.org/ns/activitystreams",
545
+ "https://w3id.org/security/v1",
546
+ "https://w3id.org/security/data-integrity/v1"
547
+ ],
548
+ id: "https://example.com/activities/inline-json-blob",
549
+ type: "Create",
550
+ "https://example.com/blob": {
551
+ type: "@json",
552
+ "@value": {
553
+ graph: { nested: true },
554
+ "@reverse": { nope: true },
555
+ "@included": [{ still: "raw-json" }]
556
+ }
557
+ },
558
+ actor: "https://example.com/person2",
559
+ object: "https://example.com/notes/1"
560
+ });
561
+ });
562
+ test("verifyJsonLd() respects @graph alias overrides", async () => {
563
+ assert(await verifyJsonLd(await signJsonLd({
564
+ "@context": [
565
+ "https://www.w3.org/ns/activitystreams",
566
+ { graph: "@graph" },
567
+ { graph: "https://example.com/graph" }
568
+ ],
569
+ id: "https://example.com/activities/1",
570
+ type: "Create",
571
+ actor: "https://example.com/person2",
572
+ object: "https://example.com/notes/1",
573
+ graph: "https://example.com/custom-graph"
574
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader }), {
575
+ documentLoader: mockDocumentLoader,
576
+ contextLoader: mockDocumentLoader
577
+ }));
578
+ });
579
+ test("compactJsonLd() respects nested @context scope for @graph aliases", async () => {
580
+ assertEquals(await compactJsonLd({
581
+ "@context": ["https://www.w3.org/ns/activitystreams", {
582
+ graph: "https://example.com/graph",
583
+ meta: {
584
+ "@id": "https://example.com/meta",
585
+ "@context": { graph: "@graph" }
586
+ }
587
+ }],
588
+ id: "https://example.com/activities/2",
589
+ type: "Create",
590
+ actor: "https://example.com/person2",
591
+ object: "https://example.com/notes/2",
592
+ graph: "https://example.com/custom-graph",
593
+ meta: { value: "ok" }
594
+ }, mockDocumentLoader), {
595
+ "@context": [
596
+ "https://w3id.org/identity/v1",
597
+ "https://www.w3.org/ns/activitystreams",
598
+ "https://w3id.org/security/v1",
599
+ "https://w3id.org/security/data-integrity/v1"
600
+ ],
601
+ id: "https://example.com/activities/2",
602
+ type: "Create",
603
+ "https://example.com/graph": "https://example.com/custom-graph",
604
+ actor: "https://example.com/person2",
605
+ object: "https://example.com/notes/2",
606
+ "https://example.com/meta": { value: "ok" }
607
+ });
608
+ });
609
+ test("compactJsonLd() resets inherited @graph aliases on @context: null", async () => {
610
+ assertEquals(await compactJsonLd({
611
+ "@context": ["https://www.w3.org/ns/activitystreams", { g: "@graph" }],
612
+ id: "https://example.com/activities/3",
613
+ type: "Create",
614
+ actor: "https://example.com/person2",
615
+ object: {
616
+ "@context": null,
617
+ g: "literal"
618
+ }
619
+ }, mockDocumentLoader), {
620
+ "@context": [
621
+ "https://w3id.org/identity/v1",
622
+ "https://www.w3.org/ns/activitystreams",
623
+ "https://w3id.org/security/v1",
624
+ "https://w3id.org/security/data-integrity/v1"
625
+ ],
626
+ id: "https://example.com/activities/3",
627
+ type: "Create",
628
+ actor: "https://example.com/person2",
629
+ object: {}
630
+ });
631
+ });
632
+ test("compactJsonLd() rejects same-object forward @graph alias chains", async () => {
633
+ await assertRejects(() => compactJsonLd({
634
+ "@context": ["https://www.w3.org/ns/activitystreams", {
635
+ a: "b",
636
+ b: "@graph"
637
+ }],
638
+ id: "https://example.com/activities/forward-graph-alias",
639
+ type: "Create",
640
+ actor: "https://example.com/person2",
641
+ a: [{
642
+ id: "https://example.com/notes/forward-graph-alias",
643
+ type: "Note",
644
+ content: "Hello"
645
+ }]
646
+ }, mockDocumentLoader), UnsafeJsonLdError, "Unsupported JSON-LD keyword: @graph.");
647
+ });
648
+ test("compactJsonLd() preserves captured @graph aliases across later overrides", async () => {
649
+ await assertRejects(() => compactJsonLd({
650
+ "@context": [
651
+ "https://www.w3.org/ns/activitystreams",
652
+ { b: "@graph" },
653
+ { a: "b" },
654
+ { b: "https://example.com/b" }
655
+ ],
656
+ id: "https://example.com/activities/captured-graph-alias",
657
+ type: "Create",
658
+ actor: "https://example.com/person2",
659
+ a: [{
660
+ id: "https://example.com/notes/captured-graph-alias",
661
+ type: "Note",
662
+ content: "Hello"
663
+ }]
664
+ }, mockDocumentLoader), UnsafeJsonLdError, "Unsupported JSON-LD keyword: @graph.");
665
+ });
666
+ test("compactJsonLd() does not retroactively apply later @graph aliases", async () => {
667
+ assertEquals(await compactJsonLd({
668
+ "@context": [
669
+ "https://www.w3.org/ns/activitystreams",
670
+ { a: "b" },
671
+ { b: "@graph" }
672
+ ],
673
+ id: "https://example.com/activities/non-retroactive-graph-alias",
674
+ type: "Create",
675
+ actor: "https://example.com/person2",
676
+ a: [{
677
+ id: "https://example.com/notes/non-retroactive-graph-alias",
678
+ type: "Note",
679
+ content: "Hello"
680
+ }]
681
+ }, mockDocumentLoader), {
682
+ "@context": [
683
+ "https://w3id.org/identity/v1",
684
+ "https://www.w3.org/ns/activitystreams",
685
+ "https://w3id.org/security/v1",
686
+ "https://w3id.org/security/data-integrity/v1"
687
+ ],
688
+ id: "https://example.com/activities/non-retroactive-graph-alias",
689
+ type: "Create",
690
+ b: {
691
+ id: "https://example.com/notes/non-retroactive-graph-alias",
692
+ type: "Note",
693
+ content: "Hello"
694
+ },
695
+ actor: "https://example.com/person2"
696
+ });
697
+ });
698
+ test("verifyJsonLd() rejects unsafe JSON-LD keywords", async () => {
699
+ const original = {
700
+ "@context": "https://www.w3.org/ns/activitystreams",
701
+ id: "https://example.com/activities/undo",
702
+ type: "Undo",
703
+ actor: "https://example.com/person2",
704
+ object: {
705
+ id: "https://example.com/activities/announce",
706
+ type: "Announce",
707
+ actor: "https://example.com/person2",
708
+ object: "https://example.com/status/1"
709
+ }
710
+ };
711
+ const signed = await signJsonLd(original, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader });
712
+ const options = {
713
+ documentLoader: mockDocumentLoader,
714
+ contextLoader: mockDocumentLoader
715
+ };
716
+ const cases = [
717
+ ["@reverse", {
718
+ "@context": ["https://www.w3.org/ns/activitystreams", { rev: "@reverse" }],
719
+ id: "https://example.com/activities/announce",
720
+ type: "Announce",
721
+ actor: "https://example.com/person2",
722
+ object: "https://example.com/status/1",
723
+ rev: { object: {
724
+ id: "https://example.com/activities/undo",
725
+ type: "Undo",
726
+ actor: "https://example.com/person2"
727
+ } },
728
+ signature: signed.signature
729
+ }],
730
+ ["@included", {
731
+ "@context": ["https://www.w3.org/ns/activitystreams", { inc: "@included" }],
732
+ id: "https://example.com/activities/announce",
733
+ type: "Announce",
734
+ actor: "https://example.com/person2",
735
+ object: "https://example.com/status/1",
736
+ inc: [{
737
+ id: "https://example.com/activities/undo",
738
+ type: "Undo",
739
+ actor: "https://example.com/person2",
740
+ object: "https://example.com/activities/announce"
741
+ }],
742
+ signature: signed.signature
743
+ }],
744
+ ["@graph", {
745
+ "@context": ["https://www.w3.org/ns/activitystreams", { graph: "@graph" }],
746
+ graph: [original],
747
+ signature: signed.signature
748
+ }],
749
+ ["@graph", {
750
+ "@context": ["https://www.w3.org/ns/activitystreams", { graph: "@graph" }],
751
+ id: "https://example.com/activities/announce",
752
+ type: "Announce",
753
+ actor: "https://example.com/person2",
754
+ object: "https://example.com/status/1",
755
+ graph: [{
756
+ id: "https://example.com/activities/undo",
757
+ type: "Undo",
758
+ actor: "https://example.com/person2",
759
+ object: "https://example.com/activities/announce"
760
+ }],
761
+ signature: signed.signature
762
+ }]
763
+ ];
764
+ for (const [keyword, jsonLd] of cases) await assertRejects(() => verifyJsonLd(jsonLd, options), UnsafeJsonLdError, `Unsupported JSON-LD keyword: ${keyword}.`);
765
+ });
766
+ test("compactJsonLd() rejects unsafe JSON-LD keywords inside signature objects", async () => {
767
+ const signed = await signJsonLd({
768
+ "@context": "https://www.w3.org/ns/activitystreams",
769
+ id: "https://example.com/activities/signed-signature-keywords",
770
+ type: "Create",
771
+ actor: "https://example.com/person2",
772
+ object: "https://example.com/notes/1"
773
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader });
774
+ for (const [keyword, value] of [
775
+ ["@reverse", { object: {
776
+ id: "https://example.com/activities/reverse-inside-signature",
777
+ type: "Undo"
778
+ } }],
779
+ ["@included", [{
780
+ id: "https://example.com/activities/included-inside-signature",
781
+ type: "Undo"
782
+ }]],
783
+ ["@graph", [{
784
+ id: "https://example.com/activities/graph-inside-signature",
785
+ type: "Undo"
786
+ }]]
787
+ ]) await assertRejects(() => compactJsonLd({
788
+ ...signed,
789
+ signature: {
790
+ ...signed.signature,
791
+ [keyword]: value
792
+ }
793
+ }, mockDocumentLoader), UnsafeJsonLdError, `Unsupported JSON-LD keyword: ${keyword}.`);
794
+ });
795
+ test("compactJsonLd() rejects inputs that compact into @graph wrappers", async () => {
796
+ await assertRejects(() => compactJsonLd([{
797
+ "@context": "https://www.w3.org/ns/activitystreams",
798
+ id: "https://example.com/notes/graph-wrapper-1",
799
+ type: "Note",
800
+ content: "one"
801
+ }, {
802
+ "@context": "https://www.w3.org/ns/activitystreams",
803
+ id: "https://example.com/notes/graph-wrapper-2",
804
+ type: "Note",
805
+ content: "two"
806
+ }], mockDocumentLoader), UnsafeJsonLdError, "Unsupported JSON-LD keyword: @graph.");
807
+ });
252
808
  //#endregion
253
809
  export {};
package/dist/sig/mod.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
- const require_http = require("../http-kPc328Pc.cjs");
5
- const require_proof = require("../proof-CZDkoeWG.cjs");
4
+ const require_http = require("../http-CzvQu1wC.cjs");
5
+ const require_proof = require("../proof-Bxo0UtfN.cjs");
6
6
  exports.attachSignature = require_proof.attachSignature;
7
7
  exports.createProof = require_proof.createProof;
8
8
  exports.createSignature = require_proof.createSignature;
package/dist/sig/mod.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { a as verifyRequestDetailed, c as fetchKeyDetailed, f as formatAcceptSignature, h as validateAcceptSignature, i as verifyRequest, l as generateCryptoKeyPair, m as parseAcceptSignature, o as exportJwk, p as fulfillAcceptSignature, r as signRequest, s as fetchKey, u as importJwk } from "../http-D8qsXrUS.js";
4
- import { a as verifyProof, c as getKeyOwner, d as detachSignature, f as hasSignatureLike, h as verifySignature, i as verifyObject, l as attachSignature, m as verifyJsonLd, n as hasProofLike, p as signJsonLd, r as signObject, s as doesActorOwnKey, t as createProof, u as createSignature } from "../proof-z93OkIov.js";
3
+ import { a as verifyRequestDetailed, c as fetchKeyDetailed, f as formatAcceptSignature, h as validateAcceptSignature, i as verifyRequest, l as generateCryptoKeyPair, m as parseAcceptSignature, o as exportJwk, p as fulfillAcceptSignature, r as signRequest, s as fetchKey, u as importJwk } from "../http-BauEA3uU.js";
4
+ import { C as verifySignature, S as verifyJsonLd, _ as hasSignatureLike, a as verifyProof, b as signJsonLd, c as getKeyOwner, d as attachSignature, i as verifyObject, m as detachSignature, n as hasProofLike, p as createSignature, r as signObject, s as doesActorOwnKey, t as createProof } from "../proof-erB_wSQi.js";
5
5
  export { attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, fetchKeyDetailed, formatAcceptSignature, fulfillAcceptSignature, generateCryptoKeyPair, getKeyOwner, hasProofLike, hasSignatureLike, importJwk, parseAcceptSignature, signJsonLd, signObject, signRequest, validateAcceptSignature, verifyJsonLd, verifyObject, verifyProof, verifyRequest, verifyRequestDetailed, verifySignature };
@@ -6,7 +6,7 @@ import "../std__assert-CRDpx_HF.mjs";
6
6
  import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assert } from "../assert-DikXweDx.mjs";
8
8
  import { o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-DGu1NFwu.mjs";
9
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-DBSV2TSl.mjs";
9
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-BIrHaRRj.mjs";
10
10
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { Create, CryptographicKey, lookupObject } from "@fedify/vocab";
12
12
  //#region src/sig/owner.test.ts
@@ -8,7 +8,7 @@ import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
8
8
  import { t as assert } from "../assert-DikXweDx.mjs";
9
9
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DGu1NFwu.mjs";
10
10
  import { r as normalizeOutgoingActivityJsonLd } from "../outgoing-jsonld-CNmZLixq.mjs";
11
- import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-tz91vdtN.mjs";
11
+ import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-B9P5A7RZ.mjs";
12
12
  import { mockDocumentLoader, test } from "@fedify/fixture";
13
13
  import { Create, DataIntegrityProof, Document, Multikey, Note, PUBLIC_COLLECTION, Place } from "@fedify/vocab";
14
14
  import { decodeMultibase, importMultibaseKey } from "@fedify/vocab-runtime";