@fedify/fedify 2.4.0-dev.1668 → 2.4.0-dev.1740

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 (151) hide show
  1. package/README.md +1 -1
  2. package/dist/{assert-CJ1KXcvv.mjs → assert-CebeUf0C.mjs} +1 -1
  3. package/dist/assert_exists-DtzkXC47.mjs +28 -0
  4. package/dist/assert_false-3pLLLsO4.mjs +23 -0
  5. package/dist/assert_greater_or_equal-BApOTh1h.mjs +30 -0
  6. package/dist/{assert_instance_of-Q9KTBnrf.mjs → assert_instance_of-g3WcyYNR.mjs} +1 -1
  7. package/dist/{assert_not_equals-EPJPoxuf.mjs → assert_not_equals-BN7yDMWe.mjs} +1 -1
  8. package/dist/assert_rejects-wFbSPn1O.mjs +39 -0
  9. package/dist/{assert_strict_equals-Ec20AUwa.mjs → assert_strict_equals-Bpjl4Psw.mjs} +1 -1
  10. package/dist/{assert_throws-NiFfqbnH.mjs → assert_throws-BJ5wuvR2.mjs} +1 -1
  11. package/dist/{builder-iXZ5jNVg.mjs → builder-Bw6LVKGw.mjs} +5 -3
  12. package/dist/{circuit-breaker-CBGyz5F7.mjs → circuit-breaker-BT7CiPbz.mjs} +191 -9
  13. package/dist/circuit-breaker-test-utils-BYIHoliq.mjs +14 -0
  14. package/dist/{client-CjF5IYQS.mjs → client-CtxvmazV.mjs} +63 -5
  15. package/dist/{collection-BIhlldqK.mjs → collection-CnnP1UAv.mjs} +1 -1
  16. package/dist/compat/mod.cjs +1 -1
  17. package/dist/compat/mod.d.cts +1 -1
  18. package/dist/compat/mod.d.ts +1 -1
  19. package/dist/compat/mod.js +1 -1
  20. package/dist/compat/outgoing-jsonld.test.mjs +3 -3
  21. package/dist/compat/public-audience.test.mjs +3 -3
  22. package/dist/compat/transformers.test.mjs +5 -5
  23. package/dist/{context-C05Rgxmu.d.cts → context-B-dsBjZ9.d.cts} +281 -7
  24. package/dist/{context-Cjnr0ig1.d.ts → context-DrLXudbA.d.ts} +281 -7
  25. package/dist/{deno-DtHcfB0f.mjs → deno-tRdp8MCl.mjs} +1 -1
  26. package/dist/{docloader-0vAfF6XW.mjs → docloader-Dg_7gMC7.mjs} +2 -2
  27. package/dist/{esm-yYQfPhIY.mjs → esm-BHXXx4Wx.mjs} +13 -6
  28. package/dist/federation/builder.test.mjs +18 -5
  29. package/dist/federation/circuit-breaker.test.mjs +626 -7
  30. package/dist/federation/collection.test.mjs +3 -3
  31. package/dist/federation/handler.test.mjs +14 -13
  32. package/dist/federation/idempotency.test.mjs +6 -6
  33. package/dist/federation/inbox.test.mjs +3 -3
  34. package/dist/federation/keycache.test.mjs +5 -5
  35. package/dist/federation/kv.test.mjs +3 -3
  36. package/dist/federation/metrics.test.mjs +4 -4
  37. package/dist/federation/middleware.test.mjs +37 -28
  38. package/dist/federation/mod.cjs +18 -540
  39. package/dist/federation/mod.d.cts +3 -4
  40. package/dist/federation/mod.d.ts +3 -4
  41. package/dist/federation/mod.js +1 -1
  42. package/dist/federation/mq.test.mjs +32 -5
  43. package/dist/federation/negotiation.test.mjs +4 -4
  44. package/dist/federation/retry.test.mjs +3 -3
  45. package/dist/federation/router.test.mjs +7 -7
  46. package/dist/federation/send.test.mjs +28 -26
  47. package/dist/federation/tasks/codec.test.mjs +4 -4
  48. package/dist/federation/tasks/enqueue.test.mjs +4 -4
  49. package/dist/federation/tasks/tasks.test.mjs +6 -6
  50. package/dist/federation/temporal.test.mjs +4 -4
  51. package/dist/federation/webfinger.test.mjs +74 -12
  52. package/dist/{middleware-DzIUFRO2.cjs → federation-BJBpt_Am.cjs} +855 -114
  53. package/dist/{http-BbnOMQoy.js → http-BIxGa6AG.js} +3 -3
  54. package/dist/{http-DUmWq5Pw.mjs → http-Day1kcpT.mjs} +5 -5
  55. package/dist/{temporal-polyfill-BCdTHexd.cjs → http-DggG1scN.cjs} +2801 -104
  56. package/dist/{key-CM7wDnZG.mjs → key-igh0AMsL.mjs} +2 -2
  57. package/dist/{kv-cache-ZQ22hm44.js → kv-cache-BIAB0HKx.js} +1 -1
  58. package/dist/{kv-cache-DEXKemJ9.mjs → kv-cache-Bz6aQOOX.mjs} +1 -1
  59. package/dist/{kv-cache-zmgG1HUp.cjs → kv-cache-C4U_uBqD.cjs} +2 -4
  60. package/dist/{ld-BttH_-8K.mjs → ld-DnT9sCWa.mjs} +5 -5
  61. package/dist/metrics-DVKYY6K1.d.cts +36 -0
  62. package/dist/{metrics-DT-CnD1g.mjs → metrics-DbdNnWIt.mjs} +2 -2
  63. package/dist/metrics-DoRtI0qU.d.ts +36 -0
  64. package/dist/{middleware-ChlYS0Af.mjs → middleware-B6GweVcg.mjs} +1 -1
  65. package/dist/{middleware-D3IAVMcT.js → middleware-CnsPXG0O.js} +241 -40
  66. package/dist/{middleware-DrroX3aD.mjs → middleware-DPIS4fsB.mjs} +60 -43
  67. package/dist/{mod-BrpVsSfY.d.cts → mod-CLHkCwLm.d.cts} +3 -3
  68. package/dist/{mod-B0hW12_O.d.cts → mod-CnGLNoVw.d.cts} +86 -4
  69. package/dist/{mod-DdONo-ep.d.cts → mod-D-abvu2C.d.cts} +1 -1
  70. package/dist/{mod-BsCE5Ihq.d.ts → mod-D6O8C7eN.d.ts} +1 -1
  71. package/dist/{mod-CNef4in0.d.ts → mod-DypxPS9H.d.ts} +3 -3
  72. package/dist/{mod-COIAjwRS.d.ts → mod-DzRXACM5.d.ts} +86 -4
  73. package/dist/mod.cjs +25 -25
  74. package/dist/mod.d.cts +10 -11
  75. package/dist/mod.d.ts +10 -11
  76. package/dist/mod.js +8 -8
  77. package/dist/nodeinfo/client.test.mjs +64 -4
  78. package/dist/nodeinfo/handler.test.mjs +5 -5
  79. package/dist/nodeinfo/mod.cjs +1 -1
  80. package/dist/nodeinfo/mod.d.cts +1 -1
  81. package/dist/nodeinfo/mod.d.ts +1 -1
  82. package/dist/nodeinfo/mod.js +1 -1
  83. package/dist/nodeinfo/types.test.mjs +4 -4
  84. package/dist/otel/exporter.test.mjs +3 -3
  85. package/dist/otel/mod.cjs +0 -1
  86. package/dist/otel/mod.d.cts +1 -1
  87. package/dist/otel/mod.d.ts +1 -1
  88. package/dist/{outgoing-jsonld-URuqsICz.mjs → outgoing-jsonld-BQSHRLhg.mjs} +2 -2
  89. package/dist/{owner-DZALmhdl.mjs → owner-B3ef8GfJ.mjs} +2 -2
  90. package/dist/{proof-CqA-2nfW.js → proof-BBLQXRWw.js} +608 -36
  91. package/dist/{proof-a60oVJ_4.cjs → proof-Cqk2TcLX.cjs} +616 -39
  92. package/dist/proof-DVoDZ8d7.mjs +890 -0
  93. package/dist/{public-audience-Cr5MsnMq.mjs → public-audience--9hx7IGx.mjs} +1 -1
  94. package/dist/runtime/mod.cjs +1 -1
  95. package/dist/runtime/mod.js +1 -1
  96. package/dist/{send-DcwZnQWG.mjs → send-PbBSZ7Qk.mjs} +3 -3
  97. package/dist/sig/accept.test.mjs +1 -1
  98. package/dist/sig/http.test.mjs +37 -11
  99. package/dist/sig/key.test.mjs +6 -6
  100. package/dist/sig/ld.test.mjs +9 -7
  101. package/dist/sig/mod.cjs +3 -2
  102. package/dist/sig/mod.d.cts +4 -4
  103. package/dist/sig/mod.d.ts +4 -4
  104. package/dist/sig/mod.js +3 -3
  105. package/dist/sig/owner.test.mjs +6 -6
  106. package/dist/sig/proof.test.mjs +965 -15
  107. package/dist/std__assert-CxFT0MNt.mjs +8 -0
  108. package/dist/{temporal-Bpxpsl2k.mjs → temporal-DLQIjuTn.mjs} +3 -3
  109. package/dist/testing/mod.d.mts +10 -0
  110. package/dist/testing/mod.mjs +2 -2
  111. package/dist/{testing-CO7ftO8A.mjs → testing-BX0Nicyq.mjs} +2 -2
  112. package/dist/{transformers-DGwl-hD1.cjs → transformers-BalCrSsr.cjs} +0 -1
  113. package/dist/{types-DC1pNgJA.js → types-Dtyf8lVj.js} +63 -5
  114. package/dist/{types-CPym83zc.cjs → types-RXm5YxpC.cjs} +62 -5
  115. package/dist/utils/docloader.test.mjs +7 -7
  116. package/dist/utils/kv-cache.test.mjs +1 -1
  117. package/dist/utils/mod.cjs +1 -1
  118. package/dist/utils/mod.d.cts +1 -1
  119. package/dist/utils/mod.d.ts +1 -1
  120. package/dist/utils/mod.js +1 -1
  121. package/package.json +7 -7
  122. package/skills/fedify/SKILL.md +462 -0
  123. package/dist/assert_rejects-EgstcQy5.mjs +0 -82
  124. package/dist/http-BpT5cE6r.cjs +0 -2694
  125. package/dist/metrics-DN13mCAw.d.cts +0 -294
  126. package/dist/metrics-v_e0n5GQ.d.ts +0 -294
  127. package/dist/proof-DiQ0uBal.mjs +0 -316
  128. package/dist/std__assert-B2NnY9bq.mjs +0 -79
  129. /package/dist/{accept-8PiolDP7.mjs → accept-CPVqki78.mjs} +0 -0
  130. /package/dist/{activity-listener-BtTSxZWA.mjs → activity-listener-C-BSbKI7.mjs} +0 -0
  131. /package/dist/{assert_equals-BV7oLMxm.mjs → assert_equals-CBlRfA-_.mjs} +0 -0
  132. /package/dist/{client-CAM_bQXx.d.cts → client-D-XP_Ccb.d.cts} +0 -0
  133. /package/dist/{client-CSddvgWN.d.ts → client-D-XP_Ccb.d.ts} +0 -0
  134. /package/dist/{codec-BBga-FWI.mjs → codec-peqOdBaE.mjs} +0 -0
  135. /package/dist/{context-BJXxPElm.mjs → context-Dt36KFEJ.mjs} +0 -0
  136. /package/dist/{http-VyDTd4G3.d.cts → http-6TI0tI03.d.cts} +0 -0
  137. /package/dist/{http-lf8Hsd91.d.ts → http-CdrSn2ip.d.ts} +0 -0
  138. /package/dist/{keycache-_DHqz5z_.mjs → keycache-0Jk78XmB.mjs} +0 -0
  139. /package/dist/{keys-Dbyd7bhl.mjs → keys-DIJNHW-Y.mjs} +0 -0
  140. /package/dist/{kv-D6hNiMTK.d.ts → kv-BhNbN8Ed.d.cts} +0 -0
  141. /package/dist/{kv-gJ8LYbxX.d.cts → kv-BhNbN8Ed.d.ts} +0 -0
  142. /package/dist/{kv-CXBAok3k.mjs → kv-DCHkaJ9-.mjs} +0 -0
  143. /package/dist/{mq-Bo7Etgh6.mjs → mq-Dm1Wmtm-.mjs} +0 -0
  144. /package/dist/{negotiation-RuwrPFqi.mjs → negotiation-CCocWT_N.mjs} +0 -0
  145. /package/dist/{owner-CnngXDNJ.d.ts → owner-DGSfntI-.d.ts} +0 -0
  146. /package/dist/{owner-DEvZuyOE.d.cts → owner-r_waTiQj.d.cts} +0 -0
  147. /package/dist/{retry-DgFqeS5k.mjs → retry-zX5xw5e0.mjs} +0 -0
  148. /package/dist/{chunk-D5IdezsZ.js → rolldown-runtime-BC-Eo5Mj.js} +0 -0
  149. /package/dist/{chunk-Czpeue4M.cjs → rolldown-runtime-Dmm3t92W.cjs} +0 -0
  150. /package/dist/{transformers-DXze6FUB.js → transformers-DAtXl_Kc.js} +0 -0
  151. /package/dist/{types-CrtdVuDP.mjs → types-DE_LV1JB.mjs} +0 -0
