@fedify/fedify 2.3.0-dev.1137 → 2.3.0-dev.1150

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 (68) hide show
  1. package/dist/{builder-BCkBXxky.mjs → builder-Bjm1Jq9n.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-DI2gRbyN.d.cts → context-CRXCkTM6.d.cts} +48 -6
  6. package/dist/{context-DCtsSHDv.d.ts → context-MgCh7YGu.d.ts} +48 -6
  7. package/dist/{deno-B_9yJW3w.mjs → deno-CKFE6Uya.mjs} +1 -1
  8. package/dist/{docloader-BT89tyFr.mjs → docloader-B-ZE1cZf.mjs} +2 -2
  9. package/dist/federation/builder.test.mjs +1 -1
  10. package/dist/federation/handler.test.mjs +1363 -44
  11. package/dist/federation/idempotency.test.mjs +2 -2
  12. package/dist/federation/metrics.test.mjs +60 -1
  13. package/dist/federation/middleware.test.mjs +1667 -163
  14. package/dist/federation/mod.cjs +1 -1
  15. package/dist/federation/mod.d.cts +2 -2
  16. package/dist/federation/mod.d.ts +2 -2
  17. package/dist/federation/mod.js +1 -1
  18. package/dist/federation/retry.test.mjs +1 -1
  19. package/dist/federation/send.test.mjs +8 -8
  20. package/dist/federation/temporal.test.d.mts +2 -0
  21. package/dist/federation/temporal.test.mjs +71 -0
  22. package/dist/federation/webfinger.test.mjs +147 -2
  23. package/dist/{getMachineId-bsd-etIyxDet.mjs → getMachineId-bsd-BY01PL1n.mjs} +1 -1
  24. package/dist/{getMachineId-darwin-D23zTf4g.mjs → getMachineId-darwin-Dr1gkBkp.mjs} +1 -1
  25. package/dist/{getMachineId-win-Dpap6v5i.mjs → getMachineId-win-QEYwcJiy.mjs} +1 -1
  26. package/dist/{http-CWoeyogl.cjs → http-DQYEA7AZ.cjs} +53 -1
  27. package/dist/{http-CToqG5ap.js → http-WbS1gKzr.js} +48 -2
  28. package/dist/{http-Cyx5SNuu.mjs → http-vHCgbhTg.mjs} +3 -3
  29. package/dist/{key-CkkMJBjF.mjs → key-N0zP_oJA.mjs} +2 -2
  30. package/dist/{kv-cache-CuCn2xvM.js → kv-cache-DM2O-Yjy.js} +1 -1
  31. package/dist/{kv-cache-DuEwFYcN.cjs → kv-cache-Dsg_bi4N.cjs} +1 -1
  32. package/dist/{kv-cache-VHFP42vY.mjs → kv-cache-GXXZEemD.mjs} +1 -1
  33. package/dist/{ld-k8yqD2a-.mjs → ld-BwKhquPx.mjs} +302 -6
  34. package/dist/{metrics-iRBg8jTk.mjs → metrics-7Vy9FvEw.mjs} +48 -2
  35. package/dist/{middleware-D7FrhN9q.js → middleware-BscgvU-m.js} +496 -115
  36. package/dist/{middleware-BWLUrbS9.cjs → middleware-D_iXrYHJ.cjs} +497 -115
  37. package/dist/{middleware-CztxpARM.mjs → middleware-Db1_qAFG.mjs} +1 -1
  38. package/dist/{middleware-DQEgdr83.mjs → middleware-ZuUcO0t1.mjs} +416 -124
  39. package/dist/{mod-C504qevA.d.cts → mod-C7HOzGqH.d.cts} +11 -2
  40. package/dist/{mod-wYfuXeDE.d.ts → mod-CpQHB3Ys.d.ts} +11 -2
  41. package/dist/mod.cjs +4 -4
  42. package/dist/mod.d.cts +2 -2
  43. package/dist/mod.d.ts +2 -2
  44. package/dist/mod.js +4 -4
  45. package/dist/nodeinfo/handler.test.mjs +1 -1
  46. package/dist/{owner-nmXdvXpc.mjs → owner-FD0H_vpj.mjs} +2 -2
  47. package/dist/{proof-CcsIJLTn.cjs → proof-CYK8T8IS.cjs} +353 -3
  48. package/dist/{proof-NRmtrTDu.js → proof-I3EokKN-.js} +300 -4
  49. package/dist/{proof-DpwO1T4S.mjs → proof-V_lafPmA.mjs} +3 -3
  50. package/dist/{send-DvX2tYyZ.mjs → send-Cc2_10tF.mjs} +3 -3
  51. package/dist/sig/http.test.mjs +2 -2
  52. package/dist/sig/key.test.mjs +1 -1
  53. package/dist/sig/ld.test.mjs +558 -2
  54. package/dist/sig/mod.cjs +2 -2
  55. package/dist/sig/mod.js +2 -2
  56. package/dist/sig/owner.test.mjs +1 -1
  57. package/dist/sig/proof.test.mjs +1 -1
  58. package/dist/temporal-BkmBfs__.mjs +95 -0
  59. package/dist/testing/mod.d.mts +48 -6
  60. package/dist/utils/docloader.test.mjs +2 -2
  61. package/dist/utils/kv-cache.test.mjs +1 -1
  62. package/dist/utils/mod.cjs +1 -1
  63. package/dist/utils/mod.js +1 -1
  64. package/package.json +6 -6
  65. /package/dist/{execAsync-DCBrgFiV.mjs → execAsync-Dxb7rNf3.mjs} +0 -0
  66. /package/dist/{getMachineId-linux-ObI47Hql.mjs → getMachineId-linux-Bbhofx-s.mjs} +0 -0
  67. /package/dist/{getMachineId-unsupported-Ddu-PFeh.mjs → getMachineId-unsupported-dIOte2Ct.mjs} +0 -0
  68. /package/dist/{retry-v_sGLH1d.mjs → retry-_VvV0h9f.mjs} +0 -0
