@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
@@ -1,453 +0,0 @@
1
- import "temporal-polyfill";
2
- import "urlpattern-polyfill";
3
- globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-BHzKn9Ig.mjs";
5
- import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-DMk-nTxI.mjs";
6
- import { getLogger } from "@logtape/logtape";
7
- import { CryptographicKey, Multikey, Object as Object$1, isActor } from "@fedify/vocab";
8
- import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
9
- import { FetchError, getDocumentLoader, parseDidKeyVerificationMethod } from "@fedify/vocab-runtime";
10
- //#region src/sig/key.ts
11
- /**
12
- * Checks if the given key is valid and supported. No-op if the key is valid,
13
- * otherwise throws an error.
14
- * @param key The key to check.
15
- * @param type Which type of key to check. If not specified, the key can be
16
- * either public or private.
17
- * @throws {TypeError} If the key is invalid or unsupported.
18
- */
19
- function validateCryptoKey(key, type) {
20
- if (type != null && key.type !== type) throw new TypeError(`The key is not a ${type} key.`);
21
- if (!key.extractable) throw new TypeError("The key is not extractable.");
22
- if (key.algorithm.name !== "RSASSA-PKCS1-v1_5" && key.algorithm.name !== "Ed25519") throw new TypeError("Currently only RSASSA-PKCS1-v1_5 and Ed25519 keys are supported. More algorithms will be added in the future!");
23
- if (key.algorithm.name === "RSASSA-PKCS1-v1_5") {
24
- if (key.algorithm.hash.name !== "SHA-256") throw new TypeError("For compatibility with the existing Fediverse software (e.g., Mastodon), hash algorithm for RSASSA-PKCS1-v1_5 keys must be SHA-256.");
25
- }
26
- }
27
- /**
28
- * Generates a key pair which is appropriate for Fedify.
29
- * @param algorithm The algorithm to use. Currently only RSASSA-PKCS1-v1_5 and
30
- * Ed25519 are supported.
31
- * @returns The generated key pair.
32
- * @throws {TypeError} If the algorithm is unsupported.
33
- */
34
- function generateCryptoKeyPair(algorithm) {
35
- if (algorithm == null) getLogger([
36
- "fedify",
37
- "sig",
38
- "key"
39
- ]).warn("No algorithm specified. Using RSASSA-PKCS1-v1_5 by default, but it is recommended to specify the algorithm explicitly as the parameter will be required in the future.");
40
- if (algorithm == null || algorithm === "RSASSA-PKCS1-v1_5") return crypto.subtle.generateKey({
41
- name: "RSASSA-PKCS1-v1_5",
42
- modulusLength: 4096,
43
- publicExponent: new Uint8Array([
44
- 1,
45
- 0,
46
- 1
47
- ]),
48
- hash: "SHA-256"
49
- }, true, ["sign", "verify"]);
50
- else if (algorithm === "Ed25519") return crypto.subtle.generateKey("Ed25519", true, ["sign", "verify"]);
51
- throw new TypeError("Unsupported algorithm: " + algorithm);
52
- }
53
- /**
54
- * Exports a key in JWK format.
55
- * @param key The key to export. Either public or private key.
56
- * @returns The exported key in JWK format. The key is suitable for
57
- * serialization and storage.
58
- * @throws {TypeError} If the key is invalid or unsupported.
59
- */
60
- async function exportJwk(key) {
61
- validateCryptoKey(key);
62
- const jwk = await crypto.subtle.exportKey("jwk", key);
63
- if (jwk.crv === "Ed25519") jwk.alg = "Ed25519";
64
- return jwk;
65
- }
66
- /**
67
- * Imports a key from JWK format.
68
- * @param jwk The key in JWK format.
69
- * @param type Which type of key to import, either `"public"` or `"private"`.
70
- * @returns The imported key.
71
- * @throws {TypeError} If the key is invalid or unsupported.
72
- */
73
- async function importJwk(jwk, type) {
74
- let key;
75
- if (jwk.kty === "RSA" && jwk.alg === "RS256") key = await crypto.subtle.importKey("jwk", jwk, {
76
- name: "RSASSA-PKCS1-v1_5",
77
- hash: "SHA-256"
78
- }, true, type === "public" ? ["verify"] : ["sign"]);
79
- else if (jwk.kty === "OKP" && jwk.crv === "Ed25519") {
80
- if (navigator?.userAgent === "Cloudflare-Workers") {
81
- jwk = { ...jwk };
82
- delete jwk.alg;
83
- }
84
- key = await crypto.subtle.importKey("jwk", jwk, "Ed25519", true, type === "public" ? ["verify"] : ["sign"]);
85
- } else throw new TypeError("Unsupported JWK format.");
86
- validateCryptoKey(key, type);
87
- return key;
88
- }
89
- async function withFetchKeySpan(keyId, tracerProvider, fetcher) {
90
- tracerProvider ??= trace.getTracerProvider();
91
- return await tracerProvider.getTracer(name, version).startActiveSpan("activitypub.fetch_key", {
92
- kind: SpanKind.CLIENT,
93
- attributes: {
94
- "http.method": "GET",
95
- "url.full": keyId.href,
96
- "url.scheme": keyId.protocol.replace(/:$/, ""),
97
- "url.domain": keyId.hostname,
98
- "url.path": keyId.pathname,
99
- "url.query": keyId.search.replace(/^\?/, ""),
100
- "url.fragment": keyId.hash.replace(/^#/, "")
101
- }
102
- }, async (span) => {
103
- try {
104
- const result = await fetcher();
105
- span.setAttribute("activitypub.actor.key.cached", result.cached);
106
- return result;
107
- } catch (e) {
108
- span.setStatus({
109
- code: SpanStatusCode.ERROR,
110
- message: String(e)
111
- });
112
- throw e;
113
- } finally {
114
- span.end();
115
- }
116
- });
117
- }
118
- /**
119
- * Fetches a {@link CryptographicKey} or {@link Multikey} from the given URL.
120
- * If the given URL contains an {@link Actor} object, it tries to find
121
- * the corresponding key in the `publicKey` or `assertionMethod` property.
122
- * @template T The type of the key to fetch. Either {@link CryptographicKey}
123
- * or {@link Multikey}.
124
- * @param keyId The URL of the key.
125
- * @param cls The class of the key to fetch. Either {@link CryptographicKey}
126
- * or {@link Multikey}.
127
- * @param options Options for fetching the key. See {@link FetchKeyOptions}.
128
- * @returns The fetched key or `null` if the key is not found.
129
- * @since 1.3.0
130
- */
131
- function fetchKey(keyId, cls, options = {}) {
132
- keyId = typeof keyId === "string" ? new URL(keyId) : keyId;
133
- return withFetchKeySpan(keyId, options.tracerProvider, () => fetchKeyInternal(keyId, cls, options));
134
- }
135
- /**
136
- * Fetches a {@link CryptographicKey} or {@link Multikey} from the given URL,
137
- * preserving transport-level fetch failures for callers that need to inspect
138
- * why the key could not be loaded.
139
- *
140
- * @template T The type of the key to fetch. Either {@link CryptographicKey}
141
- * or {@link Multikey}.
142
- * @param keyId The URL of the key.
143
- * @param cls The class of the key to fetch. Either {@link CryptographicKey}
144
- * or {@link Multikey}.
145
- * @param options Options for fetching the key.
146
- * @returns The fetched key, or detailed fetch failure information.
147
- * @since 2.1.0
148
- */
149
- async function fetchKeyDetailed(keyId, cls, options = {}) {
150
- const cacheKey = typeof keyId === "string" ? new URL(keyId) : keyId;
151
- return await withFetchKeySpan(cacheKey, options.tracerProvider, async () => {
152
- return await fetchKeyWithResult(cacheKey, cls, options, async (cacheKey, keyId, keyCache, logger) => {
153
- const fetchError = await keyCache?.getFetchError?.(cacheKey);
154
- if (fetchError != null) {
155
- logger.debug("Entry {keyId} found in cache with preserved fetch failure details.", { keyId });
156
- return {
157
- key: null,
158
- cached: true,
159
- fetchError
160
- };
161
- }
162
- logger.debug("Entry {keyId} found in cache, but no fetch failure details are available.", { keyId });
163
- return {
164
- key: null,
165
- cached: true
166
- };
167
- }, async (error, cacheKey, keyId, keyCache, logger) => {
168
- logger.debug("Failed to fetch key {keyId}.", {
169
- keyId,
170
- error
171
- });
172
- await keyCache?.set(cacheKey, null);
173
- if (error instanceof FetchError && error.response != null) {
174
- const fetchError = {
175
- status: error.response.status,
176
- response: error.response.clone()
177
- };
178
- await keyCache?.setFetchError?.(cacheKey, fetchError);
179
- return {
180
- key: null,
181
- cached: false,
182
- fetchError
183
- };
184
- }
185
- const fetchError = { error: error instanceof Error ? error : new Error(String(error)) };
186
- await keyCache?.setFetchError?.(cacheKey, fetchError);
187
- return {
188
- key: null,
189
- cached: false,
190
- fetchError
191
- };
192
- });
193
- });
194
- }
195
- async function getCachedFetchKey(cacheKey, keyId, cls, keyCache, logger) {
196
- if (keyCache == null) return null;
197
- const cachedKey = await keyCache.get(cacheKey);
198
- const hit = checkCachedKeyHit(cachedKey, keyId, cls, logger);
199
- if (hit != null) return hit;
200
- if (cachedKey === null) {
201
- logger.debug("Entry {keyId} found in cache, but it is unavailable.", { keyId });
202
- return {
203
- key: null,
204
- cached: true
205
- };
206
- }
207
- return null;
208
- }
209
- function checkCachedKeyHit(cachedKey, keyId, cls, logger) {
210
- if (cachedKey instanceof cls && cachedKey.publicKey != null) {
211
- logger.debug("Key {keyId} found in cache.", { keyId });
212
- return {
213
- key: cachedKey,
214
- cached: true
215
- };
216
- }
217
- return null;
218
- }
219
- async function clearFetchErrorMetadata(keyId, keyCache) {
220
- await keyCache?.setFetchError?.(keyId, null);
221
- }
222
- function isDidKeyUrl(keyId) {
223
- return keyId.protocol === "did:" && keyId.pathname.startsWith("key:");
224
- }
225
- async function doRawKeysMatch(left, right) {
226
- const [leftRaw, rightRaw] = await Promise.all([crypto.subtle.exportKey("raw", left), crypto.subtle.exportKey("raw", right)]);
227
- if (leftRaw.byteLength !== rightRaw.byteLength) return false;
228
- const leftBytes = new Uint8Array(leftRaw);
229
- const rightBytes = new Uint8Array(rightRaw);
230
- return leftBytes.every((byte, index) => byte === rightBytes[index]);
231
- }
232
- async function isCachedDidKeyValid(key, verificationMethod) {
233
- try {
234
- return key.id?.href === verificationMethod.id.href && key.controllerId?.href === verificationMethod.controller.href && await doRawKeysMatch(key.publicKey, verificationMethod.publicKey);
235
- } catch {
236
- return false;
237
- }
238
- }
239
- async function resolveDidKey(cacheKey, cls, keyCache, logger) {
240
- if (!isDidKeyUrl(cacheKey)) return null;
241
- const keyId = cacheKey.href;
242
- if (!(cls === Multikey)) {
243
- logger.debug("Failed to resolve did:key {keyId}; did:key verification methods are only supported as Multikey values.", { keyId });
244
- return {
245
- key: null,
246
- cached: false
247
- };
248
- }
249
- let verificationMethod;
250
- try {
251
- verificationMethod = await parseDidKeyVerificationMethod(cacheKey);
252
- } catch (error) {
253
- logger.debug("Failed to resolve did:key verification method {keyId}: {error}", {
254
- keyId,
255
- error
256
- });
257
- return {
258
- key: null,
259
- cached: false
260
- };
261
- }
262
- const hit = checkCachedKeyHit(await keyCache?.get(cacheKey), keyId, cls, logger);
263
- if (hit?.key instanceof Multikey && await isCachedDidKeyValid(hit.key, verificationMethod)) return hit;
264
- const key = new Multikey({
265
- id: verificationMethod.id,
266
- controller: verificationMethod.controller,
267
- publicKey: verificationMethod.publicKey
268
- });
269
- await keyCache?.set(cacheKey, key);
270
- await clearFetchErrorMetadata(cacheKey, keyCache);
271
- logger.debug("Resolved did:key verification method {keyId}.", { keyId });
272
- return {
273
- key,
274
- cached: false
275
- };
276
- }
277
- async function resolveFetchedKey(document, cacheKey, keyId, cls, { documentLoader, contextLoader, keyCache, tracerProvider }, logger) {
278
- let object;
279
- try {
280
- object = await Object$1.fromJsonLd(document, {
281
- documentLoader,
282
- contextLoader,
283
- tracerProvider
284
- });
285
- } catch (e) {
286
- if (!(e instanceof TypeError)) throw e;
287
- try {
288
- object = await cls.fromJsonLd(document, {
289
- documentLoader,
290
- contextLoader,
291
- tracerProvider
292
- });
293
- } catch (e) {
294
- if (e instanceof TypeError) {
295
- logger.debug("Failed to verify; key {keyId} returned an invalid object.", { keyId });
296
- await keyCache?.set(cacheKey, null);
297
- await clearFetchErrorMetadata(cacheKey, keyCache);
298
- return {
299
- key: null,
300
- cached: false
301
- };
302
- }
303
- throw e;
304
- }
305
- }
306
- let key = null;
307
- if (object instanceof cls) key = object;
308
- else if (isActor(object)) {
309
- const keys = cls === CryptographicKey ? object.getPublicKeys({
310
- documentLoader,
311
- contextLoader,
312
- suppressError: true,
313
- tracerProvider
314
- }) : object.getAssertionMethods({
315
- documentLoader,
316
- contextLoader,
317
- suppressError: true,
318
- tracerProvider
319
- });
320
- let length = 0;
321
- let lastKey = null;
322
- try {
323
- for await (const k of keys) {
324
- length++;
325
- lastKey = k;
326
- if (k.id?.href === keyId) {
327
- key = k;
328
- break;
329
- }
330
- }
331
- } catch (e) {
332
- if (!(e instanceof TypeError)) throw e;
333
- logger.debug("Failed to verify; a malformed key was encountered while iterating the keys of {keyId}; treating it as a missing key: {error}", {
334
- keyId,
335
- error: e
336
- });
337
- }
338
- const keyIdUrl = new URL(keyId);
339
- if (key == null && keyIdUrl.hash === "" && length === 1) key = lastKey;
340
- if (key == null) {
341
- logger.debug("Failed to verify; object {keyId} returned an {actorType}, but has no key matching {keyId}.", {
342
- keyId,
343
- actorType: object.constructor.name
344
- });
345
- await keyCache?.set(cacheKey, null);
346
- await clearFetchErrorMetadata(cacheKey, keyCache);
347
- return {
348
- key: null,
349
- cached: false
350
- };
351
- }
352
- } else {
353
- logger.debug("Failed to verify; key {keyId} returned an invalid object.", { keyId });
354
- await keyCache?.set(cacheKey, null);
355
- await clearFetchErrorMetadata(cacheKey, keyCache);
356
- return {
357
- key: null,
358
- cached: false
359
- };
360
- }
361
- if (key.publicKey == null) {
362
- logger.debug("Failed to verify; key {keyId} has no publicKeyPem field.", { keyId });
363
- await keyCache?.set(cacheKey, null);
364
- await clearFetchErrorMetadata(cacheKey, keyCache);
365
- return {
366
- key: null,
367
- cached: false
368
- };
369
- }
370
- if (keyCache != null) {
371
- await keyCache.set(cacheKey, key);
372
- logger.debug("Key {keyId} cached.", { keyId });
373
- }
374
- await clearFetchErrorMetadata(cacheKey, keyCache);
375
- return {
376
- key,
377
- cached: false
378
- };
379
- }
380
- async function fetchKeyWithResult(cacheKey, cls, options, onCachedUnavailable, onFetchError) {
381
- const start = performance.now();
382
- let outcome = { result: "error" };
383
- try {
384
- const logger = getLogger([
385
- "fedify",
386
- "sig",
387
- "key"
388
- ]);
389
- const keyId = cacheKey.href;
390
- const keyCache = options.keyCache;
391
- const didKey = await resolveDidKey(cacheKey, cls, keyCache, logger);
392
- if (didKey != null) {
393
- outcome = { result: didKey.key == null ? "invalid" : didKey.cached ? "hit" : "fetched" };
394
- return didKey;
395
- }
396
- const cached = await getCachedFetchKey(cacheKey, keyId, cls, keyCache, logger);
397
- if (cached?.key === null && cached.cached) {
398
- const cachedUnavailable = await onCachedUnavailable(cacheKey, keyId, keyCache, logger);
399
- outcome = { result: "hit" };
400
- return cachedUnavailable;
401
- }
402
- if (cached != null) {
403
- outcome = { result: "hit" };
404
- return cached;
405
- }
406
- logger.debug("Fetching key {keyId} to verify signature...", { keyId });
407
- let document;
408
- try {
409
- document = (await (options.documentLoader ?? getDocumentLoader())(keyId)).document;
410
- } catch (error) {
411
- const classified = classifyFetchError(error);
412
- const errored = await onFetchError(error, cacheKey, keyId, keyCache, logger);
413
- outcome = classified;
414
- return errored;
415
- }
416
- const resolved = await resolveFetchedKey(document, cacheKey, keyId, cls, options, logger);
417
- outcome = { result: resolved.key != null ? "fetched" : "invalid" };
418
- return resolved;
419
- } finally {
420
- recordKeyLookup(options.meterProvider, {
421
- durationMs: getDurationMs(start),
422
- result: outcome.result,
423
- remoteUrl: cacheKey,
424
- cacheEnabled: options.keyCache != null,
425
- statusCode: outcome.statusCode
426
- });
427
- }
428
- }
429
- async function fetchKeyInternal(keyId, cls, options = {}) {
430
- return await fetchKeyWithResult(typeof keyId === "string" ? new URL(keyId) : keyId, cls, options, (_cacheKey, _keyId, _keyCache, _logger) => {
431
- return {
432
- key: null,
433
- cached: true
434
- };
435
- }, async (error, cacheKey, keyId, keyCache, logger) => {
436
- logger.debug("Failed to fetch key {keyId}.", {
437
- keyId,
438
- error
439
- });
440
- await keyCache?.set(cacheKey, null);
441
- if (error instanceof FetchError && error.response != null) await keyCache?.setFetchError?.(cacheKey, {
442
- status: error.response.status,
443
- response: error.response.clone()
444
- });
445
- else await keyCache?.setFetchError?.(cacheKey, { error: error instanceof Error ? error : new Error(String(error)) });
446
- return {
447
- key: null,
448
- cached: false
449
- };
450
- });
451
- }
452
- //#endregion
453
- export { importJwk as a, generateCryptoKeyPair as i, fetchKey as n, validateCryptoKey as o, fetchKeyDetailed as r, exportJwk as t };
@@ -1,97 +0,0 @@
1
- import { Temporal } from "temporal-polyfill";
2
- import "urlpattern-polyfill";
3
- globalThis.addEventListener = () => {};
4
- import { CryptographicKey, Multikey } from "@fedify/vocab";
5
- //#region src/federation/keycache.ts
6
- var KvKeyCache = class {
7
- kv;
8
- prefix;
9
- options;
10
- unavailableKeyTtl;
11
- nullKeys;
12
- constructor(kv, prefix, options = {}) {
13
- this.kv = kv;
14
- this.prefix = prefix;
15
- this.options = options;
16
- this.unavailableKeyTtl = options.unavailableKeyTtl ?? Temporal.Duration.from({ minutes: 10 });
17
- this.nullKeys = /* @__PURE__ */ new Map();
18
- }
19
- #getFetchErrorKey(keyId) {
20
- return [
21
- ...this.prefix,
22
- "__fetchError",
23
- keyId.href
24
- ];
25
- }
26
- async get(keyId) {
27
- const negativeExpiration = this.nullKeys.get(keyId.href);
28
- if (negativeExpiration != null) {
29
- if (Temporal.Now.instant().until(negativeExpiration).sign >= 0) return null;
30
- this.nullKeys.delete(keyId.href);
31
- }
32
- const serialized = await this.kv.get([...this.prefix, keyId.href]);
33
- if (serialized === void 0) return void 0;
34
- if (serialized === null) {
35
- this.nullKeys.set(keyId.href, Temporal.Now.instant().add(this.unavailableKeyTtl));
36
- return null;
37
- }
38
- try {
39
- return await CryptographicKey.fromJsonLd(serialized, this.options);
40
- } catch {
41
- try {
42
- return await Multikey.fromJsonLd(serialized, this.options);
43
- } catch {
44
- await this.kv.delete([...this.prefix, keyId.href]);
45
- return;
46
- }
47
- }
48
- }
49
- async set(keyId, key) {
50
- if (key == null) {
51
- this.nullKeys.set(keyId.href, Temporal.Now.instant().add(this.unavailableKeyTtl));
52
- await this.kv.set([...this.prefix, keyId.href], null, { ttl: this.unavailableKeyTtl });
53
- return;
54
- }
55
- this.nullKeys.delete(keyId.href);
56
- const serialized = await key.toJsonLd(this.options);
57
- await this.kv.set([...this.prefix, keyId.href], serialized);
58
- }
59
- async getFetchError(keyId) {
60
- const cached = await this.kv.get(this.#getFetchErrorKey(keyId));
61
- if (cached == null || typeof cached !== "object") return void 0;
62
- if ("status" in cached && typeof cached.status === "number" && "statusText" in cached && typeof cached.statusText === "string" && "headers" in cached && Array.isArray(cached.headers) && "body" in cached && typeof cached.body === "string") return {
63
- status: cached.status,
64
- response: new Response(cached.body, {
65
- status: cached.status,
66
- statusText: cached.statusText,
67
- headers: cached.headers
68
- })
69
- };
70
- else if ("errorName" in cached && typeof cached.errorName === "string" && "errorMessage" in cached && typeof cached.errorMessage === "string") {
71
- const error = new Error(cached.errorMessage);
72
- error.name = cached.errorName;
73
- return { error };
74
- }
75
- }
76
- async setFetchError(keyId, error) {
77
- if (error == null) {
78
- await this.kv.delete(this.#getFetchErrorKey(keyId));
79
- return;
80
- }
81
- if ("status" in error) {
82
- await this.kv.set(this.#getFetchErrorKey(keyId), {
83
- status: error.status,
84
- statusText: error.response.statusText,
85
- headers: Array.from(error.response.headers.entries()),
86
- body: await error.response.clone().text()
87
- }, { ttl: this.unavailableKeyTtl });
88
- return;
89
- }
90
- await this.kv.set(this.#getFetchErrorKey(keyId), {
91
- errorName: error.error.name,
92
- errorMessage: error.error.message
93
- }, { ttl: this.unavailableKeyTtl });
94
- }
95
- };
96
- //#endregion
97
- export { KvKeyCache as t };