@@ -1,11 +1,11 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { F as version, P as name, _ as measureSignatureKeyFetch, d as validateCryptoKey, f as getDurationMs, p as getFederationMetrics, s as fetchKey } from "./http-BbnOMQoy.js";
3
+ import { F as version, P as name, _ as measureSignatureKeyFetch, d as validateCryptoKey, f as getDurationMs, p as getFederationMetrics, s as fetchKey } from "./http-BIxGa6AG.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { Activity, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1, PUBLIC_COLLECTION, getTypeId, isActor } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
7
7
  import { encodeHex } from "byte-encodings/hex";
8
- import { getDocumentLoader, haveSameFe34Origin, preloadedContexts } from "@fedify/vocab-runtime";
8
+ import { formatIri, getDocumentLoader, getFe34Origin, haveSameFe34Origin, parseIri, preloadedContexts } from "@fedify/vocab-runtime";
9
9
  import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
10
10
  import jsonld from "@fedify/vocab-runtime/jsonld";
11
11
  import serialize from "json-canon";
@@ -23,7 +23,7 @@ const localContext = [
23
23
  ];
24
24
  const localContextUrls = new Set(localContext);
25
25
  const builtInContextLoader = getDocumentLoader();
26
- const disallowedJsonLdKeywords = new Set([
26
+ const disallowedJsonLdKeywords = /* @__PURE__ */ new Set([
27
27
  "@graph",
28
28
  "@included",
29
29
  "@reverse"
@@ -523,7 +523,7 @@ async function verifySignature(jsonLd, options = {}) {
523
523
  * only from external documents and are dropped from the metric attribute to
524
524
  * avoid attacker-controlled cardinality.
525
525
  */
526
- const LD_KNOWN_SIGNATURE_TYPES = new Set(["RsaSignature2017"]);
526
+ const LD_KNOWN_SIGNATURE_TYPES = /* @__PURE__ */ new Set(["RsaSignature2017"]);
527
527
  /**
528
528
  * Reports only whether a `signature` key is present on the document, with
529
529
  * no shape check on its value. This is intentionally looser than
@@ -757,7 +757,7 @@ const logger$2 = getLogger([
757
757
  "compat",
758
758
  "public-audience"
759
759
  ]);
760
- const PUBLIC_ADDRESSING_FIELDS = new Set([
760
+ const PUBLIC_ADDRESSING_FIELDS = /* @__PURE__ */ new Set([
761
761
  "to",
762
762
  "cc",
763
763
  "bto",
@@ -922,7 +922,7 @@ const logger$1 = getLogger([
922
922
  "compat",
923
923
  "outgoing-jsonld"
924
924
  ]);
925
- const ATTACHMENT_FIELDS = new Set(["attachment", "https://www.w3.org/ns/activitystreams#attachment"]);
925
+ const ATTACHMENT_FIELDS = /* @__PURE__ */ new Set(["attachment", "https://www.w3.org/ns/activitystreams#attachment"]);
926
926
  const AS_CONTEXT_URL = "https://www.w3.org/ns/activitystreams";
927
927
  const KNOWN_SAFE_CONTEXT_URLS = getKnownSafeContextUrls();
928
928
  const MAX_TRAVERSAL_DEPTH = 64;
@@ -1120,12 +1120,22 @@ async function normalizeOutgoingActivityJsonLd(jsonLd, contextLoader) {
1120
1120
  * dropped from the metric attribute to avoid attacker-controlled
1121
1121
  * cardinality.
1122
1122
  */
1123
- const OIP_KNOWN_CRYPTOSUITES = new Set(["eddsa-jcs-2022"]);
1123
+ const OIP_KNOWN_CRYPTOSUITES = /* @__PURE__ */ new Set(["eddsa-jcs-2022"]);
1124
1124
  const logger = getLogger([
1125
1125
  "fedify",
1126
1126
  "sig",
1127
1127
  "proof"
1128
1128
  ]);
1129
+ const SECURITY_NAMESPACE = "https://w3id.org/security#";
1130
+ const SECURITY_PROOF = `${SECURITY_NAMESPACE}proof`;
1131
+ const SECURITY_PROOF_VALUE = `${SECURITY_NAMESPACE}proofValue`;
1132
+ const DATA_INTEGRITY_PROOF = `${SECURITY_NAMESPACE}DataIntegrityProof`;
1133
+ const SECURITY_VERIFICATION_METHOD = `${SECURITY_NAMESPACE}verificationMethod`;
1134
+ const SECURITY_EXPIRATION = `${SECURITY_NAMESPACE}expiration`;
1135
+ const SECURITY_DOMAIN = `${SECURITY_NAMESPACE}domain`;
1136
+ const SECURITY_CHALLENGE = `${SECURITY_NAMESPACE}challenge`;
1137
+ const SECURITY_NONCE = `${SECURITY_NAMESPACE}nonce`;
1138
+ const SECURITY_PREVIOUS_PROOF = `${SECURITY_NAMESPACE}previousProof`;
1129
1139
  /**
1130
1140
  * Checks if the given JSON-LD document has a DataIntegrityProof-like object,
1131
1141
  * without fully deserializing it into vocabulary classes.
@@ -1237,15 +1247,21 @@ async function signObject(object, privateKey, keyId, options = {}) {
1237
1247
  }
1238
1248
  /**
1239
1249
  * Verifies the given proof for the object.
1240
- * @param jsonLd The JSON-LD object to verify the proof for. If it contains
1241
- * any proofs, they will be ignored.
1250
+ * @param jsonLd The JSON-LD object to verify the proof for. Its proof
1251
+ * properties are excluded from the message, but matching proof
1252
+ * occurrences are used to authenticate the received proof
1253
+ * configuration.
1242
1254
  * @param proof The proof to verify.
1243
1255
  * @param options Additional options. See also {@link VerifyProofOptions}.
1244
1256
  * @returns The public key that was used to sign the proof, or `null` if the
1245
1257
  * proof is invalid.
1246
1258
  * @since 0.10.0
1259
+ * @since 2.4.0 Matching proof configurations are authenticated.
1247
1260
  */
1248
1261
  async function verifyProof(jsonLd, proof, options = {}) {
1262
+ return await verifyProofWithMessageDigestCache(jsonLd, proof, options);
1263
+ }
1264
+ async function verifyProofWithMessageDigestCache(jsonLd, proof, options, messageDigestCache = {}, rawProofCandidate) {
1249
1265
  return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("object_integrity_proofs.verify", async (span) => {
1250
1266
  const start = performance.now();
1251
1267
  let verified = false;
@@ -1257,7 +1273,7 @@ async function verifyProof(jsonLd, proof, options = {}) {
1257
1273
  if (proof.proofValue != null) span.setAttribute("object_integrity_proofs.signature", encodeHex(proof.proofValue));
1258
1274
  }
1259
1275
  try {
1260
- const key = await verifyProofInternal(jsonLd, proof, options);
1276
+ const key = await verifyProofInternal(jsonLd, proof, options, messageDigestCache, rawProofCandidate);
1261
1277
  if (key == null) span.setStatus({ code: SpanStatusCode.ERROR });
1262
1278
  else verified = true;
1263
1279
  return key;
@@ -1275,23 +1291,313 @@ async function verifyProof(jsonLd, proof, options = {}) {
1275
1291
  }
1276
1292
  });
1277
1293
  }
1278
- async function verifyProofInternal(jsonLd, proof, options) {
1279
- if (typeof jsonLd !== "object" || jsonLd == null || Array.isArray(jsonLd) || proof.cryptosuite !== "eddsa-jcs-2022" || proof.verificationMethodId == null || proof.proofPurpose !== "assertionMethod" || proof.proofValue == null || proof.created == null) return null;
1280
- const publicKeyPromise = measureSignatureKeyFetch(options.meterProvider, "object_integrity", () => fetchKey(proof.verificationMethodId, Multikey, options));
1281
- const proofConfig = {
1282
- "@context": jsonLd["@context"],
1283
- type: "DataIntegrityProof",
1284
- cryptosuite: proof.cryptosuite,
1285
- verificationMethod: proof.verificationMethodId.href,
1286
- proofPurpose: proof.proofPurpose,
1287
- created: proof.created.toString()
1288
- };
1294
+ function expandContextPropertyIri(activeContext, key) {
1295
+ const termId = jsonld.getContextValue(activeContext, key, "@id");
1296
+ if (termId != null) return termId;
1297
+ const colon = key.indexOf(":");
1298
+ if (colon < 1) return key;
1299
+ const prefix = key.substring(0, colon);
1300
+ const suffix = key.substring(colon + 1);
1301
+ if (prefix === "_" || suffix.startsWith("//")) return key;
1302
+ const mapping = jsonld.getContextValue(activeContext, prefix);
1303
+ if (typeof mapping === "object" && mapping != null && mapping._prefix === true && typeof mapping["@id"] === "string") return mapping["@id"] + suffix;
1304
+ return key;
1305
+ }
1306
+ async function getJsonLdPropertyNames(jsonLd, propertyIri, defaults, documentLoader = preloadedOnlyDocumentLoader, inheritedContext, rejectOnContextError = false) {
1307
+ const names = new Set(defaults);
1308
+ const context = jsonLd["@context"] ?? inheritedContext;
1309
+ if (context == null) return names;
1310
+ try {
1311
+ const options = { documentLoader };
1312
+ let activeContext = await jsonld.processContext(null, null, options);
1313
+ activeContext = await jsonld.processContext(activeContext, context, options);
1314
+ const typeScopedContext = activeContext;
1315
+ for (const key of globalThis.Object.keys(jsonLd).sort()) {
1316
+ if (key !== "@type" && expandContextPropertyIri(activeContext, key) !== "@type") continue;
1317
+ const value = jsonLd[key];
1318
+ const types = Array.isArray(value) ? value.slice().sort() : [value];
1319
+ for (const type of types) {
1320
+ if (typeof type !== "string") continue;
1321
+ const scopedContext = jsonld.getContextValue(typeScopedContext, type, "@context");
1322
+ if (scopedContext != null) activeContext = await jsonld.processContext(activeContext, scopedContext, options);
1323
+ }
1324
+ }
1325
+ for (const key of globalThis.Object.keys(jsonLd)) if (expandContextPropertyIri(activeContext, key) === propertyIri) names.add(key);
1326
+ } catch {
1327
+ if (rejectOnContextError) return null;
1328
+ }
1329
+ return names;
1330
+ }
1331
+ async function getProofPropertyNames(jsonLd, documentLoader = preloadedOnlyDocumentLoader) {
1332
+ return await getJsonLdPropertyNames(jsonLd, SECURITY_PROOF, ["proof", SECURITY_PROOF], documentLoader) ?? /* @__PURE__ */ new Set(["proof", SECURITY_PROOF]);
1333
+ }
1334
+ async function createProofMessageDigests(jsonLd, proofContextLoader, context) {
1335
+ const msg = { ...jsonLd };
1336
+ for (const property of await getProofPropertyNames(msg, proofContextLoader)) delete msg[property];
1337
+ if (context != null) msg["@context"] = structuredClone(context);
1289
1338
  const encoder = new TextEncoder();
1290
- const proofBytes = encoder.encode(serialize(proofConfig));
1339
+ const digest = async (value) => {
1340
+ const bytes = encoder.encode(serialize(value));
1341
+ return await crypto.subtle.digest("SHA-256", bytes);
1342
+ };
1343
+ const onWire = await digest(msg);
1344
+ let normalizedPromise;
1345
+ return {
1346
+ onWire,
1347
+ normalized() {
1348
+ normalizedPromise ??= (async () => {
1349
+ const normalized = await normalizeOutgoingActivityJsonLd(msg, preloadedOnlyDocumentLoader);
1350
+ return normalized === msg ? null : await digest(normalized);
1351
+ })();
1352
+ return normalizedPromise;
1353
+ }
1354
+ };
1355
+ }
1356
+ function contextValues(context) {
1357
+ return Array.isArray(context) ? context : [context];
1358
+ }
1359
+ function equalJsonValues(left, right) {
1360
+ try {
1361
+ return serialize(left) === serialize(right);
1362
+ } catch {
1363
+ return false;
1364
+ }
1365
+ }
1366
+ function contextStartsWith(documentContext, proofContext) {
1367
+ if (documentContext == null) return false;
1368
+ const documentValues = contextValues(documentContext);
1369
+ const proofValues = contextValues(proofContext);
1370
+ return proofValues.length <= documentValues.length && proofValues.every((value, index) => equalJsonValues(value, documentValues[index]));
1371
+ }
1372
+ function appendProofValues(values, value) {
1373
+ if (Array.isArray(value)) for (const item of value) appendProofValues(values, item);
1374
+ else if (isJsonLdNode(value) && Array.isArray(value["@graph"])) for (const item of value["@graph"]) appendProofValues(values, item);
1375
+ else values.push(value);
1376
+ }
1377
+ async function getRawProofValues(jsonLd, documentLoader) {
1378
+ const propertyNames = await getProofPropertyNames(jsonLd, documentLoader);
1379
+ const values = [];
1380
+ for (const [property, value] of globalThis.Object.entries(jsonLd)) if (propertyNames.has(property)) appendProofValues(values, value);
1381
+ return values;
1382
+ }
1383
+ function sameBytes(left, right) {
1384
+ if (left == null || right == null) return left === right;
1385
+ return left.length === right.length && left.every((value, index) => value === right[index]);
1386
+ }
1387
+ function sameProof(left, right) {
1388
+ 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();
1389
+ }
1390
+ function normalizeDocumentUrl(url) {
1391
+ try {
1392
+ return formatIri(parseIri(url));
1393
+ } catch {
1394
+ return URL.canParse(url) ? new URL(url).href : url;
1395
+ }
1396
+ }
1397
+ function getRawProofReference(value) {
1398
+ const node = Array.isArray(value) && value.length === 1 ? value[0] : value;
1399
+ if (typeof node === "string") return normalizeDocumentUrl(node);
1400
+ if (!isJsonLdNode(node)) return void 0;
1401
+ const id = node["@id"] ?? node.id;
1402
+ return typeof id === "string" ? normalizeDocumentUrl(id) : void 0;
1403
+ }
1404
+ async function parseRawProofCandidates(jsonLd, values, options, documentLoader) {
1405
+ const candidates = [];
1406
+ for (const value of values) {
1407
+ let parsed = null;
1408
+ if (isJsonLdNode(value)) {
1409
+ const proofJsonLd = value["@context"] == null && jsonLd["@context"] != null ? {
1410
+ "@context": jsonLd["@context"],
1411
+ ...value
1412
+ } : value;
1413
+ try {
1414
+ parsed = await DataIntegrityProof.fromJsonLd(proofJsonLd, {
1415
+ ...options,
1416
+ contextLoader: documentLoader
1417
+ });
1418
+ } catch {}
1419
+ }
1420
+ candidates.push({
1421
+ value,
1422
+ proof: parsed,
1423
+ reference: getRawProofReference(value) ?? parsed?.id?.href
1424
+ });
1425
+ }
1426
+ return candidates;
1427
+ }
1428
+ async function findRawProofCandidate(jsonLd, proof, options, documentLoader) {
1429
+ const candidates = await parseRawProofCandidates(jsonLd, await getRawProofValues(jsonLd, documentLoader), options, documentLoader);
1430
+ const matches = [];
1431
+ for (const candidate of candidates) if (candidate.proof != null && sameProof(candidate.proof, proof)) matches.push(candidate);
1432
+ if (matches.length < 1) return void 0;
1433
+ const first = matches[0];
1434
+ const configurations = await Promise.all(matches.map((candidate) => normalizeProofConfiguration(candidate.value, jsonLd["@context"], documentLoader)));
1435
+ const firstConfiguration = configurations[0];
1436
+ return firstConfiguration != null && configurations.every((configuration) => configuration != null && equalJsonValues(configuration.value, firstConfiguration.value)) ? first : null;
1437
+ }
1438
+ function takeRawProofCandidate(pool, proof) {
1439
+ for (let index = 0; index < pool.candidates.length; index++) {
1440
+ if (pool.used.has(index)) continue;
1441
+ const candidate = pool.candidates[index];
1442
+ if (candidate.proof != null && sameProof(candidate.proof, proof)) {
1443
+ pool.used.add(index);
1444
+ return candidate;
1445
+ }
1446
+ }
1447
+ }
1448
+ const STANDARD_COMPACT_PROOF_PROPERTIES = /* @__PURE__ */ new Set([
1449
+ "@context",
1450
+ "type",
1451
+ "cryptosuite",
1452
+ "verificationMethod",
1453
+ "proofPurpose",
1454
+ "proofValue",
1455
+ "created"
1456
+ ]);
1457
+ const STANDARD_EXPANDED_PROOF_PROPERTIES = /* @__PURE__ */ new Set([
1458
+ "@context",
1459
+ "@type",
1460
+ `${SECURITY_NAMESPACE}cryptosuite`,
1461
+ SECURITY_VERIFICATION_METHOD,
1462
+ `${SECURITY_NAMESPACE}proofPurpose`,
1463
+ `${SECURITY_NAMESPACE}proofValue`,
1464
+ "http://purl.org/dc/terms/created"
1465
+ ]);
1466
+ function hasAdditionalProofOptions(value) {
1467
+ const node = Array.isArray(value) && value.length === 1 ? value[0] : value;
1468
+ return isJsonLdNode(node) && globalThis.Object.keys(node).some((property) => !STANDARD_COMPACT_PROOF_PROPERTIES.has(property) && !STANDARD_EXPANDED_PROOF_PROPERTIES.has(property));
1469
+ }
1470
+ function isExpandedJsonLdNode(value) {
1471
+ const properties = globalThis.Object.keys(value).filter((key) => !key.startsWith("@"));
1472
+ return properties.length > 0 && properties.every((property) => URL.canParse(property));
1473
+ }
1474
+ async function normalizeProofConfiguration(rawProof, documentContext, documentLoader) {
1475
+ let node = Array.isArray(rawProof) && rawProof.length === 1 ? rawProof[0] : rawProof;
1476
+ if (!isJsonLdNode(node)) return null;
1477
+ if (isExpandedJsonLdNode(node)) {
1478
+ if (documentContext == null) return null;
1479
+ node = await jsonld.compact(node, documentContext, { documentLoader });
1480
+ if (!isJsonLdNode(node)) return null;
1481
+ } else node = structuredClone(node);
1482
+ const receivedContext = node["@context"];
1483
+ if (receivedContext != null && !contextStartsWith(documentContext, receivedContext)) return null;
1484
+ const context = receivedContext ?? documentContext;
1485
+ if (context != null) node["@context"] = structuredClone(context);
1486
+ const proofValueProperties = await getJsonLdPropertyNames(node, SECURITY_PROOF_VALUE, ["proofValue", SECURITY_PROOF_VALUE], documentLoader, context) ?? /* @__PURE__ */ new Set(["proofValue", SECURITY_PROOF_VALUE]);
1487
+ for (const property of proofValueProperties) delete node[property];
1488
+ return {
1489
+ value: node,
1490
+ context
1491
+ };
1492
+ }
1493
+ async function createProofConfiguration(jsonLd, proof, options, documentLoader, rawProofCandidate) {
1494
+ let rawProof;
1495
+ if (rawProofCandidate == null) {
1496
+ const match = await findRawProofCandidate(jsonLd, proof, options, documentLoader);
1497
+ if (match === null) return null;
1498
+ rawProof = match?.value;
1499
+ } else rawProof = rawProofCandidate.value;
1500
+ if (rawProof == null) {
1501
+ const serializedProof = await proof.toJsonLd();
1502
+ if (hasAdditionalProofOptions(serializedProof)) rawProof = serializedProof;
1503
+ }
1504
+ if (rawProof != null) return await normalizeProofConfiguration(rawProof, jsonLd["@context"], documentLoader);
1505
+ const context = jsonLd["@context"];
1506
+ return {
1507
+ value: {
1508
+ ...context == null ? {} : { "@context": context },
1509
+ type: "DataIntegrityProof",
1510
+ cryptosuite: proof.cryptosuite,
1511
+ verificationMethod: proof.verificationMethodId.href,
1512
+ proofPurpose: proof.proofPurpose,
1513
+ created: proof.created.toString()
1514
+ },
1515
+ context
1516
+ };
1517
+ }
1518
+ const KNOWN_PROOF_CONFIGURATION_PROPERTIES = /* @__PURE__ */ new Set([
1519
+ "@context",
1520
+ "@id",
1521
+ "@type",
1522
+ "id",
1523
+ "type",
1524
+ "cryptosuite",
1525
+ `${SECURITY_NAMESPACE}cryptosuite`,
1526
+ "verificationMethod",
1527
+ SECURITY_VERIFICATION_METHOD,
1528
+ "proofPurpose",
1529
+ `${SECURITY_NAMESPACE}proofPurpose`,
1530
+ "created",
1531
+ "http://purl.org/dc/terms/created",
1532
+ "expires",
1533
+ SECURITY_EXPIRATION,
1534
+ "domain",
1535
+ SECURITY_DOMAIN,
1536
+ "challenge",
1537
+ SECURITY_CHALLENGE,
1538
+ "nonce",
1539
+ SECURITY_NONCE,
1540
+ "previousProof",
1541
+ SECURITY_PREVIOUS_PROOF
1542
+ ]);
1543
+ async function getProofOption(proofConfig, propertyIri, defaults, documentLoader) {
1544
+ let names = await getJsonLdPropertyNames(proofConfig, propertyIri, defaults, documentLoader, proofConfig["@context"], true);
1545
+ if (names == null) {
1546
+ if (globalThis.Object.keys(proofConfig).some((property) => !KNOWN_PROOF_CONFIGURATION_PROPERTIES.has(property))) return null;
1547
+ names = new Set(defaults);
1548
+ }
1549
+ const present = globalThis.Object.keys(proofConfig).filter((property) => names.has(property));
1550
+ if (present.length > 1) return null;
1551
+ return present.length < 1 ? { present: false } : {
1552
+ present: true,
1553
+ value: proofConfig[present[0]]
1554
+ };
1555
+ }
1556
+ function parseStringSet(value) {
1557
+ if (typeof value === "string") return /* @__PURE__ */ new Set([value]);
1558
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) return null;
1559
+ return new Set(value);
1560
+ }
1561
+ function equalStringSets(left, right) {
1562
+ return left.size === right.size && [...left].every((value) => right.has(value));
1563
+ }
1564
+ async function hasValidProofOptions(proofConfig, options, documentLoader) {
1565
+ const expires = await getProofOption(proofConfig, SECURITY_EXPIRATION, ["expires", SECURITY_EXPIRATION], documentLoader);
1566
+ if (expires == null) return false;
1567
+ if (expires.present) {
1568
+ if (typeof expires.value !== "string") return false;
1569
+ let expiration;
1570
+ try {
1571
+ expiration = Temporal.Instant.from(expires.value);
1572
+ } catch {
1573
+ return false;
1574
+ }
1575
+ if (Temporal.Instant.compare(Temporal.Now.instant(), expiration) >= 0) return false;
1576
+ }
1577
+ const domain = await getProofOption(proofConfig, SECURITY_DOMAIN, ["domain", SECURITY_DOMAIN], documentLoader);
1578
+ if (domain == null) return false;
1579
+ const proofDomains = domain.present ? parseStringSet(domain.value) : null;
1580
+ if (domain.present && proofDomains == null) return false;
1581
+ if (options.domain != null) {
1582
+ const expectedDomains = parseStringSet(options.domain);
1583
+ if (expectedDomains == null || proofDomains == null || !equalStringSets(proofDomains, expectedDomains)) return false;
1584
+ }
1585
+ const challenge = await getProofOption(proofConfig, SECURITY_CHALLENGE, ["challenge", SECURITY_CHALLENGE], documentLoader);
1586
+ if (challenge == null || challenge.present && typeof challenge.value !== "string" || options.challenge != null && (!challenge.present || challenge.value !== options.challenge)) return false;
1587
+ const nonce = await getProofOption(proofConfig, SECURITY_NONCE, ["nonce", SECURITY_NONCE], documentLoader);
1588
+ if (nonce == null || nonce.present && typeof nonce.value !== "string") return false;
1589
+ const previousProof = await getProofOption(proofConfig, SECURITY_PREVIOUS_PROOF, ["previousProof", SECURITY_PREVIOUS_PROOF], documentLoader);
1590
+ if (previousProof == null || previousProof.present && typeof previousProof.value !== "string" && (!Array.isArray(previousProof.value) || previousProof.value.some((item) => typeof item !== "string"))) return false;
1591
+ return true;
1592
+ }
1593
+ async function verifyProofInternal(jsonLd, proof, options, messageDigestCache, rawProofCandidate) {
1594
+ if (!isJsonLdNode(jsonLd) || proof.cryptosuite !== "eddsa-jcs-2022" || proof.verificationMethodId == null || proof.proofPurpose !== "assertionMethod" || proof.proofValue == null || proof.created == null) return null;
1595
+ const proofContextLoader = messageDigestCache.proofContextLoader ?? preloadedOnlyDocumentLoader;
1596
+ const proofConfiguration = await createProofConfiguration(jsonLd, proof, options, proofContextLoader, rawProofCandidate);
1597
+ if (proofConfiguration == null || !await hasValidProofOptions(proofConfiguration.value, options, proofContextLoader)) return null;
1598
+ const publicKeyPromise = measureSignatureKeyFetch(options.meterProvider, "object_integrity", () => fetchKey(proof.verificationMethodId, Multikey, options));
1599
+ const proofBytes = new TextEncoder().encode(serialize(proofConfiguration.value));
1291
1600
  const proofDigest = await crypto.subtle.digest("SHA-256", proofBytes);
1292
- const msg = { ...jsonLd };
1293
- if ("proof" in msg) delete msg.proof;
1294
- if ("https://w3id.org/security#proof" in msg) delete msg["https://w3id.org/security#proof"];
1295
1601
  let fetchedKey;
1296
1602
  try {
1297
1603
  fetchedKey = await publicKeyPromise;
@@ -1323,7 +1629,7 @@ async function verifyProofInternal(jsonLd, proof, options) {
1323
1629
  get: () => Promise.resolve(void 0),
1324
1630
  set: async (keyId, key) => await options.keyCache?.set(keyId, key)
1325
1631
  }
1326
- });
1632
+ }, messageDigestCache, rawProofCandidate);
1327
1633
  }
1328
1634
  logger.debug("The fetched key (verificationMethod) for the proof is not a valid Ed25519 key:\n{keyId}", {
1329
1635
  proof,
@@ -1334,15 +1640,21 @@ async function verifyProofInternal(jsonLd, proof, options) {
1334
1640
  const digest = new Uint8Array(proofDigest.byteLength + 32);
1335
1641
  digest.set(new Uint8Array(proofDigest), 0);
1336
1642
  const proofValue = proof.proofValue;
1337
- const verifyCandidate = async (candidate) => {
1338
- const msgBytes = encoder.encode(serialize(candidate));
1339
- const msgDigest = await crypto.subtle.digest("SHA-256", msgBytes);
1643
+ const verifyCandidate = async (msgDigest) => {
1340
1644
  digest.set(new Uint8Array(msgDigest), proofDigest.byteLength);
1341
1645
  return await crypto.subtle.verify("Ed25519", publicKey.publicKey, proofValue.slice(), digest);
1342
1646
  };
1343
- if (await verifyCandidate(msg)) return publicKey;
1344
- const normalized = await normalizeOutgoingActivityJsonLd(msg, preloadedOnlyDocumentLoader);
1345
- if (normalized !== msg && await verifyCandidate(normalized)) return publicKey;
1647
+ const messageDigestKey = serialize(proofConfiguration.context ?? null);
1648
+ const messageDigestValues = messageDigestCache.values ??= /* @__PURE__ */ new Map();
1649
+ let messageDigestsPromise = messageDigestValues.get(messageDigestKey);
1650
+ if (messageDigestsPromise == null) {
1651
+ messageDigestsPromise = createProofMessageDigests(jsonLd, messageDigestCache.proofContextLoader, proofConfiguration.context);
1652
+ messageDigestValues.set(messageDigestKey, messageDigestsPromise);
1653
+ }
1654
+ const messageDigests = await messageDigestsPromise;
1655
+ if (await verifyCandidate(messageDigests.onWire)) return publicKey;
1656
+ const normalizedDigest = await messageDigests.normalized();
1657
+ if (normalizedDigest != null && await verifyCandidate(normalizedDigest)) return publicKey;
1346
1658
  if (fetchedKey.cached) {
1347
1659
  logger.debug("Failed to verify the proof with the cached key {keyId}; retrying with the freshly fetched key...", {
1348
1660
  keyId: proof.verificationMethodId.href,
@@ -1354,7 +1666,7 @@ async function verifyProofInternal(jsonLd, proof, options) {
1354
1666
  get: () => Promise.resolve(void 0),
1355
1667
  set: async (keyId, key) => await options.keyCache?.set(keyId, key)
1356
1668
  }
1357
- });
1669
+ }, messageDigestCache, rawProofCandidate);
1358
1670
  }
1359
1671
  logger.debug("Failed to verify the proof with the fetched key {keyId}:\n{proof}", {
1360
1672
  keyId: proof.verificationMethodId.href,
@@ -1362,6 +1674,228 @@ async function verifyProofInternal(jsonLd, proof, options) {
1362
1674
  });
1363
1675
  return null;
1364
1676
  }
1677
+ const AS_NAMESPACE = "https://www.w3.org/ns/activitystreams#";
1678
+ const FEP_2277_ACTOR_PROPERTIES = ["http://www.w3.org/ns/ldp#inbox", `${AS_NAMESPACE}outbox`];
1679
+ const FEP_2277_COLLECTION_PROPERTIES = [
1680
+ "items",
1681
+ "orderedItems",
1682
+ "totalItems",
1683
+ "partOf",
1684
+ "first",
1685
+ "last",
1686
+ "next",
1687
+ "prev",
1688
+ "current"
1689
+ ].map((property) => AS_NAMESPACE + property);
1690
+ const PORTABLE_OBJECT_ID_PATTERN = /^ap(?:\+ef61)?:\/\//i;
1691
+ const FUNCTIONAL_PROOF_PROPERTIES = [
1692
+ `${SECURITY_NAMESPACE}cryptosuite`,
1693
+ SECURITY_VERIFICATION_METHOD,
1694
+ `${SECURITY_NAMESPACE}proofPurpose`,
1695
+ `${SECURITY_NAMESPACE}proofValue`,
1696
+ "http://purl.org/dc/terms/created"
1697
+ ];
1698
+ function isJsonLdNode(value) {
1699
+ return typeof value === "object" && value != null && !Array.isArray(value);
1700
+ }
1701
+ function hasValidPortableProofShape(proofValue) {
1702
+ if (!isJsonLdNode(proofValue)) return false;
1703
+ let proofNode = proofValue;
1704
+ if ("@graph" in proofNode) {
1705
+ const graph = proofNode["@graph"];
1706
+ if (!Array.isArray(graph) || graph.length !== 1 || !isJsonLdNode(graph[0])) return false;
1707
+ proofNode = graph[0];
1708
+ }
1709
+ const types = proofNode["@type"];
1710
+ return Array.isArray(types) && types.length === 1 && types[0] === DATA_INTEGRITY_PROOF && FUNCTIONAL_PROOF_PROPERTIES.every((property) => {
1711
+ const values = proofNode[property];
1712
+ return Array.isArray(values) && values.length === 1 && !(isJsonLdNode(values[0]) && "@list" in values[0]);
1713
+ });
1714
+ }
1715
+ function classifyFep2277CoreType(node) {
1716
+ if (FEP_2277_ACTOR_PROPERTIES.every((property) => property in node)) return "actor";
1717
+ if (`${SECURITY_NAMESPACE}publicKeyMultibase` in node) return "verificationMethod";
1718
+ if (`${SECURITY_NAMESPACE}publicKeyPem` in node) return "publicKey";
1719
+ if (`${AS_NAMESPACE}href` in node) return "link";
1720
+ if (`${AS_NAMESPACE}actor` in node) return "activity";
1721
+ if (FEP_2277_COLLECTION_PROPERTIES.some((property) => property in node)) return "collection";
1722
+ return "object";
1723
+ }
1724
+ async function expandPortableObjectRoot(jsonLd, contextLoader) {
1725
+ if (!isJsonLdNode(jsonLd)) throw new TypeError("Expected a single JSON-LD object.");
1726
+ const loadedContexts = /* @__PURE__ */ new Map();
1727
+ const loader = getNormalizationContextLoader(contextLoader);
1728
+ const recordingLoader = async (url, options) => {
1729
+ const remoteDocument = await loader(url, options);
1730
+ const key = URL.canParse(url) ? new URL(url).href : url;
1731
+ loadedContexts.set(key, structuredClone(remoteDocument));
1732
+ return remoteDocument;
1733
+ };
1734
+ const expanded = await jsonld.expand(jsonLd, {
1735
+ documentLoader: recordingLoader,
1736
+ keepFreeFloatingNodes: true
1737
+ });
1738
+ if (expanded.length !== 1 || !isJsonLdNode(expanded[0])) throw new TypeError("Expected a single JSON-LD object.");
1739
+ return {
1740
+ root: expanded[0],
1741
+ proofContextLoader: async (url, options) => {
1742
+ const key = URL.canParse(url) ? new URL(url).href : url;
1743
+ const remoteDocument = loadedContexts.get(key);
1744
+ if (remoteDocument != null) return structuredClone(remoteDocument);
1745
+ return await preloadedOnlyDocumentLoader(url, options);
1746
+ }
1747
+ };
1748
+ }
1749
+ /**
1750
+ * Verifies the FEP-ef61 Object Integrity Proof policy for a portable object.
1751
+ *
1752
+ * This applies the FEP-2277 core-type classification to the top-level JSON-LD
1753
+ * node. Portable actors, activities, and objects require proofs. A portable
1754
+ * collection without a proof is reported separately so a caller can apply a
1755
+ * gateway trust policy. Embedded portable objects are not traversed.
1756
+ *
1757
+ * Every proof must use a DID URL whose DID matches the portable object's
1758
+ * authority, and every proof must pass {@link verifyProof}.
1759
+ *
1760
+ * @param jsonLd The JSON-LD document to verify.
1761
+ * @param options Additional options. See also
1762
+ * {@link VerifyPortableObjectProofOptions}.
1763
+ * @returns The detailed portable proof-policy result.
1764
+ * @throws {TypeError} If the input is not a single JSON-LD object or has a
1765
+ * malformed portable ID.
1766
+ * @since 2.4.0
1767
+ */
1768
+ async function verifyPortableObjectProof(jsonLd, options = {}) {
1769
+ if (isJsonLdNode(jsonLd) && typeof jsonLd["@id"] === "string" && !PORTABLE_OBJECT_ID_PATTERN.test(jsonLd["@id"])) return {
1770
+ verified: false,
1771
+ reason: { type: "notPortableObject" }
1772
+ };
1773
+ const { root, proofContextLoader } = await expandPortableObjectRoot(jsonLd, options.contextLoader);
1774
+ const id = root["@id"];
1775
+ if (typeof id !== "string" || !PORTABLE_OBJECT_ID_PATTERN.test(id)) return {
1776
+ verified: false,
1777
+ reason: { type: "notPortableObject" }
1778
+ };
1779
+ const objectId = parseIri(id);
1780
+ getFe34Origin(objectId);
1781
+ const objectType = classifyFep2277CoreType(root);
1782
+ if (objectType === "verificationMethod" || objectType === "publicKey" || objectType === "link") return {
1783
+ verified: false,
1784
+ reason: {
1785
+ type: "unsupportedObjectType",
1786
+ objectType
1787
+ }
1788
+ };
1789
+ const proofValues = root[SECURITY_PROOF];
1790
+ if (proofValues == null || Array.isArray(proofValues) && proofValues.length < 1) return objectType === "collection" ? {
1791
+ verified: false,
1792
+ reason: { type: "unsecuredCollection" }
1793
+ } : {
1794
+ verified: false,
1795
+ reason: { type: "missingProof" }
1796
+ };
1797
+ if (!Array.isArray(proofValues)) return {
1798
+ verified: false,
1799
+ reason: {
1800
+ type: "invalidProof",
1801
+ proofIndex: 0
1802
+ }
1803
+ };
1804
+ const rawProofValues = isJsonLdNode(jsonLd) ? await getRawProofValues(jsonLd, proofContextLoader) : [];
1805
+ const proofs = [];
1806
+ for (let proofIndex = 0; proofIndex < proofValues.length; proofIndex++) {
1807
+ const proofValue = proofValues[proofIndex];
1808
+ if (!hasValidPortableProofShape(proofValue)) return {
1809
+ verified: false,
1810
+ reason: {
1811
+ type: "invalidProof",
1812
+ proofIndex
1813
+ }
1814
+ };
1815
+ let proof;
1816
+ try {
1817
+ proof = await DataIntegrityProof.fromJsonLd(proofValue, options);
1818
+ } catch {
1819
+ return {
1820
+ verified: false,
1821
+ reason: {
1822
+ type: "invalidProof",
1823
+ proofIndex
1824
+ }
1825
+ };
1826
+ }
1827
+ proofs.push(proof);
1828
+ }
1829
+ for (let proofIndex = 0; proofIndex < proofs.length; proofIndex++) {
1830
+ const verificationMethod = proofs[proofIndex].verificationMethodId;
1831
+ if (verificationMethod == null) return {
1832
+ verified: false,
1833
+ reason: {
1834
+ type: "invalidProof",
1835
+ proofIndex
1836
+ }
1837
+ };
1838
+ if (verificationMethod.protocol !== "did:") return {
1839
+ verified: false,
1840
+ reason: {
1841
+ type: "unsupportedVerificationMethod",
1842
+ proofIndex,
1843
+ verificationMethod
1844
+ }
1845
+ };
1846
+ try {
1847
+ getFe34Origin(verificationMethod);
1848
+ } catch (error) {
1849
+ if (!(error instanceof TypeError)) throw error;
1850
+ return {
1851
+ verified: false,
1852
+ reason: {
1853
+ type: "unsupportedVerificationMethod",
1854
+ proofIndex,
1855
+ verificationMethod
1856
+ }
1857
+ };
1858
+ }
1859
+ if (!haveSameFe34Origin(objectId, verificationMethod)) return {
1860
+ verified: false,
1861
+ reason: {
1862
+ type: "verificationMethodMismatch",
1863
+ proofIndex,
1864
+ objectId,
1865
+ verificationMethod
1866
+ }
1867
+ };
1868
+ }
1869
+ const keys = [];
1870
+ const rawProofCandidatePool = {
1871
+ candidates: await parseRawProofCandidates(jsonLd, rawProofValues, options, proofContextLoader),
1872
+ used: /* @__PURE__ */ new Set()
1873
+ };
1874
+ const messageDigestCache = { proofContextLoader };
1875
+ for (let proofIndex = 0; proofIndex < proofs.length; proofIndex++) {
1876
+ const rawProofCandidate = takeRawProofCandidate(rawProofCandidatePool, proofs[proofIndex]);
1877
+ if (rawProofCandidate == null) return {
1878
+ verified: false,
1879
+ reason: {
1880
+ type: "invalidProof",
1881
+ proofIndex
1882
+ }
1883
+ };
1884
+ const key = await verifyProofWithMessageDigestCache(jsonLd, proofs[proofIndex], options, messageDigestCache, rawProofCandidate);
1885
+ if (key == null) return {
1886
+ verified: false,
1887
+ reason: {
1888
+ type: "invalidProof",
1889
+ proofIndex
1890
+ }
1891
+ };
1892
+ keys.push(key);
1893
+ }
1894
+ return {
1895
+ verified: true,
1896
+ keys
1897
+ };
1898
+ }
1365
1899
  /**
1366
1900
  * Verifies the given object. It will verify all the proofs in the object,
1367
1901
  * and succeed only if all the proofs are valid and all attributions and
@@ -1383,10 +1917,48 @@ async function verifyObject(cls, jsonLd, options = {}) {
1383
1917
  "proof"
1384
1918
  ]);
1385
1919
  const object = await cls.fromJsonLd(jsonLd, options);
1920
+ const defaultDocumentLoader = getDocumentLoader();
1921
+ const proofContextLoader = options.contextLoader ?? defaultDocumentLoader;
1386
1922
  const attributions = new Set(object.attributionIds.map((uri) => uri.href));
1387
1923
  if (object instanceof Activity) for (const uri of object.actorIds) attributions.add(uri.href);
1388
- for await (const proof of object.getProofs(options)) {
1389
- const key = await verifyProof(jsonLd, proof, options);
1924
+ const rawProofValues = isJsonLdNode(jsonLd) ? await getRawProofValues(jsonLd, proofContextLoader) : [];
1925
+ const rawProofCandidates = isJsonLdNode(jsonLd) ? await parseRawProofCandidates(jsonLd, rawProofValues, options, proofContextLoader) : [];
1926
+ const rawProofCandidatePool = {
1927
+ candidates: rawProofCandidates,
1928
+ used: /* @__PURE__ */ new Set()
1929
+ };
1930
+ const baseDocumentLoader = options.documentLoader ?? defaultDocumentLoader;
1931
+ const hydratedCandidates = /* @__PURE__ */ new Set();
1932
+ const proofDocumentLoader = async (url, loaderOptions) => {
1933
+ const remoteDocument = await baseDocumentLoader(url, loaderOptions);
1934
+ const reference = normalizeDocumentUrl(url);
1935
+ const candidateIndex = rawProofCandidates.findIndex((candidate, index) => !hydratedCandidates.has(index) && !rawProofCandidatePool.used.has(index) && candidate.reference === reference);
1936
+ if (candidateIndex >= 0) {
1937
+ hydratedCandidates.add(candidateIndex);
1938
+ let parsed = null;
1939
+ try {
1940
+ parsed = await DataIntegrityProof.fromJsonLd(remoteDocument.document, {
1941
+ documentLoader: baseDocumentLoader,
1942
+ contextLoader: proofContextLoader,
1943
+ tracerProvider: options.tracerProvider,
1944
+ baseUrl: parseIri(remoteDocument.documentUrl)
1945
+ });
1946
+ } catch {}
1947
+ rawProofCandidates[candidateIndex] = {
1948
+ value: structuredClone(remoteDocument.document),
1949
+ proof: parsed,
1950
+ reference
1951
+ };
1952
+ }
1953
+ return remoteDocument;
1954
+ };
1955
+ for await (const proof of object.getProofs({
1956
+ ...options,
1957
+ documentLoader: proofDocumentLoader
1958
+ })) {
1959
+ const rawProofCandidate = takeRawProofCandidate(rawProofCandidatePool, proof);
1960
+ if (rawProofCandidate == null) return null;
1961
+ const key = await verifyProofWithMessageDigestCache(jsonLd, proof, options, { proofContextLoader }, rawProofCandidate);
1390
1962
  if (key === null) return null;
1391
1963
  if (proof.verificationMethodId == null) return null;
1392
1964
  if (key.controllerId == null) {
@@ -1412,4 +1984,4 @@ function hasCryptographicOrigin(iri) {
1412
1984
  return /^did:/i.test(iri) || /^ap(?:\+ef61)?:\/\//i.test(iri);
1413
1985
  }
1414
1986
  //#endregion
1415
- export { verifySignature as C, verifyJsonLd as S, hasSignatureLike as _, verifyProof as a, signJsonLd as b, getKeyOwner as c, attachSignature as d, compactJsonLd as f, hasSignature as g, getNormalizationContextLoader as h, verifyObject as i, InvalidContextReferenceError as l, detachSignature as m, hasProofLike as n, normalizeOutgoingActivityJsonLd as o, createSignature as p, signObject as r, doesActorOwnKey as s, createProof as t, assertSafeJsonLd as u, isClearlyMalformedContextReference as v, wrapContextLoaderForJsonLd as w, verifyCompactJsonLd as x, isInvalidUrlTypeError as y };
1987
+ export { verifyJsonLd as C, verifyCompactJsonLd as S, wrapContextLoaderForJsonLd as T, hasSignature as _, verifyPortableObjectProof as a, isInvalidUrlTypeError as b, doesActorOwnKey as c, assertSafeJsonLd as d, attachSignature as f, getNormalizationContextLoader as g, detachSignature as h, verifyObject as i, getKeyOwner as l, createSignature as m, hasProofLike as n, verifyProof as o, compactJsonLd as p, signObject as r, normalizeOutgoingActivityJsonLd as s, createProof as t, InvalidContextReferenceError as u, hasSignatureLike as v, verifySignature as w, signJsonLd as x, isClearlyMalformedContextReference as y };