@fedify/fedify 2.4.0-pr.934.40 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/README.md +48 -40
  2. package/dist/{assert-CJ1KXcvv.mjs → assert-D1Eafmd_.mjs} +1 -1
  3. package/dist/{assert_equals-BV7oLMxm.mjs → assert_equals-Z6IcEbWU.mjs} +2 -28
  4. package/dist/assert_exists-cffSpJ7X.mjs +28 -0
  5. package/dist/assert_false-CPdRnc3E.mjs +23 -0
  6. package/dist/assert_greater_or_equal-BlafOF4-.mjs +31 -0
  7. package/dist/{assert_instance_of-Q9KTBnrf.mjs → assert_instance_of-mrXWWNY-.mjs} +1 -1
  8. package/dist/{assert_not_equals-EPJPoxuf.mjs → assert_not_equals-CpPK2t89.mjs} +2 -1
  9. package/dist/assert_rejects-CTptdYck.mjs +39 -0
  10. package/dist/{assert_strict_equals-Ec20AUwa.mjs → assert_strict_equals-CYvBmkpC.mjs} +2 -1
  11. package/dist/{assert_throws-NiFfqbnH.mjs → assert_throws-BYITOvPO.mjs} +2 -1
  12. package/dist/assertion_error-B-cx0fFA.mjs +31 -0
  13. package/dist/audience-CHQ-FlLD.mjs +95 -0
  14. package/dist/{builder-BBPwtB2v.mjs → builder-lJDh222H.mjs} +169 -14
  15. package/dist/{circuit-breaker-CBGyz5F7.mjs → circuit-breaker-XJ53md4S.mjs} +224 -17
  16. package/dist/circuit-breaker-test-utils-DW6YC_Pe.mjs +14 -0
  17. package/dist/{client-CjF5IYQS.mjs → client-CEnNz8O7.mjs} +144 -8
  18. package/dist/{codec-BBga-FWI.mjs → codec-C6rTrpIp.mjs} +26 -3
  19. package/dist/{collection-BIhlldqK.mjs → collection-CnnP1UAv.mjs} +1 -1
  20. package/dist/compat/mod.cjs +1 -1
  21. package/dist/compat/mod.d.cts +1 -1
  22. package/dist/compat/mod.d.ts +1 -1
  23. package/dist/compat/mod.js +1 -1
  24. package/dist/compat/outgoing-jsonld.test.mjs +71 -3
  25. package/dist/compat/public-audience.test.mjs +14 -5
  26. package/dist/compat/secured-document.test.d.mts +2 -0
  27. package/dist/compat/secured-document.test.mjs +58 -0
  28. package/dist/compat/transformers.test.mjs +5 -5
  29. package/dist/compound-proof-zAjqsHiN.mjs +989 -0
  30. package/dist/{context-Cjnr0ig1.d.ts → context-7NyiqIcg.d.ts} +1600 -25
  31. package/dist/{context-BJXxPElm.mjs → context-8Tu9kea0.mjs} +21 -63
  32. package/dist/{context-C05Rgxmu.d.cts → context-tsYPJ2Ew.d.cts} +1600 -25
  33. package/dist/{deno-D3c0o_N0.mjs → deno-D8wr4ikF.mjs} +1 -1
  34. package/dist/dist-DJQM4u7i.mjs +189 -0
  35. package/dist/docloader-TCvsU9vF.mjs +87 -0
  36. package/dist/{esm-yYQfPhIY.mjs → esm-BHXXx4Wx.mjs} +13 -6
  37. package/dist/federation/audience.test.d.mts +2 -0
  38. package/dist/federation/audience.test.mjs +130 -0
  39. package/dist/federation/builder.test.mjs +54 -5
  40. package/dist/federation/circuit-breaker.test.mjs +838 -7
  41. package/dist/federation/collection.test.mjs +3 -3
  42. package/dist/federation/compound-fanout.test.d.mts +2 -0
  43. package/dist/federation/compound-fanout.test.mjs +228 -0
  44. package/dist/federation/handler-compound-proof.test.d.mts +2 -0
  45. package/dist/federation/handler-compound-proof.test.mjs +384 -0
  46. package/dist/federation/handler.test.mjs +387 -15
  47. package/dist/federation/hashlink-media.test.d.mts +2 -0
  48. package/dist/federation/hashlink-media.test.mjs +422 -0
  49. package/dist/federation/idempotency.test.mjs +6 -6
  50. package/dist/federation/inbox-report.test.d.mts +2 -0
  51. package/dist/federation/inbox-report.test.mjs +475 -0
  52. package/dist/federation/inbox.test.mjs +3 -3
  53. package/dist/federation/keycache.test.mjs +215 -14
  54. package/dist/federation/kv.test.mjs +3 -3
  55. package/dist/federation/metrics.test.mjs +5 -5
  56. package/dist/federation/middleware.test.mjs +967 -35
  57. package/dist/federation/mod.cjs +18 -540
  58. package/dist/federation/mod.d.cts +5 -5
  59. package/dist/federation/mod.d.ts +5 -5
  60. package/dist/federation/mod.js +1 -1
  61. package/dist/federation/mq.test.mjs +104 -47
  62. package/dist/federation/negotiation.test.mjs +4 -4
  63. package/dist/federation/outgoing-proof.test.d.mts +2 -0
  64. package/dist/federation/outgoing-proof.test.mjs +931 -0
  65. package/dist/federation/portable-actor.test.d.mts +2 -0
  66. package/dist/federation/portable-actor.test.mjs +496 -0
  67. package/dist/federation/portable-chain.test.d.mts +2 -0
  68. package/dist/federation/portable-chain.test.mjs +370 -0
  69. package/dist/federation/portable-collection.test.d.mts +2 -0
  70. package/dist/federation/portable-collection.test.mjs +832 -0
  71. package/dist/federation/portable-delivery.test.d.mts +2 -0
  72. package/dist/federation/portable-delivery.test.mjs +746 -0
  73. package/dist/federation/portable-gateway-keys.test.d.mts +2 -0
  74. package/dist/federation/portable-gateway-keys.test.mjs +686 -0
  75. package/dist/federation/portable-inbox.test.d.mts +2 -0
  76. package/dist/federation/portable-inbox.test.mjs +1535 -0
  77. package/dist/federation/portable-parse-uri.test.d.mts +2 -0
  78. package/dist/federation/portable-parse-uri.test.mjs +348 -0
  79. package/dist/federation/portable-route-activity.test.d.mts +2 -0
  80. package/dist/federation/portable-route-activity.test.mjs +259 -0
  81. package/dist/federation/portable.test.d.mts +2 -0
  82. package/dist/federation/portable.test.mjs +1072 -0
  83. package/dist/federation/retry.test.mjs +4 -3
  84. package/dist/federation/router.test.mjs +9 -159
  85. package/dist/federation/send.test.mjs +245 -27
  86. package/dist/federation/tasks/codec.test.mjs +4 -4
  87. package/dist/federation/tasks/enqueue.test.mjs +5 -4
  88. package/dist/federation/tasks/tasks.test.mjs +7 -6
  89. package/dist/federation/temporal.test.mjs +4 -4
  90. package/dist/federation/webfinger.test.mjs +275 -12
  91. package/dist/{middleware-BW7WQltk.cjs → federation-Dfl-i7Jt.cjs} +6098 -895
  92. package/dist/{http-Dm0JAUa_.mjs → http-BAgKAAGY.mjs} +397 -168
  93. package/dist/http-CYO4wjB5.cjs +10630 -0
  94. package/dist/http-RW_i_Nkq.js +6527 -0
  95. package/dist/key-C1nv7_jD.d.ts +1125 -0
  96. package/dist/key-D979vduq.mjs +951 -0
  97. package/dist/key-DYxuyd-s.d.cts +1125 -0
  98. package/dist/key-owner-evidence-APB6NpSk.mjs +108 -0
  99. package/dist/keycache-Da8A8mZa.mjs +200 -0
  100. package/dist/{kv-D6hNiMTK.d.ts → kv-B2mzK5tl.d.cts} +3 -2
  101. package/dist/{kv-gJ8LYbxX.d.cts → kv-B2mzK5tl.d.ts} +3 -2
  102. package/dist/kv-DBRWVx3Q.mjs +104 -0
  103. package/dist/{kv-cache-BxUZRBC2.js → kv-cache-Cqfdytdd.js} +54 -16
  104. package/dist/{kv-cache-B7H7lZ84.mjs → kv-cache-Gh05Xv-P.mjs} +1 -1
  105. package/dist/{kv-cache-D-hbjJAD.cjs → kv-cache-zd0dNGxi.cjs} +55 -19
  106. package/dist/{ld-DAPAVL_7.mjs → ld-wmqC-95l.mjs} +44 -12
  107. package/dist/map-local-context-conflict-DOYEEJ3u.mjs +204 -0
  108. package/dist/map-local-create-note-B0SeXJms.mjs +214 -0
  109. package/dist/{metrics-BMaatuZi.mjs → metrics-DPdi_XK7.mjs} +3 -2
  110. package/dist/metrics-DVKYY6K1.d.cts +36 -0
  111. package/dist/metrics-DoRtI0qU.d.ts +36 -0
  112. package/dist/{middleware-O2LHXFEk.mjs → middleware-CqQ5Qahj.mjs} +3155 -269
  113. package/dist/{middleware-CfZR_riY.js → middleware-DbCI_eni.js} +5527 -865
  114. package/dist/{middleware-DfPBAh9L.mjs → middleware-DjEMIAP5.mjs} +1 -1
  115. package/dist/{mod-DdONo-ep.d.cts → mod-BojP2Bw3.d.cts} +1 -1
  116. package/dist/mod-CavhAgLw.d.cts +320 -0
  117. package/dist/mod-CtpF2BU5.d.ts +320 -0
  118. package/dist/{mod-CNef4in0.d.ts → mod-DEZXwV6J.d.ts} +9 -3
  119. package/dist/{mod-BrpVsSfY.d.cts → mod-Dw-nPxQh.d.cts} +9 -3
  120. package/dist/{mod-BsCE5Ihq.d.ts → mod-Xj5P4s4d.d.ts} +1 -1
  121. package/dist/mod.cjs +40 -39
  122. package/dist/mod.d.cts +10 -11
  123. package/dist/mod.d.ts +10 -11
  124. package/dist/mod.js +8 -8
  125. package/dist/nodeinfo/client.test.mjs +139 -4
  126. package/dist/nodeinfo/handler.test.mjs +5 -5
  127. package/dist/nodeinfo/mod.cjs +1 -1
  128. package/dist/nodeinfo/mod.d.cts +1 -1
  129. package/dist/nodeinfo/mod.d.ts +1 -1
  130. package/dist/nodeinfo/mod.js +1 -1
  131. package/dist/nodeinfo/types.test.mjs +4 -4
  132. package/dist/otel/exporter.test.mjs +3 -3
  133. package/dist/otel/mod.cjs +0 -1
  134. package/dist/otel/mod.d.cts +1 -1
  135. package/dist/otel/mod.d.ts +1 -1
  136. package/dist/{outgoing-jsonld-URuqsICz.mjs → outgoing-jsonld-4IJqPYos.mjs} +12 -10
  137. package/dist/{owner-DEvZuyOE.d.cts → owner-BF0L9cMt.d.cts} +11 -0
  138. package/dist/{owner-CnngXDNJ.d.ts → owner-BSzr5-I8.d.ts} +11 -0
  139. package/dist/owner-BfygwLNy.mjs +267 -0
  140. package/dist/portable-collection-DSrR0BSV.js +670 -0
  141. package/dist/portable-collection-L8jCHlci.cjs +686 -0
  142. package/dist/portable-collection-idA006Sj.mjs +418 -0
  143. package/dist/portable-key-CA6u-dST.mjs +549 -0
  144. package/dist/portable-key-id-Ca30-hOa.mjs +248 -0
  145. package/dist/proof-DeC9pb6t.mjs +1299 -0
  146. package/dist/{public-audience-Cr5MsnMq.mjs → public-audience--klBIOk1.mjs} +15 -10
  147. package/dist/router-u5O5KCQr.mjs +156 -0
  148. package/dist/runtime/mod.cjs +1 -1
  149. package/dist/runtime/mod.js +1 -1
  150. package/dist/secured-document-CxzZZ9nL.mjs +35 -0
  151. package/dist/send-1tcGhW1h.mjs +495 -0
  152. package/dist/sig/accept.test.mjs +1 -1
  153. package/dist/sig/compound-proof-discovery.test.d.mts +2 -0
  154. package/dist/sig/compound-proof-discovery.test.mjs +331 -0
  155. package/dist/sig/compound-proof-producer.test.d.mts +2 -0
  156. package/dist/sig/compound-proof-producer.test.mjs +107 -0
  157. package/dist/sig/compound-proof-verification.test.d.mts +2 -0
  158. package/dist/sig/compound-proof-verification.test.mjs +833 -0
  159. package/dist/sig/compound-proof.test.d.mts +2 -0
  160. package/dist/sig/compound-proof.test.mjs +411 -0
  161. package/dist/sig/http.test.mjs +702 -31
  162. package/dist/sig/key-owner-evidence.test.d.mts +2 -0
  163. package/dist/sig/key-owner-evidence.test.mjs +100 -0
  164. package/dist/sig/key.test.mjs +220 -8
  165. package/dist/sig/ld.test.mjs +65 -7
  166. package/dist/sig/mitra-receive-interop.test.d.mts +2 -0
  167. package/dist/sig/mitra-receive-interop.test.mjs +260 -0
  168. package/dist/sig/mitra-send-interop.test.d.mts +2 -0
  169. package/dist/sig/mitra-send-interop.test.mjs +461 -0
  170. package/dist/sig/mod.cjs +18 -16
  171. package/dist/sig/mod.d.cts +4 -4
  172. package/dist/sig/mod.d.ts +4 -4
  173. package/dist/sig/mod.js +3 -3
  174. package/dist/sig/owner.test.mjs +108 -9
  175. package/dist/sig/portable-collection.test.d.mts +2 -0
  176. package/dist/sig/portable-collection.test.mjs +697 -0
  177. package/dist/sig/portable-interop.test.d.mts +2 -0
  178. package/dist/sig/portable-interop.test.mjs +156 -0
  179. package/dist/sig/portable-key-id.test.d.mts +2 -0
  180. package/dist/sig/portable-key-id.test.mjs +67 -0
  181. package/dist/sig/portable-key.test.d.mts +2 -0
  182. package/dist/sig/portable-key.test.mjs +1439 -0
  183. package/dist/sig/proof.test.mjs +1753 -16
  184. package/dist/sig/tootik-request-interop.test.d.mts +2 -0
  185. package/dist/sig/tootik-request-interop.test.mjs +190 -0
  186. package/dist/sig/tootik-send-interop.test.d.mts +2 -0
  187. package/dist/sig/tootik-send-interop.test.mjs +331 -0
  188. package/dist/sig/verification.test.d.mts +2 -0
  189. package/dist/sig/verification.test.mjs +310 -0
  190. package/dist/std__assert-DvMDRPes.mjs +8 -0
  191. package/dist/{testing-CO7ftO8A.mjs → tasks-IG3pHfvZ.mjs} +2 -2
  192. package/dist/{temporal-yE5EcfNX.mjs → temporal-DA7r1fm3.mjs} +3 -3
  193. package/dist/testing/context.test.d.mts +2 -0
  194. package/dist/testing/context.test.mjs +19 -0
  195. package/dist/testing/kv.test.d.mts +2 -0
  196. package/dist/testing/kv.test.mjs +101 -0
  197. package/dist/testing/mod.d.mts +1604 -48
  198. package/dist/testing/mod.mjs +6 -3
  199. package/dist/testing-t8xDeJZ5.mjs +8 -0
  200. package/dist/{transformers-DGwl-hD1.cjs → transformers-BalCrSsr.cjs} +0 -1
  201. package/dist/{types-DC1pNgJA.js → types-_S2_MeLF.js} +144 -8
  202. package/dist/{types-CPym83zc.cjs → types-poIao40f.cjs} +160 -7
  203. package/dist/utils/docloader.test.mjs +530 -8
  204. package/dist/utils/kv-cache.test.mjs +2 -2
  205. package/dist/utils/mod.cjs +1 -1
  206. package/dist/utils/mod.d.cts +1 -1
  207. package/dist/utils/mod.d.ts +1 -1
  208. package/dist/utils/mod.js +1 -1
  209. package/dist/verification-C3954hQh.mjs +5 -0
  210. package/dist/verification-Dpfcw8ml.mjs +105 -0
  211. package/dist/vocab/cjs.test.mjs +1 -1
  212. package/package.json +9 -9
  213. package/dist/assert_rejects-EgstcQy5.mjs +0 -82
  214. package/dist/docloader-BCecHIxU.mjs +0 -49
  215. package/dist/http-Ctb_KhZ8.js +0 -2483
  216. package/dist/http-VyDTd4G3.d.cts +0 -553
  217. package/dist/http-jr0TkgZe.cjs +0 -2694
  218. package/dist/http-lf8Hsd91.d.ts +0 -553
  219. package/dist/key-C_gNKtxm.mjs +0 -453
  220. package/dist/keycache-_DHqz5z_.mjs +0 -97
  221. package/dist/metrics-DN13mCAw.d.cts +0 -294
  222. package/dist/metrics-v_e0n5GQ.d.ts +0 -294
  223. package/dist/mod-B0hW12_O.d.cts +0 -307
  224. package/dist/mod-COIAjwRS.d.ts +0 -307
  225. package/dist/owner-Dcx-czqn.mjs +0 -120
  226. package/dist/proof-BkAxvrjt.mjs +0 -316
  227. package/dist/proof-D-H_PnJW.js +0 -1415
  228. package/dist/proof-NY0D8Oux.cjs +0 -1562
  229. package/dist/send-D_j7E-oC.mjs +0 -239
  230. package/dist/std__assert-B2NnY9bq.mjs +0 -79
  231. package/dist/temporal-polyfill-BCdTHexd.cjs +0 -3565
  232. /package/dist/{accept-8PiolDP7.mjs → accept-CPVqki78.mjs} +0 -0
  233. /package/dist/{activity-listener-BtTSxZWA.mjs → activity-listener-C-BSbKI7.mjs} +0 -0
  234. /package/dist/{client-CAM_bQXx.d.cts → client-D-XP_Ccb.d.cts} +0 -0
  235. /package/dist/{client-CSddvgWN.d.ts → client-D-XP_Ccb.d.ts} +0 -0
  236. /package/dist/{keys-Dbyd7bhl.mjs → keys-DIJNHW-Y.mjs} +0 -0
  237. /package/dist/{kv-CXBAok3k.mjs → kv-DCHkaJ9-.mjs} +0 -0
  238. /package/dist/{mq-Bo7Etgh6.mjs → mq-Dm1Wmtm-.mjs} +0 -0
  239. /package/dist/{negotiation-RuwrPFqi.mjs → negotiation-CCocWT_N.mjs} +0 -0
  240. /package/dist/{retry-DgFqeS5k.mjs → retry-zX5xw5e0.mjs} +0 -0
  241. /package/dist/{chunk-D5IdezsZ.js → rolldown-runtime-BC-Eo5Mj.js} +0 -0
  242. /package/dist/{chunk-Czpeue4M.cjs → rolldown-runtime-Dmm3t92W.cjs} +0 -0
  243. /package/dist/{transformers-DXze6FUB.js → transformers-DAtXl_Kc.js} +0 -0
  244. /package/dist/{types-CrtdVuDP.mjs → types-DE_LV1JB.mjs} +0 -0