@@ -5,13 +5,21 @@ import { t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
5
5
  import { n as assertGreaterOrEqual, r as assertFalse, t as assertRejects } from "../assert_rejects-DN60FHPX.mjs";
6
6
  import { t as assertThrows } from "../assert_throws-BOkhLGYc.mjs";
7
7
  import { t as assert } from "../assert-OguE97r2.mjs";
8
- import { i as generateCryptoKeyPair } from "../key-CkkMJBjF.mjs";
8
+ import { i as generateCryptoKeyPair } from "../key-N0zP_oJA.mjs";
9
9
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-C3kae-6B.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-k8yqD2a-.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-BwKhquPx.mjs";
11
11
  import { CryptographicKey } from "@fedify/vocab";
12
12
  import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
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",
@@ -382,5 +390,553 @@ test("verifyJsonLd() records verification duration metric", async (t) => {
382
390
  assertFalse("ld_signatures.type" in measurements[0].attributes);
383
391
  });
384
392
  });
393
+ test("compactJsonLd() with restrictive context loader", async () => {
394
+ const restrictiveContextLoader = async (resource) => {
395
+ const url = new URL(resource).href;
396
+ if (url === "https://www.w3.org/ns/activitystreams" || url === "https://w3id.org/identity/v1") return await mockDocumentLoader(url);
397
+ throw new Error(`Unexpected context: ${url}`);
398
+ };
399
+ const signed = await signJsonLd({
400
+ "@context": [
401
+ "https://www.w3.org/ns/activitystreams",
402
+ "https://w3id.org/identity/v1",
403
+ "https://w3id.org/security/v1",
404
+ "https://w3id.org/security/data-integrity/v1"
405
+ ],
406
+ id: "https://example.com/1",
407
+ type: "Create",
408
+ actor: "https://example.com/person2"
409
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader });
410
+ assertEquals(await compactJsonLd(signed, restrictiveContextLoader), {
411
+ "@context": [
412
+ "https://w3id.org/identity/v1",
413
+ "https://www.w3.org/ns/activitystreams",
414
+ "https://w3id.org/security/v1",
415
+ "https://w3id.org/security/data-integrity/v1"
416
+ ],
417
+ id: "https://example.com/1",
418
+ type: "Create",
419
+ actor: "https://example.com/person2",
420
+ signature: signed.signature
421
+ });
422
+ });
423
+ test("compactJsonLd() caches repeated remote contexts across graph scan and compaction", async () => {
424
+ const remoteUrl = "https://example.com/context";
425
+ let calls = 0;
426
+ const countingLoader = async (resource) => {
427
+ const url = new URL(resource).href;
428
+ if (url === remoteUrl) {
429
+ calls++;
430
+ return {
431
+ contextUrl: null,
432
+ documentUrl: url,
433
+ document: { "@context": { extra: "https://example.com/extra" } }
434
+ };
435
+ }
436
+ return await mockDocumentLoader(url);
437
+ };
438
+ await compactJsonLd({
439
+ "@context": "https://www.w3.org/ns/activitystreams",
440
+ id: "https://example.com/activities/remote-contexts",
441
+ type: "Create",
442
+ actor: "https://example.com/person2",
443
+ object: [
444
+ {
445
+ "@context": ["https://www.w3.org/ns/activitystreams", remoteUrl],
446
+ type: "Note",
447
+ content: "one"
448
+ },
449
+ {
450
+ "@context": ["https://www.w3.org/ns/activitystreams", remoteUrl],
451
+ type: "Note",
452
+ content: "two"
453
+ },
454
+ {
455
+ "@context": ["https://www.w3.org/ns/activitystreams", remoteUrl],
456
+ type: "Note",
457
+ content: "three"
458
+ }
459
+ ]
460
+ }, countingLoader);
461
+ assertEquals(calls, 1);
462
+ });
463
+ test("compactJsonLd() reuses the same remote context response for graph scan and compaction", async () => {
464
+ const remoteUrl = "https://example.com/context";
465
+ let calls = 0;
466
+ const compacted = await compactJsonLd({
467
+ "@context": [remoteUrl, "https://www.w3.org/ns/activitystreams"],
468
+ id: "https://example.com/activities/memoized-remote-context",
469
+ type: "Create",
470
+ actor: "https://example.com/person2",
471
+ graph: "https://example.com/custom-graph",
472
+ object: "https://example.com/notes/1"
473
+ }, async (resource) => {
474
+ const url = new URL(resource).href;
475
+ if (url === remoteUrl) {
476
+ calls++;
477
+ if (calls > 1) throw new Error(`Remote context should not be fetched twice: ${url}`);
478
+ return {
479
+ contextUrl: null,
480
+ documentUrl: url,
481
+ document: { "@context": { graph: "https://example.com/graph" } }
482
+ };
483
+ }
484
+ return await mockDocumentLoader(url);
485
+ });
486
+ assertEquals(calls, 1);
487
+ assertEquals(compacted, {
488
+ "@context": [
489
+ "https://w3id.org/identity/v1",
490
+ "https://www.w3.org/ns/activitystreams",
491
+ "https://w3id.org/security/v1",
492
+ "https://w3id.org/security/data-integrity/v1"
493
+ ],
494
+ id: "https://example.com/activities/memoized-remote-context",
495
+ type: "Create",
496
+ actor: "https://example.com/person2",
497
+ "https://example.com/graph": "https://example.com/custom-graph",
498
+ object: "https://example.com/notes/1"
499
+ });
500
+ });
501
+ test("compactJsonLd() preserves opaque top-level ids and resolves relative remote contexts against documentUrl during graph scan", async () => {
502
+ const rootContextId = "opaque-root";
503
+ const rootContextUrl = "https://example.com/contexts/root";
504
+ const childContextUrl = "https://example.com/contexts/child";
505
+ const calls = [];
506
+ const customLoader = async (resource) => {
507
+ calls.push(resource);
508
+ if (resource === rootContextId) return {
509
+ contextUrl: null,
510
+ documentUrl: rootContextUrl,
511
+ document: { "@context": {
512
+ "@import": "./child",
513
+ ext: "https://example.com/ext"
514
+ } }
515
+ };
516
+ if (resource === childContextUrl || resource === "child") return {
517
+ contextUrl: null,
518
+ documentUrl: childContextUrl,
519
+ document: { "@context": { child: "https://example.com/child" } }
520
+ };
521
+ return await mockDocumentLoader(resource);
522
+ };
523
+ assertEquals(await compactJsonLd({
524
+ "@context": [rootContextId, "https://www.w3.org/ns/activitystreams"],
525
+ id: "https://example.com/activities/custom-loader-contexts",
526
+ type: "Create",
527
+ actor: "https://example.com/person2",
528
+ ext: "preserve-me",
529
+ object: {
530
+ type: "Note",
531
+ content: "Hello"
532
+ }
533
+ }, customLoader), {
534
+ "@context": [
535
+ "https://w3id.org/identity/v1",
536
+ "https://www.w3.org/ns/activitystreams",
537
+ "https://w3id.org/security/v1",
538
+ "https://w3id.org/security/data-integrity/v1"
539
+ ],
540
+ id: "https://example.com/activities/custom-loader-contexts",
541
+ type: "Create",
542
+ actor: "https://example.com/person2",
543
+ "https://example.com/ext": "preserve-me",
544
+ object: {
545
+ type: "Note",
546
+ content: "Hello"
547
+ }
548
+ });
549
+ assert(calls.includes(rootContextId));
550
+ assert(calls.includes(childContextUrl));
551
+ assertFalse(calls.includes("./child"));
552
+ });
553
+ test("compactJsonLd() preserves base URLs for property-scoped remote contexts", async () => {
554
+ const rootContextId = "opaque-root";
555
+ const rootContextUrl = "https://example.com/contexts/root";
556
+ const childContextUrl = "https://example.com/contexts/child";
557
+ const calls = [];
558
+ const customLoader = async (resource) => {
559
+ calls.push(resource);
560
+ if (resource === rootContextId) return {
561
+ contextUrl: null,
562
+ documentUrl: rootContextUrl,
563
+ document: { "@context": { p: {
564
+ "@id": "https://example.com/p",
565
+ "@context": "./child"
566
+ } } }
567
+ };
568
+ if (resource === childContextUrl) return {
569
+ contextUrl: null,
570
+ documentUrl: childContextUrl,
571
+ document: { "@context": { nested: "https://example.com/nested" } }
572
+ };
573
+ return await mockDocumentLoader(resource);
574
+ };
575
+ assertEquals(await compactJsonLd({
576
+ "@context": [rootContextId, "https://www.w3.org/ns/activitystreams"],
577
+ id: "https://example.com/activities/property-scoped-contexts",
578
+ type: "Create",
579
+ actor: "https://example.com/person2",
580
+ p: { nested: "value" },
581
+ object: "https://example.com/notes/1"
582
+ }, customLoader), {
583
+ "@context": [
584
+ "https://w3id.org/identity/v1",
585
+ "https://www.w3.org/ns/activitystreams",
586
+ "https://w3id.org/security/v1",
587
+ "https://w3id.org/security/data-integrity/v1"
588
+ ],
589
+ id: "https://example.com/activities/property-scoped-contexts",
590
+ type: "Create",
591
+ actor: "https://example.com/person2",
592
+ "https://example.com/p": { "https://example.com/nested": "value" },
593
+ object: "https://example.com/notes/1"
594
+ });
595
+ assert(calls.includes(rootContextId));
596
+ assert(calls.includes(childContextUrl));
597
+ assertFalse(calls.includes("./child"));
598
+ });
599
+ test("compactJsonLd() ignores unsafe-looking keys inside @json values", async () => {
600
+ const remoteContextUrl = "https://example.com/contexts/json";
601
+ assertEquals(await compactJsonLd({
602
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
603
+ id: "https://example.com/activities/json-blob",
604
+ type: "Create",
605
+ actor: "https://example.com/person2",
606
+ blob: {
607
+ graph: { nested: true },
608
+ "@reverse": { nope: true },
609
+ "@included": [{ still: "raw-json" }]
610
+ },
611
+ object: "https://example.com/notes/1"
612
+ }, async (resource) => {
613
+ const url = new URL(resource).href;
614
+ if (url === remoteContextUrl) return {
615
+ contextUrl: null,
616
+ documentUrl: url,
617
+ document: { "@context": {
618
+ blob: {
619
+ "@id": "https://example.com/blob",
620
+ "@type": "@json"
621
+ },
622
+ graph: "@graph"
623
+ } }
624
+ };
625
+ return await mockDocumentLoader(url);
626
+ }), {
627
+ "@context": [
628
+ "https://w3id.org/identity/v1",
629
+ "https://www.w3.org/ns/activitystreams",
630
+ "https://w3id.org/security/v1",
631
+ "https://w3id.org/security/data-integrity/v1"
632
+ ],
633
+ id: "https://example.com/activities/json-blob",
634
+ type: "Create",
635
+ "https://example.com/blob": {
636
+ type: "@json",
637
+ "@value": {
638
+ graph: { nested: true },
639
+ "@reverse": { nope: true },
640
+ "@included": [{ still: "raw-json" }]
641
+ }
642
+ },
643
+ actor: "https://example.com/person2",
644
+ object: "https://example.com/notes/1"
645
+ });
646
+ });
647
+ test("compactJsonLd() ignores unsafe-looking keys inside inline @json value wrappers", async () => {
648
+ const remoteContextUrl = "https://example.com/contexts/inline-json";
649
+ assertEquals(await compactJsonLd({
650
+ "@context": [remoteContextUrl, "https://www.w3.org/ns/activitystreams"],
651
+ id: "https://example.com/activities/inline-json-blob",
652
+ type: "Create",
653
+ actor: "https://example.com/person2",
654
+ blob: {
655
+ "@value": {
656
+ graph: { nested: true },
657
+ "@reverse": { nope: true },
658
+ "@included": [{ still: "raw-json" }]
659
+ },
660
+ "@type": "@json"
661
+ },
662
+ object: "https://example.com/notes/1"
663
+ }, async (resource) => {
664
+ const url = new URL(resource).href;
665
+ if (url === remoteContextUrl) return {
666
+ contextUrl: null,
667
+ documentUrl: url,
668
+ document: { "@context": {
669
+ blob: "https://example.com/blob",
670
+ graph: "@graph"
671
+ } }
672
+ };
673
+ return await mockDocumentLoader(url);
674
+ }), {
675
+ "@context": [
676
+ "https://w3id.org/identity/v1",
677
+ "https://www.w3.org/ns/activitystreams",
678
+ "https://w3id.org/security/v1",
679
+ "https://w3id.org/security/data-integrity/v1"
680
+ ],
681
+ id: "https://example.com/activities/inline-json-blob",
682
+ type: "Create",
683
+ "https://example.com/blob": {
684
+ type: "@json",
685
+ "@value": {
686
+ graph: { nested: true },
687
+ "@reverse": { nope: true },
688
+ "@included": [{ still: "raw-json" }]
689
+ }
690
+ },
691
+ actor: "https://example.com/person2",
692
+ object: "https://example.com/notes/1"
693
+ });
694
+ });
695
+ test("verifyJsonLd() respects @graph alias overrides", async () => {
696
+ assert(await verifyJsonLd(await signJsonLd({
697
+ "@context": [
698
+ "https://www.w3.org/ns/activitystreams",
699
+ { graph: "@graph" },
700
+ { graph: "https://example.com/graph" }
701
+ ],
702
+ id: "https://example.com/activities/1",
703
+ type: "Create",
704
+ actor: "https://example.com/person2",
705
+ object: "https://example.com/notes/1",
706
+ graph: "https://example.com/custom-graph"
707
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader }), {
708
+ documentLoader: mockDocumentLoader,
709
+ contextLoader: mockDocumentLoader
710
+ }));
711
+ });
712
+ test("compactJsonLd() respects nested @context scope for @graph aliases", async () => {
713
+ assertEquals(await compactJsonLd({
714
+ "@context": ["https://www.w3.org/ns/activitystreams", {
715
+ graph: "https://example.com/graph",
716
+ meta: {
717
+ "@id": "https://example.com/meta",
718
+ "@context": { graph: "@graph" }
719
+ }
720
+ }],
721
+ id: "https://example.com/activities/2",
722
+ type: "Create",
723
+ actor: "https://example.com/person2",
724
+ object: "https://example.com/notes/2",
725
+ graph: "https://example.com/custom-graph",
726
+ meta: { value: "ok" }
727
+ }, mockDocumentLoader), {
728
+ "@context": [
729
+ "https://w3id.org/identity/v1",
730
+ "https://www.w3.org/ns/activitystreams",
731
+ "https://w3id.org/security/v1",
732
+ "https://w3id.org/security/data-integrity/v1"
733
+ ],
734
+ id: "https://example.com/activities/2",
735
+ type: "Create",
736
+ "https://example.com/graph": "https://example.com/custom-graph",
737
+ actor: "https://example.com/person2",
738
+ object: "https://example.com/notes/2",
739
+ "https://example.com/meta": { value: "ok" }
740
+ });
741
+ });
742
+ test("compactJsonLd() resets inherited @graph aliases on @context: null", async () => {
743
+ assertEquals(await compactJsonLd({
744
+ "@context": ["https://www.w3.org/ns/activitystreams", { g: "@graph" }],
745
+ id: "https://example.com/activities/3",
746
+ type: "Create",
747
+ actor: "https://example.com/person2",
748
+ object: {
749
+ "@context": null,
750
+ g: "literal"
751
+ }
752
+ }, mockDocumentLoader), {
753
+ "@context": [
754
+ "https://w3id.org/identity/v1",
755
+ "https://www.w3.org/ns/activitystreams",
756
+ "https://w3id.org/security/v1",
757
+ "https://w3id.org/security/data-integrity/v1"
758
+ ],
759
+ id: "https://example.com/activities/3",
760
+ type: "Create",
761
+ actor: "https://example.com/person2",
762
+ object: {}
763
+ });
764
+ });
765
+ test("compactJsonLd() rejects same-object forward @graph alias chains", async () => {
766
+ await assertRejects(() => compactJsonLd({
767
+ "@context": ["https://www.w3.org/ns/activitystreams", {
768
+ a: "b",
769
+ b: "@graph"
770
+ }],
771
+ id: "https://example.com/activities/forward-graph-alias",
772
+ type: "Create",
773
+ actor: "https://example.com/person2",
774
+ a: [{
775
+ id: "https://example.com/notes/forward-graph-alias",
776
+ type: "Note",
777
+ content: "Hello"
778
+ }]
779
+ }, mockDocumentLoader), UnsafeJsonLdError, "Unsupported JSON-LD keyword: @graph.");
780
+ });
781
+ test("compactJsonLd() preserves captured @graph aliases across later overrides", async () => {
782
+ await assertRejects(() => compactJsonLd({
783
+ "@context": [
784
+ "https://www.w3.org/ns/activitystreams",
785
+ { b: "@graph" },
786
+ { a: "b" },
787
+ { b: "https://example.com/b" }
788
+ ],
789
+ id: "https://example.com/activities/captured-graph-alias",
790
+ type: "Create",
791
+ actor: "https://example.com/person2",
792
+ a: [{
793
+ id: "https://example.com/notes/captured-graph-alias",
794
+ type: "Note",
795
+ content: "Hello"
796
+ }]
797
+ }, mockDocumentLoader), UnsafeJsonLdError, "Unsupported JSON-LD keyword: @graph.");
798
+ });
799
+ test("compactJsonLd() does not retroactively apply later @graph aliases", async () => {
800
+ assertEquals(await compactJsonLd({
801
+ "@context": [
802
+ "https://www.w3.org/ns/activitystreams",
803
+ { a: "b" },
804
+ { b: "@graph" }
805
+ ],
806
+ id: "https://example.com/activities/non-retroactive-graph-alias",
807
+ type: "Create",
808
+ actor: "https://example.com/person2",
809
+ a: [{
810
+ id: "https://example.com/notes/non-retroactive-graph-alias",
811
+ type: "Note",
812
+ content: "Hello"
813
+ }]
814
+ }, mockDocumentLoader), {
815
+ "@context": [
816
+ "https://w3id.org/identity/v1",
817
+ "https://www.w3.org/ns/activitystreams",
818
+ "https://w3id.org/security/v1",
819
+ "https://w3id.org/security/data-integrity/v1"
820
+ ],
821
+ id: "https://example.com/activities/non-retroactive-graph-alias",
822
+ type: "Create",
823
+ b: {
824
+ id: "https://example.com/notes/non-retroactive-graph-alias",
825
+ type: "Note",
826
+ content: "Hello"
827
+ },
828
+ actor: "https://example.com/person2"
829
+ });
830
+ });
831
+ test("verifyJsonLd() rejects unsafe JSON-LD keywords", async () => {
832
+ const original = {
833
+ "@context": "https://www.w3.org/ns/activitystreams",
834
+ id: "https://example.com/activities/undo",
835
+ type: "Undo",
836
+ actor: "https://example.com/person2",
837
+ object: {
838
+ id: "https://example.com/activities/announce",
839
+ type: "Announce",
840
+ actor: "https://example.com/person2",
841
+ object: "https://example.com/status/1"
842
+ }
843
+ };
844
+ const signed = await signJsonLd(original, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader });
845
+ const options = {
846
+ documentLoader: mockDocumentLoader,
847
+ contextLoader: mockDocumentLoader
848
+ };
849
+ const cases = [
850
+ ["@reverse", {
851
+ "@context": ["https://www.w3.org/ns/activitystreams", { rev: "@reverse" }],
852
+ id: "https://example.com/activities/announce",
853
+ type: "Announce",
854
+ actor: "https://example.com/person2",
855
+ object: "https://example.com/status/1",
856
+ rev: { object: {
857
+ id: "https://example.com/activities/undo",
858
+ type: "Undo",
859
+ actor: "https://example.com/person2"
860
+ } },
861
+ signature: signed.signature
862
+ }],
863
+ ["@included", {
864
+ "@context": ["https://www.w3.org/ns/activitystreams", { inc: "@included" }],
865
+ id: "https://example.com/activities/announce",
866
+ type: "Announce",
867
+ actor: "https://example.com/person2",
868
+ object: "https://example.com/status/1",
869
+ inc: [{
870
+ id: "https://example.com/activities/undo",
871
+ type: "Undo",
872
+ actor: "https://example.com/person2",
873
+ object: "https://example.com/activities/announce"
874
+ }],
875
+ signature: signed.signature
876
+ }],
877
+ ["@graph", {
878
+ "@context": ["https://www.w3.org/ns/activitystreams", { graph: "@graph" }],
879
+ graph: [original],
880
+ signature: signed.signature
881
+ }],
882
+ ["@graph", {
883
+ "@context": ["https://www.w3.org/ns/activitystreams", { graph: "@graph" }],
884
+ id: "https://example.com/activities/announce",
885
+ type: "Announce",
886
+ actor: "https://example.com/person2",
887
+ object: "https://example.com/status/1",
888
+ graph: [{
889
+ id: "https://example.com/activities/undo",
890
+ type: "Undo",
891
+ actor: "https://example.com/person2",
892
+ object: "https://example.com/activities/announce"
893
+ }],
894
+ signature: signed.signature
895
+ }]
896
+ ];
897
+ for (const [keyword, jsonLd] of cases) await assertRejects(() => verifyJsonLd(jsonLd, options), UnsafeJsonLdError, `Unsupported JSON-LD keyword: ${keyword}.`);
898
+ });
899
+ test("compactJsonLd() rejects unsafe JSON-LD keywords inside signature objects", async () => {
900
+ const signed = await signJsonLd({
901
+ "@context": "https://www.w3.org/ns/activitystreams",
902
+ id: "https://example.com/activities/signed-signature-keywords",
903
+ type: "Create",
904
+ actor: "https://example.com/person2",
905
+ object: "https://example.com/notes/1"
906
+ }, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader });
907
+ for (const [keyword, value] of [
908
+ ["@reverse", { object: {
909
+ id: "https://example.com/activities/reverse-inside-signature",
910
+ type: "Undo"
911
+ } }],
912
+ ["@included", [{
913
+ id: "https://example.com/activities/included-inside-signature",
914
+ type: "Undo"
915
+ }]],
916
+ ["@graph", [{
917
+ id: "https://example.com/activities/graph-inside-signature",
918
+ type: "Undo"
919
+ }]]
920
+ ]) await assertRejects(() => compactJsonLd({
921
+ ...signed,
922
+ signature: {
923
+ ...signed.signature,
924
+ [keyword]: value
925
+ }
926
+ }, mockDocumentLoader), UnsafeJsonLdError, `Unsupported JSON-LD keyword: ${keyword}.`);
927
+ });
928
+ test("compactJsonLd() rejects inputs that compact into @graph wrappers", async () => {
929
+ await assertRejects(() => compactJsonLd([{
930
+ "@context": "https://www.w3.org/ns/activitystreams",
931
+ id: "https://example.com/notes/graph-wrapper-1",
932
+ type: "Note",
933
+ content: "one"
934
+ }, {
935
+ "@context": "https://www.w3.org/ns/activitystreams",
936
+ id: "https://example.com/notes/graph-wrapper-2",
937
+ type: "Note",
938
+ content: "two"
939
+ }], mockDocumentLoader), UnsafeJsonLdError, "Unsupported JSON-LD keyword: @graph.");
940
+ });
385
941
  //#endregion
