@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.
- package/README.md +54 -0
- package/dist/lib/auth/oauth/diagnose.js +3 -11
- package/dist/lib/auth/oauth/diagnose.mjs +4 -12
- package/dist/lib/auth/oauth/diagnostics.d.mts +2 -1
- package/dist/lib/auth/oauth/diagnostics.d.ts +2 -1
- package/dist/lib/auth/oauth/diagnostics.js +8 -10
- package/dist/lib/auth/oauth/diagnostics.mjs +7 -10
- package/dist/lib/core/ConversationTypes.d.mts +8 -3
- package/dist/lib/core/ConversationTypes.d.ts +8 -3
- package/dist/lib/core/SingleAgentClient.d.mts +5 -3
- package/dist/lib/core/SingleAgentClient.d.ts +5 -3
- package/dist/lib/core/TaskExecutor.js +5 -1
- package/dist/lib/core/TaskExecutor.mjs +5 -1
- package/dist/lib/errors/index.d.mts +9 -4
- package/dist/lib/errors/index.d.ts +9 -4
- package/dist/lib/index.d.mts +3 -3
- package/dist/lib/index.d.ts +3 -3
- package/dist/lib/index.js +8 -0
- package/dist/lib/index.mjs +14 -2
- package/dist/lib/negotiation/types.d.mts +20 -39
- package/dist/lib/negotiation/types.d.ts +20 -39
- package/dist/lib/protocols/index.d.mts +60 -24
- package/dist/lib/protocols/index.d.ts +60 -24
- package/dist/lib/protocols/index.js +9 -4
- package/dist/lib/protocols/index.mjs +3 -0
- package/dist/lib/protocols/mcp-modern.js +1 -0
- package/dist/lib/protocols/mcp-modern.mjs +2 -1
- package/dist/lib/protocols/mcp.js +1 -0
- package/dist/lib/protocols/mcp.mjs +2 -1
- package/dist/lib/protocols/responseSizeLimit.d.mts +91 -5
- package/dist/lib/protocols/responseSizeLimit.d.ts +91 -5
- package/dist/lib/protocols/responseSizeLimit.js +195 -31
- package/dist/lib/protocols/responseSizeLimit.mjs +192 -31
- package/dist/lib/reporting/consumer-runtime.js +2 -1
- package/dist/lib/reporting/consumer-runtime.mjs +2 -1
- package/dist/lib/reporting/ledger/handler.js +50 -11
- package/dist/lib/reporting/ledger/handler.mjs +50 -12
- package/dist/lib/reporting/ledger/index.d.mts +17 -14
- package/dist/lib/reporting/ledger/index.d.ts +17 -14
- package/dist/lib/reporting/ledger/index.js +32 -20
- package/dist/lib/reporting/ledger/index.mjs +21 -10
- package/dist/lib/reporting/ledger/offering-validation.d.mts +9 -0
- package/dist/lib/reporting/ledger/offering-validation.d.ts +9 -0
- package/dist/lib/reporting/{gcs/bucket-policy.js → ledger/offering-validation.js} +9 -8
- package/dist/lib/reporting/ledger/offering-validation.mjs +8 -0
- package/dist/lib/reporting/ledger/receipts.d.mts +48 -0
- package/dist/lib/reporting/ledger/receipts.d.ts +48 -0
- package/dist/lib/reporting/ledger/receipts.js +186 -0
- package/dist/lib/reporting/ledger/receipts.mjs +161 -0
- package/dist/lib/reporting/ledger/status-ingest.js +3 -3
- package/dist/lib/reporting/ledger/status-ingest.mjs +4 -5
- package/dist/lib/reporting/ledger/types.d.mts +43 -0
- package/dist/lib/reporting/ledger/types.d.ts +43 -0
- package/dist/lib/reporting/ledger/types.js +31 -2
- package/dist/lib/reporting/ledger/types.mjs +26 -1
- package/dist/lib/reporting/pagination.d.mts +6 -0
- package/dist/lib/reporting/pagination.d.ts +6 -0
- package/dist/lib/reporting/{gcs/errors.js → pagination.js} +12 -17
- package/dist/lib/reporting/pagination.mjs +12 -0
- package/dist/lib/reporting/reconciliation.d.mts +1 -0
- package/dist/lib/reporting/reconciliation.d.ts +1 -0
- package/dist/lib/reporting/reconciliation.js +3 -2
- package/dist/lib/reporting/reconciliation.mjs +3 -2
- package/dist/lib/reporting/service/index.d.mts +79 -153
- package/dist/lib/reporting/service/index.d.ts +79 -153
- package/dist/lib/reporting/service/index.js +34 -491
- package/dist/lib/reporting/service/index.mjs +36 -510
- package/dist/lib/reporting/service/scheduler-support.d.mts +43 -0
- package/dist/lib/reporting/service/scheduler-support.d.ts +43 -0
- package/dist/lib/reporting/service/scheduler-support.js +125 -0
- package/dist/lib/reporting/service/scheduler-support.mjs +96 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/signing/canonicalize.d.mts +4 -0
- package/dist/lib/signing/canonicalize.d.ts +4 -0
- package/dist/lib/signing/canonicalize.js +14 -8
- package/dist/lib/signing/canonicalize.mjs +14 -8
- package/dist/lib/signing/content-digest.d.mts +8 -0
- package/dist/lib/signing/content-digest.d.ts +8 -0
- package/dist/lib/signing/content-digest.js +11 -5
- package/dist/lib/signing/content-digest.mjs +10 -5
- package/dist/lib/signing/crypto.d.mts +15 -0
- package/dist/lib/signing/crypto.d.ts +15 -0
- package/dist/lib/signing/crypto.js +75 -3
- package/dist/lib/signing/crypto.mjs +78 -3
- package/dist/lib/signing/server.d.mts +1 -1
- package/dist/lib/signing/server.d.ts +1 -1
- package/dist/lib/signing/server.js +2 -0
- package/dist/lib/signing/server.mjs +2 -1
- package/dist/lib/signing/signer.js +11 -14
- package/dist/lib/signing/signer.mjs +13 -16
- package/dist/lib/signing/testing.js +2 -6
- package/dist/lib/signing/testing.mjs +3 -7
- package/dist/lib/signing/verifier.js +2 -2
- package/dist/lib/signing/verifier.mjs +3 -3
- package/dist/lib/signing/web-bot-auth.js +122 -43
- package/dist/lib/signing/web-bot-auth.mjs +128 -44
- package/dist/lib/signing/webhook-verifier.js +2 -2
- package/dist/lib/signing/webhook-verifier.mjs +3 -3
- package/dist/lib/substitution/compile.js +2 -1
- package/dist/lib/substitution/compile.mjs +2 -1
- package/dist/lib/substitution/consent-macros.d.mts +4 -0
- package/dist/lib/substitution/consent-macros.d.ts +4 -0
- package/dist/lib/substitution/consent-macros.js +45 -0
- package/dist/lib/substitution/consent-macros.mjs +20 -0
- package/dist/lib/substitution/index.d.mts +1 -1
- package/dist/lib/substitution/index.d.ts +1 -1
- package/dist/lib/substitution/index.js +2 -0
- package/dist/lib/substitution/index.mjs +2 -1
- package/dist/lib/substitution/translate.d.mts +15 -2
- package/dist/lib/substitution/translate.d.ts +15 -2
- package/dist/lib/substitution/translate.js +148 -26
- package/dist/lib/substitution/translate.mjs +147 -26
- package/dist/lib/testing/client.js +2 -1
- package/dist/lib/testing/client.mjs +2 -1
- package/dist/lib/testing/scenarios/capabilities.js +1 -1
- package/dist/lib/testing/scenarios/capabilities.mjs +1 -1
- package/dist/lib/testing/storyboard/junit.js +16 -3
- package/dist/lib/testing/storyboard/junit.mjs +16 -3
- package/dist/lib/testing/storyboard/request-signing/builder.js +12 -14
- package/dist/lib/testing/storyboard/request-signing/builder.mjs +13 -15
- package/dist/lib/testing/storyboard/runner.js +94 -25
- package/dist/lib/testing/storyboard/runner.mjs +94 -25
- package/dist/lib/testing/storyboard/signer-grader/grader.js +2 -7
- package/dist/lib/testing/storyboard/signer-grader/grader.mjs +2 -7
- package/dist/lib/testing/storyboard/types.d.mts +6 -0
- package/dist/lib/testing/storyboard/types.d.ts +6 -0
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/enums.generated.d.mts +3 -0
- package/dist/lib/types/enums.generated.d.ts +3 -0
- package/dist/lib/types/enums.generated.js +9 -0
- package/dist/lib/types/enums.generated.mjs +6 -0
- package/dist/lib/validation/schema-loader.js +25 -0
- package/dist/lib/validation/schema-loader.mjs +24 -0
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/docs/TYPE-SUMMARY.md +28 -5
- package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +3 -2
- package/docs/guides/REPORTING-GCS-FENCE.md +3 -3
- package/docs/guides/REPORTING-GCS-MANAGED.md +4 -4
- package/docs/guides/REPORTING-LEDGER-CUTOVER.md +7 -7
- package/docs/guides/REPORTING-LEDGER.md +107 -51
- package/docs/guides/REPORTING-OPERATIONS.md +66 -5
- package/docs/guides/REPORTING-STABILITY.md +36 -32
- package/docs/guides/UNIVERSAL-MACRO-COMPILATION.md +38 -0
- package/docs/guides/VALIDATE-YOUR-AGENT.md +12 -0
- package/docs/llms.txt +4 -3
- package/docs/migration-14.x-rc-worksheet.md +4 -7
- package/docs/migration-reporting-storage-package.md +186 -0
- package/examples/README.md +1 -1
- package/package.json +14 -78
- package/dist/lib/reporting/azure/index.d.mts +0 -31
- package/dist/lib/reporting/azure/index.d.ts +0 -31
- package/dist/lib/reporting/azure/index.js +0 -266
- package/dist/lib/reporting/azure/index.mjs +0 -249
- package/dist/lib/reporting/bigquery/index.d.mts +0 -246
- package/dist/lib/reporting/bigquery/index.d.ts +0 -246
- package/dist/lib/reporting/bigquery/index.js +0 -633
- package/dist/lib/reporting/bigquery/index.mjs +0 -594
- package/dist/lib/reporting/gcs/adapter.d.mts +0 -38
- package/dist/lib/reporting/gcs/adapter.d.ts +0 -38
- package/dist/lib/reporting/gcs/adapter.js +0 -342
- package/dist/lib/reporting/gcs/adapter.mjs +0 -325
- package/dist/lib/reporting/gcs/bucket-policy.d.mts +0 -3
- package/dist/lib/reporting/gcs/bucket-policy.d.ts +0 -3
- package/dist/lib/reporting/gcs/bucket-policy.mjs +0 -7
- package/dist/lib/reporting/gcs/errors.d.mts +0 -11
- package/dist/lib/reporting/gcs/errors.d.ts +0 -11
- package/dist/lib/reporting/gcs/errors.mjs +0 -16
- package/dist/lib/reporting/gcs/fence.d.mts +0 -41
- package/dist/lib/reporting/gcs/fence.d.ts +0 -41
- package/dist/lib/reporting/gcs/fence.js +0 -250
- package/dist/lib/reporting/gcs/fence.mjs +0 -230
- package/dist/lib/reporting/gcs/index.d.mts +0 -18
- package/dist/lib/reporting/gcs/index.d.ts +0 -18
- package/dist/lib/reporting/gcs/index.js +0 -44
- package/dist/lib/reporting/gcs/index.mjs +0 -14
- package/dist/lib/reporting/gcs/io.d.mts +0 -7
- package/dist/lib/reporting/gcs/io.d.ts +0 -7
- package/dist/lib/reporting/gcs/io.js +0 -95
- package/dist/lib/reporting/gcs/io.mjs +0 -69
- package/dist/lib/reporting/gcs/reader.d.mts +0 -67
- package/dist/lib/reporting/gcs/reader.d.ts +0 -67
- package/dist/lib/reporting/gcs/reader.js +0 -193
- package/dist/lib/reporting/gcs/reader.mjs +0 -169
- package/dist/lib/reporting/gcs/row-provider.d.mts +0 -39
- package/dist/lib/reporting/gcs/row-provider.d.ts +0 -39
- package/dist/lib/reporting/gcs/row-provider.js +0 -225
- package/dist/lib/reporting/gcs/row-provider.mjs +0 -208
- package/dist/lib/reporting/gcs/validation.d.mts +0 -5
- package/dist/lib/reporting/gcs/validation.d.ts +0 -5
- package/dist/lib/reporting/gcs/validation.js +0 -49
- package/dist/lib/reporting/gcs/validation.mjs +0 -25
- package/dist/lib/reporting/ledger/change-feed.d.mts +0 -69
- package/dist/lib/reporting/ledger/change-feed.d.ts +0 -69
- package/dist/lib/reporting/ledger/change-feed.js +0 -107
- package/dist/lib/reporting/ledger/change-feed.mjs +0 -80
- package/dist/lib/reporting/ledger/managed-postgres.d.mts +0 -293
- package/dist/lib/reporting/ledger/managed-postgres.d.ts +0 -293
- package/dist/lib/reporting/ledger/managed-postgres.js +0 -2346
- package/dist/lib/reporting/ledger/managed-postgres.mjs +0 -2332
- package/dist/lib/reporting/ledger/managed-router.d.mts +0 -148
- package/dist/lib/reporting/ledger/managed-router.d.ts +0 -148
- package/dist/lib/reporting/ledger/managed-router.js +0 -280
- package/dist/lib/reporting/ledger/managed-router.mjs +0 -258
- package/dist/lib/reporting/ledger/managed.d.mts +0 -535
- package/dist/lib/reporting/ledger/managed.d.ts +0 -535
- package/dist/lib/reporting/ledger/managed.js +0 -761
- package/dist/lib/reporting/ledger/managed.mjs +0 -729
- package/dist/lib/reporting/ledger/notification-activity.d.mts +0 -332
- package/dist/lib/reporting/ledger/notification-activity.d.ts +0 -332
- package/dist/lib/reporting/ledger/notification-activity.js +0 -1366
- package/dist/lib/reporting/ledger/notification-activity.mjs +0 -1337
- package/dist/lib/reporting/ledger/object-writes.d.mts +0 -128
- package/dist/lib/reporting/ledger/object-writes.d.ts +0 -128
- package/dist/lib/reporting/ledger/object-writes.js +0 -147
- package/dist/lib/reporting/ledger/object-writes.mjs +0 -114
- package/dist/lib/reporting/ledger/postgres.d.mts +0 -689
- package/dist/lib/reporting/ledger/postgres.d.ts +0 -689
- package/dist/lib/reporting/ledger/postgres.js +0 -4462
- package/dist/lib/reporting/ledger/postgres.mjs +0 -4462
- package/dist/lib/reporting/ledger/row-storage-migration.d.mts +0 -59
- package/dist/lib/reporting/ledger/row-storage-migration.d.ts +0 -59
- package/dist/lib/reporting/ledger/row-storage-migration.js +0 -365
- package/dist/lib/reporting/ledger/row-storage-migration.mjs +0 -339
- package/dist/lib/reporting/ledger/row-storage-object.d.mts +0 -203
- package/dist/lib/reporting/ledger/row-storage-object.d.ts +0 -203
- package/dist/lib/reporting/ledger/row-storage-object.js +0 -379
- package/dist/lib/reporting/ledger/row-storage-object.mjs +0 -335
- package/dist/lib/reporting/ledger/row-storage-provider-io.d.mts +0 -44
- package/dist/lib/reporting/ledger/row-storage-provider-io.d.ts +0 -44
- package/dist/lib/reporting/ledger/row-storage-provider-io.js +0 -142
- package/dist/lib/reporting/ledger/row-storage-provider-io.mjs +0 -111
- package/dist/lib/reporting/ledger/row-storage.d.mts +0 -316
- package/dist/lib/reporting/ledger/row-storage.d.ts +0 -316
- package/dist/lib/reporting/ledger/row-storage.js +0 -812
- package/dist/lib/reporting/ledger/row-storage.mjs +0 -802
- package/dist/lib/reporting/s3/index.d.mts +0 -34
- package/dist/lib/reporting/s3/index.d.ts +0 -34
- package/dist/lib/reporting/s3/index.js +0 -347
- package/dist/lib/reporting/s3/index.mjs +0 -340
- package/dist/lib/reporting/service/maintenance.d.mts +0 -148
- package/dist/lib/reporting/service/maintenance.d.ts +0 -148
- package/dist/lib/reporting/service/maintenance.js +0 -185
- package/dist/lib/reporting/service/maintenance.mjs +0 -159
- 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((
|
|
180
|
-
const bare =
|
|
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}"${
|
|
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
|
|
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
|
|
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
|
|
390
|
-
const memberKey =
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
679
|
+
return { algorithm: alg, sign: async (data) => Buffer.from(await key.provider.sign(Buffer.from(data))) };
|
|
667
680
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
return
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
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 = [
|
|
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(
|
|
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((
|
|
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
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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
|
-
|
|
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"] =
|
|
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
|
|
729
|
-
buildWebBotAuthSignatureBase(
|
|
730
|
-
|
|
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
|
|
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
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
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(
|
|
775
|
-
signatures.push(
|
|
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((
|
|
140
|
-
const bare =
|
|
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}"${
|
|
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
|
|
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
|
|
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
|
|
350
|
-
const memberKey =
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
644
|
+
return { algorithm: alg, sign: async (data) => Buffer.from(await key.provider.sign(Buffer.from(data))) };
|
|
627
645
|
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
return
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
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 = [
|
|
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(
|
|
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((
|
|
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
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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
|
-
|
|
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"] =
|
|
686
|
-
const input = parseSignatureInput(headers["signature-input"], label);
|
|
734
|
+
if (priorInput) headers["signature-input"] = priorInput;
|
|
687
735
|
if (priorSignature) headers.signature = priorSignature;
|
|
688
|
-
const
|
|
689
|
-
buildWebBotAuthSignatureBase(
|
|
690
|
-
|
|
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
|
|
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
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
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(
|
|
735
|
-
signatures.push(
|
|
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
|
-
|
|
176
|
-
const valid = (0, import_crypto.
|
|
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,
|
|
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
|
-
|
|
149
|
-
const valid =
|
|
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;
|