@@ -0,0 +1,2 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import { URLPattern } from "urlpattern-polyfill";
@@ -0,0 +1,100 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { n as getCanonicalPortableId } from "../portable-key-id-Ca30-hOa.mjs";
5
+ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
6
+ import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
7
+ import "../std__assert-DvMDRPes.mjs";
8
+ import { t as assert } from "../assert-D1Eafmd_.mjs";
9
+ import { a as promoteKeyOwnerEvidence, i as parseKeyOwnerEvidence, n as attachKeyOwnerEvidence, r as getVerifiedKeyOwnerEvidence } from "../key-owner-evidence-APB6NpSk.mjs";
10
+ import { r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
11
+ import { CryptographicKey, Person } from "@fedify/vocab";
12
+ import { exportDidKey, parseIri } from "@fedify/vocab-runtime";
13
+ import { test } from "@fedify/fixture";
14
+ //#region src/sig/key-owner-evidence.test.ts
15
+ const did = await exportDidKey(ed25519PublicKey.publicKey);
16
+ const rawActorId = `ap://${did}/actors/alice`;
17
+ const actorId = parseIri(rawActorId);
18
+ const keyId = new URL(`https://gw.example/.well-known/apgateway/${did}/actors/alice#main-key`);
19
+ const document = {
20
+ "@id": rawActorId,
21
+ "@type": ["https://www.w3.org/ns/activitystreams#Person"],
22
+ "https://www.w3.org/ns/activitystreams#name": [{ "@value": "Alice" }]
23
+ };
24
+ const expires = Temporal.Now.instant().add({ hours: 1 });
25
+ function createKey(owner = actorId) {
26
+ return new CryptographicKey({
27
+ id: new URL(keyId.href),
28
+ owner: parseIri(owner.href),
29
+ publicKey: rsaPublicKey2.publicKey
30
+ });
31
+ }
32
+ test("getVerifiedKeyOwnerEvidence() only returns promoted evidence", () => {
33
+ const key = createKey();
34
+ assert(attachKeyOwnerEvidence(key, document, expires));
35
+ assertEquals(getVerifiedKeyOwnerEvidence(key), void 0);
36
+ promoteKeyOwnerEvidence(key);
37
+ const evidence = getVerifiedKeyOwnerEvidence(key);
38
+ assertEquals(evidence?.ownerId, getCanonicalPortableId(actorId));
39
+ assertEquals(evidence?.keyId, keyId.href);
40
+ assertEquals(evidence?.expires, expires);
41
+ const other = createKey();
42
+ promoteKeyOwnerEvidence(other);
43
+ assertEquals(getVerifiedKeyOwnerEvidence(other), void 0);
44
+ });
45
+ test("attachKeyOwnerEvidence() refuses evidence about other actors", () => {
46
+ const otherActorId = parseIri(`ap://${did}/actors/bob`);
47
+ assertFalse(attachKeyOwnerEvidence(createKey(otherActorId), {
48
+ ...document,
49
+ "@id": otherActorId.href
50
+ }, expires));
51
+ assertFalse(attachKeyOwnerEvidence(createKey(), {
52
+ ...document,
53
+ "@id": `ap://${did}/actors/bob`
54
+ }, expires));
55
+ assertFalse(attachKeyOwnerEvidence(createKey(), {
56
+ ...document,
57
+ "@id": `ap://${did}/x/../actors/alice`
58
+ }, expires));
59
+ assertFalse(attachKeyOwnerEvidence(createKey(), {}, expires));
60
+ assertFalse(attachKeyOwnerEvidence(createKey(), [document], expires));
61
+ });
62
+ test("getVerifiedKeyOwnerEvidence() ignores expired evidence", () => {
63
+ const key = createKey();
64
+ attachKeyOwnerEvidence(key, document, expires);
65
+ promoteKeyOwnerEvidence(key);
66
+ assert(getVerifiedKeyOwnerEvidence(key, expires.subtract({ seconds: 1 })));
67
+ assertEquals(getVerifiedKeyOwnerEvidence(key, expires), void 0);
68
+ });
69
+ test("getVerifiedKeyOwnerEvidence() ignores keys changed since", () => {
70
+ const key = createKey();
71
+ attachKeyOwnerEvidence(key, document, expires);
72
+ promoteKeyOwnerEvidence(key);
73
+ key.clone({}).ownerId.href = parseIri(`ap://${did}/actors/bob`).href;
74
+ assertEquals(getVerifiedKeyOwnerEvidence(key), void 0);
75
+ const moved = createKey();
76
+ attachKeyOwnerEvidence(moved, document, expires);
77
+ promoteKeyOwnerEvidence(moved);
78
+ moved.ownerId.href = `https://other.example/.well-known/apgateway/${did}/actors/alice`;
79
+ assertEquals(getVerifiedKeyOwnerEvidence(moved), void 0);
80
+ const verified = createKey();
81
+ attachKeyOwnerEvidence(verified, document, expires);
82
+ promoteKeyOwnerEvidence(verified);
83
+ assertEquals(getVerifiedKeyOwnerEvidence(verified.clone({})), void 0);
84
+ });
85
+ test("parseKeyOwnerEvidence() parses a new actor every time", async () => {
86
+ const key = createKey();
87
+ const doc = structuredClone(document);
88
+ attachKeyOwnerEvidence(key, doc, expires);
89
+ promoteKeyOwnerEvidence(key);
90
+ doc["@id"] = `ap://${did}/actors/bob`;
91
+ const evidence = getVerifiedKeyOwnerEvidence(key);
92
+ const actor = await parseKeyOwnerEvidence(evidence);
93
+ assert(actor instanceof Person);
94
+ assertEquals(actor.id?.href, actorId.href);
95
+ assertEquals(actor.name?.toString(), "Alice");
96
+ actor.id.href = parseIri(`ap://${did}/actors/bob`).href;
97
+ assertEquals((await parseKeyOwnerEvidence(evidence))?.id?.href, actorId.href);
98
+ });
99
+ //#endregion
100
+ export {};
@@ -1,15 +1,16 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { t as assertEquals } from "../assert_equals-BV7oLMxm.mjs";
5
- import "../std__assert-B2NnY9bq.mjs";
6
- import { t as assertRejects } from "../assert_rejects-EgstcQy5.mjs";
7
- import { t as assertThrows } from "../assert_throws-NiFfqbnH.mjs";
8
- import { a as importJwk, i as generateCryptoKeyPair, n as fetchKey, o as validateCryptoKey, r as fetchKeyDetailed, t as exportJwk } from "../key-C_gNKtxm.mjs";
9
- import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-Dbyd7bhl.mjs";
4
+ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
5
+ import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
6
+ import "../std__assert-DvMDRPes.mjs";
7
+ import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
8
+ import { t as assert } from "../assert-D1Eafmd_.mjs";
9
+ import { a as fetchKeyDetailed, c as validateCryptoKey, i as fetchKey, n as exportJwk, o as generateCryptoKeyPair, s as importJwk } from "../key-D979vduq.mjs";
10
+ import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
10
11
  import { CryptographicKey, Multikey } from "@fedify/vocab";
11
- import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
12
12
  import { FetchError, exportDidKey } from "@fedify/vocab-runtime";
13
+ import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
13
14
  //#region src/sig/key.test.ts
14
15
  test("validateCryptoKey()", async () => {
15
16
  const pkcs1v15 = await crypto.subtle.generateKey({
@@ -267,7 +268,7 @@ test("fetchKeyDetailed()", async () => {
267
268
  key: rsaPublicKey1,
268
269
  cached: false
269
270
  });
270
- assertEquals(documentLoaderCalls, 1);
271
+ assertEquals(documentLoaderCalls, 2);
271
272
  const spans = exporter.getSpans("activitypub.fetch_key");
272
273
  assertEquals(spans.length, 2);
273
274
  assertEquals(spans[0].attributes["activitypub.actor.key.cached"], true);
@@ -584,6 +585,51 @@ test("fetchKey() works when meterProvider is omitted", async () => {
584
585
  contextLoader: mockDocumentLoader
585
586
  })).cached, false);
586
587
  });
588
+ test("fetchKey() rejects standalone keys with a mismatched id", async () => {
589
+ for (const { keyId, standaloneKey, fetch } of [{
590
+ keyId: "https://example.com/key",
591
+ standaloneKey: rsaPublicKey1,
592
+ fetch: (keyId, options) => fetchKey(keyId, CryptographicKey, options)
593
+ }, {
594
+ keyId: "https://example.com/multikey",
595
+ standaloneKey: ed25519Multikey,
596
+ fetch: (keyId, options) => fetchKey(keyId, Multikey, options)
597
+ }]) {
598
+ const cache = {};
599
+ const options = {
600
+ async documentLoader(resource) {
601
+ if (resource === keyId) return {
602
+ contextUrl: null,
603
+ documentUrl: resource,
604
+ document: {
605
+ ...await standaloneKey.toJsonLd({ contextLoader: mockDocumentLoader }),
606
+ id: "https://example.com/different-key"
607
+ }
608
+ };
609
+ return await mockDocumentLoader(resource);
610
+ },
611
+ contextLoader: mockDocumentLoader,
612
+ keyCache: {
613
+ get(keyId) {
614
+ return Promise.resolve(cache[keyId.href]);
615
+ },
616
+ set(keyId, key) {
617
+ cache[keyId.href] = key;
618
+ return Promise.resolve();
619
+ }
620
+ }
621
+ };
622
+ assertEquals(await fetch(keyId, options), {
623
+ key: null,
624
+ cached: false
625
+ });
626
+ assertEquals(cache, { [keyId]: null });
627
+ assertEquals(await fetch(keyId, options), {
628
+ key: null,
629
+ cached: true
630
+ });
631
+ }
632
+ });
587
633
  test("fetchKey() returns null for a malformed actor publicKey", async () => {
588
634
  const actorId = "https://example.com/malformed-public-key";
589
635
  const keyId = "https://example.com/malformed-public-key#main-key";
@@ -634,5 +680,171 @@ test("fetchKey() returns null for a malformed actor publicKey", async () => {
634
680
  cached: true
635
681
  });
636
682
  });
683
+ test("fetchKey() rejects a key whose owner does not link back", async () => {
684
+ const keyId = "https://attacker.example/key";
685
+ const keyDocument = await rsaPublicKey1.toJsonLd({ contextLoader: mockDocumentLoader });
686
+ const serveKeyOwnedBy = (owner) => ({
687
+ documentLoader(resource) {
688
+ if (resource === keyId) return Promise.resolve({
689
+ contextUrl: null,
690
+ documentUrl: resource,
691
+ document: {
692
+ ...keyDocument,
693
+ id: keyId,
694
+ owner
695
+ }
696
+ });
697
+ return mockDocumentLoader(resource);
698
+ },
699
+ contextLoader: mockDocumentLoader
700
+ });
701
+ assertEquals(await fetchKey(keyId, CryptographicKey, serveKeyOwnedBy("https://example.com/person")), {
702
+ key: null,
703
+ cached: false
704
+ });
705
+ assertEquals(await fetchKey(keyId, CryptographicKey, serveKeyOwnedBy("https://impersonated.invalid/users/victim")), {
706
+ key: null,
707
+ cached: false
708
+ });
709
+ });
710
+ test("fetchKey() rejects a Multikey whose controller does not link back", async () => {
711
+ const keyId = "https://attacker.example/multikey";
712
+ const keyDocument = await ed25519Multikey.toJsonLd({ contextLoader: mockDocumentLoader });
713
+ assertEquals(await fetchKey(keyId, Multikey, {
714
+ documentLoader(resource) {
715
+ if (resource === keyId) return Promise.resolve({
716
+ contextUrl: null,
717
+ documentUrl: resource,
718
+ document: {
719
+ ...keyDocument,
720
+ id: keyId,
721
+ controller: "https://example.com/person2"
722
+ }
723
+ });
724
+ return mockDocumentLoader(resource);
725
+ },
726
+ contextLoader: mockDocumentLoader
727
+ }), {
728
+ key: null,
729
+ cached: false
730
+ });
731
+ });
732
+ test("fetchKey() rejects an actor document from another origin", async () => {
733
+ const keyId = "https://attacker.example/key";
734
+ const impersonated = "https://example.com/person";
735
+ const { publicKeyPem } = await rsaPublicKey1.toJsonLd({ contextLoader: mockDocumentLoader });
736
+ assertEquals(await fetchKey(keyId, CryptographicKey, {
737
+ documentLoader(resource) {
738
+ if (resource === keyId) return Promise.resolve({
739
+ contextUrl: null,
740
+ documentUrl: resource,
741
+ document: {
742
+ "@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
743
+ id: impersonated,
744
+ type: "Person",
745
+ publicKey: [{
746
+ id: `${impersonated}#main-key`,
747
+ type: "CryptographicKey",
748
+ owner: impersonated,
749
+ publicKeyPem
750
+ }]
751
+ }
752
+ });
753
+ return mockDocumentLoader(resource);
754
+ },
755
+ contextLoader: mockDocumentLoader
756
+ }), {
757
+ key: null,
758
+ cached: false
759
+ });
760
+ });
761
+ test("fetchKey() rejects a key that disowns the actor document holding it", async () => {
762
+ const actorId = "https://attacker.example/actor";
763
+ const keyId = `${actorId}#main-key`;
764
+ const { publicKeyPem } = await rsaPublicKey1.toJsonLd({ contextLoader: mockDocumentLoader });
765
+ assertEquals(await fetchKey(keyId, CryptographicKey, {
766
+ documentLoader(resource) {
767
+ if (resource === keyId || resource === actorId) return Promise.resolve({
768
+ contextUrl: null,
769
+ documentUrl: resource,
770
+ document: {
771
+ "@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
772
+ id: actorId,
773
+ type: "Person",
774
+ publicKey: [{
775
+ id: keyId,
776
+ type: "CryptographicKey",
777
+ owner: "https://example.com/person",
778
+ publicKeyPem
779
+ }]
780
+ }
781
+ });
782
+ return mockDocumentLoader(resource);
783
+ },
784
+ contextLoader: mockDocumentLoader
785
+ }), {
786
+ key: null,
787
+ cached: false
788
+ });
789
+ });
790
+ test("fetchKey() records the owner its actor document establishes", async () => {
791
+ const { key } = await fetchKey("https://example.com/users/handle#main-key", CryptographicKey, {
792
+ documentLoader: mockDocumentLoader,
793
+ contextLoader: mockDocumentLoader
794
+ });
795
+ assertEquals(key?.ownerId, new URL("https://example.com/users/handle"));
796
+ });
797
+ test("fetchKey() accepts a key document that leaves its id implicit", async () => {
798
+ const keyId = "https://example.com/key";
799
+ const keyDocument = await rsaPublicKey1.toJsonLd({ contextLoader: mockDocumentLoader });
800
+ delete keyDocument.id;
801
+ const { key } = await fetchKey(keyId, CryptographicKey, {
802
+ documentLoader(resource) {
803
+ if (resource === keyId) return Promise.resolve({
804
+ contextUrl: null,
805
+ documentUrl: resource,
806
+ document: keyDocument
807
+ });
808
+ return mockDocumentLoader(resource);
809
+ },
810
+ contextLoader: mockDocumentLoader
811
+ });
812
+ assertEquals(key?.id, new URL(keyId));
813
+ assertEquals(key?.ownerId, new URL("https://example.com/person"));
814
+ assert(key?.publicKey != null);
815
+ });
816
+ test("fetchKey() records the controller an actor document establishes", async () => {
817
+ const actorId = "https://example.com/multikey-actor";
818
+ const keyId = `${actorId}#assertion`;
819
+ const { publicKeyMultibase } = await ed25519Multikey.toJsonLd({ contextLoader: mockDocumentLoader });
820
+ const { key } = await fetchKey(keyId, Multikey, {
821
+ documentLoader(resource) {
822
+ if (resource === actorId || resource === keyId) return Promise.resolve({
823
+ contextUrl: null,
824
+ documentUrl: actorId,
825
+ document: {
826
+ "@context": [
827
+ "https://www.w3.org/ns/activitystreams",
828
+ "https://w3id.org/security/v1",
829
+ "https://w3id.org/security/multikey/v1",
830
+ "https://w3id.org/security/data-integrity/v1",
831
+ "https://www.w3.org/ns/did/v1"
832
+ ],
833
+ id: actorId,
834
+ type: "Person",
835
+ assertionMethod: [{
836
+ id: keyId,
837
+ type: "Multikey",
838
+ publicKeyMultibase
839
+ }]
840
+ }
841
+ });
842
+ return mockDocumentLoader(resource);
843
+ },
844
+ contextLoader: mockDocumentLoader
845
+ });
846
+ assertEquals(key?.controllerId, new URL(actorId));
847
+ assert(key?.publicKey != null);
848
+ });
637
849
  //#endregion
638
850
  export {};
@@ -1,18 +1,24 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { t as assertEquals } from "../assert_equals-BV7oLMxm.mjs";
5
- import { n as assertGreaterOrEqual, r as assertFalse, t as assertRejects } from "../assert_rejects-EgstcQy5.mjs";
6
- import { t as assertThrows } from "../assert_throws-NiFfqbnH.mjs";
7
- import { t as assert } from "../assert-CJ1KXcvv.mjs";
8
- import { i as generateCryptoKeyPair } from "../key-C_gNKtxm.mjs";
9
- import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-Dbyd7bhl.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-DAPAVL_7.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 assertGreaterOrEqual } from "../assert_greater_or_equal-BlafOF4-.mjs";
7
+ import { t as assertInstanceOf } from "../assert_instance_of-mrXWWNY-.mjs";
8
+ import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
9
+ import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
10
+ import { t as assert } from "../assert-D1Eafmd_.mjs";
11
+ import { o as generateCryptoKeyPair } from "../key-D979vduq.mjs";
12
+ 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-wmqC-95l.mjs";
13
+ import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
11
14
  import { CryptographicKey } from "@fedify/vocab";