386
942
  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-CWoeyogl.cjs");
5
- const require_proof = require("../proof-CcsIJLTn.cjs");
4
+ const require_http = require("../http-DQYEA7AZ.cjs");
5
+ const require_proof = require("../proof-CYK8T8IS.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 { C as formatAcceptSignature, E as validateAcceptSignature, T as parseAcceptSignature, a as verifyRequestDetailed, c as fetchKeyDetailed, i as verifyRequest, l as generateCryptoKeyPair, o as exportJwk, r as signRequest, s as fetchKey, u as importJwk, w as fulfillAcceptSignature } from "../http-CToqG5ap.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-NRmtrTDu.js";
3
+ import { D as validateAcceptSignature, E as parseAcceptSignature, T as fulfillAcceptSignature, a as verifyRequestDetailed, c as fetchKeyDetailed, i as verifyRequest, l as generateCryptoKeyPair, o as exportJwk, r as signRequest, s as fetchKey, u as importJwk, w as formatAcceptSignature } from "../http-WbS1gKzr.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-I3EokKN-.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-BBjXFNOb.mjs";
6
6
  import { r as assertFalse } from "../assert_rejects-DN60FHPX.mjs";
7
7
  import { t as assert } from "../assert-OguE97r2.mjs";
8
8
  import { o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-C3kae-6B.mjs";
9
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-nmXdvXpc.mjs";
9
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-FD0H_vpj.mjs";
10
10
  import { Create, CryptographicKey, lookupObject } from "@fedify/vocab";
11
11
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
12
12
  //#region src/sig/owner.test.ts
@@ -8,7 +8,7 @@ import { t as assertInstanceOf } from "../assert_instance_of-DBC5X09g.mjs";
8
8
  import { t as assert } from "../assert-OguE97r2.mjs";
9
9
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-C3kae-6B.mjs";
10
10
  import { r as normalizeOutgoingActivityJsonLd } from "../outgoing-jsonld-BgFLCJQ_.mjs";
11
- import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-DpwO1T4S.mjs";
11
+ import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-V_lafPmA.mjs";
12
12
  import { Create, DataIntegrityProof, Document, Multikey, Note, PUBLIC_COLLECTION, Place } from "@fedify/vocab";
13
13
  import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
14
14
  import { decodeMultibase, importMultibaseKey } from "@fedify/vocab-runtime";