@adcp/sdk 16.0.0-beta.2 → 16.0.0-beta.4

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 (248) hide show
  1. package/README.md +54 -0
  2. package/dist/lib/auth/oauth/diagnose.js +3 -11
  3. package/dist/lib/auth/oauth/diagnose.mjs +4 -12
  4. package/dist/lib/auth/oauth/diagnostics.d.mts +2 -1
  5. package/dist/lib/auth/oauth/diagnostics.d.ts +2 -1
  6. package/dist/lib/auth/oauth/diagnostics.js +8 -10
  7. package/dist/lib/auth/oauth/diagnostics.mjs +7 -10
  8. package/dist/lib/core/ConversationTypes.d.mts +8 -3
  9. package/dist/lib/core/ConversationTypes.d.ts +8 -3
  10. package/dist/lib/core/SingleAgentClient.d.mts +5 -3
  11. package/dist/lib/core/SingleAgentClient.d.ts +5 -3
  12. package/dist/lib/core/TaskExecutor.js +5 -1
  13. package/dist/lib/core/TaskExecutor.mjs +5 -1
  14. package/dist/lib/errors/index.d.mts +9 -4
  15. package/dist/lib/errors/index.d.ts +9 -4
  16. package/dist/lib/index.d.mts +3 -3
  17. package/dist/lib/index.d.ts +3 -3
  18. package/dist/lib/index.js +8 -0
  19. package/dist/lib/index.mjs +14 -2
  20. package/dist/lib/negotiation/types.d.mts +20 -39
  21. package/dist/lib/negotiation/types.d.ts +20 -39
  22. package/dist/lib/protocols/index.d.mts +60 -24
  23. package/dist/lib/protocols/index.d.ts +60 -24
  24. package/dist/lib/protocols/index.js +9 -4
  25. package/dist/lib/protocols/index.mjs +3 -0
  26. package/dist/lib/protocols/mcp-modern.js +1 -0
  27. package/dist/lib/protocols/mcp-modern.mjs +2 -1
  28. package/dist/lib/protocols/mcp.js +1 -0
  29. package/dist/lib/protocols/mcp.mjs +2 -1
  30. package/dist/lib/protocols/responseSizeLimit.d.mts +91 -5
  31. package/dist/lib/protocols/responseSizeLimit.d.ts +91 -5
  32. package/dist/lib/protocols/responseSizeLimit.js +195 -31
  33. package/dist/lib/protocols/responseSizeLimit.mjs +192 -31
  34. package/dist/lib/reporting/consumer-runtime.js +2 -1
  35. package/dist/lib/reporting/consumer-runtime.mjs +2 -1
  36. package/dist/lib/reporting/ledger/handler.js +50 -11
  37. package/dist/lib/reporting/ledger/handler.mjs +50 -12
  38. package/dist/lib/reporting/ledger/index.d.mts +17 -14
  39. package/dist/lib/reporting/ledger/index.d.ts +17 -14
  40. package/dist/lib/reporting/ledger/index.js +32 -20
  41. package/dist/lib/reporting/ledger/index.mjs +21 -10
  42. package/dist/lib/reporting/ledger/offering-validation.d.mts +9 -0
  43. package/dist/lib/reporting/ledger/offering-validation.d.ts +9 -0
  44. package/dist/lib/reporting/{gcs/bucket-policy.js → ledger/offering-validation.js} +9 -8
  45. package/dist/lib/reporting/ledger/offering-validation.mjs +8 -0
  46. package/dist/lib/reporting/ledger/receipts.d.mts +48 -0
  47. package/dist/lib/reporting/ledger/receipts.d.ts +48 -0
  48. package/dist/lib/reporting/ledger/receipts.js +186 -0
  49. package/dist/lib/reporting/ledger/receipts.mjs +161 -0
  50. package/dist/lib/reporting/ledger/status-ingest.js +3 -3
  51. package/dist/lib/reporting/ledger/status-ingest.mjs +4 -5
  52. package/dist/lib/reporting/ledger/types.d.mts +43 -0
  53. package/dist/lib/reporting/ledger/types.d.ts +43 -0
  54. package/dist/lib/reporting/ledger/types.js +31 -2
  55. package/dist/lib/reporting/ledger/types.mjs +26 -1
  56. package/dist/lib/reporting/pagination.d.mts +6 -0
  57. package/dist/lib/reporting/pagination.d.ts +6 -0
  58. package/dist/lib/reporting/{gcs/errors.js → pagination.js} +12 -17
  59. package/dist/lib/reporting/pagination.mjs +12 -0
  60. package/dist/lib/reporting/reconciliation.d.mts +1 -0
  61. package/dist/lib/reporting/reconciliation.d.ts +1 -0
  62. package/dist/lib/reporting/reconciliation.js +3 -2
  63. package/dist/lib/reporting/reconciliation.mjs +3 -2
  64. package/dist/lib/reporting/service/index.d.mts +79 -153
  65. package/dist/lib/reporting/service/index.d.ts +79 -153
  66. package/dist/lib/reporting/service/index.js +34 -491
  67. package/dist/lib/reporting/service/index.mjs +36 -510
  68. package/dist/lib/reporting/service/scheduler-support.d.mts +43 -0
  69. package/dist/lib/reporting/service/scheduler-support.d.ts +43 -0
  70. package/dist/lib/reporting/service/scheduler-support.js +125 -0
  71. package/dist/lib/reporting/service/scheduler-support.mjs +96 -0
  72. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  73. package/dist/lib/signing/canonicalize.d.mts +4 -0
  74. package/dist/lib/signing/canonicalize.d.ts +4 -0
  75. package/dist/lib/signing/canonicalize.js +14 -8
  76. package/dist/lib/signing/canonicalize.mjs +14 -8
  77. package/dist/lib/signing/content-digest.d.mts +8 -0
  78. package/dist/lib/signing/content-digest.d.ts +8 -0
  79. package/dist/lib/signing/content-digest.js +11 -5
  80. package/dist/lib/signing/content-digest.mjs +10 -5
  81. package/dist/lib/signing/crypto.d.mts +15 -0
  82. package/dist/lib/signing/crypto.d.ts +15 -0
  83. package/dist/lib/signing/crypto.js +75 -3
  84. package/dist/lib/signing/crypto.mjs +78 -3
  85. package/dist/lib/signing/server.d.mts +1 -1
  86. package/dist/lib/signing/server.d.ts +1 -1
  87. package/dist/lib/signing/server.js +2 -0
  88. package/dist/lib/signing/server.mjs +2 -1
  89. package/dist/lib/signing/signer.js +11 -14
  90. package/dist/lib/signing/signer.mjs +13 -16
  91. package/dist/lib/signing/testing.js +2 -6
  92. package/dist/lib/signing/testing.mjs +3 -7
  93. package/dist/lib/signing/verifier.js +2 -2
  94. package/dist/lib/signing/verifier.mjs +3 -3
  95. package/dist/lib/signing/web-bot-auth.js +122 -43
  96. package/dist/lib/signing/web-bot-auth.mjs +128 -44
  97. package/dist/lib/signing/webhook-verifier.js +2 -2
  98. package/dist/lib/signing/webhook-verifier.mjs +3 -3
  99. package/dist/lib/substitution/compile.js +2 -1
  100. package/dist/lib/substitution/compile.mjs +2 -1
  101. package/dist/lib/substitution/consent-macros.d.mts +4 -0
  102. package/dist/lib/substitution/consent-macros.d.ts +4 -0
  103. package/dist/lib/substitution/consent-macros.js +45 -0
  104. package/dist/lib/substitution/consent-macros.mjs +20 -0
  105. package/dist/lib/substitution/index.d.mts +1 -1
  106. package/dist/lib/substitution/index.d.ts +1 -1
  107. package/dist/lib/substitution/index.js +2 -0
  108. package/dist/lib/substitution/index.mjs +2 -1
  109. package/dist/lib/substitution/translate.d.mts +15 -2
  110. package/dist/lib/substitution/translate.d.ts +15 -2
  111. package/dist/lib/substitution/translate.js +148 -26
  112. package/dist/lib/substitution/translate.mjs +147 -26
  113. package/dist/lib/testing/client.js +2 -1
  114. package/dist/lib/testing/client.mjs +2 -1
  115. package/dist/lib/testing/scenarios/capabilities.js +1 -1
  116. package/dist/lib/testing/scenarios/capabilities.mjs +1 -1
  117. package/dist/lib/testing/storyboard/junit.js +16 -3
  118. package/dist/lib/testing/storyboard/junit.mjs +16 -3
  119. package/dist/lib/testing/storyboard/request-signing/builder.js +12 -14
  120. package/dist/lib/testing/storyboard/request-signing/builder.mjs +13 -15
  121. package/dist/lib/testing/storyboard/runner.js +94 -25
  122. package/dist/lib/testing/storyboard/runner.mjs +94 -25
  123. package/dist/lib/testing/storyboard/signer-grader/grader.js +2 -7
  124. package/dist/lib/testing/storyboard/signer-grader/grader.mjs +2 -7
  125. package/dist/lib/testing/storyboard/types.d.mts +6 -0
  126. package/dist/lib/testing/storyboard/types.d.ts +6 -0
  127. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  128. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  129. package/dist/lib/types/enums.generated.d.mts +3 -0
  130. package/dist/lib/types/enums.generated.d.ts +3 -0
  131. package/dist/lib/types/enums.generated.js +9 -0
  132. package/dist/lib/types/enums.generated.mjs +6 -0
  133. package/dist/lib/validation/schema-loader.js +25 -0
  134. package/dist/lib/validation/schema-loader.mjs +24 -0
  135. package/dist/lib/version.d.mts +3 -3
  136. package/dist/lib/version.d.ts +3 -3
  137. package/dist/lib/version.js +3 -3
  138. package/dist/lib/version.mjs +3 -3
  139. package/docs/TYPE-SUMMARY.md +28 -5
  140. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +3 -2
  141. package/docs/guides/REPORTING-GCS-FENCE.md +3 -3
  142. package/docs/guides/REPORTING-GCS-MANAGED.md +4 -4
  143. package/docs/guides/REPORTING-LEDGER-CUTOVER.md +7 -7
  144. package/docs/guides/REPORTING-LEDGER.md +107 -51
  145. package/docs/guides/REPORTING-OPERATIONS.md +66 -5
  146. package/docs/guides/REPORTING-STABILITY.md +36 -32
  147. package/docs/guides/UNIVERSAL-MACRO-COMPILATION.md +38 -0
  148. package/docs/guides/VALIDATE-YOUR-AGENT.md +12 -0
  149. package/docs/llms.txt +4 -3
  150. package/docs/migration-14.x-rc-worksheet.md +4 -7
  151. package/docs/migration-reporting-storage-package.md +186 -0
  152. package/examples/README.md +1 -1
  153. package/package.json +14 -78
  154. package/dist/lib/reporting/azure/index.d.mts +0 -31
  155. package/dist/lib/reporting/azure/index.d.ts +0 -31
  156. package/dist/lib/reporting/azure/index.js +0 -266
  157. package/dist/lib/reporting/azure/index.mjs +0 -249
  158. package/dist/lib/reporting/bigquery/index.d.mts +0 -246
  159. package/dist/lib/reporting/bigquery/index.d.ts +0 -246
  160. package/dist/lib/reporting/bigquery/index.js +0 -633
  161. package/dist/lib/reporting/bigquery/index.mjs +0 -594
  162. package/dist/lib/reporting/gcs/adapter.d.mts +0 -38
  163. package/dist/lib/reporting/gcs/adapter.d.ts +0 -38
  164. package/dist/lib/reporting/gcs/adapter.js +0 -342
  165. package/dist/lib/reporting/gcs/adapter.mjs +0 -325
  166. package/dist/lib/reporting/gcs/bucket-policy.d.mts +0 -3
  167. package/dist/lib/reporting/gcs/bucket-policy.d.ts +0 -3
  168. package/dist/lib/reporting/gcs/bucket-policy.mjs +0 -7
  169. package/dist/lib/reporting/gcs/errors.d.mts +0 -11
  170. package/dist/lib/reporting/gcs/errors.d.ts +0 -11
  171. package/dist/lib/reporting/gcs/errors.mjs +0 -16
  172. package/dist/lib/reporting/gcs/fence.d.mts +0 -41
  173. package/dist/lib/reporting/gcs/fence.d.ts +0 -41
  174. package/dist/lib/reporting/gcs/fence.js +0 -250
  175. package/dist/lib/reporting/gcs/fence.mjs +0 -230
  176. package/dist/lib/reporting/gcs/index.d.mts +0 -18
  177. package/dist/lib/reporting/gcs/index.d.ts +0 -18
  178. package/dist/lib/reporting/gcs/index.js +0 -44
  179. package/dist/lib/reporting/gcs/index.mjs +0 -14
  180. package/dist/lib/reporting/gcs/io.d.mts +0 -7
  181. package/dist/lib/reporting/gcs/io.d.ts +0 -7
  182. package/dist/lib/reporting/gcs/io.js +0 -95
  183. package/dist/lib/reporting/gcs/io.mjs +0 -69
  184. package/dist/lib/reporting/gcs/reader.d.mts +0 -67
  185. package/dist/lib/reporting/gcs/reader.d.ts +0 -67
  186. package/dist/lib/reporting/gcs/reader.js +0 -193
  187. package/dist/lib/reporting/gcs/reader.mjs +0 -169
  188. package/dist/lib/reporting/gcs/row-provider.d.mts +0 -39
  189. package/dist/lib/reporting/gcs/row-provider.d.ts +0 -39
  190. package/dist/lib/reporting/gcs/row-provider.js +0 -225
  191. package/dist/lib/reporting/gcs/row-provider.mjs +0 -208
  192. package/dist/lib/reporting/gcs/validation.d.mts +0 -5
  193. package/dist/lib/reporting/gcs/validation.d.ts +0 -5
  194. package/dist/lib/reporting/gcs/validation.js +0 -49
  195. package/dist/lib/reporting/gcs/validation.mjs +0 -25
  196. package/dist/lib/reporting/ledger/change-feed.d.mts +0 -69
  197. package/dist/lib/reporting/ledger/change-feed.d.ts +0 -69
  198. package/dist/lib/reporting/ledger/change-feed.js +0 -107
  199. package/dist/lib/reporting/ledger/change-feed.mjs +0 -80
  200. package/dist/lib/reporting/ledger/managed-postgres.d.mts +0 -293
  201. package/dist/lib/reporting/ledger/managed-postgres.d.ts +0 -293
  202. package/dist/lib/reporting/ledger/managed-postgres.js +0 -2346
  203. package/dist/lib/reporting/ledger/managed-postgres.mjs +0 -2332
  204. package/dist/lib/reporting/ledger/managed-router.d.mts +0 -148
  205. package/dist/lib/reporting/ledger/managed-router.d.ts +0 -148
  206. package/dist/lib/reporting/ledger/managed-router.js +0 -280
  207. package/dist/lib/reporting/ledger/managed-router.mjs +0 -258
  208. package/dist/lib/reporting/ledger/managed.d.mts +0 -535
  209. package/dist/lib/reporting/ledger/managed.d.ts +0 -535
  210. package/dist/lib/reporting/ledger/managed.js +0 -761
  211. package/dist/lib/reporting/ledger/managed.mjs +0 -729
  212. package/dist/lib/reporting/ledger/notification-activity.d.mts +0 -332
  213. package/dist/lib/reporting/ledger/notification-activity.d.ts +0 -332
  214. package/dist/lib/reporting/ledger/notification-activity.js +0 -1366
  215. package/dist/lib/reporting/ledger/notification-activity.mjs +0 -1337
  216. package/dist/lib/reporting/ledger/object-writes.d.mts +0 -128
  217. package/dist/lib/reporting/ledger/object-writes.d.ts +0 -128
  218. package/dist/lib/reporting/ledger/object-writes.js +0 -147
  219. package/dist/lib/reporting/ledger/object-writes.mjs +0 -114
  220. package/dist/lib/reporting/ledger/postgres.d.mts +0 -689
  221. package/dist/lib/reporting/ledger/postgres.d.ts +0 -689
  222. package/dist/lib/reporting/ledger/postgres.js +0 -4462
  223. package/dist/lib/reporting/ledger/postgres.mjs +0 -4462
  224. package/dist/lib/reporting/ledger/row-storage-migration.d.mts +0 -59
  225. package/dist/lib/reporting/ledger/row-storage-migration.d.ts +0 -59
  226. package/dist/lib/reporting/ledger/row-storage-migration.js +0 -365
  227. package/dist/lib/reporting/ledger/row-storage-migration.mjs +0 -339
  228. package/dist/lib/reporting/ledger/row-storage-object.d.mts +0 -203
  229. package/dist/lib/reporting/ledger/row-storage-object.d.ts +0 -203
  230. package/dist/lib/reporting/ledger/row-storage-object.js +0 -379
  231. package/dist/lib/reporting/ledger/row-storage-object.mjs +0 -335
  232. package/dist/lib/reporting/ledger/row-storage-provider-io.d.mts +0 -44
  233. package/dist/lib/reporting/ledger/row-storage-provider-io.d.ts +0 -44
  234. package/dist/lib/reporting/ledger/row-storage-provider-io.js +0 -142
  235. package/dist/lib/reporting/ledger/row-storage-provider-io.mjs +0 -111
  236. package/dist/lib/reporting/ledger/row-storage.d.mts +0 -316
  237. package/dist/lib/reporting/ledger/row-storage.d.ts +0 -316
  238. package/dist/lib/reporting/ledger/row-storage.js +0 -812
  239. package/dist/lib/reporting/ledger/row-storage.mjs +0 -802
  240. package/dist/lib/reporting/s3/index.d.mts +0 -34
  241. package/dist/lib/reporting/s3/index.d.ts +0 -34
  242. package/dist/lib/reporting/s3/index.js +0 -347
  243. package/dist/lib/reporting/s3/index.mjs +0 -340
  244. package/dist/lib/reporting/service/maintenance.d.mts +0 -148
  245. package/dist/lib/reporting/service/maintenance.d.ts +0 -148
  246. package/dist/lib/reporting/service/maintenance.js +0 -185
  247. package/dist/lib/reporting/service/maintenance.mjs +0 -159
  248. package/examples/reliable-reporting-service/README.md +0 -169