12
15
  import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
13
16
  import { encodeBase64 } from "byte-encodings/base64";
14
17
  //#region src/sig/ld.test.ts
15
18
  test("isInvalidUrlTypeError()", () => {
19
+ assert(isInvalidUrlTypeError(/* @__PURE__ */ new TypeError("Invalid URL string.")));
20
+ assertFalse(isInvalidUrlTypeError(/* @__PURE__ */ new Error("Invalid URL string.")));
21
+ assertFalse(isInvalidUrlTypeError(/* @__PURE__ */ new TypeError("Invalid URL string. Other error")));
16
22
  assert(isInvalidUrlTypeError(/* @__PURE__ */ new TypeError("Invalid URL: http://[")));
17
23
  assert(isInvalidUrlTypeError(/* @__PURE__ */ new TypeError("\"http://[\" cannot be parsed as a URL.")));
18
24
  const error = /* @__PURE__ */ new TypeError("Failed to parse URL");
@@ -938,5 +944,57 @@ test("compactJsonLd() rejects inputs that compact into @graph wrappers", async (
938
944
  content: "two"
939
945
  }], mockDocumentLoader), UnsafeJsonLdError, "Unsupported JSON-LD keyword: @graph.");
940
946
  });
947
+ test("verifyJsonLd() rejects a key that claims a forged owner", async () => {
948
+ const keyId = new URL("https://attacker.example/key");
949
+ const impersonated = "https://example.com/person";
950
+ const { publicKeyPem } = await rsaPublicKey2.toJsonLd({ contextLoader: mockDocumentLoader });
951
+ const signed = await signJsonLd({
952
+ "@context": "https://www.w3.org/ns/activitystreams",
953
+ id: "https://attacker.example/activities/1",
954
+ type: "Create",
955
+ actor: impersonated
956
+ }, rsaPrivateKey2, keyId, { contextLoader: mockDocumentLoader });
957
+ const serveKeyOwnedBy = (owner) => (resource) => {
958
+ if (resource === keyId.href) return Promise.resolve({
959
+ contextUrl: null,
960
+ documentUrl: resource,
961
+ document: {
962
+ "@context": "https://w3id.org/security/v1",
963
+ id: keyId.href,
964
+ type: "CryptographicKey",
965
+ owner,
966
+ publicKeyPem
967
+ }
968
+ });
969
+ if (resource === "https://attacker.example/actor") return Promise.resolve({
970
+ contextUrl: null,
971
+ documentUrl: resource,
972
+ document: {
973
+ "@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
974
+ id: resource,
975
+ type: "Person",
976
+ publicKey: [keyId.href]
977
+ }
978
+ });
979
+ return mockDocumentLoader(resource);
980
+ };
981
+ assertEquals(await verifySignature(signed, {
982
+ documentLoader: serveKeyOwnedBy(impersonated),
983
+ contextLoader: mockDocumentLoader
984
+ }), null);
985
+ assertFalse(await verifyJsonLd(signed, {
986
+ documentLoader: serveKeyOwnedBy(impersonated),
987
+ contextLoader: mockDocumentLoader
988
+ }));
989
+ const honestLoader = serveKeyOwnedBy("https://attacker.example/actor");
990
+ assertInstanceOf(await verifySignature(signed, {
991
+ documentLoader: honestLoader,
992
+ contextLoader: mockDocumentLoader
993
+ }), CryptographicKey);
994
+ assertFalse(await verifyJsonLd(signed, {
995
+ documentLoader: honestLoader,
996
+ contextLoader: mockDocumentLoader
997
+ }));
998
+ });
941
999
  //#endregion
942
1000
  export {};
@@ -0,0 +1,2 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import { URLPattern } from "urlpattern-polyfill";