@adcp/sdk 16.0.0-beta.9 → 16.1.0
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 -2
- package/bin/adcp-identity.js +3 -2
- package/dist/lib/client/core.d.mts +1 -1
- package/dist/lib/client/core.d.ts +1 -1
- package/dist/lib/core/AgentClient.d.mts +8 -1
- package/dist/lib/core/AgentClient.d.ts +8 -1
- package/dist/lib/core/AgentClient.js +10 -0
- package/dist/lib/core/AgentClient.mjs +10 -0
- package/dist/lib/core/AsyncHandler.d.mts +2 -0
- package/dist/lib/core/AsyncHandler.d.ts +2 -0
- package/dist/lib/core/AsyncHandler.js +1 -1
- package/dist/lib/core/AsyncHandler.mjs +1 -1
- package/dist/lib/core/ConversationTypes.d.mts +32 -0
- package/dist/lib/core/ConversationTypes.d.ts +32 -0
- package/dist/lib/core/SingleAgentClient.d.mts +11 -1
- package/dist/lib/core/SingleAgentClient.d.ts +11 -1
- package/dist/lib/core/SingleAgentClient.js +25 -6
- package/dist/lib/core/SingleAgentClient.mjs +26 -7
- package/dist/lib/core/TaskExecutor.d.mts +3 -1
- package/dist/lib/core/TaskExecutor.d.ts +3 -1
- package/dist/lib/core/TaskExecutor.js +127 -34
- package/dist/lib/core/TaskExecutor.mjs +127 -34
- package/dist/lib/core/task-deadline.d.mts +2 -0
- package/dist/lib/core/task-deadline.d.ts +2 -0
- package/dist/lib/core/task-deadline.js +20 -2
- package/dist/lib/core/task-deadline.mjs +19 -2
- package/dist/lib/identity-3.3/revocation.js +6 -7
- package/dist/lib/identity-3.3/revocation.mjs +6 -7
- package/dist/lib/identity-3.3/schemas.draft.js +1 -1
- package/dist/lib/identity-3.3/schemas.draft.mjs +1 -1
- package/dist/lib/identity-3.3/trust.d.mts +8 -0
- package/dist/lib/identity-3.3/trust.d.ts +8 -0
- package/dist/lib/identity-3.3/trust.js +41 -12
- package/dist/lib/identity-3.3/trust.mjs +40 -12
- package/dist/lib/index.d.mts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/server/account-sync-contract.js +4 -1
- package/dist/lib/server/account-sync-contract.mjs +4 -1
- package/dist/lib/server/create-adcp-server.js +1 -1
- package/dist/lib/server/create-adcp-server.mjs +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +22 -17
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +22 -17
- package/dist/lib/signing/crypto.d.mts +1 -1
- package/dist/lib/signing/crypto.d.ts +1 -1
- package/dist/lib/signing/crypto.js +2 -45
- package/dist/lib/signing/crypto.mjs +2 -46
- package/dist/lib/signing/web-bot-auth.d.mts +18 -10
- package/dist/lib/signing/web-bot-auth.d.ts +18 -10
- package/dist/lib/signing/web-bot-auth.js +48 -28
- package/dist/lib/signing/web-bot-auth.mjs +49 -29
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/v2/projection/catalog.d.mts +10 -0
- package/dist/lib/v2/projection/catalog.d.ts +10 -0
- package/dist/lib/v2/projection/catalog.js +5 -0
- package/dist/lib/v2/projection/catalog.mjs +4 -0
- package/dist/lib/v2/projection/creative-delivery.d.mts +15 -9
- package/dist/lib/v2/projection/creative-delivery.d.ts +15 -9
- package/dist/lib/v2/projection/creative-delivery.js +71 -10
- package/dist/lib/v2/projection/creative-delivery.mjs +71 -10
- package/dist/lib/v2/projection/v1-to-v2.js +3 -2
- package/dist/lib/v2/projection/v1-to-v2.mjs +4 -3
- 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 +12 -2
- package/docs/guides/CREATIVE-DELIVERY.md +18 -1
- package/docs/guides/REPORTING-STABILITY.md +7 -7
- package/docs/llms.txt +3 -3
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-agent-identity-3.3.md +56 -23
- package/docs/migration-reporting-storage-package.md +3 -3
- package/docs/releases/16.0.0.md +20 -0
- package/package.json +1 -1
|
@@ -32,6 +32,7 @@ __export(trust_exports, {
|
|
|
32
32
|
TrustEvaluator: () => TrustEvaluator,
|
|
33
33
|
TrustMembershipError: () => TrustMembershipError,
|
|
34
34
|
TrustRecordUnavailableError: () => TrustRecordUnavailableError,
|
|
35
|
+
assertPublishableTrustRecord: () => assertPublishableTrustRecord,
|
|
35
36
|
authorizeDemandGrant: () => authorizeDemandGrant,
|
|
36
37
|
createTrustRecord: () => createTrustRecord,
|
|
37
38
|
validateIdentity33Schema: () => validateIdentity33Schema,
|
|
@@ -110,8 +111,34 @@ function validateTrustRecord(value) {
|
|
|
110
111
|
origins.add(origin);
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
|
-
function
|
|
114
|
+
function registrableGrantee(grantee) {
|
|
115
|
+
try {
|
|
116
|
+
return (0, import_etld.eTldPlusOne)(grantee) === grantee ? grantee : void 0;
|
|
117
|
+
} catch {
|
|
118
|
+
return void 0;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function grantAgentOrigin(url) {
|
|
122
|
+
try {
|
|
123
|
+
return (0, import_canonicalize.canonicalAgentOrigin)(url);
|
|
124
|
+
} catch {
|
|
125
|
+
return void 0;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function assertPublishableTrustRecord(record) {
|
|
114
129
|
validateTrustRecord(record);
|
|
130
|
+
for (const grant of record.grants ?? []) {
|
|
131
|
+
if (registrableGrantee(grant.grantee) === void 0)
|
|
132
|
+
throw new TypeError(
|
|
133
|
+
`Grant grantee "${grant.grantee}" is not a registrable domain; name the organization's registrable domain and narrow with agents[]`
|
|
134
|
+
);
|
|
135
|
+
for (const agent of grant.agents ?? [])
|
|
136
|
+
if (grantAgentOrigin(agent.url) === void 0)
|
|
137
|
+
throw new TypeError(`Grant agents[] URL "${agent.url}" is not a valid agent origin`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function createTrustRecord(record) {
|
|
141
|
+
assertPublishableTrustRecord(record);
|
|
115
142
|
return structuredClone(record);
|
|
116
143
|
}
|
|
117
144
|
class TrustEvaluator {
|
|
@@ -308,13 +335,15 @@ function authorityGroup(operator) {
|
|
|
308
335
|
const provider = (0, import_tldts.parse)(operator).domain;
|
|
309
336
|
return `private:${provider ?? operator}`;
|
|
310
337
|
}
|
|
338
|
+
function grantsScope(grant, scope) {
|
|
339
|
+
return grant.scopes.some(
|
|
340
|
+
(granted) => granted === "*" || granted === scope || granted === "adcp:all" && scope.startsWith("adcp:")
|
|
341
|
+
);
|
|
342
|
+
}
|
|
311
343
|
function grantMatches(grant, target, claim, now) {
|
|
312
|
-
if ((
|
|
313
|
-
if (!grant.
|
|
314
|
-
|
|
315
|
-
))
|
|
316
|
-
return false;
|
|
317
|
-
if (grant.agents && !grant.agents.some((agent) => (0, import_canonicalize.canonicalAgentOrigin)(agent.url) === (0, import_canonicalize.canonicalAgentOrigin)(claim.signerOrigin)))
|
|
344
|
+
if (registrableGrantee(grant.grantee) !== target) return false;
|
|
345
|
+
if (!grantsScope(grant, claim.scope)) return false;
|
|
346
|
+
if (grant.agents && !grant.agents.some((agent) => grantAgentOrigin(agent.url) === (0, import_canonicalize.canonicalAgentOrigin)(claim.signerOrigin)))
|
|
318
347
|
return false;
|
|
319
348
|
const brands = grant.profiles?.adcp?.brands;
|
|
320
349
|
if (brands && !brands.includes("*") && (!claim.brand.brand_id || !brands.includes(claim.brand.brand_id)))
|
|
@@ -361,11 +390,10 @@ async function authorizeDemandGrant(claim, options) {
|
|
|
361
390
|
if (second) return result("trust", [brand, account, operator], [first[0], second]);
|
|
362
391
|
}
|
|
363
392
|
}
|
|
364
|
-
const covered = (record.record.grants ?? []).some(
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
);
|
|
393
|
+
const covered = (record.record.grants ?? []).some((g) => {
|
|
394
|
+
const grantee = registrableGrantee(g.grantee);
|
|
395
|
+
return grantee !== void 0 && (grantee === account || selfOperated && grantee === operator) && grantsScope(g, claim.scope);
|
|
396
|
+
});
|
|
369
397
|
if (!covered && !record.record.exclusive_grants && await options.sellerAuthorization?.(claim))
|
|
370
398
|
return result("seller", [brand, account, operator]);
|
|
371
399
|
throw new IdentityAuthorizationError("grant_absent");
|
|
@@ -376,6 +404,7 @@ async function authorizeDemandGrant(claim, options) {
|
|
|
376
404
|
TrustEvaluator,
|
|
377
405
|
TrustMembershipError,
|
|
378
406
|
TrustRecordUnavailableError,
|
|
407
|
+
assertPublishableTrustRecord,
|
|
379
408
|
authorizeDemandGrant,
|
|
380
409
|
createTrustRecord,
|
|
381
410
|
validateIdentity33Schema,
|
|
@@ -70,8 +70,34 @@ function validateTrustRecord(value) {
|
|
|
70
70
|
origins.add(origin);
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
function
|
|
73
|
+
function registrableGrantee(grantee) {
|
|
74
|
+
try {
|
|
75
|
+
return eTldPlusOne(grantee) === grantee ? grantee : void 0;
|
|
76
|
+
} catch {
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function grantAgentOrigin(url) {
|
|
81
|
+
try {
|
|
82
|
+
return canonicalAgentOrigin(url);
|
|
83
|
+
} catch {
|
|
84
|
+
return void 0;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function assertPublishableTrustRecord(record) {
|
|
74
88
|
validateTrustRecord(record);
|
|
89
|
+
for (const grant of record.grants ?? []) {
|
|
90
|
+
if (registrableGrantee(grant.grantee) === void 0)
|
|
91
|
+
throw new TypeError(
|
|
92
|
+
`Grant grantee "${grant.grantee}" is not a registrable domain; name the organization's registrable domain and narrow with agents[]`
|
|
93
|
+
);
|
|
94
|
+
for (const agent of grant.agents ?? [])
|
|
95
|
+
if (grantAgentOrigin(agent.url) === void 0)
|
|
96
|
+
throw new TypeError(`Grant agents[] URL "${agent.url}" is not a valid agent origin`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function createTrustRecord(record) {
|
|
100
|
+
assertPublishableTrustRecord(record);
|
|
75
101
|
return structuredClone(record);
|
|
76
102
|
}
|
|
77
103
|
class TrustEvaluator {
|
|
@@ -268,13 +294,15 @@ function authorityGroup(operator) {
|
|
|
268
294
|
const provider = parseDomain(operator).domain;
|
|
269
295
|
return `private:${provider ?? operator}`;
|
|
270
296
|
}
|
|
297
|
+
function grantsScope(grant, scope) {
|
|
298
|
+
return grant.scopes.some(
|
|
299
|
+
(granted) => granted === "*" || granted === scope || granted === "adcp:all" && scope.startsWith("adcp:")
|
|
300
|
+
);
|
|
301
|
+
}
|
|
271
302
|
function grantMatches(grant, target, claim, now) {
|
|
272
|
-
if (
|
|
273
|
-
if (!grant.
|
|
274
|
-
|
|
275
|
-
))
|
|
276
|
-
return false;
|
|
277
|
-
if (grant.agents && !grant.agents.some((agent) => canonicalAgentOrigin(agent.url) === canonicalAgentOrigin(claim.signerOrigin)))
|
|
303
|
+
if (registrableGrantee(grant.grantee) !== target) return false;
|
|
304
|
+
if (!grantsScope(grant, claim.scope)) return false;
|
|
305
|
+
if (grant.agents && !grant.agents.some((agent) => grantAgentOrigin(agent.url) === canonicalAgentOrigin(claim.signerOrigin)))
|
|
278
306
|
return false;
|
|
279
307
|
const brands = grant.profiles?.adcp?.brands;
|
|
280
308
|
if (brands && !brands.includes("*") && (!claim.brand.brand_id || !brands.includes(claim.brand.brand_id)))
|
|
@@ -321,11 +349,10 @@ async function authorizeDemandGrant(claim, options) {
|
|
|
321
349
|
if (second) return result("trust", [brand, account, operator], [first[0], second]);
|
|
322
350
|
}
|
|
323
351
|
}
|
|
324
|
-
const covered = (record.record.grants ?? []).some(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
);
|
|
352
|
+
const covered = (record.record.grants ?? []).some((g) => {
|
|
353
|
+
const grantee = registrableGrantee(g.grantee);
|
|
354
|
+
return grantee !== void 0 && (grantee === account || selfOperated && grantee === operator) && grantsScope(g, claim.scope);
|
|
355
|
+
});
|
|
329
356
|
if (!covered && !record.record.exclusive_grants && await options.sellerAuthorization?.(claim))
|
|
330
357
|
return result("seller", [brand, account, operator]);
|
|
331
358
|
throw new IdentityAuthorizationError("grant_absent");
|
|
@@ -335,6 +362,7 @@ export {
|
|
|
335
362
|
TrustEvaluator,
|
|
336
363
|
TrustMembershipError,
|
|
337
364
|
TrustRecordUnavailableError,
|
|
365
|
+
assertPublishableTrustRecord,
|
|
338
366
|
authorizeDemandGrant,
|
|
339
367
|
createTrustRecord,
|
|
340
368
|
validateIdentity33Schema,
|
package/dist/lib/index.d.mts
CHANGED
|
@@ -36,7 +36,7 @@ export { match, attachMatch } from './core/match.mjs';
|
|
|
36
36
|
export type { MatchHandlers, PartialMatchHandlers } from './core/match.mjs';
|
|
37
37
|
export { ProtocolResponseParser, responseParser, ADCP_STATUS, type ADCPStatus } from './core/ProtocolResponseParser.mjs';
|
|
38
38
|
export { ResponseValidator, responseValidator, type ValidationResult, type ValidationOptions, } from './core/ResponseValidator.mjs';
|
|
39
|
-
export type { Message, InputRequest, InputHandler, InputHandlerResponse, ConversationContext, TaskOptions, WebhookToolPredicate, WebhookUrlTemplate, TaskResult, TaskResultCompleted, TaskResultIntermediate, TaskResultFailure, TaskResultMetadata, DeferredContinuation, DirectPauseRecoveryRequest, TaskState, TaskStatus, ConversationConfig, AdcpErrorInfo, AdcpValidationIssue, } from './core/ConversationTypes.mjs';
|
|
39
|
+
export type { Message, InputRequest, InputHandler, InputHandlerResponse, ConversationContext, TaskOptions, TrackTaskRequest, TrackedTask, SubmittedContinuation, TaskInfo, WebhookToolPredicate, WebhookUrlTemplate, TaskResult, TaskResultCompleted, TaskResultIntermediate, TaskResultFailure, TaskResultMetadata, DeferredContinuation, DirectPauseRecoveryRequest, TaskState, TaskStatus, ConversationConfig, AdcpErrorInfo, AdcpValidationIssue, } from './core/ConversationTypes.mjs';
|
|
40
40
|
export type { GovernanceConfig, CampaignGovernanceConfig, GovernanceCheckResult, GovernanceOutcome, GovernanceFinding, GovernanceIntentDetails, GovernanceCondition, GovernanceEscalation, NormalizedGovernanceApproved, NormalizedGovernanceConditions, NormalizedGovernanceDenied, NormalizedGovernanceVerdict, } from './core/GovernanceTypes.mjs';
|
|
41
41
|
export { GovernanceMiddleware } from './core/GovernanceMiddleware.mjs';
|
|
42
42
|
export { isGovernanceApproved, isGovernanceConditions, isGovernanceDenied, normalizeGovernanceVerdict, } from './core/GovernanceTypes.mjs';
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export { match, attachMatch } from './core/match';
|
|
|
36
36
|
export type { MatchHandlers, PartialMatchHandlers } from './core/match';
|
|
37
37
|
export { ProtocolResponseParser, responseParser, ADCP_STATUS, type ADCPStatus } from './core/ProtocolResponseParser';
|
|
38
38
|
export { ResponseValidator, responseValidator, type ValidationResult, type ValidationOptions, } from './core/ResponseValidator';
|
|
39
|
-
export type { Message, InputRequest, InputHandler, InputHandlerResponse, ConversationContext, TaskOptions, WebhookToolPredicate, WebhookUrlTemplate, TaskResult, TaskResultCompleted, TaskResultIntermediate, TaskResultFailure, TaskResultMetadata, DeferredContinuation, DirectPauseRecoveryRequest, TaskState, TaskStatus, ConversationConfig, AdcpErrorInfo, AdcpValidationIssue, } from './core/ConversationTypes';
|
|
39
|
+
export type { Message, InputRequest, InputHandler, InputHandlerResponse, ConversationContext, TaskOptions, TrackTaskRequest, TrackedTask, SubmittedContinuation, TaskInfo, WebhookToolPredicate, WebhookUrlTemplate, TaskResult, TaskResultCompleted, TaskResultIntermediate, TaskResultFailure, TaskResultMetadata, DeferredContinuation, DirectPauseRecoveryRequest, TaskState, TaskStatus, ConversationConfig, AdcpErrorInfo, AdcpValidationIssue, } from './core/ConversationTypes';
|
|
40
40
|
export type { GovernanceConfig, CampaignGovernanceConfig, GovernanceCheckResult, GovernanceOutcome, GovernanceFinding, GovernanceIntentDetails, GovernanceCondition, GovernanceEscalation, NormalizedGovernanceApproved, NormalizedGovernanceConditions, NormalizedGovernanceDenied, NormalizedGovernanceVerdict, } from './core/GovernanceTypes';
|
|
41
41
|
export { GovernanceMiddleware } from './core/GovernanceMiddleware';
|
|
42
42
|
export { isGovernanceApproved, isGovernanceConditions, isGovernanceDenied, normalizeGovernanceVerdict, } from './core/GovernanceTypes';
|
|
@@ -28,6 +28,7 @@ module.exports = __toCommonJS(account_sync_contract_exports);
|
|
|
28
28
|
var import_account_key = require('../core/account-key.js');
|
|
29
29
|
var import_account = require('./decisioning/account.js');
|
|
30
30
|
var import_async_outcome = require('./decisioning/async-outcome.js');
|
|
31
|
+
const NATURAL_KEY_FIELDS = ["brand", "operator", "operator_unit", "currency", "timezone", "sandbox"];
|
|
31
32
|
function isolateAccountCallbackInput(ctx) {
|
|
32
33
|
const descriptors = Object.getOwnPropertyDescriptors(ctx);
|
|
33
34
|
delete descriptors.input;
|
|
@@ -58,7 +59,9 @@ function naturalRef(entry) {
|
|
|
58
59
|
const ref = entry.account ?? entry;
|
|
59
60
|
if (!ref || "account_id" in ref || !("brand" in ref) || !ref.brand || typeof ref.operator !== "string")
|
|
60
61
|
return void 0;
|
|
61
|
-
return
|
|
62
|
+
return Object.fromEntries(
|
|
63
|
+
NATURAL_KEY_FIELDS.filter((field) => ref[field] !== void 0).map((field) => [field, ref[field]])
|
|
64
|
+
);
|
|
62
65
|
}
|
|
63
66
|
async function lookup(accounts, ref, ctx, onUnsupported) {
|
|
64
67
|
try {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { accountReferenceKey } from "../core/account-key.mjs";
|
|
2
2
|
import { AccountNotFoundError, toWireAccount } from "./decisioning/account.mjs";
|
|
3
3
|
import { AdcpError } from "./decisioning/async-outcome.mjs";
|
|
4
|
+
const NATURAL_KEY_FIELDS = ["brand", "operator", "operator_unit", "currency", "timezone", "sandbox"];
|
|
4
5
|
function isolateAccountCallbackInput(ctx) {
|
|
5
6
|
const descriptors = Object.getOwnPropertyDescriptors(ctx);
|
|
6
7
|
delete descriptors.input;
|
|
@@ -31,7 +32,9 @@ function naturalRef(entry) {
|
|
|
31
32
|
const ref = entry.account ?? entry;
|
|
32
33
|
if (!ref || "account_id" in ref || !("brand" in ref) || !ref.brand || typeof ref.operator !== "string")
|
|
33
34
|
return void 0;
|
|
34
|
-
return
|
|
35
|
+
return Object.fromEntries(
|
|
36
|
+
NATURAL_KEY_FIELDS.filter((field) => ref[field] !== void 0).map((field) => [field, ref[field]])
|
|
37
|
+
);
|
|
35
38
|
}
|
|
36
39
|
async function lookup(accounts, ref, ctx, onUnsupported) {
|
|
37
40
|
try {
|
|
@@ -4581,7 +4581,7 @@ function createAdcpServer(config) {
|
|
|
4581
4581
|
.../* @__PURE__ */ new Set([
|
|
4582
4582
|
algorithm,
|
|
4583
4583
|
// `algorithms` lists AdCP webhook-profile values; a Web Bot Auth key
|
|
4584
|
-
// is Ed25519
|
|
4584
|
+
// is Ed25519 (adcp#7894), which has the value `ed25519` here.
|
|
4585
4585
|
...webhooks.webBotAuth && ("privateKey" in webhooks.webBotAuth.key ? webhooks.webBotAuth.key.privateKey.crv : webhooks.webBotAuth.key.publicKey.crv) === "Ed25519" ? ["ed25519"] : []
|
|
4586
4586
|
])
|
|
4587
4587
|
],
|
|
@@ -4672,7 +4672,7 @@ function createAdcpServer(config) {
|
|
|
4672
4672
|
.../* @__PURE__ */ new Set([
|
|
4673
4673
|
algorithm,
|
|
4674
4674
|
// `algorithms` lists AdCP webhook-profile values; a Web Bot Auth key
|
|
4675
|
-
// is Ed25519
|
|
4675
|
+
// is Ed25519 (adcp#7894), which has the value `ed25519` here.
|
|
4676
4676
|
...webhooks.webBotAuth && ("privateKey" in webhooks.webBotAuth.key ? webhooks.webBotAuth.key.privateKey.crv : webhooks.webBotAuth.key.publicKey.crv) === "Ed25519" ? ["ed25519"] : []
|
|
4677
4677
|
])
|
|
4678
4678
|
],
|
|
@@ -1009,23 +1009,28 @@ function jsonValuesEqual(left, right) {
|
|
|
1009
1009
|
return leftKeys.length === rightKeys.length && leftKeys.every((key) => Object.hasOwn(rightRecord, key) && jsonValuesEqual(leftRecord[key], rightRecord[key]));
|
|
1010
1010
|
}
|
|
1011
1011
|
function matchLegacyRefToDeclaration(declaration, ref, ownerId, legacyFormatConverter) {
|
|
1012
|
-
const
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1012
|
+
const compare = (authoritativeOnly) => {
|
|
1013
|
+
const projected = (0, import_v1_to_v2.projectV1ProductToV2)(
|
|
1014
|
+
{
|
|
1015
|
+
product_id: ownerId,
|
|
1016
|
+
name: ownerId,
|
|
1017
|
+
description: ownerId,
|
|
1018
|
+
format_ids: [ref]
|
|
1019
|
+
},
|
|
1020
|
+
{ legacyFormatConverter, _authoritativeOnly: authoritativeOnly }
|
|
1021
|
+
);
|
|
1022
|
+
if (projected.diagnostics.length > 0 || projected.v2.format_options.length !== 1) return "unresolved";
|
|
1023
|
+
const expected = projected.v2.format_options[0];
|
|
1024
|
+
if (declaration.format_kind !== expected.format_kind) return "kind_mismatch";
|
|
1025
|
+
const params = declaration.params !== null && typeof declaration.params === "object" && !Array.isArray(declaration.params) ? declaration.params : {};
|
|
1026
|
+
for (const [key, expectedValue] of Object.entries(expected.params)) {
|
|
1027
|
+
if (!Object.hasOwn(params, key) || !jsonValuesEqual(params[key], expectedValue)) return "params_mismatch";
|
|
1028
|
+
}
|
|
1029
|
+
return "match";
|
|
1030
|
+
};
|
|
1031
|
+
const authoritative = compare(true);
|
|
1032
|
+
if (authoritative !== "unresolved") return authoritative;
|
|
1033
|
+
return compare(false) === "match" ? "match" : "unresolved";
|
|
1029
1034
|
}
|
|
1030
1035
|
function validateLegacyRefNarrowing(declaration, ref, ownerId, field, legacyFormatConverter) {
|
|
1031
1036
|
const match = matchLegacyRefToDeclaration(declaration, ref, ownerId, legacyFormatConverter);
|
|
@@ -1041,23 +1041,28 @@ function jsonValuesEqual(left, right) {
|
|
|
1041
1041
|
return leftKeys.length === rightKeys.length && leftKeys.every((key) => Object.hasOwn(rightRecord, key) && jsonValuesEqual(leftRecord[key], rightRecord[key]));
|
|
1042
1042
|
}
|
|
1043
1043
|
function matchLegacyRefToDeclaration(declaration, ref, ownerId, legacyFormatConverter) {
|
|
1044
|
-
const
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1044
|
+
const compare = (authoritativeOnly) => {
|
|
1045
|
+
const projected = projectV1ProductToV2(
|
|
1046
|
+
{
|
|
1047
|
+
product_id: ownerId,
|
|
1048
|
+
name: ownerId,
|
|
1049
|
+
description: ownerId,
|
|
1050
|
+
format_ids: [ref]
|
|
1051
|
+
},
|
|
1052
|
+
{ legacyFormatConverter, _authoritativeOnly: authoritativeOnly }
|
|
1053
|
+
);
|
|
1054
|
+
if (projected.diagnostics.length > 0 || projected.v2.format_options.length !== 1) return "unresolved";
|
|
1055
|
+
const expected = projected.v2.format_options[0];
|
|
1056
|
+
if (declaration.format_kind !== expected.format_kind) return "kind_mismatch";
|
|
1057
|
+
const params = declaration.params !== null && typeof declaration.params === "object" && !Array.isArray(declaration.params) ? declaration.params : {};
|
|
1058
|
+
for (const [key, expectedValue] of Object.entries(expected.params)) {
|
|
1059
|
+
if (!Object.hasOwn(params, key) || !jsonValuesEqual(params[key], expectedValue)) return "params_mismatch";
|
|
1060
|
+
}
|
|
1061
|
+
return "match";
|
|
1062
|
+
};
|
|
1063
|
+
const authoritative = compare(true);
|
|
1064
|
+
if (authoritative !== "unresolved") return authoritative;
|
|
1065
|
+
return compare(false) === "match" ? "match" : "unresolved";
|
|
1061
1066
|
}
|
|
1062
1067
|
function validateLegacyRefNarrowing(declaration, ref, ownerId, field, legacyFormatConverter) {
|
|
1063
1068
|
const match = matchLegacyRefToDeclaration(declaration, ref, ownerId, legacyFormatConverter);
|
|
@@ -15,5 +15,5 @@ export declare function verifySignatureAsync(alg: string, publicKey: KeyObject |
|
|
|
15
15
|
* path passes the key as a JWK so workerd accepts it (#3243).
|
|
16
16
|
*/
|
|
17
17
|
export declare function signWithPrivateJwk(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Uint8Array;
|
|
18
|
-
/** {@link signWithPrivateJwk}, preferring WebCrypto for ES256
|
|
18
|
+
/** {@link signWithPrivateJwk}, preferring WebCrypto for ES256 when available (workerd, #3243). */
|
|
19
19
|
export declare function signWithPrivateJwkAsync(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Promise<Uint8Array>;
|
|
@@ -15,5 +15,5 @@ export declare function verifySignatureAsync(alg: string, publicKey: KeyObject |
|
|
|
15
15
|
* path passes the key as a JWK so workerd accepts it (#3243).
|
|
16
16
|
*/
|
|
17
17
|
export declare function signWithPrivateJwk(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Uint8Array;
|
|
18
|
-
/** {@link signWithPrivateJwk}, preferring WebCrypto for ES256
|
|
18
|
+
/** {@link signWithPrivateJwk}, preferring WebCrypto for ES256 when available (workerd, #3243). */
|
|
19
19
|
export declare function signWithPrivateJwkAsync(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Promise<Uint8Array>;
|
|
@@ -59,14 +59,6 @@ function verifySignature(alg, publicKey, data, signature) {
|
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
if (alg === "rsa-pss-sha512") {
|
|
63
|
-
return (0, import_crypto.verify)(
|
|
64
|
-
"sha512",
|
|
65
|
-
data,
|
|
66
|
-
{ key: publicKey, padding: import_crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 64 },
|
|
67
|
-
signature
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
62
|
return false;
|
|
71
63
|
} catch {
|
|
72
64
|
return false;
|
|
@@ -87,36 +79,15 @@ function privateP256Jwk(jwk) {
|
|
|
87
79
|
async function verifySignatureAsync(alg, publicKey, data, signature) {
|
|
88
80
|
const subtle = subtleCrypto();
|
|
89
81
|
const keyObject = () => isKeyObject(publicKey) ? publicKey : jwkToPublicKey(publicKey);
|
|
90
|
-
if (alg !== "ecdsa-p256-sha256"
|
|
91
|
-
return verifySignature(alg, keyObject(), data, signature);
|
|
82
|
+
if (alg !== "ecdsa-p256-sha256" || !subtle) return verifySignature(alg, keyObject(), data, signature);
|
|
92
83
|
try {
|
|
93
84
|
const jwk = isKeyObject(publicKey) ? publicKey.export({ format: "jwk" }) : publicKey;
|
|
94
|
-
if (alg === "rsa-pss-sha512") {
|
|
95
|
-
const key2 = await importRsaPssVerifyKey(subtle, jwk);
|
|
96
|
-
return await subtle.verify(RSA_PSS_SHA512_SIGN, key2, toArrayBuffer(signature), toArrayBuffer(data));
|
|
97
|
-
}
|
|
98
85
|
const key = await importP256VerifyKey(subtle, jwk);
|
|
99
86
|
return await subtle.verify(P256_SHA256, key, toArrayBuffer(signature), toArrayBuffer(data));
|
|
100
87
|
} catch {
|
|
101
88
|
return false;
|
|
102
89
|
}
|
|
103
90
|
}
|
|
104
|
-
const RSA_PSS_SHA512 = { name: "RSA-PSS", hash: "SHA-512" };
|
|
105
|
-
const RSA_PSS_SHA512_SIGN = { name: "RSA-PSS", saltLength: 64 };
|
|
106
|
-
const rsaPssVerifyKeys = /* @__PURE__ */ new Map();
|
|
107
|
-
function importRsaPssVerifyKey(subtle, jwk) {
|
|
108
|
-
if (jwk.kty !== "RSA" || typeof jwk.n !== "string" || typeof jwk.e !== "string")
|
|
109
|
-
return Promise.reject(new TypeError("Not an RSA public key"));
|
|
110
|
-
const cacheKey = `${jwk.e}.${jwk.n}`;
|
|
111
|
-
let key = rsaPssVerifyKeys.get(cacheKey);
|
|
112
|
-
if (!key) {
|
|
113
|
-
key = subtle.importKey("jwk", { kty: "RSA", n: jwk.n, e: jwk.e }, RSA_PSS_SHA512, false, ["verify"]);
|
|
114
|
-
key.catch(() => rsaPssVerifyKeys.delete(cacheKey));
|
|
115
|
-
if (rsaPssVerifyKeys.size >= 256) rsaPssVerifyKeys.delete(rsaPssVerifyKeys.keys().next().value);
|
|
116
|
-
rsaPssVerifyKeys.set(cacheKey, key);
|
|
117
|
-
}
|
|
118
|
-
return key;
|
|
119
|
-
}
|
|
120
91
|
function isKeyObject(value) {
|
|
121
92
|
return typeof value?.export === "function" && "asymmetricKeyType" in value;
|
|
122
93
|
}
|
|
@@ -139,25 +110,11 @@ function signWithPrivateJwk(alg, privateJwk, data) {
|
|
|
139
110
|
return new Uint8Array((0, import_crypto.sign)(null, data, (0, import_crypto.createPrivateKey)({ key: privateJwk, format: "jwk" })));
|
|
140
111
|
if (alg === "ecdsa-p256-sha256")
|
|
141
112
|
return new Uint8Array((0, import_crypto.sign)("sha256", data, { key: privateJwk, format: "jwk", dsaEncoding: "ieee-p1363" }));
|
|
142
|
-
if (alg === "rsa-pss-sha512")
|
|
143
|
-
return new Uint8Array(
|
|
144
|
-
(0, import_crypto.sign)("sha512", data, {
|
|
145
|
-
key: (0, import_crypto.createPrivateKey)({ key: privateJwk, format: "jwk" }),
|
|
146
|
-
padding: import_crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
147
|
-
saltLength: 64
|
|
148
|
-
})
|
|
149
|
-
);
|
|
150
113
|
throw new TypeError(`Unsupported signing algorithm: ${alg}`);
|
|
151
114
|
}
|
|
152
115
|
async function signWithPrivateJwkAsync(alg, privateJwk, data) {
|
|
153
116
|
const subtle = subtleCrypto();
|
|
154
|
-
if (alg !== "ecdsa-p256-sha256"
|
|
155
|
-
return signWithPrivateJwk(alg, privateJwk, data);
|
|
156
|
-
if (alg === "rsa-pss-sha512") {
|
|
157
|
-
const { kty, n, e, d, p, q, dp, dq, qi } = privateJwk;
|
|
158
|
-
const key2 = await subtle.importKey("jwk", { kty, n, e, d, p, q, dp, dq, qi }, RSA_PSS_SHA512, false, ["sign"]);
|
|
159
|
-
return new Uint8Array(await subtle.sign(RSA_PSS_SHA512_SIGN, key2, toArrayBuffer(data)));
|
|
160
|
-
}
|
|
117
|
+
if (alg !== "ecdsa-p256-sha256" || !subtle) return signWithPrivateJwk(alg, privateJwk, data);
|
|
161
118
|
const key = await subtle.importKey("jwk", privateP256Jwk(privateJwk), P256, false, ["sign"]);
|
|
162
119
|
return new Uint8Array(await subtle.sign(P256_SHA256, key, toArrayBuffer(data)));
|
|
163
120
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
constants,
|
|
3
2
|
createPrivateKey,
|
|
4
3
|
createPublicKey,
|
|
5
4
|
sign as nodeSign,
|
|
@@ -38,14 +37,6 @@ function verifySignature(alg, publicKey, data, signature) {
|
|
|
38
37
|
);
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
|
-
if (alg === "rsa-pss-sha512") {
|
|
42
|
-
return nodeVerify(
|
|
43
|
-
"sha512",
|
|
44
|
-
data,
|
|
45
|
-
{ key: publicKey, padding: constants.RSA_PKCS1_PSS_PADDING, saltLength: 64 },
|
|
46
|
-
signature
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
40
|
return false;
|
|
50
41
|
} catch {
|
|
51
42
|
return false;
|
|
@@ -66,36 +57,15 @@ function privateP256Jwk(jwk) {
|
|
|
66
57
|
async function verifySignatureAsync(alg, publicKey, data, signature) {
|
|
67
58
|
const subtle = subtleCrypto();
|
|
68
59
|
const keyObject = () => isKeyObject(publicKey) ? publicKey : jwkToPublicKey(publicKey);
|
|
69
|
-
if (alg !== "ecdsa-p256-sha256"
|
|
70
|
-
return verifySignature(alg, keyObject(), data, signature);
|
|
60
|
+
if (alg !== "ecdsa-p256-sha256" || !subtle) return verifySignature(alg, keyObject(), data, signature);
|
|
71
61
|
try {
|
|
72
62
|
const jwk = isKeyObject(publicKey) ? publicKey.export({ format: "jwk" }) : publicKey;
|
|
73
|
-
if (alg === "rsa-pss-sha512") {
|
|
74
|
-
const key2 = await importRsaPssVerifyKey(subtle, jwk);
|
|
75
|
-
return await subtle.verify(RSA_PSS_SHA512_SIGN, key2, toArrayBuffer(signature), toArrayBuffer(data));
|
|
76
|
-
}
|
|
77
63
|
const key = await importP256VerifyKey(subtle, jwk);
|
|
78
64
|
return await subtle.verify(P256_SHA256, key, toArrayBuffer(signature), toArrayBuffer(data));
|
|
79
65
|
} catch {
|
|
80
66
|
return false;
|
|
81
67
|
}
|
|
82
68
|
}
|
|
83
|
-
const RSA_PSS_SHA512 = { name: "RSA-PSS", hash: "SHA-512" };
|
|
84
|
-
const RSA_PSS_SHA512_SIGN = { name: "RSA-PSS", saltLength: 64 };
|
|
85
|
-
const rsaPssVerifyKeys = /* @__PURE__ */ new Map();
|
|
86
|
-
function importRsaPssVerifyKey(subtle, jwk) {
|
|
87
|
-
if (jwk.kty !== "RSA" || typeof jwk.n !== "string" || typeof jwk.e !== "string")
|
|
88
|
-
return Promise.reject(new TypeError("Not an RSA public key"));
|
|
89
|
-
const cacheKey = `${jwk.e}.${jwk.n}`;
|
|
90
|
-
let key = rsaPssVerifyKeys.get(cacheKey);
|
|
91
|
-
if (!key) {
|
|
92
|
-
key = subtle.importKey("jwk", { kty: "RSA", n: jwk.n, e: jwk.e }, RSA_PSS_SHA512, false, ["verify"]);
|
|
93
|
-
key.catch(() => rsaPssVerifyKeys.delete(cacheKey));
|
|
94
|
-
if (rsaPssVerifyKeys.size >= 256) rsaPssVerifyKeys.delete(rsaPssVerifyKeys.keys().next().value);
|
|
95
|
-
rsaPssVerifyKeys.set(cacheKey, key);
|
|
96
|
-
}
|
|
97
|
-
return key;
|
|
98
|
-
}
|
|
99
69
|
function isKeyObject(value) {
|
|
100
70
|
return typeof value?.export === "function" && "asymmetricKeyType" in value;
|
|
101
71
|
}
|
|
@@ -118,25 +88,11 @@ function signWithPrivateJwk(alg, privateJwk, data) {
|
|
|
118
88
|
return new Uint8Array(nodeSign(null, data, createPrivateKey({ key: privateJwk, format: "jwk" })));
|
|
119
89
|
if (alg === "ecdsa-p256-sha256")
|
|
120
90
|
return new Uint8Array(nodeSign("sha256", data, { key: privateJwk, format: "jwk", dsaEncoding: "ieee-p1363" }));
|
|
121
|
-
if (alg === "rsa-pss-sha512")
|
|
122
|
-
return new Uint8Array(
|
|
123
|
-
nodeSign("sha512", data, {
|
|
124
|
-
key: createPrivateKey({ key: privateJwk, format: "jwk" }),
|
|
125
|
-
padding: constants.RSA_PKCS1_PSS_PADDING,
|
|
126
|
-
saltLength: 64
|
|
127
|
-
})
|
|
128
|
-
);
|
|
129
91
|
throw new TypeError(`Unsupported signing algorithm: ${alg}`);
|
|
130
92
|
}
|
|
131
93
|
async function signWithPrivateJwkAsync(alg, privateJwk, data) {
|
|
132
94
|
const subtle = subtleCrypto();
|
|
133
|
-
if (alg !== "ecdsa-p256-sha256"
|
|
134
|
-
return signWithPrivateJwk(alg, privateJwk, data);
|
|
135
|
-
if (alg === "rsa-pss-sha512") {
|
|
136
|
-
const { kty, n, e, d, p, q, dp, dq, qi } = privateJwk;
|
|
137
|
-
const key2 = await subtle.importKey("jwk", { kty, n, e, d, p, q, dp, dq, qi }, RSA_PSS_SHA512, false, ["sign"]);
|
|
138
|
-
return new Uint8Array(await subtle.sign(RSA_PSS_SHA512_SIGN, key2, toArrayBuffer(data)));
|
|
139
|
-
}
|
|
95
|
+
if (alg !== "ecdsa-p256-sha256" || !subtle) return signWithPrivateJwk(alg, privateJwk, data);
|
|
140
96
|
const key = await subtle.importKey("jwk", privateP256Jwk(privateJwk), P256, false, ["sign"]);
|
|
141
97
|
return new Uint8Array(await subtle.sign(P256_SHA256, key, toArrayBuffer(data)));
|
|
142
98
|
}
|
|
@@ -8,8 +8,8 @@ export declare const WEB_BOT_AUTH_PROFILE: "web-bot-auth";
|
|
|
8
8
|
export declare const WEB_BOT_AUTH_DRAFT_REVISION: "draft-ietf-webbotauth-httpsig-protocol-00";
|
|
9
9
|
export declare const SIGNATURE_DIRECTORY_PATH = "/.well-known/http-message-signatures-directory";
|
|
10
10
|
export declare const SIGNATURE_DIRECTORY_MEDIA_TYPE = "application/http-message-signatures-directory+json";
|
|
11
|
-
/** The profile's signature
|
|
12
|
-
export declare const WEB_BOT_AUTH_ALGORITHMS: readonly ["ed25519"
|
|
11
|
+
/** The profile's signature algorithm: Ed25519 only. ES256 is RFC 9421 profile only. */
|
|
12
|
+
export declare const WEB_BOT_AUTH_ALGORITHMS: readonly ["ed25519"];
|
|
13
13
|
/**
|
|
14
14
|
* The profile's `Accept-Signature` member (RFC 9421 §5.1): the label, the
|
|
15
15
|
* components the profile requires, and its parameters. A replay challenge
|
|
@@ -73,7 +73,12 @@ export declare function jwkThumbprint(jwk: Partial<Pick<AdcpJsonWebKey, 'kty' |
|
|
|
73
73
|
* time rather than on the first request.
|
|
74
74
|
*/
|
|
75
75
|
export declare function assertWebBotAuthSigningKey(key: WebBotSigningKey): void;
|
|
76
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* A received identity origin, which must be exactly the canonical https
|
|
78
|
+
* origin string (WBA §5.2.1): lowercase host, no default port, and no path,
|
|
79
|
+
* trailing `/`, query, fragment, or userinfo. The string is compared as
|
|
80
|
+
* received, never normalized first.
|
|
81
|
+
*/
|
|
77
82
|
export declare function receivedAgentOrigin(value: string): string;
|
|
78
83
|
export declare function getWebBotAuthLegacyOriginGate(resolver: Function | undefined): ((origin: string) => Promise<void>) | undefined;
|
|
79
84
|
export interface WebBotAuthAuthorizationFailure {
|
|
@@ -136,8 +141,9 @@ export interface VerifyWebBotAuthOptions {
|
|
|
136
141
|
/**
|
|
137
142
|
* Verify a Web Bot Auth request (wba-profile.mdx "Verification"). Resolves to
|
|
138
143
|
* exactly one verified signer: the profile takes one `web-bot-auth` signature
|
|
139
|
-
* and one `Signature-Agent` member per request
|
|
140
|
-
* principal resolvers written
|
|
144
|
+
* and one `Signature-Agent` member per request, and does not read signatures
|
|
145
|
+
* with other tags. The array shape is kept for principal resolvers written
|
|
146
|
+
* against earlier drafts.
|
|
141
147
|
*/
|
|
142
148
|
export declare function verifyWebBotAuth(request: RequestLike, options: VerifyWebBotAuthOptions): Promise<VerifiedWebBotSigner[]>;
|
|
143
149
|
export interface VerifiedSignatureDirectory {
|
|
@@ -151,11 +157,13 @@ export interface VerifiedSignatureDirectory {
|
|
|
151
157
|
}
|
|
152
158
|
/**
|
|
153
159
|
* Verify a key directory response (wba-profile.mdx "Key directories", WBA
|
|
154
|
-
* Appendix B.1). The response must be signed once per key, each
|
|
155
|
-
* covering `"@authority";req` and `content-digest` with `created`,
|
|
156
|
-
* the key's thumbprint as `keyid` and
|
|
157
|
-
* and verifying under the key the
|
|
158
|
-
* directory
|
|
160
|
+
* Appendix B.1). The response must be signed once per usable key, each
|
|
161
|
+
* signature covering `"@authority";req` and `content-digest` with `created`,
|
|
162
|
+
* `expires`, the key's thumbprint as `keyid` and
|
|
163
|
+
* `tag="http-message-signatures-directory"`, and verifying under the key the
|
|
164
|
+
* directory itself provides. Keys the profile cannot use, and their
|
|
165
|
+
* signatures, are ignored. An unsigned directory, or one without a usable
|
|
166
|
+
* key, is a discovery failure.
|
|
159
167
|
*/
|
|
160
168
|
export declare function verifyKeyDirectory(response: ResponseLike, now?: number, options?: {
|
|
161
169
|
allowTestKeys?: boolean;
|