@@ -51,6 +51,7 @@ module.exports = __toCommonJS(web_bot_auth_exports);
51
51
  var import_version = require('../version.js');
52
52
  var import_crypto = require("crypto");
53
53
  var import_structured_headers = require("structured-headers");
54
+ var import_http_message_sig = require("http-message-sig");
54
55
  var import_net = require('../net/index.js');
55
56
  var import_etld = require('./agent-resolver/etld.js');
56
57
  var import_canonicalize = require('./agent-resolver/canonicalize.js');
@@ -176,11 +177,11 @@ function receivedAgentOrigin(value) {
176
177
  }
177
178
  }
178
179
  function buildWebBotAuthSignatureBase(input, request, response) {
179
- const lines = input.components.map((component) => {
180
- const bare = component.split(";", 1)[0];
180
+ const lines = input.components.map((component2) => {
181
+ const bare = component2.split(";", 1)[0];
181
182
  let identifier;
182
183
  try {
183
- identifier = (0, import_structured_headers.parseItem)(`"${bare}"${component.slice(bare.length)}`);
184
+ identifier = (0, import_structured_headers.parseItem)(`"${bare}"${component2.slice(bare.length)}`);
184
185
  } catch {
185
186
  return bad("component");
186
187
  }
@@ -237,17 +238,29 @@ function assertDigest(headers, body) {
237
238
  if (!digest || !(0, import_content_digest.contentDigestUsesEncoding)(digest, "rfc8941-base64") || !(0, import_content_digest.contentDigestMatches)(digest, body))
238
239
  denied("content_digest");
239
240
  }
240
- function verifyBytes(input, request, jwk, response) {
241
+ function signatureBytes(input, request, jwk, response) {
241
242
  const alg = algorithm(jwk);
242
243
  if (input.params.alg !== void 0 && input.params.alg !== alg) denied("algorithm");
243
244
  const signature = (0, import_canonicalize2.getHeaderValue)(response?.headers ?? request.headers, "signature");
244
245
  if (signature === void 0 || signature === "") denied("headers_missing");
245
- let bytes;
246
246
  try {
247
- bytes = (0, import_parser.parseSignature)(signature ?? "", input.label, "rfc8941-base64").bytes;
247
+ return { alg, bytes: (0, import_parser.parseSignature)(signature ?? "", input.label, "rfc8941-base64").bytes };
248
248
  } catch {
249
249
  return bad("signature");
250
250
  }
251
+ }
252
+ async function verifyBytesAsync(input, request, jwk) {
253
+ const { alg, bytes } = signatureBytes(input, request, jwk);
254
+ let valid = false;
255
+ try {
256
+ valid = await (0, import_crypto2.verifySignatureAsync)(alg, jwk, Buffer.from(buildWebBotAuthSignatureBase(input, request)), bytes);
257
+ } catch (error) {
258
+ if (error instanceof WebBotAuthError) throw error;
259
+ }
260
+ if (!valid) denied("signature_invalid");
261
+ }
262
+ function verifyBytes(input, request, jwk, response) {
263
+ const { alg, bytes } = signatureBytes(input, request, jwk, response);
251
264
  let valid = false;
252
265
  try {
253
266
  valid = (0, import_crypto2.verifySignature)(
@@ -386,8 +399,8 @@ async function verifyWebBotAuth(request, options) {
386
399
  (c) => c.startsWith("signature-agent;key=") && !verified.some((s) => selected.find((i) => i.label === s.label).components.includes(c))
387
400
  );
388
401
  if (agentComponents.length !== 1) denied("agent_not_covered");
389
- const component = (0, import_structured_headers.parseItem)(`"${agentComponents[0].replace("signature-agent;", 'signature-agent";')}`);
390
- const memberKey = component[1].get("key");
402
+ const component2 = (0, import_structured_headers.parseItem)(`"${agentComponents[0].replace("signature-agent;", 'signature-agent";')}`);
403
+ const memberKey = component2[1].get("key");
391
404
  if (typeof memberKey !== "string" || memberKey !== input.label) bad("agent_member");
392
405
  const member = agents.get(memberKey);
393
406
  if (!member) denied("agent_not_covered");
@@ -419,7 +432,7 @@ async function verifyWebBotAuth(request, options) {
419
432
  denied("directory_key");
420
433
  const key = checkedDirectory.keys.find((key2) => key2.kid === keyid);
421
434
  if (!key || jwkThumbprint(key) !== keyid) denied("key");
422
- verifyBytes(input, request, key);
435
+ await verifyBytesAsync(input, request, key);
423
436
  if (options.isRevoked) await legacyRevocationCheck(options, origin, keyid);
424
437
  const nonceTuple = JSON.stringify([origin, nonce]);
425
438
  if (nonces.has(nonceTuple)) throw new WebBotAuthError(options.replayStatus ?? 429, "nonce_replayed");
@@ -655,7 +668,7 @@ class SignatureDirectoryResolver {
655
668
  return this.getVerifiedDirectory(origin)?.proof;
656
669
  }
657
670
  }
658
- async function signBase(base, key) {
671
+ function webBotSigner(key) {
659
672
  const jwk = "privateKey" in key ? key.privateKey : key.publicKey;
660
673
  const alg = algorithm(jwk);
661
674
  if (!["test", "development"].includes(process.env.NODE_ENV ?? "") && TEST_KIDS.has(jwkThumbprint(jwk)))
@@ -663,16 +676,40 @@ async function signBase(base, key) {
663
676
  if ("provider" in key) {
664
677
  if (key.provider.keyid !== jwkThumbprint(jwk) || key.provider.algorithm !== alg)
665
678
  throw new TypeError("Web Bot Auth provider identity does not match its public key");
666
- return key.provider.sign(Buffer.from(base));
679
+ return { algorithm: alg, sign: async (data) => Buffer.from(await key.provider.sign(Buffer.from(data))) };
667
680
  }
668
- const privateKey = (0, import_crypto.createPrivateKey)({ key: jwk, format: "jwk" });
669
- if (alg === "rsa-pss-sha512")
670
- return (0, import_crypto.sign)("sha512", Buffer.from(base), {
671
- key: privateKey,
672
- padding: import_crypto.constants.RSA_PKCS1_PSS_PADDING,
673
- saltLength: 64
674
- });
675
- return alg === "ed25519" ? (0, import_crypto.sign)(null, Buffer.from(base), privateKey) : (0, import_crypto.sign)("sha256", Buffer.from(base), { key: privateKey, dsaEncoding: "ieee-p1363" });
681
+ if (alg === "rsa-pss-sha512") {
682
+ const privateKey = (0, import_crypto.createPrivateKey)({ key: jwk, format: "jwk" });
683
+ return {
684
+ algorithm: alg,
685
+ sign: (data) => (0, import_crypto.sign)("sha512", Buffer.from(data), {
686
+ key: privateKey,
687
+ padding: import_crypto.constants.RSA_PKCS1_PSS_PADDING,
688
+ saltLength: 64
689
+ })
690
+ };
691
+ }
692
+ return { algorithm: alg, sign: (data) => (0, import_crypto2.signWithPrivateJwkAsync)(alg, jwk, Buffer.from(data)) };
693
+ }
694
+ async function createWebBotSignature(...args) {
695
+ try {
696
+ return await (0, import_http_message_sig.createSignature)(...args);
697
+ } catch (error) {
698
+ if ((0, import_http_message_sig.isSignatureError)(error)) throw new WebBotAuthError(400, "component_value");
699
+ throw error;
700
+ }
701
+ }
702
+ function componentDescriptor(identifier) {
703
+ const bare = identifier.split(";", 1)[0];
704
+ const [, params] = (0, import_structured_headers.parseItem)(`"${bare}"${identifier.slice(bare.length)}`);
705
+ return (0, import_http_message_sig.component)(bare, Object.fromEntries(params));
706
+ }
707
+ function coveredFields(components, headers) {
708
+ const names = new Set(components.filter((c) => !c.name.startsWith("@")).map((c) => c.name));
709
+ return [...names].flatMap((name) => {
710
+ const value = (0, import_canonicalize2.getHeaderValue)(headers, name);
711
+ return value === void 0 ? [] : [{ name, value }];
712
+ });
676
713
  }
677
714
  async function signWebBotAuth(request, key, options) {
678
715
  const origin = (0, import_canonicalize.canonicalAgentOrigin)(options.origin);
@@ -682,6 +719,7 @@ async function signWebBotAuth(request, key, options) {
682
719
  const now = Math.floor((options.now ?? (() => Date.now() / 1e3))());
683
720
  const window = options.windowSeconds ?? 300;
684
721
  const nonce = options.nonce ?? (0, import_crypto.randomBytes)(64).toString("base64url");
722
+ if (!Number.isSafeInteger(now)) throw new TypeError("Invalid Web Bot Auth clock");
685
723
  if (!Number.isInteger(window) || window < 1 || window > 300 || !/^[A-Za-z0-9_+\/-]{22,256}={0,2}$/.test(nonce))
686
724
  throw new TypeError("Invalid Web Bot Auth lifetime or nonce");
687
725
  if (!options.relay && ["signature", "signature-input", "signature-agent"].some(
@@ -694,42 +732,69 @@ async function signWebBotAuth(request, key, options) {
694
732
  for (const [name, value] of Object.entries(request.headers))
695
733
  if (value !== void 0 && !["signature", "signature-input", "signature-agent", "content-digest"].includes(name.toLowerCase()))
696
734
  headers[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
697
- const components = ['"@method"', '"@target-uri"', '"@authority"'];
735
+ const components = [(0, import_http_message_sig.component)("@method"), (0, import_http_message_sig.component)("@target-uri"), (0, import_http_message_sig.component)("@authority")];
698
736
  if (request.body !== void 0 && request.body !== "") {
699
737
  if (!(0, import_canonicalize2.getHeaderValue)(headers, "content-type"))
700
738
  throw new TypeError("Body-bearing Web Bot Auth requests need Content-Type");
701
739
  headers["content-digest"] = (0, import_content_digest.computeContentDigest)(request.body, "rfc8941-base64");
702
- components.push('"content-type"', '"content-digest"');
740
+ components.push((0, import_http_message_sig.component)("content-type"), (0, import_http_message_sig.component)("content-digest"));
703
741
  }
704
742
  if (options.relay && ["signature", "signature-input", "signature-agent"].some((name) => !(0, import_canonicalize2.getHeaderValue)(request.headers, name)))
705
743
  throw new TypeError("Relay requires the existing signature fields");
706
744
  const earlier = options.relay ? inputs(request.headers) : [];
707
- if (earlier.some((input2) => input2.label === label || input2.params.tag !== WEB_BOT_AUTH_PROFILE))
745
+ if (earlier.some((input) => input.label === label || input.params.tag !== WEB_BOT_AUTH_PROFILE))
708
746
  throw new TypeError("Relay requires existing Web Bot Auth signatures and a fresh label");
709
747
  const priorAgent = options.relay ? (0, import_canonicalize2.getHeaderValue)(request.headers, "signature-agent") : void 0;
710
748
  if (priorAgent) dictionary(priorAgent, "Signature-Agent");
711
749
  headers["signature-agent"] = `${priorAgent ? priorAgent + ", " : ""}${label}="${origin}"`;
712
- components.push(`"signature-agent";key="${label}"`);
713
- for (const inner of earlier) {
714
- for (const component of inner.components) {
715
- const bare = component.split(";", 1)[0];
716
- const encoded = `"${bare}"${component.slice(bare.length)}`;
717
- if (!components.includes(encoded)) components.push(encoded);
750
+ if (priorAgent) dictionary(headers["signature-agent"], "Signature-Agent");
751
+ components.push((0, import_http_message_sig.component)("signature-agent", { key: label }));
752
+ const covered = new Set(components.map(import_http_message_sig.componentIdentity));
753
+ const cover = (descriptor) => {
754
+ const identity = (0, import_http_message_sig.componentIdentity)(descriptor);
755
+ if (!covered.has(identity)) {
756
+ covered.add(identity);
757
+ components.push(descriptor);
718
758
  }
719
- components.push(`"signature-input";key="${inner.label}"`, `"signature";key="${inner.label}"`);
759
+ };
760
+ for (const inner of earlier) {
761
+ for (const identifier of inner.components) cover(componentDescriptor(identifier));
762
+ cover((0, import_http_message_sig.component)("signature-input", { key: inner.label }));
763
+ cover((0, import_http_message_sig.component)("signature", { key: inner.label }));
720
764
  }
721
765
  const priorInput = options.relay ? (0, import_canonicalize2.getHeaderValue)(request.headers, "signature-input") : void 0;
722
766
  const priorSignature = options.relay ? (0, import_canonicalize2.getHeaderValue)(request.headers, "signature") : void 0;
723
767
  if (options.relay && (!priorInput || !priorSignature || !priorAgent))
724
768
  throw new TypeError("Relay requires the existing signature fields");
725
- headers["signature-input"] = `${priorInput ? priorInput + ", " : ""}${label}=(${components.join(" ")});created=${now};expires=${now + window};nonce="${nonce}";keyid="${jwkThumbprint(jwk)}";alg="${algorithm(jwk)}";tag="web-bot-auth"`;
726
- const input = (0, import_parser.parseSignatureInput)(headers["signature-input"], label);
769
+ if (priorInput) headers["signature-input"] = priorInput;
727
770
  if (priorSignature) headers.signature = priorSignature;
728
- const bytes = await signBase(
729
- buildWebBotAuthSignatureBase(input, { ...request, url: new URL(request.url).href, headers }),
730
- key
771
+ for (const inner of earlier)
772
+ buildWebBotAuthSignatureBase(inner, { ...request, url: new URL(request.url).href, headers });
773
+ const targetUri = new URL(request.url);
774
+ targetUri.hash = "";
775
+ const signed = await createWebBotSignature(
776
+ {
777
+ kind: "request",
778
+ method: request.method.toUpperCase(),
779
+ targetUri: targetUri.href,
780
+ fields: coveredFields(components, headers)
781
+ },
782
+ {
783
+ label,
784
+ components,
785
+ parameters: {
786
+ created: now,
787
+ expires: now + window,
788
+ nonce,
789
+ keyid: jwkThumbprint(jwk),
790
+ alg: algorithm(jwk),
791
+ tag: WEB_BOT_AUTH_PROFILE
792
+ },
793
+ signer: webBotSigner(key)
794
+ }
731
795
  );
732
- headers.signature = `${priorSignature ? priorSignature + ", " : ""}${label}=:${Buffer.from(bytes).toString("base64")}:`;
796
+ headers["signature-input"] = `${priorInput ? priorInput + ", " : ""}${signed.signatureInput}`;
797
+ headers.signature = `${priorSignature ? priorSignature + ", " : ""}${signed.signature}`;
733
798
  return headers;
734
799
  }
735
800
  async function createSignedSignatureDirectory(originUrl, signingKeys, options = {}) {
@@ -764,15 +829,29 @@ async function createSignedSignatureDirectory(originUrl, signingKeys, options =
764
829
  };
765
830
  const signatureInputs = [], signatures = [];
766
831
  for (let i = 0; i < keys.length; i++) {
767
- const label = `key${i + 1}`;
768
- const value = `${label}=("@authority";req "content-digest");created=${now - DIRECTORY_CLOCK_SKEW_SECONDS};expires=${now + lifetime};keyid="${keys[i].kid}";alg="${algorithm(keys[i])}";tag="${DIRECTORY_TAG}"`;
769
- const input = (0, import_parser.parseSignatureInput)(value, label);
770
- const bytes = await signBase(
771
- buildWebBotAuthSignatureBase(input, { method: "GET", url: response.request.url, headers: {} }, response),
772
- signingKeys[i]
832
+ const signed = await createWebBotSignature(
833
+ {
834
+ kind: "response",
835
+ status: response.status,
836
+ fields: coveredFields([(0, import_http_message_sig.component)("content-digest")], response.headers),
837
+ request: { kind: "request", method: "GET", targetUri: response.request.url, fields: [] }
838
+ },
839
+ {
840
+ label: `key${i + 1}`,
841
+ components: [(0, import_http_message_sig.component)("@authority", { req: true }), (0, import_http_message_sig.component)("content-digest")],
842
+ parameters: {
843
+ // Backdate created so verifiers whose clocks run slightly behind accept a fresh proof.
844
+ created: now - DIRECTORY_CLOCK_SKEW_SECONDS,
845
+ expires: now + lifetime,
846
+ keyid: keys[i].kid,
847
+ alg: algorithm(keys[i]),
848
+ tag: DIRECTORY_TAG
849
+ },
850
+ signer: webBotSigner(signingKeys[i])
851
+ }
773
852
  );
774
- signatureInputs.push(value);
775
- signatures.push(`${label}=:${Buffer.from(bytes).toString("base64")}:`);
853
+ signatureInputs.push(signed.signatureInput);
854
+ signatures.push(signed.signature);
776
855
  }
777
856
  response.headers["signature-input"] = signatureInputs.join(", ");
778
857
  response.headers.signature = signatures.join(", ");
@@ -7,6 +7,12 @@ import {
7
7
  sign as nodeSign
8
8
  } from "crypto";
9
9
  import { parseDictionary, parseItem, serializeItem } from "structured-headers";
10
+ import {
11
+ component,
12
+ componentIdentity,
13
+ createSignature,
14
+ isSignatureError
15
+ } from "http-message-sig";
10
16
  import { ssrfSafeFetch } from "../net/index.mjs";
11
17
  import { eTldPlusOne } from "./agent-resolver/etld.mjs";
12
18
  import { canonicalAgentOrigin } from "./agent-resolver/canonicalize.mjs";
@@ -14,7 +20,7 @@ import { canonicalAgentUrl } from "./agent-resolver/select-agent.mjs";
14
20
  import { parseStrictJson } from "./agent-resolver/strict-json.mjs";
15
21
  import { getHeaderValue } from "./canonicalize.mjs";
16
22
  import { computeContentDigest, contentDigestMatches, contentDigestUsesEncoding } from "./content-digest.mjs";
17
- import { jwkToPublicKey, verifySignature } from "./crypto.mjs";
23
+ import { jwkToPublicKey, signWithPrivateJwkAsync, verifySignature, verifySignatureAsync } from "./crypto.mjs";
18
24
  import {
19
25
  parseSignature,
20
26
  parseSignatureInput,
@@ -136,11 +142,11 @@ function receivedAgentOrigin(value) {
136
142
  }
137
143
  }
138
144
  function buildWebBotAuthSignatureBase(input, request, response) {
139
- const lines = input.components.map((component) => {
140
- const bare = component.split(";", 1)[0];
145
+ const lines = input.components.map((component2) => {
146
+ const bare = component2.split(";", 1)[0];
141
147
  let identifier;
142
148
  try {
143
- identifier = parseItem(`"${bare}"${component.slice(bare.length)}`);
149
+ identifier = parseItem(`"${bare}"${component2.slice(bare.length)}`);
144
150
  } catch {
145
151
  return bad("component");
146
152
  }
@@ -197,17 +203,29 @@ function assertDigest(headers, body) {
197
203
  if (!digest || !contentDigestUsesEncoding(digest, "rfc8941-base64") || !contentDigestMatches(digest, body))
198
204
  denied("content_digest");
199
205
  }
200
- function verifyBytes(input, request, jwk, response) {
206
+ function signatureBytes(input, request, jwk, response) {
201
207
  const alg = algorithm(jwk);
202
208
  if (input.params.alg !== void 0 && input.params.alg !== alg) denied("algorithm");
203
209
  const signature = getHeaderValue(response?.headers ?? request.headers, "signature");
204
210
  if (signature === void 0 || signature === "") denied("headers_missing");
205
- let bytes;
206
211
  try {
207
- bytes = parseSignature(signature ?? "", input.label, "rfc8941-base64").bytes;
212
+ return { alg, bytes: parseSignature(signature ?? "", input.label, "rfc8941-base64").bytes };
208
213
  } catch {
209
214
  return bad("signature");
210
215
  }
216
+ }
217
+ async function verifyBytesAsync(input, request, jwk) {
218
+ const { alg, bytes } = signatureBytes(input, request, jwk);
219
+ let valid = false;
220
+ try {
221
+ valid = await verifySignatureAsync(alg, jwk, Buffer.from(buildWebBotAuthSignatureBase(input, request)), bytes);
222
+ } catch (error) {
223
+ if (error instanceof WebBotAuthError) throw error;
224
+ }
225
+ if (!valid) denied("signature_invalid");
226
+ }
227
+ function verifyBytes(input, request, jwk, response) {
228
+ const { alg, bytes } = signatureBytes(input, request, jwk, response);
211
229
  let valid = false;
212
230
  try {
213
231
  valid = verifySignature(
@@ -346,8 +364,8 @@ async function verifyWebBotAuth(request, options) {
346
364
  (c) => c.startsWith("signature-agent;key=") && !verified.some((s) => selected.find((i) => i.label === s.label).components.includes(c))
347
365
  );
348
366
  if (agentComponents.length !== 1) denied("agent_not_covered");
349
- const component = parseItem(`"${agentComponents[0].replace("signature-agent;", 'signature-agent";')}`);
350
- const memberKey = component[1].get("key");
367
+ const component2 = parseItem(`"${agentComponents[0].replace("signature-agent;", 'signature-agent";')}`);
368
+ const memberKey = component2[1].get("key");
351
369
  if (typeof memberKey !== "string" || memberKey !== input.label) bad("agent_member");
352
370
  const member = agents.get(memberKey);
353
371
  if (!member) denied("agent_not_covered");
@@ -379,7 +397,7 @@ async function verifyWebBotAuth(request, options) {
379
397
  denied("directory_key");
380
398
  const key = checkedDirectory.keys.find((key2) => key2.kid === keyid);
381
399
  if (!key || jwkThumbprint(key) !== keyid) denied("key");
382
- verifyBytes(input, request, key);
400
+ await verifyBytesAsync(input, request, key);
383
401
  if (options.isRevoked) await legacyRevocationCheck(options, origin, keyid);
384
402
  const nonceTuple = JSON.stringify([origin, nonce]);
385
403
  if (nonces.has(nonceTuple)) throw new WebBotAuthError(options.replayStatus ?? 429, "nonce_replayed");
@@ -615,7 +633,7 @@ class SignatureDirectoryResolver {
615
633
  return this.getVerifiedDirectory(origin)?.proof;
616
634
  }
617
635
  }
618
- async function signBase(base, key) {
636
+ function webBotSigner(key) {
619
637
  const jwk = "privateKey" in key ? key.privateKey : key.publicKey;
620
638
  const alg = algorithm(jwk);
621
639
  if (!["test", "development"].includes(process.env.NODE_ENV ?? "") && TEST_KIDS.has(jwkThumbprint(jwk)))
@@ -623,16 +641,40 @@ async function signBase(base, key) {
623
641
  if ("provider" in key) {
624
642
  if (key.provider.keyid !== jwkThumbprint(jwk) || key.provider.algorithm !== alg)
625
643
  throw new TypeError("Web Bot Auth provider identity does not match its public key");
626
- return key.provider.sign(Buffer.from(base));
644
+ return { algorithm: alg, sign: async (data) => Buffer.from(await key.provider.sign(Buffer.from(data))) };
627
645
  }
628
- const privateKey = createPrivateKey({ key: jwk, format: "jwk" });
629
- if (alg === "rsa-pss-sha512")
630
- return nodeSign("sha512", Buffer.from(base), {
631
- key: privateKey,
632
- padding: cryptoConstants.RSA_PKCS1_PSS_PADDING,
633
- saltLength: 64
634
- });
635
- return alg === "ed25519" ? nodeSign(null, Buffer.from(base), privateKey) : nodeSign("sha256", Buffer.from(base), { key: privateKey, dsaEncoding: "ieee-p1363" });
646
+ if (alg === "rsa-pss-sha512") {
647
+ const privateKey = createPrivateKey({ key: jwk, format: "jwk" });
648
+ return {
649
+ algorithm: alg,
650
+ sign: (data) => nodeSign("sha512", Buffer.from(data), {
651
+ key: privateKey,
652
+ padding: cryptoConstants.RSA_PKCS1_PSS_PADDING,
653
+ saltLength: 64
654
+ })
655
+ };
656
+ }
657
+ return { algorithm: alg, sign: (data) => signWithPrivateJwkAsync(alg, jwk, Buffer.from(data)) };
658
+ }
659
+ async function createWebBotSignature(...args) {
660
+ try {
661
+ return await createSignature(...args);
662
+ } catch (error) {
663
+ if (isSignatureError(error)) throw new WebBotAuthError(400, "component_value");
664
+ throw error;
665
+ }
666
+ }
667
+ function componentDescriptor(identifier) {
668
+ const bare = identifier.split(";", 1)[0];
669
+ const [, params] = parseItem(`"${bare}"${identifier.slice(bare.length)}`);
670
+ return component(bare, Object.fromEntries(params));
671
+ }
672
+ function coveredFields(components, headers) {
673
+ const names = new Set(components.filter((c) => !c.name.startsWith("@")).map((c) => c.name));
674
+ return [...names].flatMap((name) => {
675
+ const value = getHeaderValue(headers, name);
676
+ return value === void 0 ? [] : [{ name, value }];
677
+ });
636
678
  }
637
679
  async function signWebBotAuth(request, key, options) {
638
680
  const origin = canonicalAgentOrigin(options.origin);
@@ -642,6 +684,7 @@ async function signWebBotAuth(request, key, options) {
642
684
  const now = Math.floor((options.now ?? (() => Date.now() / 1e3))());
643
685
  const window = options.windowSeconds ?? 300;
644
686
  const nonce = options.nonce ?? randomBytes(64).toString("base64url");
687
+ if (!Number.isSafeInteger(now)) throw new TypeError("Invalid Web Bot Auth clock");
645
688
  if (!Number.isInteger(window) || window < 1 || window > 300 || !/^[A-Za-z0-9_+\/-]{22,256}={0,2}$/.test(nonce))
646
689
  throw new TypeError("Invalid Web Bot Auth lifetime or nonce");
647
690
  if (!options.relay && ["signature", "signature-input", "signature-agent"].some(
@@ -654,42 +697,69 @@ async function signWebBotAuth(request, key, options) {
654
697
  for (const [name, value] of Object.entries(request.headers))
655
698
  if (value !== void 0 && !["signature", "signature-input", "signature-agent", "content-digest"].includes(name.toLowerCase()))
656
699
  headers[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
657
- const components = ['"@method"', '"@target-uri"', '"@authority"'];
700
+ const components = [component("@method"), component("@target-uri"), component("@authority")];
658
701
  if (request.body !== void 0 && request.body !== "") {
659
702
  if (!getHeaderValue(headers, "content-type"))
660
703
  throw new TypeError("Body-bearing Web Bot Auth requests need Content-Type");
661
704
  headers["content-digest"] = computeContentDigest(request.body, "rfc8941-base64");
662
- components.push('"content-type"', '"content-digest"');
705
+ components.push(component("content-type"), component("content-digest"));
663
706
  }
664
707
  if (options.relay && ["signature", "signature-input", "signature-agent"].some((name) => !getHeaderValue(request.headers, name)))
665
708
  throw new TypeError("Relay requires the existing signature fields");
666
709
  const earlier = options.relay ? inputs(request.headers) : [];
667
- if (earlier.some((input2) => input2.label === label || input2.params.tag !== WEB_BOT_AUTH_PROFILE))
710
+ if (earlier.some((input) => input.label === label || input.params.tag !== WEB_BOT_AUTH_PROFILE))
668
711
  throw new TypeError("Relay requires existing Web Bot Auth signatures and a fresh label");
669
712
  const priorAgent = options.relay ? getHeaderValue(request.headers, "signature-agent") : void 0;
670
713
  if (priorAgent) dictionary(priorAgent, "Signature-Agent");
671
714
  headers["signature-agent"] = `${priorAgent ? priorAgent + ", " : ""}${label}="${origin}"`;
672
- components.push(`"signature-agent";key="${label}"`);
673
- for (const inner of earlier) {
674
- for (const component of inner.components) {
675
- const bare = component.split(";", 1)[0];
676
- const encoded = `"${bare}"${component.slice(bare.length)}`;
677
- if (!components.includes(encoded)) components.push(encoded);
715
+ if (priorAgent) dictionary(headers["signature-agent"], "Signature-Agent");
716
+ components.push(component("signature-agent", { key: label }));
717
+ const covered = new Set(components.map(componentIdentity));
718
+ const cover = (descriptor) => {
719
+ const identity = componentIdentity(descriptor);
720
+ if (!covered.has(identity)) {
721
+ covered.add(identity);
722
+ components.push(descriptor);
678
723
  }
679
- components.push(`"signature-input";key="${inner.label}"`, `"signature";key="${inner.label}"`);
724
+ };
725
+ for (const inner of earlier) {
726
+ for (const identifier of inner.components) cover(componentDescriptor(identifier));
727
+ cover(component("signature-input", { key: inner.label }));
728
+ cover(component("signature", { key: inner.label }));
680
729
  }
681
730
  const priorInput = options.relay ? getHeaderValue(request.headers, "signature-input") : void 0;
682
731
  const priorSignature = options.relay ? getHeaderValue(request.headers, "signature") : void 0;
683
732
  if (options.relay && (!priorInput || !priorSignature || !priorAgent))
684
733
  throw new TypeError("Relay requires the existing signature fields");
685
- headers["signature-input"] = `${priorInput ? priorInput + ", " : ""}${label}=(${components.join(" ")});created=${now};expires=${now + window};nonce="${nonce}";keyid="${jwkThumbprint(jwk)}";alg="${algorithm(jwk)}";tag="web-bot-auth"`;
686
- const input = parseSignatureInput(headers["signature-input"], label);
734
+ if (priorInput) headers["signature-input"] = priorInput;
687
735
  if (priorSignature) headers.signature = priorSignature;
688
- const bytes = await signBase(
689
- buildWebBotAuthSignatureBase(input, { ...request, url: new URL(request.url).href, headers }),
690
- key
736
+ for (const inner of earlier)
737
+ buildWebBotAuthSignatureBase(inner, { ...request, url: new URL(request.url).href, headers });
738
+ const targetUri = new URL(request.url);
739
+ targetUri.hash = "";
740
+ const signed = await createWebBotSignature(
741
+ {
742
+ kind: "request",
743
+ method: request.method.toUpperCase(),
744
+ targetUri: targetUri.href,
745
+ fields: coveredFields(components, headers)
746
+ },
747
+ {
748
+ label,
749
+ components,
750
+ parameters: {
751
+ created: now,
752
+ expires: now + window,
753
+ nonce,
754
+ keyid: jwkThumbprint(jwk),
755
+ alg: algorithm(jwk),
756
+ tag: WEB_BOT_AUTH_PROFILE
757
+ },
758
+ signer: webBotSigner(key)
759
+ }
691
760
  );
692
- headers.signature = `${priorSignature ? priorSignature + ", " : ""}${label}=:${Buffer.from(bytes).toString("base64")}:`;
761
+ headers["signature-input"] = `${priorInput ? priorInput + ", " : ""}${signed.signatureInput}`;
762
+ headers.signature = `${priorSignature ? priorSignature + ", " : ""}${signed.signature}`;
693
763
  return headers;
694
764
  }
695
765
  async function createSignedSignatureDirectory(originUrl, signingKeys, options = {}) {
@@ -724,15 +794,29 @@ async function createSignedSignatureDirectory(originUrl, signingKeys, options =
724
794
  };
725
795
  const signatureInputs = [], signatures = [];
726
796
  for (let i = 0; i < keys.length; i++) {
727
- const label = `key${i + 1}`;
728
- const value = `${label}=("@authority";req "content-digest");created=${now - DIRECTORY_CLOCK_SKEW_SECONDS};expires=${now + lifetime};keyid="${keys[i].kid}";alg="${algorithm(keys[i])}";tag="${DIRECTORY_TAG}"`;
729
- const input = parseSignatureInput(value, label);
730
- const bytes = await signBase(
731
- buildWebBotAuthSignatureBase(input, { method: "GET", url: response.request.url, headers: {} }, response),
732
- signingKeys[i]
797
+ const signed = await createWebBotSignature(
798
+ {
799
+ kind: "response",
800
+ status: response.status,
801
+ fields: coveredFields([component("content-digest")], response.headers),
802
+ request: { kind: "request", method: "GET", targetUri: response.request.url, fields: [] }
803
+ },
804
+ {
805
+ label: `key${i + 1}`,
806
+ components: [component("@authority", { req: true }), component("content-digest")],
807
+ parameters: {
808
+ // Backdate created so verifiers whose clocks run slightly behind accept a fresh proof.
809
+ created: now - DIRECTORY_CLOCK_SKEW_SECONDS,
810
+ expires: now + lifetime,
811
+ keyid: keys[i].kid,
812
+ alg: algorithm(keys[i]),
813
+ tag: DIRECTORY_TAG
814
+ },
815
+ signer: webBotSigner(signingKeys[i])
816
+ }
733
817
  );
734
- signatureInputs.push(value);
735
- signatures.push(`${label}=:${Buffer.from(bytes).toString("base64")}:`);
818
+ signatureInputs.push(signed.signatureInput);
819
+ signatures.push(signed.signature);
736
820
  }
737
821
  response.headers["signature-input"] = signatureInputs.join(", ");
738
822
  response.headers.signature = signatures.join(", ");
@@ -172,8 +172,8 @@ async function verifyWebhookSignature(request, options) {
172
172
  parsedInput.signatureParamsValue,
173
173
  "3.2"
174
174
  );
175
- const publicKey = (0, import_crypto.jwkToPublicKey)(jwk);
176
- const valid = (0, import_crypto.verifySignature)(parsedInput.params.alg, publicKey, Buffer.from(base, "utf8"), parsedSig.bytes);
175
+ (0, import_crypto.jwkToPublicKey)(jwk);
176
+ const valid = await (0, import_crypto.verifySignatureAsync)(parsedInput.params.alg, jwk, Buffer.from(base, "utf8"), parsedSig.bytes);
177
177
  if (!valid) {
178
178
  throw new import_errors.WebhookSignatureError(
179
179
  "webhook_signature_invalid",
@@ -4,7 +4,7 @@ import { RequestSignatureError, WebhookSignatureError } from "./errors.mjs";
4
4
  import { AgentResolverError } from "./agent-resolver/errors.mjs";
5
5
  import { BrandJsonResolverError } from "./brand-jwks.mjs";
6
6
  import { parseSignature, parseSignatureInput } from "./parser.mjs";
7
- import { jwkToPublicKey, verifySignature } from "./crypto.mjs";
7
+ import { jwkToPublicKey, verifySignatureAsync } from "./crypto.mjs";
8
8
  import { assertPublisherPins } from "./publisher-pins.mjs";
9
9
  import { InMemoryReplayStore } from "./replay.mjs";
10
10
  import { InMemoryRevocationStore } from "./revocation.mjs";
@@ -145,8 +145,8 @@ async function verifyWebhookSignature(request, options) {
145
145
  parsedInput.signatureParamsValue,
146
146
  "3.2"
147
147
  );
148
- const publicKey = jwkToPublicKey(jwk);
149
- const valid = verifySignature(parsedInput.params.alg, publicKey, Buffer.from(base, "utf8"), parsedSig.bytes);
148
+ jwkToPublicKey(jwk);
149
+ const valid = await verifySignatureAsync(parsedInput.params.alg, jwk, Buffer.from(base, "utf8"), parsedSig.bytes);
150
150
  if (!valid) {
151
151
  throw new WebhookSignatureError(
152
152
  "webhook_signature_invalid",
@@ -22,6 +22,7 @@ __export(compile_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(compile_exports);
24
24
  var import_enums = require('../types/enums.generated.js');
25
+ var import_consent_macros = require('./consent-macros.js');
25
26
  const BUILT_IN_SOURCE_SYNTAXES = /* @__PURE__ */ new Set([
26
27
  "adcp",
27
28
  "double_brace",
@@ -61,7 +62,7 @@ function universalMacroName(token) {
61
62
  }
62
63
  function isUniversalMacro(token) {
63
64
  const name = universalMacroName(token);
64
- return name !== null && UNIVERSAL_MACRO_NAMES.has(name);
65
+ return name !== null && (UNIVERSAL_MACRO_NAMES.has(name) || (0, import_consent_macros.isConsentMacro)(token));
65
66
  }
66
67
  function syntaxForExactToken(token, builtIns, customSyntaxes) {
67
68
  for (const syntax of customSyntaxes) {
@@ -1,4 +1,5 @@
1
1
  import { UniversalMacroValues } from "../types/enums.generated.mjs";
2
+ import { isConsentMacro } from "./consent-macros.mjs";
2
3
  const BUILT_IN_SOURCE_SYNTAXES = /* @__PURE__ */ new Set([
3
4
  "adcp",
4
5
  "double_brace",
@@ -38,7 +39,7 @@ function universalMacroName(token) {
38
39
  }
39
40
  function isUniversalMacro(token) {
40
41
  const name = universalMacroName(token);
41
- return name !== null && UNIVERSAL_MACRO_NAMES.has(name);
42
+ return name !== null && (UNIVERSAL_MACRO_NAMES.has(name) || isConsentMacro(token));
42
43
  }
43
44
  function syntaxForExactToken(token, builtIns, customSyntaxes) {
44
45
  for (const syntax of customSyntaxes) {
@@ -0,0 +1,4 @@
1
+ /** The complete token retains the receiving vendor's positive decimal GVL ID. */
2
+ export declare function isVendorScopedConsentMacro(token: string): boolean;
3
+ /** Recognize privacy signals for helper compilation and consent diagnostics. */
4
+ export declare function isConsentMacro(token: string): boolean;
@@ -0,0 +1,4 @@
1
+ /** The complete token retains the receiving vendor's positive decimal GVL ID. */
2
+ export declare function isVendorScopedConsentMacro(token: string): boolean;
3
+ /** Recognize privacy signals for helper compilation and consent diagnostics. */
4
+ export declare function isConsentMacro(token: string): boolean;