@fedify/fedify 2.4.0-pr.936.41 → 2.5.0-dev.2271

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 +50 -39
  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-DonuxRl_.mjs → builder-Bda6LK7A.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-B-9mXxFW.mjs +989 -0
  30. package/dist/{context-Zii1f5xS.d.ts → context-7NyiqIcg.d.ts} +1600 -25
  31. package/dist/{context-BJXxPElm.mjs → context-8Tu9kea0.mjs} +21 -63
  32. package/dist/{context-lxX6I7as.d.cts → context-tsYPJ2Ew.d.cts} +1600 -25
  33. package/dist/{deno-BHzKn9Ig.mjs → deno-oR5aJKpU.mjs} +1 -1
  34. package/dist/dist-DJQM4u7i.mjs +189 -0
  35. package/dist/docloader-DBoYbvYW.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 +385 -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 -261
  58. package/dist/federation/mod.d.cts +5 -5
  59. package/dist/federation/mod.d.ts +5 -5
  60. package/dist/federation/mod.js +279 -1
  61. package/dist/federation/mq.test.mjs +123 -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 +42 -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-FrSMAYEx.cjs → federation-CkZiAcWY.cjs} +8640 -3722
  92. package/dist/http-B5JT115n.cjs +10630 -0
  93. package/dist/http-DydWCB7R.js +6527 -0
  94. package/dist/{http-CPVMUgsW.mjs → http-siciWkmx.mjs} +397 -168
  95. package/dist/key-BspPiXqn.mjs +951 -0
  96. package/dist/key-C1nv7_jD.d.ts +1125 -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-KyGqJqSp.mjs → kv-cache-BF1hnW65.mjs} +1 -1
  104. package/dist/{kv-cache-5bnX3-Jq.js → kv-cache-CTQr1tbn.js} +54 -16
  105. package/dist/{kv-cache-DQ29C4XL.cjs → kv-cache-DCac1nEU.cjs} +55 -19
  106. package/dist/{ld-Cj9F_5AP.mjs → ld-CzaP-hJl.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-DMk-nTxI.mjs → metrics-CYg9yxBL.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-Y-kpsp6S.js → middleware-CsDDXKuL.js} +5493 -1103
  113. package/dist/{middleware-CvwTUgnP.mjs → middleware-D7_LO-Vs.mjs} +3157 -272
  114. package/dist/{middleware-CEctxBN6.mjs → middleware-DWjrfpcz.mjs} +1 -1
  115. package/dist/{mod-gOlPDuT8.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-BtEaIEcD.d.cts → mod-DEZXwV6J.d.ts} +10 -4
  119. package/dist/{mod-UMmveiO0.d.ts → mod-Dw-nPxQh.d.cts} +10 -4
  120. package/dist/{mod-DLc2Ot6f.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 +9 -9
  125. package/dist/{mq-llHKivST.mjs → mq-Dm1Wmtm-.mjs} +6 -0
  126. package/dist/nodeinfo/client.test.mjs +139 -4
  127. package/dist/nodeinfo/handler.test.mjs +5 -5
  128. package/dist/nodeinfo/mod.cjs +1 -1
  129. package/dist/nodeinfo/mod.d.cts +1 -1
  130. package/dist/nodeinfo/mod.d.ts +1 -1
  131. package/dist/nodeinfo/mod.js +1 -1
  132. package/dist/nodeinfo/types.test.mjs +4 -4
  133. package/dist/otel/exporter.test.mjs +3 -3
  134. package/dist/otel/mod.cjs +0 -1
  135. package/dist/otel/mod.d.cts +1 -1
  136. package/dist/otel/mod.d.ts +1 -1
  137. package/dist/{outgoing-jsonld-URuqsICz.mjs → outgoing-jsonld-4IJqPYos.mjs} +12 -10
  138. package/dist/{owner-DEvZuyOE.d.cts → owner-BF0L9cMt.d.cts} +11 -0
  139. package/dist/{owner-CnngXDNJ.d.ts → owner-BSzr5-I8.d.ts} +11 -0
  140. package/dist/owner-DYgfTFHy.mjs +267 -0
  141. package/dist/portable-collection-BpsVsRov.js +670 -0
  142. package/dist/portable-collection-C74P1vtC.mjs +418 -0
  143. package/dist/portable-collection-DZd2bm7M.cjs +686 -0
  144. package/dist/portable-key-BIMLrAP4.mjs +549 -0
  145. package/dist/portable-key-id-Ca30-hOa.mjs +248 -0
  146. package/dist/proof-Dxy6ByqI.mjs +1299 -0
  147. package/dist/{public-audience-Cr5MsnMq.mjs → public-audience--klBIOk1.mjs} +15 -10
  148. package/dist/router-u5O5KCQr.mjs +156 -0
  149. package/dist/runtime/mod.cjs +1 -1
  150. package/dist/runtime/mod.js +1 -1
  151. package/dist/secured-document-CxzZZ9nL.mjs +35 -0
  152. package/dist/send-C4dDpAxm.mjs +495 -0
  153. package/dist/sig/accept.test.mjs +1 -1
  154. package/dist/sig/compound-proof-discovery.test.d.mts +2 -0
  155. package/dist/sig/compound-proof-discovery.test.mjs +331 -0
  156. package/dist/sig/compound-proof-producer.test.d.mts +2 -0
  157. package/dist/sig/compound-proof-producer.test.mjs +107 -0
  158. package/dist/sig/compound-proof-verification.test.d.mts +2 -0
  159. package/dist/sig/compound-proof-verification.test.mjs +833 -0
  160. package/dist/sig/compound-proof.test.d.mts +2 -0
  161. package/dist/sig/compound-proof.test.mjs +411 -0
  162. package/dist/sig/http.test.mjs +702 -31
  163. package/dist/sig/key-owner-evidence.test.d.mts +2 -0
  164. package/dist/sig/key-owner-evidence.test.mjs +100 -0
  165. package/dist/sig/key.test.mjs +220 -8
  166. package/dist/sig/ld.test.mjs +65 -7
  167. package/dist/sig/mitra-receive-interop.test.d.mts +2 -0
  168. package/dist/sig/mitra-receive-interop.test.mjs +260 -0
  169. package/dist/sig/mitra-send-interop.test.d.mts +2 -0
  170. package/dist/sig/mitra-send-interop.test.mjs +461 -0
  171. package/dist/sig/mod.cjs +18 -16
  172. package/dist/sig/mod.d.cts +4 -4
  173. package/dist/sig/mod.d.ts +4 -4
  174. package/dist/sig/mod.js +3 -3
  175. package/dist/sig/owner.test.mjs +108 -9
  176. package/dist/sig/portable-collection.test.d.mts +2 -0
  177. package/dist/sig/portable-collection.test.mjs +697 -0
  178. package/dist/sig/portable-interop.test.d.mts +2 -0
  179. package/dist/sig/portable-interop.test.mjs +156 -0
  180. package/dist/sig/portable-key-id.test.d.mts +2 -0
  181. package/dist/sig/portable-key-id.test.mjs +67 -0
  182. package/dist/sig/portable-key.test.d.mts +2 -0
  183. package/dist/sig/portable-key.test.mjs +1439 -0
  184. package/dist/sig/proof.test.mjs +1753 -16
  185. package/dist/sig/tootik-request-interop.test.d.mts +2 -0
  186. package/dist/sig/tootik-request-interop.test.mjs +190 -0
  187. package/dist/sig/tootik-send-interop.test.d.mts +2 -0
  188. package/dist/sig/tootik-send-interop.test.mjs +331 -0
  189. package/dist/sig/verification.test.d.mts +2 -0
  190. package/dist/sig/verification.test.mjs +310 -0
  191. package/dist/std__assert-DvMDRPes.mjs +8 -0
  192. package/dist/{testing-CO7ftO8A.mjs → tasks-IG3pHfvZ.mjs} +2 -2
  193. package/dist/{temporal-fsXO5IvD.mjs → temporal-D0KJI4NF.mjs} +3 -3
  194. package/dist/testing/context.test.d.mts +2 -0
  195. package/dist/testing/context.test.mjs +19 -0
  196. package/dist/testing/kv.test.d.mts +2 -0
  197. package/dist/testing/kv.test.mjs +101 -0
  198. package/dist/testing/mod.d.mts +1617 -48
  199. package/dist/testing/mod.mjs +6 -3
  200. package/dist/testing-t8xDeJZ5.mjs +8 -0
  201. package/dist/{transformers-DGwl-hD1.cjs → transformers-BalCrSsr.cjs} +0 -1
  202. package/dist/{types-DC1pNgJA.js → types-_S2_MeLF.js} +144 -8
  203. package/dist/{types-CPym83zc.cjs → types-poIao40f.cjs} +160 -7
  204. package/dist/utils/docloader.test.mjs +530 -8
  205. package/dist/utils/kv-cache.test.mjs +2 -2
  206. package/dist/utils/mod.cjs +1 -1
  207. package/dist/utils/mod.d.cts +1 -1
  208. package/dist/utils/mod.d.ts +1 -1
  209. package/dist/utils/mod.js +1 -1
  210. package/dist/verification-C3954hQh.mjs +5 -0
  211. package/dist/verification-Dpfcw8ml.mjs +105 -0
  212. package/dist/vocab/cjs.test.mjs +1 -1
  213. package/package.json +8 -8
  214. package/dist/assert_rejects-EgstcQy5.mjs +0 -82
  215. package/dist/docloader-e1khNUKy.mjs +0 -49
  216. package/dist/http-CsmQ-BQ4.js +0 -2483
  217. package/dist/http-VyDTd4G3.d.cts +0 -553
  218. package/dist/http-hlIjmewS.cjs +0 -2694
  219. package/dist/http-lf8Hsd91.d.ts +0 -553
  220. package/dist/key-DfPsX8hv.mjs +0 -453
  221. package/dist/keycache-_DHqz5z_.mjs +0 -97
  222. package/dist/metrics-CoUJLQhZ.d.cts +0 -276
  223. package/dist/metrics-Dc4jR-IC.d.ts +0 -276
  224. package/dist/mod-B0hW12_O.d.cts +0 -307
  225. package/dist/mod-COIAjwRS.d.ts +0 -307
  226. package/dist/owner-Br9YYzn_.mjs +0 -120
  227. package/dist/proof-B4ngoaNQ.mjs +0 -316
  228. package/dist/proof-B6E0XUXJ.js +0 -1415
  229. package/dist/proof-NN4xCQGL.cjs +0 -1562
  230. package/dist/send-CxHKUNzv.mjs +0 -239
  231. package/dist/std__assert-B2NnY9bq.mjs +0 -79
  232. package/dist/temporal-polyfill-BCdTHexd.cjs +0 -3565
  233. /package/dist/{accept-8PiolDP7.mjs → accept-CPVqki78.mjs} +0 -0
  234. /package/dist/{activity-listener-BtTSxZWA.mjs → activity-listener-C-BSbKI7.mjs} +0 -0
  235. /package/dist/{client-CAM_bQXx.d.cts → client-D-XP_Ccb.d.cts} +0 -0
  236. /package/dist/{client-CSddvgWN.d.ts → client-D-XP_Ccb.d.ts} +0 -0
  237. /package/dist/{keys-Dbyd7bhl.mjs → keys-DIJNHW-Y.mjs} +0 -0
  238. /package/dist/{kv-CXBAok3k.mjs → kv-DCHkaJ9-.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-DfPsX8hv.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-BspPiXqn.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-DfPsX8hv.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-Cj9F_5AP.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-BspPiXqn.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-CzaP-hJl.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";