@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,1299 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { i as getPortableDid, l as isPortableId } from "./portable-key-id-Ca30-hOa.mjs";
5
+ import { a as verificationObservation, i as triedKey, n as observeCheck, t as observeAttempt } from "./verification-Dpfcw8ml.mjs";
6
+ import { n as version, t as name } from "./deno-oR5aJKpU.mjs";
7
+ import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-CYg9yxBL.mjs";
8
+ import { c as validateCryptoKey, i as fetchKey, t as bypassKeyCacheReads } from "./key-BspPiXqn.mjs";
9
+ import { n as preloadedOnlyDocumentLoader } from "./public-audience--klBIOk1.mjs";
10
+ import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-4IJqPYos.mjs";
11
+ import { c as getNormalizationContextLoader } from "./ld-CzaP-hJl.mjs";
12
+ import { getLogger } from "@logtape/logtape";
13
+ import { Activity, DataIntegrityProof, Multikey, getTypeId } from "@fedify/vocab";
14
+ import { SpanStatusCode, trace } from "@opentelemetry/api";
15
+ import { encodeMultibase, formatIri, fromCompatibleEf61Id, getDocumentLoader, getFe34Origin, parseGatewayUrl, parseIri } from "@fedify/vocab-runtime";
16
+ import { encodeHex } from "byte-encodings/hex";
17
+ import { getPortableActorGateways } from "@fedify/vocab-runtime/internal/jsonld-cache";
18
+ import { isPlainJsonTree, retainSignedRepresentation } from "@fedify/vocab-runtime/internal/signed-representation";
19
+ import jsonld from "@fedify/vocab-runtime/jsonld";
20
+ import serialize from "json-canon";
21
+ //#region src/sig/proof.ts
22
+ /**
23
+ * Known Object Integrity Proof `cryptosuite` values, used to keep
24
+ * `object_integrity_proofs.cryptosuite` on a bounded set of spec-defined
25
+ * string values. Fedify currently signs and verifies only
26
+ * `eddsa-jcs-2022`; other values come in only from external proofs and are
27
+ * dropped from the metric attribute to avoid attacker-controlled
28
+ * cardinality.
29
+ */
30
+ const OIP_KNOWN_CRYPTOSUITES = /* @__PURE__ */ new Set(["eddsa-jcs-2022"]);
31
+ const logger = getLogger([
32
+ "fedify",
33
+ "sig",
34
+ "proof"
35
+ ]);
36
+ const SECURITY_NAMESPACE = "https://w3id.org/security#";
37
+ const SECURITY_PROOF = `${SECURITY_NAMESPACE}proof`;
38
+ const SECURITY_PROOF_VALUE = `${SECURITY_NAMESPACE}proofValue`;
39
+ const DATA_INTEGRITY_PROOF = `${SECURITY_NAMESPACE}DataIntegrityProof`;
40
+ const SECURITY_VERIFICATION_METHOD = `${SECURITY_NAMESPACE}verificationMethod`;
41
+ const SECURITY_EXPIRATION = `${SECURITY_NAMESPACE}expiration`;
42
+ const SECURITY_DOMAIN = `${SECURITY_NAMESPACE}domain`;
43
+ const SECURITY_CHALLENGE = `${SECURITY_NAMESPACE}challenge`;
44
+ const SECURITY_NONCE = `${SECURITY_NAMESPACE}nonce`;
45
+ const SECURITY_PREVIOUS_PROOF = `${SECURITY_NAMESPACE}previousProof`;
46
+ /**
47
+ * Checks if the given JSON-LD document has a DataIntegrityProof-like object,
48
+ * without fully deserializing it into vocabulary classes.
49
+ * @param jsonLd The JSON-LD document to check.
50
+ * @returns `true` if the document has a proof-like object; `false` otherwise.
51
+ * @since 2.2.0
52
+ */
53
+ function hasProofLike(jsonLd) {
54
+ if (typeof jsonLd !== "object" || jsonLd == null) return false;
55
+ const record = jsonLd;
56
+ const proof = record.proof ?? record["https://w3id.org/security#proof"];
57
+ const getField = (source, compact, expanded) => source[compact] ?? source[expanded];
58
+ const isReference = (value) => {
59
+ if (typeof value === "string") return true;
60
+ if (Array.isArray(value)) return value.some(isReference);
61
+ return typeof value === "object" && value != null && ("id" in value && typeof value.id === "string" || "@id" in value && typeof value["@id"] === "string" || "@value" in value && typeof value["@value"] === "string");
62
+ };
63
+ const hasType = (value) => {
64
+ if (typeof value === "string") return value === "DataIntegrityProof" || value === "https://w3id.org/security#DataIntegrityProof";
65
+ if (Array.isArray(value)) return value.some(hasType);
66
+ return false;
67
+ };
68
+ const isProofLike = (value) => {
69
+ if (typeof value !== "object" || value == null) return false;
70
+ const proofRecord = value;
71
+ return hasType(proofRecord.type ?? proofRecord["@type"]) && isReference(getField(proofRecord, "verificationMethod", "https://w3id.org/security#verificationMethod")) && isReference(getField(proofRecord, "proofPurpose", "https://w3id.org/security#proofPurpose")) && isReference(getField(proofRecord, "proofValue", "https://w3id.org/security#proofValue"));
72
+ };
73
+ return Array.isArray(proof) ? proof.some(isProofLike) : isProofLike(proof);
74
+ }
75
+ function isJsonMap(value) {
76
+ return typeof value === "object" && value != null && !Array.isArray(value);
77
+ }
78
+ /**
79
+ * Assembles the secured JSON document from the bytes that were just signed.
80
+ *
81
+ * The document is not re-derived from the vocabulary object: it is
82
+ * `compactMsg`, the value whose JCS form was hashed, with the serialized
83
+ * proof added. Every part of it is then checked against the digests and the
84
+ * signature that {@link createProofInternal} produced, so a document that is
85
+ * returned verifies under the map-local compound-proof profile by
86
+ * construction. Anything that does not check out yields `null`, and the
87
+ * caller simply does not retain a representation.
88
+ */
89
+ async function captureSecuredDocument(proof, compactMsg, msgCanon, proofCanon, proofValue, contextLoader) {
90
+ if (!isJsonMap(compactMsg)) return null;
91
+ const documentContext = compactMsg["@context"];
92
+ if (documentContext == null) return null;
93
+ if (globalThis.Object.hasOwn(compactMsg, "proof")) return null;
94
+ try {
95
+ const proofJson = await proof.toJsonLd({
96
+ format: "compact",
97
+ contextLoader,
98
+ context: documentContext
99
+ });
100
+ if (!isJsonMap(proofJson)) return null;
101
+ const { proofValue: serializedProofValue, ...proofConfiguration } = proofJson;
102
+ if (serializedProofValue !== proofValue) return null;
103
+ if (serialize(proofConfiguration) !== proofCanon) return null;
104
+ const securedDocument = {
105
+ ...structuredClone(compactMsg),
106
+ proof: structuredClone(proofJson)
107
+ };
108
+ const { proof: _embeddedProof, ...unsecuredDocument } = securedDocument;
109
+ if (serialize(unsecuredDocument) !== msgCanon) return null;
110
+ if (!isPlainJsonTree(securedDocument)) return null;
111
+ return securedDocument;
112
+ } catch (error) {
113
+ logger.debug("Failed to capture the secured JSON document for a created proof; the signed object will not preserve its representation when it is embedded in another object.\n{error}", { error });
114
+ return null;
115
+ }
116
+ }
117
+ async function createProofInternal(object, privateKey, keyId, { contextLoader, context, created } = {}, capture = false) {
118
+ validateCryptoKey(privateKey, "private");
119
+ if (privateKey.algorithm.name !== "Ed25519") throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name);
120
+ let compactMsg = await object.clone({ proofs: [] }).toJsonLd({
121
+ format: "compact",
122
+ contextLoader,
123
+ context
124
+ });
125
+ compactMsg = await normalizeOutgoingActivityJsonLd(compactMsg, contextLoader, { preserveNestedSecuredDocuments: true });
126
+ const msgCanon = serialize(compactMsg);
127
+ const encoder = new TextEncoder();
128
+ const msgBytes = encoder.encode(msgCanon);
129
+ const msgDigest = await crypto.subtle.digest("SHA-256", msgBytes);
130
+ created ??= Temporal.Now.instant();
131
+ const proofCanon = serialize({
132
+ "@context": compactMsg["@context"],
133
+ type: "DataIntegrityProof",
134
+ cryptosuite: "eddsa-jcs-2022",
135
+ verificationMethod: keyId.href,
136
+ proofPurpose: "assertionMethod",
137
+ created: created.toString()
138
+ });
139
+ const proofBytes = encoder.encode(proofCanon);
140
+ const proofDigest = await crypto.subtle.digest("SHA-256", proofBytes);
141
+ const digest = new Uint8Array(proofDigest.byteLength + msgDigest.byteLength);
142
+ digest.set(new Uint8Array(proofDigest), 0);
143
+ digest.set(new Uint8Array(msgDigest), proofDigest.byteLength);
144
+ const sig = new Uint8Array(await crypto.subtle.sign("Ed25519", privateKey, digest));
145
+ const proof = new DataIntegrityProof({
146
+ cryptosuite: "eddsa-jcs-2022",
147
+ verificationMethod: keyId,
148
+ proofPurpose: "assertionMethod",
149
+ created,
150
+ proofValue: sig
151
+ });
152
+ return {
153
+ proof,
154
+ securedDocument: capture ? await captureSecuredDocument(proof, compactMsg, msgCanon, proofCanon, new TextDecoder().decode(encodeMultibase("base58btc", sig)), contextLoader) : null
155
+ };
156
+ }
157
+ /**
158
+ * Creates a proof for the given object.
159
+ * @param object The object to create a proof for.
160
+ * @param privateKey The private key to sign the proof with.
161
+ * @param keyId The key ID to use in the proof. It will be used by the verifier.
162
+ * @param options Additional options. See also {@link CreateProofOptions}.
163
+ * @returns The created proof.
164
+ * @throws {TypeError} If the private key is invalid or unsupported.
165
+ * @since 0.10.0
166
+ */
167
+ async function createProof(object, privateKey, keyId, options = {}) {
168
+ const { proof } = await createProofInternal(object, privateKey, keyId, options);
169
+ return proof;
170
+ }
171
+ /**
172
+ * Signs the given object with the private key and returns the signed object.
173
+ * @param object The object to create a proof for.
174
+ * @param privateKey The private key to sign the proof with.
175
+ * @param keyId The key ID to use in the proof. It will be used by the verifier.
176
+ * @param options Additional options. See also {@link SignObjectOptions}.
177
+ * @returns The signed object.
178
+ * @throws {TypeError} If the private key is invalid or unsupported.
179
+ * @since 0.10.0
180
+ */
181
+ async function signObject(object, privateKey, keyId, options = {}) {
182
+ return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("object_integrity_proofs.sign", { attributes: { "activitypub.object.type": getTypeId(object).href } }, async (span) => {
183
+ try {
184
+ if (object.id != null) span.setAttribute("activitypub.object.id", object.id.href);
185
+ const existingProofs = [];
186
+ for await (const proof of object.getProofs(options)) existingProofs.push(proof);
187
+ const { proof, securedDocument } = await createProofInternal(object, privateKey, keyId, options, existingProofs.length < 1);
188
+ if (span.isRecording()) {
189
+ if (proof.cryptosuite != null) span.setAttribute("object_integrity_proofs.cryptosuite", proof.cryptosuite);
190
+ if (proof.verificationMethodId != null) span.setAttribute("object_integrity_proofs.key_id", proof.verificationMethodId.href);
191
+ if (proof.proofValue != null) span.setAttribute("object_integrity_proofs.signature", encodeHex(proof.proofValue));
192
+ }
193
+ const signed = object.clone({ proofs: [...existingProofs, proof] });
194
+ if (securedDocument != null) retainSignedRepresentation(signed, securedDocument);
195
+ else if (existingProofs.length > 0) logger.debug("The object {objectId} already had {proofCount} proof(s), so its signed representation is not retained for embedding; the map-local compound-proof profile accepts exactly one direct proof per map.", {
196
+ objectId: object.id?.href,
197
+ proofCount: existingProofs.length
198
+ });
199
+ return signed;
200
+ } catch (error) {
201
+ span.setStatus({
202
+ code: SpanStatusCode.ERROR,
203
+ message: String(error)
204
+ });
205
+ throw error;
206
+ } finally {
207
+ span.end();
208
+ }
209
+ });
210
+ }
211
+ /**
212
+ * Verifies the given proof for the object.
213
+ * @param jsonLd The JSON-LD object to verify the proof for. Its proof
214
+ * properties are excluded from the message, but matching proof
215
+ * occurrences are used to authenticate the received proof
216
+ * configuration.
217
+ * @param proof The proof to verify.
218
+ * @param options Additional options. See also {@link VerifyProofOptions}.
219
+ * @returns The public key that was used to sign the proof, or `null` if the
220
+ * proof is invalid.
221
+ * @since 0.10.0
222
+ * @since 2.4.0 Matching proof configurations are authenticated.
223
+ */
224
+ async function verifyProof(jsonLd, proof, options = {}) {
225
+ return await verifyProofWithMessageDigestCache(jsonLd, proof, options);
226
+ }
227
+ /**
228
+ * Verifies the one direct literal proof on a map-local secured document.
229
+ *
230
+ * Unlike {@link verifyProof}, this removes only the literal `proof` member
231
+ * from the message digest. JSON-LD aliases remain part of the signed input,
232
+ * and the document's received `@context` is not replaced by the proof
233
+ * configuration context.
234
+ *
235
+ * @internal
236
+ */
237
+ async function verifyMapLocalProof(jsonLd, options = {}) {
238
+ if (!isJsonLdNode(jsonLd) || !globalThis.Object.hasOwn(jsonLd, "proof") || !isJsonLdNode(jsonLd.proof)) return null;
239
+ const rawProof = jsonLd.proof;
240
+ const previousChecks = options[verificationObservation]?.attempt?.checks.length;
241
+ const malformed = () => observeCheck(options, {
242
+ mechanism: "objectIntegrity",
243
+ proofId: typeof rawProof.id === "string" ? rawProof.id : typeof rawProof["@id"] === "string" ? rawProof["@id"] : null,
244
+ proofIndex: previousChecks ?? null
245
+ }, getDeclaredProofKeyId(rawProof), () => Promise.resolve(null));
246
+ const proofContextLoader = getNormalizationContextLoader(preloadedOnlyDocumentLoader);
247
+ try {
248
+ const [candidate] = await parseRawProofCandidates(jsonLd, [jsonLd.proof], options, proofContextLoader);
249
+ if (candidate.proof == null) return await malformed();
250
+ return await verifyProofWithMessageDigestCache(jsonLd, candidate.proof, options, {
251
+ proofContextLoader,
252
+ proofPropertyMode: "literal"
253
+ }, candidate);
254
+ } catch {
255
+ if (previousChecks != null && options[verificationObservation]?.attempt?.checks.length === previousChecks) return await malformed();
256
+ return null;
257
+ }
258
+ }
259
+ function getDeclaredProofKeyId(value, propertyNames = ["verificationMethod", "https://w3id.org/security#verificationMethod"]) {
260
+ if (!isJsonLdNode(value)) return null;
261
+ const method = Array.from(propertyNames, (name) => value[name]).find((v) => v != null);
262
+ const candidate = Array.isArray(method) ? method[0] : method;
263
+ if (typeof candidate === "string") return candidate;
264
+ return isJsonLdNode(candidate) && typeof candidate["@id"] === "string" ? candidate["@id"] : null;
265
+ }
266
+ async function verifyProofWithMessageDigestCache(jsonLd, proof, options, messageDigestCache = {}, rawProofCandidate, keyIdBoundByCaller = false) {
267
+ if (options[verificationObservation] == null) return await verifyProofWithMessageDigestCache(jsonLd, proof, {
268
+ ...options,
269
+ [verificationObservation]: {
270
+ attempts: [],
271
+ attempt: { checks: [] },
272
+ captureRawKeyIds: false
273
+ }
274
+ }, messageDigestCache, rawProofCandidate, keyIdBoundByCaller);
275
+ if (options[verificationObservation]?.attempt != null && options[verificationObservation]?.check == null) return await observeCheck(options, {
276
+ mechanism: "objectIntegrity",
277
+ proofId: proof.id?.href ?? null,
278
+ proofIndex: options[verificationObservation].attempt.checks.length
279
+ }, rawProofCandidate?.declaredKeyId ?? getDeclaredProofKeyId(rawProofCandidate?.value) ?? proof.verificationMethodId?.href ?? null, (observation) => verifyProofWithMessageDigestCache(jsonLd, proof, {
280
+ ...options,
281
+ [verificationObservation]: observation
282
+ }, messageDigestCache, rawProofCandidate, keyIdBoundByCaller));
283
+ return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("object_integrity_proofs.verify", async (span) => {
284
+ const start = performance.now();
285
+ let verified = false;
286
+ let threw = false;
287
+ const cryptosuite = proof.cryptosuite != null && OIP_KNOWN_CRYPTOSUITES.has(proof.cryptosuite) ? proof.cryptosuite : void 0;
288
+ if (span.isRecording()) {
289
+ if (proof.cryptosuite != null) span.setAttribute("object_integrity_proofs.cryptosuite", proof.cryptosuite);
290
+ if (proof.verificationMethodId != null) span.setAttribute("object_integrity_proofs.key_id", proof.verificationMethodId.href);
291
+ if (proof.proofValue != null) span.setAttribute("object_integrity_proofs.signature", encodeHex(proof.proofValue));
292
+ }
293
+ try {
294
+ const key = await verifyProofInternal(jsonLd, proof, options, messageDigestCache, rawProofCandidate, keyIdBoundByCaller);
295
+ if (key == null) {
296
+ span.setStatus({ code: SpanStatusCode.ERROR });
297
+ span.setAttribute("activitypub.verification.failure_reason", options[verificationObservation]?.check?.reason?.type ?? "invalidSignature");
298
+ } else verified = true;
299
+ return key;
300
+ } catch (error) {
301
+ threw = true;
302
+ span.setStatus({
303
+ code: SpanStatusCode.ERROR,
304
+ message: String(error)
305
+ });
306
+ throw error;
307
+ } finally {
308
+ const classified = threw ? "error" : verified ? "verified" : "rejected";
309
+ getFederationMetrics(options.meterProvider).recordSignatureVerificationDuration(getDurationMs(start), "object_integrity", classified, {
310
+ cryptosuite,
311
+ verificationFailureReason: verified || threw ? void 0 : options[verificationObservation]?.check?.reason?.type ?? "invalidSignature"
312
+ });
313
+ span.end();
314
+ }
315
+ });
316
+ }
317
+ function expandContextPropertyIri(activeContext, key) {
318
+ const termId = jsonld.getContextValue(activeContext, key, "@id");
319
+ if (termId != null) return termId;
320
+ const colon = key.indexOf(":");
321
+ if (colon < 1) return key;
322
+ const prefix = key.substring(0, colon);
323
+ const suffix = key.substring(colon + 1);
324
+ if (prefix === "_" || suffix.startsWith("//")) return key;
325
+ const mapping = jsonld.getContextValue(activeContext, prefix);
326
+ if (typeof mapping === "object" && mapping != null && mapping._prefix === true && typeof mapping["@id"] === "string") return mapping["@id"] + suffix;
327
+ return key;
328
+ }
329
+ async function getJsonLdPropertyNames(jsonLd, propertyIri, defaults, documentLoader = preloadedOnlyDocumentLoader, inheritedContext, rejectOnContextError = false, contextState) {
330
+ const names = new Set(defaults);
331
+ const context = jsonLd["@context"] ?? inheritedContext;
332
+ if (context == null && contextState?.initial == null) return names;
333
+ try {
334
+ const options = { documentLoader };
335
+ let activeContext = contextState?.initial ?? await jsonld.processContext(null, null, options);
336
+ if (contextState?.scoped != null) activeContext = await jsonld.processContext(activeContext, contextState.scoped, options);
337
+ if (context != null) activeContext = await jsonld.processContext(activeContext, context, options);
338
+ const typeScopedContext = activeContext;
339
+ for (const key of globalThis.Object.keys(jsonLd).sort()) {
340
+ if (key !== "@type" && expandContextPropertyIri(activeContext, key) !== "@type") continue;
341
+ const value = jsonLd[key];
342
+ const types = Array.isArray(value) ? value.slice().sort() : [value];
343
+ for (const type of types) {
344
+ if (typeof type !== "string") continue;
345
+ const scopedContext = jsonld.getContextValue(typeScopedContext, type, "@context");
346
+ if (scopedContext != null) activeContext = await jsonld.processContext(activeContext, scopedContext, options);
347
+ }
348
+ }
349
+ if (contextState != null) contextState.active = activeContext;
350
+ for (const key of globalThis.Object.keys(jsonLd)) if (expandContextPropertyIri(activeContext, key) === propertyIri) names.add(key);
351
+ } catch {
352
+ if (rejectOnContextError) return null;
353
+ }
354
+ return names;
355
+ }
356
+ async function getProofPropertyNames(jsonLd, documentLoader = preloadedOnlyDocumentLoader) {
357
+ return await getJsonLdPropertyNames(jsonLd, SECURITY_PROOF, ["proof", SECURITY_PROOF], documentLoader) ?? /* @__PURE__ */ new Set(["proof", SECURITY_PROOF]);
358
+ }
359
+ async function createProofMessageDigests(jsonLd, proofContextLoader, context, proofPropertyMode = "jsonLd") {
360
+ const msg = { ...jsonLd };
361
+ if (proofPropertyMode === "literal") delete msg.proof;
362
+ else for (const property of await getProofPropertyNames(msg, proofContextLoader)) delete msg[property];
363
+ if (proofPropertyMode === "jsonLd" && context != null) msg["@context"] = structuredClone(context);
364
+ const encoder = new TextEncoder();
365
+ const digest = async (value) => {
366
+ const bytes = encoder.encode(serialize(value));
367
+ return await crypto.subtle.digest("SHA-256", bytes);
368
+ };
369
+ const onWire = await digest(msg);
370
+ let normalizedPromise;
371
+ return {
372
+ onWire,
373
+ normalized() {
374
+ normalizedPromise ??= (async () => {
375
+ const normalized = await normalizeOutgoingActivityJsonLd(msg, preloadedOnlyDocumentLoader);
376
+ return normalized === msg ? null : await digest(normalized);
377
+ })();
378
+ return normalizedPromise;
379
+ }
380
+ };
381
+ }
382
+ function contextValues(context) {
383
+ return Array.isArray(context) ? context : [context];
384
+ }
385
+ function equalJsonValues(left, right) {
386
+ try {
387
+ return serialize(left) === serialize(right);
388
+ } catch {
389
+ return false;
390
+ }
391
+ }
392
+ function contextStartsWith(documentContext, proofContext) {
393
+ if (documentContext == null) return false;
394
+ const documentValues = contextValues(documentContext);
395
+ const proofValues = contextValues(proofContext);
396
+ return proofValues.length <= documentValues.length && proofValues.every((value, index) => equalJsonValues(value, documentValues[index]));
397
+ }
398
+ function appendProofValues(values, value) {
399
+ if (Array.isArray(value)) for (const item of value) appendProofValues(values, item);
400
+ else if (isJsonLdNode(value) && Array.isArray(value["@graph"])) for (const item of value["@graph"]) appendProofValues(values, item);
401
+ else values.push(value);
402
+ }
403
+ async function getRawProofValues(jsonLd, documentLoader) {
404
+ const propertyNames = await getProofPropertyNames(jsonLd, documentLoader);
405
+ const values = [];
406
+ for (const [property, value] of globalThis.Object.entries(jsonLd)) if (propertyNames.has(property)) appendProofValues(values, value);
407
+ return values;
408
+ }
409
+ function sameBytes(left, right) {
410
+ if (left == null || right == null) return left === right;
411
+ return left.length === right.length && left.every((value, index) => value === right[index]);
412
+ }
413
+ function sameProof(left, right) {
414
+ return left.cryptosuite === right.cryptosuite && left.verificationMethodId?.href === right.verificationMethodId?.href && left.proofPurpose === right.proofPurpose && sameBytes(left.proofValue, right.proofValue) && left.created?.toString() === right.created?.toString();
415
+ }
416
+ function recordProofContexts(documentLoader) {
417
+ const documents = /* @__PURE__ */ new Map();
418
+ return {
419
+ loader: async (url, options) => {
420
+ const document = await documentLoader(url, options);
421
+ documents.set(url, document);
422
+ return document;
423
+ },
424
+ replay: (url, options) => {
425
+ const document = documents.get(url);
426
+ return document == null ? preloadedOnlyDocumentLoader(url, options) : Promise.resolve(document);
427
+ }
428
+ };
429
+ }
430
+ async function getAliasedDeclaredProofKeyId(value, inheritedContext, contextLoader) {
431
+ if (!isJsonLdNode(value)) return null;
432
+ const contextState = {};
433
+ const names = await getJsonLdPropertyNames(value, "https://w3id.org/security#verificationMethod", ["verificationMethod", "https://w3id.org/security#verificationMethod"], contextLoader, inheritedContext, false, contextState);
434
+ const methodName = Array.from(names ?? []).find((name) => value[name] != null);
435
+ const method = methodName == null ? void 0 : value[methodName];
436
+ const candidate = Array.isArray(method) ? method[0] : method;
437
+ if (typeof candidate === "string") return candidate;
438
+ if (!isJsonLdNode(candidate)) return null;
439
+ const idNames = await getJsonLdPropertyNames(candidate, "@id", ["@id"], contextLoader, void 0, false, {
440
+ initial: contextState.active,
441
+ scoped: contextState.active == null || methodName == null ? void 0 : jsonld.getContextValue(contextState.active, methodName, "@context")
442
+ });
443
+ for (const name of idNames ?? []) if (typeof candidate[name] === "string") return candidate[name];
444
+ return null;
445
+ }
446
+ function normalizeDocumentUrl(url) {
447
+ try {
448
+ return formatIri(parseIri(url));
449
+ } catch {
450
+ return URL.canParse(url) ? new URL(url).href : url;
451
+ }
452
+ }
453
+ function getRawProofReference(value) {
454
+ const node = Array.isArray(value) && value.length === 1 ? value[0] : value;
455
+ if (typeof node === "string") return normalizeDocumentUrl(node);
456
+ if (!isJsonLdNode(node)) return void 0;
457
+ const id = node["@id"] ?? node.id;
458
+ return typeof id === "string" ? normalizeDocumentUrl(id) : void 0;
459
+ }
460
+ async function parseRawProofCandidates(jsonLd, values, options, documentLoader) {
461
+ const candidates = [];
462
+ for (const value of values) {
463
+ let parsed = null;
464
+ const contexts = options[verificationObservation] != null && options[verificationObservation]?.captureRawKeyIds !== false ? recordProofContexts(documentLoader) : void 0;
465
+ if (isJsonLdNode(value)) {
466
+ const proofJsonLd = value["@context"] == null && jsonLd["@context"] != null ? {
467
+ "@context": jsonLd["@context"],
468
+ ...value
469
+ } : value;
470
+ try {
471
+ parsed = await DataIntegrityProof.fromJsonLd(proofJsonLd, {
472
+ ...options,
473
+ contextLoader: contexts?.loader ?? documentLoader
474
+ });
475
+ } catch {}
476
+ }
477
+ candidates.push({
478
+ value,
479
+ proof: parsed,
480
+ reference: getRawProofReference(value) ?? parsed?.id?.href,
481
+ declaredKeyId: contexts == null ? void 0 : await getAliasedDeclaredProofKeyId(value, jsonLd["@context"], contexts.replay)
482
+ });
483
+ }
484
+ return candidates;
485
+ }
486
+ async function findRawProofCandidate(jsonLd, proof, options, documentLoader) {
487
+ const candidates = await parseRawProofCandidates(jsonLd, await getRawProofValues(jsonLd, documentLoader), options, documentLoader);
488
+ const matches = [];
489
+ for (const candidate of candidates) if (candidate.proof != null && sameProof(candidate.proof, proof)) matches.push(candidate);
490
+ if (matches.length < 1) return void 0;
491
+ const first = matches[0];
492
+ const configurations = await Promise.all(matches.map((candidate) => normalizeProofConfiguration(candidate.value, jsonLd["@context"], documentLoader)));
493
+ const firstConfiguration = configurations[0];
494
+ return firstConfiguration != null && configurations.every((configuration) => configuration != null && equalJsonValues(configuration.value, firstConfiguration.value)) ? first : null;
495
+ }
496
+ function takeRawProofCandidate(pool, proof) {
497
+ for (let index = 0; index < pool.candidates.length; index++) {
498
+ if (pool.used.has(index)) continue;
499
+ const candidate = pool.candidates[index];
500
+ if (candidate.proof != null && sameProof(candidate.proof, proof)) {
501
+ pool.used.add(index);
502
+ return candidate;
503
+ }
504
+ }
505
+ }
506
+ const STANDARD_COMPACT_PROOF_PROPERTIES = /* @__PURE__ */ new Set([
507
+ "@context",
508
+ "type",
509
+ "cryptosuite",
510
+ "verificationMethod",
511
+ "proofPurpose",
512
+ "proofValue",
513
+ "created"
514
+ ]);
515
+ const STANDARD_EXPANDED_PROOF_PROPERTIES = /* @__PURE__ */ new Set([
516
+ "@context",
517
+ "@type",
518
+ `${SECURITY_NAMESPACE}cryptosuite`,
519
+ SECURITY_VERIFICATION_METHOD,
520
+ `${SECURITY_NAMESPACE}proofPurpose`,
521
+ `${SECURITY_NAMESPACE}proofValue`,
522
+ "http://purl.org/dc/terms/created"
523
+ ]);
524
+ function hasAdditionalProofOptions(value) {
525
+ const node = Array.isArray(value) && value.length === 1 ? value[0] : value;
526
+ return isJsonLdNode(node) && globalThis.Object.keys(node).some((property) => !STANDARD_COMPACT_PROOF_PROPERTIES.has(property) && !STANDARD_EXPANDED_PROOF_PROPERTIES.has(property));
527
+ }
528
+ function isExpandedJsonLdNode(value) {
529
+ const properties = globalThis.Object.keys(value).filter((key) => !key.startsWith("@"));
530
+ return properties.length > 0 && properties.every((property) => URL.canParse(property));
531
+ }
532
+ async function normalizeProofConfiguration(rawProof, documentContext, documentLoader) {
533
+ let node = Array.isArray(rawProof) && rawProof.length === 1 ? rawProof[0] : rawProof;
534
+ if (!isJsonLdNode(node)) return null;
535
+ if (isExpandedJsonLdNode(node)) {
536
+ if (documentContext == null) return null;
537
+ node = await jsonld.compact(node, documentContext, { documentLoader });
538
+ if (!isJsonLdNode(node)) return null;
539
+ } else node = structuredClone(node);
540
+ const receivedContext = node["@context"];
541
+ if (receivedContext != null && !contextStartsWith(documentContext, receivedContext)) return null;
542
+ const context = receivedContext ?? documentContext;
543
+ if (context != null) node["@context"] = structuredClone(context);
544
+ const proofValueProperties = await getJsonLdPropertyNames(node, SECURITY_PROOF_VALUE, ["proofValue", SECURITY_PROOF_VALUE], documentLoader, context) ?? /* @__PURE__ */ new Set(["proofValue", SECURITY_PROOF_VALUE]);
545
+ for (const property of proofValueProperties) delete node[property];
546
+ return {
547
+ value: node,
548
+ context
549
+ };
550
+ }
551
+ async function createProofConfiguration(jsonLd, proof, options, documentLoader, rawProofCandidate) {
552
+ let rawProof;
553
+ if (rawProofCandidate == null) {
554
+ const match = await findRawProofCandidate(jsonLd, proof, options, documentLoader);
555
+ if (match === null) return null;
556
+ rawProof = match?.value;
557
+ } else rawProof = rawProofCandidate.value;
558
+ if (rawProof == null) {
559
+ const serializedProof = await proof.toJsonLd();
560
+ if (hasAdditionalProofOptions(serializedProof)) rawProof = serializedProof;
561
+ }
562
+ if (rawProof != null) return await normalizeProofConfiguration(rawProof, jsonLd["@context"], documentLoader);
563
+ const context = jsonLd["@context"];
564
+ return {
565
+ value: {
566
+ ...context == null ? {} : { "@context": context },
567
+ type: "DataIntegrityProof",
568
+ cryptosuite: proof.cryptosuite,
569
+ verificationMethod: proof.verificationMethodId.href,
570
+ proofPurpose: proof.proofPurpose,
571
+ created: proof.created.toString()
572
+ },
573
+ context
574
+ };
575
+ }
576
+ const KNOWN_PROOF_CONFIGURATION_PROPERTIES = /* @__PURE__ */ new Set([
577
+ "@context",
578
+ "@id",
579
+ "@type",
580
+ "id",
581
+ "type",
582
+ "cryptosuite",
583
+ `${SECURITY_NAMESPACE}cryptosuite`,
584
+ "verificationMethod",
585
+ SECURITY_VERIFICATION_METHOD,
586
+ "proofPurpose",
587
+ `${SECURITY_NAMESPACE}proofPurpose`,
588
+ "created",
589
+ "http://purl.org/dc/terms/created",
590
+ "expires",
591
+ SECURITY_EXPIRATION,
592
+ "domain",
593
+ SECURITY_DOMAIN,
594
+ "challenge",
595
+ SECURITY_CHALLENGE,
596
+ "nonce",
597
+ SECURITY_NONCE,
598
+ "previousProof",
599
+ SECURITY_PREVIOUS_PROOF
600
+ ]);
601
+ async function getProofOption(proofConfig, propertyIri, defaults, documentLoader) {
602
+ let names = await getJsonLdPropertyNames(proofConfig, propertyIri, defaults, documentLoader, proofConfig["@context"], true);
603
+ if (names == null) {
604
+ if (globalThis.Object.keys(proofConfig).some((property) => !KNOWN_PROOF_CONFIGURATION_PROPERTIES.has(property))) return null;
605
+ names = new Set(defaults);
606
+ }
607
+ const present = globalThis.Object.keys(proofConfig).filter((property) => names.has(property));
608
+ if (present.length > 1) return null;
609
+ return present.length < 1 ? { present: false } : {
610
+ present: true,
611
+ value: proofConfig[present[0]]
612
+ };
613
+ }
614
+ function parseStringSet(value) {
615
+ if (typeof value === "string") return /* @__PURE__ */ new Set([value]);
616
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) return null;
617
+ return new Set(value);
618
+ }
619
+ function equalStringSets(left, right) {
620
+ return left.size === right.size && [...left].every((value) => right.has(value));
621
+ }
622
+ async function hasValidProofOptions(proofConfig, options, documentLoader) {
623
+ const expires = await getProofOption(proofConfig, SECURITY_EXPIRATION, ["expires", SECURITY_EXPIRATION], documentLoader);
624
+ if (expires == null) return null;
625
+ let expiration;
626
+ if (expires.present) {
627
+ if (typeof expires.value !== "string") return null;
628
+ try {
629
+ expiration = Temporal.Instant.from(expires.value);
630
+ } catch {
631
+ return null;
632
+ }
633
+ if (Temporal.Instant.compare(Temporal.Now.instant(), expiration) >= 0) return null;
634
+ }
635
+ const domain = await getProofOption(proofConfig, SECURITY_DOMAIN, ["domain", SECURITY_DOMAIN], documentLoader);
636
+ if (domain == null) return null;
637
+ const proofDomains = domain.present ? parseStringSet(domain.value) : null;
638
+ if (domain.present && proofDomains == null) return null;
639
+ if (options.domain != null) {
640
+ const expectedDomains = parseStringSet(options.domain);
641
+ if (expectedDomains == null || proofDomains == null || !equalStringSets(proofDomains, expectedDomains)) return null;
642
+ }
643
+ const challenge = await getProofOption(proofConfig, SECURITY_CHALLENGE, ["challenge", SECURITY_CHALLENGE], documentLoader);
644
+ if (challenge == null || challenge.present && typeof challenge.value !== "string" || options.challenge != null && (!challenge.present || challenge.value !== options.challenge)) return null;
645
+ const nonce = await getProofOption(proofConfig, SECURITY_NONCE, ["nonce", SECURITY_NONCE], documentLoader);
646
+ if (nonce == null || nonce.present && typeof nonce.value !== "string") return null;
647
+ const previousProof = await getProofOption(proofConfig, SECURITY_PREVIOUS_PROOF, ["previousProof", SECURITY_PREVIOUS_PROOF], documentLoader);
648
+ if (previousProof == null || previousProof.present && typeof previousProof.value !== "string" && (!Array.isArray(previousProof.value) || previousProof.value.some((item) => typeof item !== "string"))) return null;
649
+ return { expires: expiration };
650
+ }
651
+ async function verifyProofInternal(jsonLd, proof, options, messageDigestCache, rawProofCandidate, keyIdBoundByCaller = false) {
652
+ if (!isJsonLdNode(jsonLd) || proof.cryptosuite !== "eddsa-jcs-2022" || proof.verificationMethodId == null || proof.proofPurpose !== "assertionMethod" || proof.proofValue == null || proof.created == null) return null;
653
+ const proofContextLoader = messageDigestCache.proofContextLoader ?? preloadedOnlyDocumentLoader;
654
+ const proofConfiguration = await createProofConfiguration(jsonLd, proof, options, proofContextLoader, rawProofCandidate);
655
+ if (proofConfiguration == null) return null;
656
+ const validProofOptions = await hasValidProofOptions(proofConfiguration.value, options, proofContextLoader);
657
+ if (validProofOptions == null) return null;
658
+ const { expires } = validProofOptions;
659
+ if (expires != null && (messageDigestCache.expires == null || Temporal.Instant.compare(expires, messageDigestCache.expires) < 0)) messageDigestCache.expires = expires;
660
+ const publicKeyPromise = measureSignatureKeyFetch(options.meterProvider, "object_integrity", () => fetchKey(proof.verificationMethodId, Multikey, {
661
+ ...options,
662
+ keyIdBoundByCaller
663
+ }));
664
+ const proofBytes = new TextEncoder().encode(serialize(proofConfiguration.value));
665
+ const proofDigest = await crypto.subtle.digest("SHA-256", proofBytes);
666
+ let fetchedKey;
667
+ try {
668
+ fetchedKey = await publicKeyPromise;
669
+ } catch (error) {
670
+ logger.debug("Failed to get the key (verificationMethod) for the proof:\n{proof}", {
671
+ proof,
672
+ keyId: proof.verificationMethodId.href,
673
+ error
674
+ });
675
+ return null;
676
+ }
677
+ const publicKey = fetchedKey.key;
678
+ if (publicKey == null) {
679
+ logger.debug("Failed to get the key (verificationMethod) for the proof:\n{proof}", {
680
+ proof,
681
+ keyId: proof.verificationMethodId.href
682
+ });
683
+ return null;
684
+ }
685
+ if (publicKey.publicKey.algorithm.name !== "Ed25519") {
686
+ if (fetchedKey.cached) {
687
+ logger.debug("The cached key (verificationMethod) for the proof is not a valid Ed25519 key:\n{keyId}; retrying with the freshly fetched key...", {
688
+ proof,
689
+ keyId: proof.verificationMethodId.href
690
+ });
691
+ return await verifyProofInternal(jsonLd, proof, {
692
+ ...options,
693
+ keyCache: bypassKeyCacheReads(options.keyCache)
694
+ }, messageDigestCache, rawProofCandidate, keyIdBoundByCaller);
695
+ }
696
+ logger.debug("The fetched key (verificationMethod) for the proof is not a valid Ed25519 key:\n{keyId}", {
697
+ proof,
698
+ keyId: proof.verificationMethodId.href
699
+ });
700
+ return null;
701
+ }
702
+ const digest = new Uint8Array(proofDigest.byteLength + 32);
703
+ digest.set(new Uint8Array(proofDigest), 0);
704
+ const proofValue = proof.proofValue;
705
+ let keyTried = false;
706
+ const verifyCandidate = async (msgDigest) => {
707
+ digest.set(new Uint8Array(msgDigest), proofDigest.byteLength);
708
+ if (!keyTried) {
709
+ triedKey(options, publicKey);
710
+ keyTried = true;
711
+ }
712
+ return await crypto.subtle.verify("Ed25519", publicKey.publicKey, proofValue.slice(), digest);
713
+ };
714
+ const messageDigestKey = serialize(proofConfiguration.context ?? null);
715
+ const messageDigestValues = messageDigestCache.values ??= /* @__PURE__ */ new Map();
716
+ let messageDigestsPromise = messageDigestValues.get(messageDigestKey);
717
+ if (messageDigestsPromise == null) {
718
+ messageDigestsPromise = createProofMessageDigests(jsonLd, messageDigestCache.proofContextLoader, proofConfiguration.context, messageDigestCache.proofPropertyMode);
719
+ messageDigestValues.set(messageDigestKey, messageDigestsPromise);
720
+ }
721
+ const messageDigests = await messageDigestsPromise;
722
+ if (await verifyCandidate(messageDigests.onWire)) return publicKey;
723
+ if (messageDigestCache.proofPropertyMode !== "literal") {
724
+ const normalizedDigest = await messageDigests.normalized();
725
+ if (normalizedDigest != null && await verifyCandidate(normalizedDigest)) return publicKey;
726
+ }
727
+ if (fetchedKey.cached) {
728
+ logger.debug("Failed to verify the proof with the cached key {keyId}; retrying with the freshly fetched key...", {
729
+ keyId: proof.verificationMethodId.href,
730
+ proof
731
+ });
732
+ return await verifyProofInternal(jsonLd, proof, {
733
+ ...options,
734
+ keyCache: bypassKeyCacheReads(options.keyCache)
735
+ }, messageDigestCache, rawProofCandidate, keyIdBoundByCaller);
736
+ }
737
+ logger.debug("Failed to verify the proof with the fetched key {keyId}:\n{proof}", {
738
+ keyId: proof.verificationMethodId.href,
739
+ proof
740
+ });
741
+ return null;
742
+ }
743
+ const AS_NAMESPACE = "https://www.w3.org/ns/activitystreams#";
744
+ const FEP_2277_ACTOR_PROPERTIES = ["http://www.w3.org/ns/ldp#inbox", `${AS_NAMESPACE}outbox`];
745
+ const FEP_2277_COLLECTION_PROPERTIES = [
746
+ "items",
747
+ "orderedItems",
748
+ "totalItems",
749
+ "partOf",
750
+ "first",
751
+ "last",
752
+ "next",
753
+ "prev",
754
+ "current"
755
+ ].map((property) => AS_NAMESPACE + property);
756
+ const PORTABLE_OBJECT_ID_PATTERN = /^ap(?:\+ef61)?:\/\//i;
757
+ const FUNCTIONAL_PROOF_PROPERTIES = [
758
+ `${SECURITY_NAMESPACE}cryptosuite`,
759
+ SECURITY_VERIFICATION_METHOD,
760
+ `${SECURITY_NAMESPACE}proofPurpose`,
761
+ `${SECURITY_NAMESPACE}proofValue`,
762
+ "http://purl.org/dc/terms/created"
763
+ ];
764
+ function isJsonLdNode(value) {
765
+ return typeof value === "object" && value != null && !Array.isArray(value);
766
+ }
767
+ function hasValidPortableProofShape(proofValue) {
768
+ if (!isJsonLdNode(proofValue)) return false;
769
+ let proofNode = proofValue;
770
+ if ("@graph" in proofNode) {
771
+ const graph = proofNode["@graph"];
772
+ if (!Array.isArray(graph) || graph.length !== 1 || !isJsonLdNode(graph[0])) return false;
773
+ proofNode = graph[0];
774
+ }
775
+ const types = proofNode["@type"];
776
+ return Array.isArray(types) && types.length === 1 && types[0] === DATA_INTEGRITY_PROOF && FUNCTIONAL_PROOF_PROPERTIES.every((property) => {
777
+ const values = proofNode[property];
778
+ return Array.isArray(values) && values.length === 1 && !(isJsonLdNode(values[0]) && "@list" in values[0]);
779
+ });
780
+ }
781
+ /**
782
+ * Checks whether an expanded portable actor node has the `gateways` that
783
+ * FEP-ef61 requires: a non-empty list whose items are all HTTP(S) URIs with
784
+ * an empty path, query, and fragment. Like the generated vocabulary decoder,
785
+ * this also tolerates a plain set of values instead of a `@list`, and gateway
786
+ * strings given as `@value`s instead of `@id`s. JCS-authenticated actors may
787
+ * also supply an unmapped literal `gateways` list.
788
+ */
789
+ function hasValidPortableActorGateways(node, allowUnmapped) {
790
+ const values = getPortableActorGateways(node, allowUnmapped);
791
+ if (!Array.isArray(values)) return false;
792
+ let items = values;
793
+ if (values.some((value) => isJsonLdNode(value) && "@list" in value)) {
794
+ if (values.length !== 1 || !isJsonLdNode(values[0])) return false;
795
+ items = values[0]["@list"];
796
+ }
797
+ if (!Array.isArray(items) || items.length < 1) return false;
798
+ return items.every((item) => {
799
+ if (!isJsonLdNode(item)) return false;
800
+ const gateway = typeof item["@id"] === "string" ? item["@id"] : item["@value"];
801
+ if (typeof gateway !== "string") return false;
802
+ try {
803
+ parseGatewayUrl(gateway);
804
+ } catch (error) {
805
+ if (error instanceof TypeError) return false;
806
+ throw error;
807
+ }
808
+ return true;
809
+ });
810
+ }
811
+ /**
812
+ * Classifies an expanded JSON-LD node into an FEP-2277 core type by the
813
+ * properties it has.
814
+ * @internal
815
+ */
816
+ function classifyFep2277CoreType(node) {
817
+ if (FEP_2277_ACTOR_PROPERTIES.every((property) => property in node)) return "actor";
818
+ if (`${SECURITY_NAMESPACE}publicKeyMultibase` in node) return "verificationMethod";
819
+ if (`${SECURITY_NAMESPACE}publicKeyPem` in node) return "publicKey";
820
+ if (`${AS_NAMESPACE}href` in node) return "link";
821
+ if (`${AS_NAMESPACE}actor` in node) return "activity";
822
+ if (FEP_2277_COLLECTION_PROPERTIES.some((property) => property in node)) return "collection";
823
+ return "object";
824
+ }
825
+ async function expandPortableObjectRoot(jsonLd, contextLoader) {
826
+ if (!isJsonLdNode(jsonLd)) throw new TypeError("Expected a single JSON-LD object.");
827
+ const loadedContexts = /* @__PURE__ */ new Map();
828
+ const loader = getNormalizationContextLoader(contextLoader);
829
+ const recordingLoader = async (url, options) => {
830
+ const remoteDocument = await loader(url, options);
831
+ const key = URL.canParse(url) ? new URL(url).href : url;
832
+ loadedContexts.set(key, structuredClone(remoteDocument));
833
+ return remoteDocument;
834
+ };
835
+ const expanded = await jsonld.expand(jsonLd, {
836
+ documentLoader: recordingLoader,
837
+ keepFreeFloatingNodes: true
838
+ });
839
+ if (expanded.length !== 1 || !isJsonLdNode(expanded[0])) throw new TypeError("Expected a single JSON-LD object.");
840
+ return {
841
+ root: expanded[0],
842
+ proofContextLoader: async (url, options) => {
843
+ const key = URL.canParse(url) ? new URL(url).href : url;
844
+ const remoteDocument = loadedContexts.get(key);
845
+ if (remoteDocument != null) return structuredClone(remoteDocument);
846
+ return await preloadedOnlyDocumentLoader(url, options);
847
+ }
848
+ };
849
+ }
850
+ /**
851
+ * Gets the DID of a portable object ID, which is either an `ap:` or
852
+ * `ap+ef61:` URI or an FEP-ef61 compatible identifier.
853
+ * @throws {TypeError} If the ID is malformed.
854
+ */
855
+ function getObjectDid(id) {
856
+ try {
857
+ parseIri(id);
858
+ if (PORTABLE_OBJECT_ID_PATTERN.test(id)) return getFe34Origin(id);
859
+ const portableId = fromCompatibleEf61Id(id);
860
+ if (portableId != null) return getFe34Origin(portableId);
861
+ } catch (error) {
862
+ if (!(error instanceof TypeError)) throw error;
863
+ throw new InvalidPortableObjectIdError(id, { cause: error });
864
+ }
865
+ throw new InvalidPortableObjectIdError(id);
866
+ }
867
+ /**
868
+ * The error thrown when a document's ID looks portable, i.e., it is an `ap:`
869
+ * or `ap+ef61:` URI or looks like an FEP-ef61 compatible identifier, but is
870
+ * malformed.
871
+ * @internal
872
+ */
873
+ var InvalidPortableObjectIdError = class extends TypeError {
874
+ constructor(id, options) {
875
+ super(`Invalid portable object ID: ${id}`, options);
876
+ this.name = "InvalidPortableObjectIdError";
877
+ }
878
+ };
879
+ async function preparePortableObjectProof(jsonLd, options) {
880
+ if (isJsonLdNode(jsonLd) && typeof jsonLd["@id"] === "string" && !isPortableId(jsonLd["@id"])) return {
881
+ prepared: false,
882
+ result: {
883
+ verified: false,
884
+ reason: { type: "notPortableObject" }
885
+ }
886
+ };
887
+ const { root, proofContextLoader } = await expandPortableObjectRoot(jsonLd, options.contextLoader);
888
+ const id = root["@id"];
889
+ if (typeof id !== "string" || !isPortableId(id)) return {
890
+ prepared: false,
891
+ result: {
892
+ verified: false,
893
+ reason: { type: "notPortableObject" }
894
+ }
895
+ };
896
+ const objectDid = getObjectDid(id);
897
+ const objectId = parseIri(id);
898
+ const objectType = classifyFep2277CoreType(root);
899
+ if (objectType === "verificationMethod" || objectType === "publicKey" || objectType === "link") return {
900
+ prepared: false,
901
+ result: {
902
+ verified: false,
903
+ reason: {
904
+ type: "unsupportedObjectType",
905
+ objectType
906
+ }
907
+ }
908
+ };
909
+ const proofValues = root[SECURITY_PROOF];
910
+ if (proofValues == null || Array.isArray(proofValues) && proofValues.length < 1) return {
911
+ prepared: false,
912
+ root,
913
+ objectType,
914
+ result: objectType === "collection" ? {
915
+ verified: false,
916
+ reason: { type: "unsecuredCollection" }
917
+ } : {
918
+ verified: false,
919
+ reason: { type: "missingProof" }
920
+ }
921
+ };
922
+ if (!Array.isArray(proofValues)) return {
923
+ prepared: false,
924
+ result: {
925
+ verified: false,
926
+ reason: {
927
+ type: "invalidProof",
928
+ proofIndex: 0
929
+ }
930
+ }
931
+ };
932
+ const rawProofValues = isJsonLdNode(jsonLd) ? await getRawProofValues(jsonLd, proofContextLoader) : [];
933
+ const proofs = [];
934
+ for (let proofIndex = 0; proofIndex < proofValues.length; proofIndex++) {
935
+ const proofValue = proofValues[proofIndex];
936
+ if (!hasValidPortableProofShape(proofValue)) return {
937
+ prepared: false,
938
+ result: {
939
+ verified: false,
940
+ reason: {
941
+ type: "invalidProof",
942
+ proofIndex
943
+ }
944
+ }
945
+ };
946
+ let proof;
947
+ try {
948
+ proof = await DataIntegrityProof.fromJsonLd(proofValue, options);
949
+ } catch {
950
+ return {
951
+ prepared: false,
952
+ result: {
953
+ verified: false,
954
+ reason: {
955
+ type: "invalidProof",
956
+ proofIndex
957
+ }
958
+ }
959
+ };
960
+ }
961
+ proofs.push(proof);
962
+ }
963
+ for (let proofIndex = 0; proofIndex < proofs.length; proofIndex++) {
964
+ const verificationMethod = proofs[proofIndex].verificationMethodId;
965
+ if (verificationMethod == null) return {
966
+ prepared: false,
967
+ result: {
968
+ verified: false,
969
+ reason: {
970
+ type: "invalidProof",
971
+ proofIndex
972
+ }
973
+ }
974
+ };
975
+ if (verificationMethod.protocol !== "did:") return {
976
+ prepared: false,
977
+ result: {
978
+ verified: false,
979
+ reason: {
980
+ type: "unsupportedVerificationMethod",
981
+ proofIndex,
982
+ verificationMethod
983
+ }
984
+ }
985
+ };
986
+ try {
987
+ getFe34Origin(verificationMethod);
988
+ } catch (error) {
989
+ if (!(error instanceof TypeError)) throw error;
990
+ return {
991
+ prepared: false,
992
+ result: {
993
+ verified: false,
994
+ reason: {
995
+ type: "unsupportedVerificationMethod",
996
+ proofIndex,
997
+ verificationMethod
998
+ }
999
+ }
1000
+ };
1001
+ }
1002
+ if (getFe34Origin(verificationMethod) !== objectDid) return {
1003
+ prepared: false,
1004
+ result: {
1005
+ verified: false,
1006
+ reason: {
1007
+ type: "verificationMethodMismatch",
1008
+ proofIndex,
1009
+ objectId,
1010
+ verificationMethod
1011
+ }
1012
+ }
1013
+ };
1014
+ }
1015
+ if (objectType === "actor" && !hasValidPortableActorGateways(root, proofs.every((proof) => proof.cryptosuite === "eddsa-jcs-2022"))) return {
1016
+ prepared: false,
1017
+ root,
1018
+ objectType,
1019
+ result: {
1020
+ verified: false,
1021
+ reason: { type: "invalidGateways" }
1022
+ }
1023
+ };
1024
+ return {
1025
+ prepared: true,
1026
+ root,
1027
+ objectType,
1028
+ objectId,
1029
+ proofs,
1030
+ rawProofValues,
1031
+ proofContextLoader
1032
+ };
1033
+ }
1034
+ /**
1035
+ * Applies portable-object proof policy to one map-local cryptographic result.
1036
+ *
1037
+ * @internal
1038
+ */
1039
+ async function verifyPortableObjectProofPolicy(jsonLd, key, options = {}) {
1040
+ const policyOptions = {
1041
+ ...options,
1042
+ contextLoader: preloadedOnlyDocumentLoader
1043
+ };
1044
+ const prepared = await preparePortableObjectProof(jsonLd, policyOptions);
1045
+ if (!prepared.prepared) return prepared.result;
1046
+ const policyProof = prepared.proofs[0];
1047
+ const literalProof = isJsonLdNode(jsonLd) && isJsonLdNode(jsonLd.proof) ? (await parseRawProofCandidates(jsonLd, [jsonLd.proof], policyOptions, prepared.proofContextLoader))[0]?.proof : null;
1048
+ const verificationMethod = policyProof?.verificationMethodId;
1049
+ if (prepared.proofs.length !== 1 || key == null || policyProof == null || literalProof == null || !sameProof(policyProof, literalProof) || verificationMethod == null || key.id?.href !== verificationMethod.href) return {
1050
+ verified: false,
1051
+ reason: {
1052
+ type: "invalidProof",
1053
+ proofIndex: prepared.proofs.length > 1 ? 1 : 0
1054
+ }
1055
+ };
1056
+ return {
1057
+ verified: true,
1058
+ keys: [key],
1059
+ objectId: formatIri(prepared.objectId)
1060
+ };
1061
+ }
1062
+ /**
1063
+ * Verifies the FEP-ef61 Object Integrity Proof policy for a portable object.
1064
+ *
1065
+ * This applies the FEP-2277 core-type classification to the top-level JSON-LD
1066
+ * node. Portable actors, activities, and objects require proofs. A portable
1067
+ * collection without a proof is reported separately so a caller can apply a
1068
+ * gateway trust policy. Embedded portable objects are not traversed.
1069
+ *
1070
+ * A portable object is a document whose ID is an `ap:` or `ap+ef61:` URI, or
1071
+ * an [FEP-ef61] compatible identifier such as
1072
+ * `https://gw.example/.well-known/apgateway/did:key:z6Mk…/actor`, which
1073
+ * stands for the portable ID `ap+ef61://did:key:z6Mk…/actor`.
1074
+ *
1075
+ * Every proof must use a DID URL whose DID matches the portable object's
1076
+ * authority, i.e., the DID of its canonical portable ID, and every proof must
1077
+ * pass {@link verifyProof}. A portable actor must also have a non-empty
1078
+ * `gateways` list whose items are all HTTP(S) URIs with an empty path, query,
1079
+ * and fragment; otherwise, it is rejected with the `invalidGateways` reason
1080
+ * before its proofs are verified. The proofs are verified over the document as
1081
+ * given; a compatible identifier is never rewritten into a portable ID.
1082
+ * An unmapped literal `gateways` property is also accepted when every proof
1083
+ * uses `eddsa-jcs-2022`, which authenticates the original JSON properties.
1084
+ *
1085
+ * [FEP-ef61]: https://w3id.org/fep/ef61
1086
+ *
1087
+ * @param jsonLd The JSON-LD document to verify.
1088
+ * @param options Additional options. See also
1089
+ * {@link VerifyPortableObjectProofOptions}.
1090
+ * @returns The detailed portable proof-policy result.
1091
+ * @throws {TypeError} If the input is not a single JSON-LD object or has a
1092
+ * malformed portable ID or compatible identifier.
1093
+ * @since 2.4.0
1094
+ */
1095
+ async function verifyPortableObjectProof(jsonLd, options = {}) {
1096
+ return (await verifyPortableObjectProofWithRoot(jsonLd, options)).result;
1097
+ }
1098
+ /**
1099
+ * Same as {@link verifyPortableObjectProof}, but also returns the expanded
1100
+ * root node and its FEP-2277 core type, so that a caller can apply further
1101
+ * policy, such as the gateway trust policy for unsecured collections, to the
1102
+ * same interpretation of the document.
1103
+ * @internal
1104
+ */
1105
+ async function verifyPortableObjectProofWithRoot(jsonLd, options = {}) {
1106
+ const prepared = await preparePortableObjectProof(jsonLd, options);
1107
+ if (!prepared.prepared) return {
1108
+ result: prepared.result,
1109
+ ...prepared.root == null ? {} : { root: prepared.root },
1110
+ ...prepared.objectType == null ? {} : { objectType: prepared.objectType }
1111
+ };
1112
+ const { root, objectType, proofContextLoader } = prepared;
1113
+ const messageDigestCache = { proofContextLoader };
1114
+ const result = await verifyPreparedPortableObjectProof(jsonLd, prepared, options, messageDigestCache);
1115
+ const { expires } = messageDigestCache;
1116
+ return {
1117
+ result,
1118
+ root,
1119
+ objectType,
1120
+ ...result.verified && expires != null ? { expires } : {}
1121
+ };
1122
+ }
1123
+ async function verifyPreparedPortableObjectProof(jsonLd, prepared, options, messageDigestCache) {
1124
+ const { proofs, rawProofValues, proofContextLoader } = prepared;
1125
+ const keys = [];
1126
+ const rawProofCandidatePool = {
1127
+ candidates: await parseRawProofCandidates(jsonLd, rawProofValues, options, proofContextLoader),
1128
+ used: /* @__PURE__ */ new Set()
1129
+ };
1130
+ for (let proofIndex = 0; proofIndex < proofs.length; proofIndex++) {
1131
+ const rawProofCandidate = takeRawProofCandidate(rawProofCandidatePool, proofs[proofIndex]);
1132
+ if (rawProofCandidate == null) return {
1133
+ verified: false,
1134
+ reason: {
1135
+ type: "invalidProof",
1136
+ proofIndex
1137
+ }
1138
+ };
1139
+ const key = await verifyProofWithMessageDigestCache(jsonLd, proofs[proofIndex], options, messageDigestCache, rawProofCandidate, true);
1140
+ if (key == null) return {
1141
+ verified: false,
1142
+ reason: {
1143
+ type: "invalidProof",
1144
+ proofIndex
1145
+ }
1146
+ };
1147
+ keys.push(key);
1148
+ }
1149
+ return {
1150
+ verified: true,
1151
+ keys
1152
+ };
1153
+ }
1154
+ /**
1155
+ * Verifies the given object. It will verify all the proofs in the object,
1156
+ * and succeed only if all the proofs are valid and all attributions and
1157
+ * actors are authenticated by the proofs.
1158
+ * @template T The type of the object to verify.
1159
+ * @param cls The class of the object to verify. It must be a subclass of
1160
+ * the {@link Object}.
1161
+ * @param jsonLd The JSON-LD object to verify. It's assumed that the object
1162
+ * is a compacted JSON-LD representation of a `T` with `@context`.
1163
+ * @param options Additional options. See also {@link VerifyObjectOptions}.
1164
+ * @returns The object if it's verified, or `null` if it's not.
1165
+ * @throws {TypeError} If the object is invalid or unsupported.
1166
+ * @since 0.10.0
1167
+ */
1168
+ async function verifyObject(cls, jsonLd, options = {}) {
1169
+ if (options[verificationObservation]?.attempt == null) {
1170
+ const observedOptions = {
1171
+ ...options,
1172
+ [verificationObservation]: options[verificationObservation] ?? {
1173
+ attempts: [],
1174
+ captureRawKeyIds: false
1175
+ }
1176
+ };
1177
+ return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("object_integrity_proofs.verify_object", async (span) => {
1178
+ try {
1179
+ return await observeAttempt(observedOptions, "objectIntegrity", async (observation) => {
1180
+ const object = await verifyObject(cls, jsonLd, {
1181
+ ...options,
1182
+ [verificationObservation]: observation
1183
+ });
1184
+ if (object == null) {
1185
+ span.setStatus({ code: SpanStatusCode.ERROR });
1186
+ span.setAttribute("activitypub.verification.failure_reason", observation.attempt?.reason?.type ?? "signatureVerificationFailed");
1187
+ }
1188
+ return object;
1189
+ }, (value) => value != null);
1190
+ } catch (error) {
1191
+ span.setStatus({
1192
+ code: SpanStatusCode.ERROR,
1193
+ message: String(error)
1194
+ });
1195
+ throw error;
1196
+ } finally {
1197
+ span.end();
1198
+ }
1199
+ });
1200
+ }
1201
+ const observation = options[verificationObservation];
1202
+ const logger = getLogger([
1203
+ "fedify",
1204
+ "sig",
1205
+ "proof"
1206
+ ]);
1207
+ const object = await cls.fromJsonLd(jsonLd, options);
1208
+ observation?.parsedObject?.(object);
1209
+ if (observation?.subject != null) observation.subject.id = object.id == null ? null : new URL(object.id.href);
1210
+ const defaultDocumentLoader = getDocumentLoader();
1211
+ const proofContextLoader = options.contextLoader ?? defaultDocumentLoader;
1212
+ const attributions = new Set(object.attributionIds.map((uri) => uri.href));
1213
+ if (object instanceof Activity) for (const uri of object.actorIds) attributions.add(uri.href);
1214
+ const rawProofValues = isJsonLdNode(jsonLd) ? await getRawProofValues(jsonLd, proofContextLoader) : [];
1215
+ const rawProofCandidates = isJsonLdNode(jsonLd) ? await parseRawProofCandidates(jsonLd, rawProofValues, options, proofContextLoader) : [];
1216
+ const rawProofCandidatePool = {
1217
+ candidates: rawProofCandidates,
1218
+ used: /* @__PURE__ */ new Set()
1219
+ };
1220
+ const baseDocumentLoader = options.documentLoader ?? defaultDocumentLoader;
1221
+ const hydratedCandidates = /* @__PURE__ */ new Set();
1222
+ let loadedPortableProofs = 0;
1223
+ let acceptedPortableProofs = 0;
1224
+ const acceptPortableProofDocument = async () => {
1225
+ acceptedPortableProofs++;
1226
+ return { verified: true };
1227
+ };
1228
+ const proofDocumentLoader = async (url, loaderOptions) => {
1229
+ const remoteDocument = await baseDocumentLoader(url, loaderOptions);
1230
+ if (isPortableId(url)) loadedPortableProofs++;
1231
+ const reference = normalizeDocumentUrl(url);
1232
+ const candidateIndex = rawProofCandidates.findIndex((candidate, index) => !hydratedCandidates.has(index) && !rawProofCandidatePool.used.has(index) && candidate.reference === reference);
1233
+ if (candidateIndex >= 0) {
1234
+ hydratedCandidates.add(candidateIndex);
1235
+ let parsed = null;
1236
+ const contexts = options[verificationObservation] != null && options[verificationObservation]?.captureRawKeyIds !== false ? recordProofContexts(proofContextLoader) : void 0;
1237
+ try {
1238
+ parsed = await DataIntegrityProof.fromJsonLd(remoteDocument.document, {
1239
+ documentLoader: baseDocumentLoader,
1240
+ contextLoader: contexts?.loader ?? proofContextLoader,
1241
+ tracerProvider: options.tracerProvider,
1242
+ baseUrl: parseIri(remoteDocument.documentUrl)
1243
+ });
1244
+ } catch {}
1245
+ rawProofCandidates[candidateIndex] = {
1246
+ value: structuredClone(remoteDocument.document),
1247
+ proof: parsed,
1248
+ reference,
1249
+ declaredKeyId: contexts == null ? void 0 : await getAliasedDeclaredProofKeyId(remoteDocument.document, void 0, contexts.replay)
1250
+ };
1251
+ }
1252
+ return remoteDocument;
1253
+ };
1254
+ for await (const proof of object.getProofs({
1255
+ ...options,
1256
+ documentLoader: proofDocumentLoader,
1257
+ gateways: [],
1258
+ verifyPortableObject: acceptPortableProofDocument,
1259
+ inheritPortableObjectVerifier: false
1260
+ })) {
1261
+ const rawProofCandidate = takeRawProofCandidate(rawProofCandidatePool, proof);
1262
+ if (rawProofCandidate == null) return null;
1263
+ const key = await verifyProofWithMessageDigestCache(jsonLd, proof, options, { proofContextLoader }, rawProofCandidate);
1264
+ if (key === null) return null;
1265
+ if (proof.verificationMethodId == null) return null;
1266
+ if (key.controllerId == null) {
1267
+ logger.debug("Key {keyId} does not have a controller.", { keyId: key.id?.href });
1268
+ continue;
1269
+ }
1270
+ deleteAuthenticatedAttribution(attributions, key.controllerId, proof.verificationMethodId);
1271
+ }
1272
+ if (acceptedPortableProofs < loadedPortableProofs) {
1273
+ logger.debug("Some portable proof references could not be dereferenced.");
1274
+ return null;
1275
+ }
1276
+ if (attributions.size > 0) {
1277
+ if (observation?.attempt != null) observation.attempt.reason = observation.attempt.checks.length === 0 ? { type: "noSignature" } : {
1278
+ type: "uncoveredAttribution",
1279
+ attributionIds: [...attributions].map((id) => new URL(id))
1280
+ };
1281
+ logger.debug("Some attributions are not authenticated by the proofs: {attributions}.", { attributions: [...attributions] });
1282
+ return null;
1283
+ }
1284
+ return object;
1285
+ }
1286
+ function deleteAuthenticatedAttribution(attributions, controllerId, verificationMethodId) {
1287
+ if (!hasCryptographicOrigin(controllerId.href) && !isPortableId(controllerId)) {
1288
+ attributions.delete(controllerId.href);
1289
+ return;
1290
+ }
1291
+ const did = getPortableDid(controllerId);
1292
+ if (did == null || !hasCryptographicOrigin(verificationMethodId.href) || getPortableDid(verificationMethodId) !== did) return;
1293
+ for (const attribution of [...attributions]) if ((hasCryptographicOrigin(attribution) || isPortableId(attribution)) && getPortableDid(attribution) === did) attributions.delete(attribution);
1294
+ }
1295
+ function hasCryptographicOrigin(iri) {
1296
+ return /^did:/i.test(iri) || /^ap(?:\+ef61)?:\/\//i.test(iri);
1297
+ }
1298
+ //#endregion
1299
+ export { signObject as a, verifyPortableObjectProof as c, verifyProof as d, hasProofLike as i, verifyPortableObjectProofPolicy as l, classifyFep2277CoreType as n, verifyMapLocalProof as o, createProof as r, verifyObject as s, InvalidPortableObjectIdError as t, verifyPortableObjectProofWithRoot as u };