@adcp/sdk 16.0.0-beta.6 → 16.0.0-beta.8
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 +17 -0
- package/dist/lib/conformance/index.d.mts +2 -0
- package/dist/lib/conformance/index.d.ts +2 -0
- package/dist/lib/conformance/index.js +3 -0
- package/dist/lib/conformance/index.mjs +2 -0
- package/dist/lib/conformance/property-lists.d.mts +14 -0
- package/dist/lib/conformance/property-lists.d.ts +14 -0
- package/dist/lib/conformance/property-lists.js +45 -0
- package/dist/lib/conformance/property-lists.mjs +21 -0
- package/dist/lib/conformance/runConformance.js +20 -1
- package/dist/lib/conformance/runConformance.mjs +20 -1
- package/dist/lib/conformance/types.d.mts +3 -0
- package/dist/lib/conformance/types.d.ts +3 -0
- package/dist/lib/core/SingleAgentClient.d.mts +13 -3
- package/dist/lib/core/SingleAgentClient.d.ts +13 -3
- package/dist/lib/core/SingleAgentClient.js +109 -21
- package/dist/lib/core/SingleAgentClient.mjs +112 -22
- package/dist/lib/core/TaskExecutor.d.mts +1 -0
- package/dist/lib/core/TaskExecutor.d.ts +1 -0
- package/dist/lib/core/TaskExecutor.js +48 -34
- package/dist/lib/core/TaskExecutor.mjs +49 -35
- package/dist/lib/identifiers.d.mts +53 -0
- package/dist/lib/identifiers.d.ts +53 -0
- package/dist/lib/identifiers.js +212 -0
- package/dist/lib/identifiers.mjs +163 -0
- package/dist/lib/identity-3.3/revocation.js +5 -4
- package/dist/lib/identity-3.3/revocation.mjs +5 -4
- package/dist/lib/index.d.mts +3 -1
- package/dist/lib/index.d.ts +3 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.mjs +1 -0
- package/dist/lib/media-buy/index.d.mts +1 -1
- package/dist/lib/media-buy/index.d.ts +1 -1
- package/dist/lib/media-buy/property-policy.d.mts +15 -1
- package/dist/lib/media-buy/property-policy.d.ts +15 -1
- package/dist/lib/media-buy/property-policy.js +135 -3
- package/dist/lib/media-buy/property-policy.mjs +134 -3
- package/dist/lib/registry/index.d.mts +12 -0
- package/dist/lib/registry/index.d.ts +12 -0
- package/dist/lib/registry/index.js +159 -5
- package/dist/lib/registry/index.mjs +156 -4
- package/dist/lib/registry/types.d.mts +23 -0
- package/dist/lib/registry/types.d.ts +23 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/auth-signature.js +23 -2
- package/dist/lib/server/auth-signature.mjs +26 -2
- package/dist/lib/server/auth.d.mts +6 -0
- package/dist/lib/server/auth.d.ts +6 -0
- package/dist/lib/server/auth.js +6 -0
- package/dist/lib/server/auth.mjs +6 -0
- package/dist/lib/server/create-adcp-server.js +19 -3
- package/dist/lib/server/create-adcp-server.mjs +23 -4
- package/dist/lib/server/decisioning/runtime/from-platform.js +6 -2
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +6 -2
- package/dist/lib/server/decisioning/specialisms/lists.d.mts +4 -4
- package/dist/lib/server/decisioning/specialisms/lists.d.ts +4 -4
- package/dist/lib/server/index.d.mts +3 -0
- package/dist/lib/server/index.d.ts +3 -0
- package/dist/lib/server/index.js +8 -1
- package/dist/lib/server/index.mjs +4 -0
- package/dist/lib/server/property-lists.d.mts +36 -0
- package/dist/lib/server/property-lists.d.ts +36 -0
- package/dist/lib/server/property-lists.js +154 -0
- package/dist/lib/server/property-lists.mjs +129 -0
- package/dist/lib/server/serve.js +2 -1
- package/dist/lib/server/serve.mjs +2 -1
- package/dist/lib/server/targeting-helpers.d.mts +2 -0
- package/dist/lib/server/targeting-helpers.d.ts +2 -0
- package/dist/lib/server/targeting-helpers.js +28 -1
- package/dist/lib/server/targeting-helpers.mjs +18 -1
- package/dist/lib/server/webhook-emitter.js +1 -0
- package/dist/lib/server/webhook-emitter.mjs +2 -1
- package/dist/lib/signing/crypto.d.mts +1 -1
- package/dist/lib/signing/crypto.d.ts +1 -1
- package/dist/lib/signing/crypto.js +37 -2
- package/dist/lib/signing/crypto.mjs +37 -2
- package/dist/lib/signing/parser.d.mts +6 -0
- package/dist/lib/signing/parser.d.ts +6 -0
- package/dist/lib/signing/parser.js +7 -3
- package/dist/lib/signing/parser.mjs +6 -3
- package/dist/lib/signing/server.d.mts +1 -1
- package/dist/lib/signing/server.d.ts +1 -1
- package/dist/lib/signing/server.mjs +5 -1
- package/dist/lib/signing/web-bot-auth.d.mts +61 -22
- package/dist/lib/signing/web-bot-auth.d.ts +61 -22
- package/dist/lib/signing/web-bot-auth.js +286 -266
- package/dist/lib/signing/web-bot-auth.mjs +288 -277
- package/dist/lib/signing/webhook-verifier.d.mts +11 -0
- package/dist/lib/signing/webhook-verifier.d.ts +11 -0
- package/dist/lib/signing/webhook-verifier.js +11 -3
- package/dist/lib/signing/webhook-verifier.mjs +11 -3
- package/dist/lib/supply-path/verify.js +12 -2
- package/dist/lib/supply-path/verify.mjs +2 -2
- package/dist/lib/testing/client.js +3 -5
- package/dist/lib/testing/client.mjs +4 -6
- package/dist/lib/testing/compliance/comply.js +7 -2
- package/dist/lib/testing/compliance/comply.mjs +8 -3
- package/dist/lib/testing/index.d.mts +1 -1
- package/dist/lib/testing/index.d.ts +1 -1
- package/dist/lib/testing/index.js +4 -2
- package/dist/lib/testing/index.mjs +8 -2
- package/dist/lib/testing/storyboard/runner.js +12 -12
- package/dist/lib/testing/storyboard/runner.mjs +14 -13
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/testing/storyboard/validations.js +23 -1
- package/dist/lib/testing/storyboard/validations.mjs +28 -2
- package/dist/lib/testing/types.d.mts +39 -0
- package/dist/lib/testing/types.d.ts +39 -0
- package/dist/lib/v2/projection/augment-response.js +6 -3
- package/dist/lib/v2/projection/augment-response.mjs +8 -5
- package/dist/lib/v2/projection/creative-delivery.js +29 -17
- package/dist/lib/v2/projection/creative-delivery.mjs +31 -18
- package/dist/lib/v2/projection/v1-to-v2.d.mts +7 -0
- package/dist/lib/v2/projection/v1-to-v2.d.ts +7 -0
- package/dist/lib/v2/projection/v1-to-v2.js +70 -2
- package/dist/lib/v2/projection/v1-to-v2.mjs +72 -1
- package/dist/lib/validation/index.d.mts +1 -1
- package/dist/lib/validation/index.d.ts +1 -1
- package/dist/lib/validation/index.js +4 -2
- package/dist/lib/validation/index.mjs +4 -2
- package/dist/lib/validation/schema-loader.d.mts +26 -0
- package/dist/lib/validation/schema-loader.d.ts +26 -0
- package/dist/lib/validation/schema-loader.js +98 -14
- package/dist/lib/validation/schema-loader.mjs +95 -13
- 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 +2 -2
- package/docs/guides/PROPERTY-LISTS.md +264 -0
- package/docs/guides/SIGNING-GUIDE.md +25 -0
- package/docs/guides/VALIDATE-YOUR-AGENT.md +34 -0
- package/docs/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-agent-identity-3.3.md +60 -23
- package/package.json +1 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { GetPropertyListRequestSchema, GetPropertyListResponseSchema } from "../types/schemas.generated.mjs";
|
|
3
|
+
import { stripCtxMetadata } from "./ctx-metadata/wire-shape.mjs";
|
|
4
|
+
function registerPropertyListTool(server, options) {
|
|
5
|
+
return server.registerTool(
|
|
6
|
+
"get_property_list",
|
|
7
|
+
{
|
|
8
|
+
description: "Retrieve an authorized property list and a page of resolved identifiers.",
|
|
9
|
+
inputSchema: GetPropertyListRequestSchema,
|
|
10
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true }
|
|
11
|
+
},
|
|
12
|
+
async (request, extra) => {
|
|
13
|
+
const denied = () => toolError("PERMISSION_DENIED", "Property list access denied.", request.context);
|
|
14
|
+
const headers = extra.requestInfo?.headers ?? {};
|
|
15
|
+
for (const name of ["authorization", "x-adcp-auth"]) {
|
|
16
|
+
const values = Object.entries(headers).filter(([key]) => key.toLowerCase() === name);
|
|
17
|
+
if (values.length > 1 || values.length === 1 && typeof values[0][1] !== "string") return denied();
|
|
18
|
+
}
|
|
19
|
+
const readHeader = (name) => {
|
|
20
|
+
const values = Object.entries(headers).filter(([key]) => key.toLowerCase() === name);
|
|
21
|
+
if (values.length !== 1 || typeof values[0][1] !== "string") return void 0;
|
|
22
|
+
return values[0][1];
|
|
23
|
+
};
|
|
24
|
+
const authorization = readHeader("authorization");
|
|
25
|
+
const bearer = authorization?.match(/^Bearer ([^\s]+)$/i)?.[1];
|
|
26
|
+
const adcpToken = readHeader("x-adcp-auth");
|
|
27
|
+
const authenticatedToken = extra.authInfo?.token;
|
|
28
|
+
const tokens = [bearer, adcpToken, authenticatedToken].filter((token) => token !== void 0);
|
|
29
|
+
if (!tokens.length || tokens.some((token) => !token || token !== tokens[0]) || authorization !== void 0 && !bearer)
|
|
30
|
+
return denied();
|
|
31
|
+
let principal;
|
|
32
|
+
try {
|
|
33
|
+
principal = await options.verifyToken({ listId: request.list_id, token: tokens[0] });
|
|
34
|
+
} catch {
|
|
35
|
+
return denied();
|
|
36
|
+
}
|
|
37
|
+
if (principal === null || principal === false || principal === void 0) return denied();
|
|
38
|
+
try {
|
|
39
|
+
const page = await options.loadPage(request, principal);
|
|
40
|
+
if (page.list.list_id !== request.list_id) throw new Error("Invalid list identity");
|
|
41
|
+
if (request.resolve !== false && !Array.isArray(page.identifiers))
|
|
42
|
+
throw new Error("Missing resolved identifiers");
|
|
43
|
+
const limit = request.pagination?.max_results ?? 1e3;
|
|
44
|
+
if (request.resolve !== false && (page.identifiers?.length ?? 0) > limit) throw new Error("Invalid page size");
|
|
45
|
+
if (page.pagination?.has_more && !page.pagination.cursor) throw new Error("Missing continuation cursor");
|
|
46
|
+
if (!page.pagination?.has_more && page.pagination?.cursor) throw new Error("Unexpected continuation cursor");
|
|
47
|
+
const payload = GetPropertyListResponseSchema.parse({
|
|
48
|
+
list: Object.fromEntries(
|
|
49
|
+
[
|
|
50
|
+
"list_id",
|
|
51
|
+
"name",
|
|
52
|
+
"description",
|
|
53
|
+
"account",
|
|
54
|
+
"base_properties",
|
|
55
|
+
"filters",
|
|
56
|
+
"brand",
|
|
57
|
+
"webhook_url",
|
|
58
|
+
"cache_duration_hours",
|
|
59
|
+
"created_at",
|
|
60
|
+
"updated_at",
|
|
61
|
+
"property_count",
|
|
62
|
+
"pricing_options"
|
|
63
|
+
].filter((key) => Object.hasOwn(page.list, key)).map((key) => [key, page.list[key]])
|
|
64
|
+
),
|
|
65
|
+
...page.identifiers !== void 0 ? { identifiers: page.identifiers.map((identifier) => ({ type: identifier.type, value: identifier.value })) } : {},
|
|
66
|
+
...page.pagination !== void 0 ? {
|
|
67
|
+
pagination: {
|
|
68
|
+
has_more: page.pagination.has_more,
|
|
69
|
+
cursor: page.pagination.cursor,
|
|
70
|
+
total_count: page.pagination.total_count
|
|
71
|
+
}
|
|
72
|
+
} : {},
|
|
73
|
+
...page.resolved_at !== void 0 ? { resolved_at: page.resolved_at } : {},
|
|
74
|
+
...page.cache_valid_until !== void 0 ? { cache_valid_until: page.cache_valid_until } : {},
|
|
75
|
+
...page.coverage_gaps !== void 0 ? { coverage_gaps: page.coverage_gaps } : {},
|
|
76
|
+
status: "completed",
|
|
77
|
+
...request.resolve === false ? { identifiers: void 0, pagination: void 0 } : {},
|
|
78
|
+
...request.context ? { context: request.context } : {}
|
|
79
|
+
});
|
|
80
|
+
stripCtxMetadata({ property_list: payload.list });
|
|
81
|
+
return { content: [{ type: "text", text: JSON.stringify(payload) }], structuredContent: payload };
|
|
82
|
+
} catch {
|
|
83
|
+
return toolError("INTERNAL_ERROR", "Property list could not be loaded.", request.context);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
function toolError(code, message, context) {
|
|
89
|
+
const payload = { status: "failed", errors: [{ code, message }], ...context !== void 0 ? { context } : {} };
|
|
90
|
+
return {
|
|
91
|
+
isError: true,
|
|
92
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
93
|
+
structuredContent: payload
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function sendPropertyListChanged(emitter, options) {
|
|
97
|
+
const { notification, ...delivery } = options;
|
|
98
|
+
const dateTime = z.string().datetime({ offset: true });
|
|
99
|
+
if (!notification.list_id || !dateTime.safeParse(notification.resolved_at).success || notification.cache_valid_until !== void 0 && !dateTime.safeParse(notification.cache_valid_until).success) {
|
|
100
|
+
throw new TypeError("Property-list notifications require a list_id and valid timestamps");
|
|
101
|
+
}
|
|
102
|
+
const summary = notification.change_summary === void 0 ? void 0 : Object.fromEntries(
|
|
103
|
+
["properties_added", "properties_removed", "total_properties"].filter(
|
|
104
|
+
(key) => Object.hasOwn(notification.change_summary, key) && notification.change_summary[key] !== void 0
|
|
105
|
+
).map((key) => [key, notification.change_summary[key]])
|
|
106
|
+
);
|
|
107
|
+
for (const count of Object.values(summary ?? {})) {
|
|
108
|
+
if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0)
|
|
109
|
+
throw new TypeError("Property-list change counts must be nonnegative integers");
|
|
110
|
+
}
|
|
111
|
+
return emitter.emit({
|
|
112
|
+
...delivery,
|
|
113
|
+
authentication: null,
|
|
114
|
+
signingProfile: "adcp/webhook-signing/v1",
|
|
115
|
+
payload: {
|
|
116
|
+
event: "property_list_changed",
|
|
117
|
+
list_id: notification.list_id,
|
|
118
|
+
resolved_at: notification.resolved_at,
|
|
119
|
+
...notification.list_name !== void 0 ? { list_name: notification.list_name } : {},
|
|
120
|
+
...notification.cache_valid_until !== void 0 ? { cache_valid_until: notification.cache_valid_until } : {},
|
|
121
|
+
...summary !== void 0 ? { change_summary: summary } : {},
|
|
122
|
+
signature: "rfc9421"
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
export {
|
|
127
|
+
registerPropertyListTool,
|
|
128
|
+
sendPropertyListChanged
|
|
129
|
+
};
|
package/dist/lib/server/serve.js
CHANGED
|
@@ -322,7 +322,8 @@ function serve(createAgent, options) {
|
|
|
322
322
|
(0, import_auth.respondUnauthorized)(req, res, {
|
|
323
323
|
signatureError: signatureCode,
|
|
324
324
|
errorDescription: publicMessage,
|
|
325
|
-
resourceMetadata: resourceMetadataUrl
|
|
325
|
+
resourceMetadata: resourceMetadataUrl,
|
|
326
|
+
...err instanceof import_auth.AuthError && err.headers && { headers: err.headers }
|
|
326
327
|
});
|
|
327
328
|
return;
|
|
328
329
|
}
|
|
@@ -305,7 +305,8 @@ function serve(createAgent, options) {
|
|
|
305
305
|
respondUnauthorized(req, res, {
|
|
306
306
|
signatureError: signatureCode,
|
|
307
307
|
errorDescription: publicMessage,
|
|
308
|
-
resourceMetadata: resourceMetadataUrl
|
|
308
|
+
resourceMetadata: resourceMetadataUrl,
|
|
309
|
+
...err instanceof AuthError && err.headers && { headers: err.headers }
|
|
309
310
|
});
|
|
310
311
|
return;
|
|
311
312
|
}
|
|
@@ -56,6 +56,8 @@ export declare const defaultResolvedListCache: ResolvedListCache;
|
|
|
56
56
|
export declare function clearDefaultResolvedListCache(): void;
|
|
57
57
|
export type ResolveListCallTool = (agentUrl: string, toolName: 'get_property_list' | 'get_collection_list', args: Record<string, unknown>, authToken?: string) => Promise<unknown>;
|
|
58
58
|
export interface ResolveListOptions {
|
|
59
|
+
/** Require schema-valid property-list pages with identifiers when resolving. Used for certification. */
|
|
60
|
+
strictResponseValidation?: boolean;
|
|
59
61
|
/** Maximum page size when calling get_property_list / get_collection_list. Defaults to 1000. */
|
|
60
62
|
pageSize?: number;
|
|
61
63
|
/** Maximum number of pages to walk before treating pagination as unsafe. Defaults to 100. */
|
|
@@ -56,6 +56,8 @@ export declare const defaultResolvedListCache: ResolvedListCache;
|
|
|
56
56
|
export declare function clearDefaultResolvedListCache(): void;
|
|
57
57
|
export type ResolveListCallTool = (agentUrl: string, toolName: 'get_property_list' | 'get_collection_list', args: Record<string, unknown>, authToken?: string) => Promise<unknown>;
|
|
58
58
|
export interface ResolveListOptions {
|
|
59
|
+
/** Require schema-valid property-list pages with identifiers when resolving. Used for certification. */
|
|
60
|
+
strictResponseValidation?: boolean;
|
|
59
61
|
/** Maximum page size when calling get_property_list / get_collection_list. Defaults to 1000. */
|
|
60
62
|
pageSize?: number;
|
|
61
63
|
/** Maximum number of pages to walk before treating pagination as unsafe. Defaults to 100. */
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
var targeting_helpers_exports = {};
|
|
20
30
|
__export(targeting_helpers_exports, {
|
|
@@ -75,7 +85,7 @@ async function resolvePropertyList(ref, options = {}) {
|
|
|
75
85
|
const cache = cacheForOptions(options);
|
|
76
86
|
const nowMs = nowMsForOptions(options);
|
|
77
87
|
const cacheKey = resolvedListCacheKey("property", structurallyNormalizedRef, options);
|
|
78
|
-
const cached = cacheKey ? cache?.get(cacheKey, nowMs) : void 0;
|
|
88
|
+
const cached = cacheKey && !options.strictResponseValidation ? cache?.get(cacheKey, nowMs) : void 0;
|
|
79
89
|
if (cached) return cached;
|
|
80
90
|
const normalizedRef = options.callTool ? structurallyNormalizedRef : await normalizePropertyListReference(structurallyNormalizedRef, { resolveDns: false });
|
|
81
91
|
const result = await fetchResolvedPropertyList(normalizedRef, options);
|
|
@@ -89,6 +99,7 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
89
99
|
let cacheValidUntil;
|
|
90
100
|
let missingCacheValidUntil = false;
|
|
91
101
|
let cursor;
|
|
102
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
92
103
|
for (let pageIndex = 0; pageIndex < maxPagesForOptions(options); pageIndex += 1) {
|
|
93
104
|
const args = buildResolveListArgs(ref.list_id, pageSizeForOptions(options), cursor);
|
|
94
105
|
const raw = await callTool(ref.agent_url, "get_property_list", args, ref.auth_token);
|
|
@@ -96,6 +107,20 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
96
107
|
throw new Error("property_list_invalid_response");
|
|
97
108
|
}
|
|
98
109
|
const response = raw;
|
|
110
|
+
if (response.status !== void 0 && response.status !== "completed" || raw.errors !== void 0 && (!Array.isArray(raw.errors) || raw.errors.some((error) => !error || typeof error !== "object" || error.severity !== "warning")) || raw.adcp_error !== void 0 || !Array.isArray(response.identifiers)) {
|
|
111
|
+
throw new Error("property_list_invalid_response");
|
|
112
|
+
}
|
|
113
|
+
if (options.strictResponseValidation) {
|
|
114
|
+
const { GetPropertyListResponseSchema } = await import("../types/schemas.generated.js");
|
|
115
|
+
if (!GetPropertyListResponseSchema.safeParse(raw).success || response.status !== "completed" || response.identifiers.length > pageSizeForOptions(options)) {
|
|
116
|
+
throw new Error("property_list_invalid_response");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!response.list || response.list.list_id !== ref.list_id || response.identifiers !== void 0 && (!Array.isArray(response.identifiers) || response.identifiers.some(
|
|
120
|
+
(identifier) => !identifier || typeof identifier !== "object" || typeof identifier.type !== "string" || typeof identifier.value !== "string"
|
|
121
|
+
))) {
|
|
122
|
+
throw new Error("property_list_invalid_response");
|
|
123
|
+
}
|
|
99
124
|
listId = response.list.list_id;
|
|
100
125
|
identifiers.push(...response.identifiers ?? []);
|
|
101
126
|
if (typeof response.cache_valid_until === "string") {
|
|
@@ -118,6 +143,8 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
118
143
|
if (!pagination.cursor) {
|
|
119
144
|
throw new Error("property_list_invalid_pagination");
|
|
120
145
|
}
|
|
146
|
+
if (seenCursors.has(pagination.cursor)) throw new Error("property_list_invalid_pagination");
|
|
147
|
+
seenCursors.add(pagination.cursor);
|
|
121
148
|
cursor = pagination.cursor;
|
|
122
149
|
}
|
|
123
150
|
throw new Error("property_list_pagination_limit_exceeded");
|
|
@@ -44,7 +44,7 @@ async function resolvePropertyList(ref, options = {}) {
|
|
|
44
44
|
const cache = cacheForOptions(options);
|
|
45
45
|
const nowMs = nowMsForOptions(options);
|
|
46
46
|
const cacheKey = resolvedListCacheKey("property", structurallyNormalizedRef, options);
|
|
47
|
-
const cached = cacheKey ? cache?.get(cacheKey, nowMs) : void 0;
|
|
47
|
+
const cached = cacheKey && !options.strictResponseValidation ? cache?.get(cacheKey, nowMs) : void 0;
|
|
48
48
|
if (cached) return cached;
|
|
49
49
|
const normalizedRef = options.callTool ? structurallyNormalizedRef : await normalizePropertyListReference(structurallyNormalizedRef, { resolveDns: false });
|
|
50
50
|
const result = await fetchResolvedPropertyList(normalizedRef, options);
|
|
@@ -58,6 +58,7 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
58
58
|
let cacheValidUntil;
|
|
59
59
|
let missingCacheValidUntil = false;
|
|
60
60
|
let cursor;
|
|
61
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
61
62
|
for (let pageIndex = 0; pageIndex < maxPagesForOptions(options); pageIndex += 1) {
|
|
62
63
|
const args = buildResolveListArgs(ref.list_id, pageSizeForOptions(options), cursor);
|
|
63
64
|
const raw = await callTool(ref.agent_url, "get_property_list", args, ref.auth_token);
|
|
@@ -65,6 +66,20 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
65
66
|
throw new Error("property_list_invalid_response");
|
|
66
67
|
}
|
|
67
68
|
const response = raw;
|
|
69
|
+
if (response.status !== void 0 && response.status !== "completed" || raw.errors !== void 0 && (!Array.isArray(raw.errors) || raw.errors.some((error) => !error || typeof error !== "object" || error.severity !== "warning")) || raw.adcp_error !== void 0 || !Array.isArray(response.identifiers)) {
|
|
70
|
+
throw new Error("property_list_invalid_response");
|
|
71
|
+
}
|
|
72
|
+
if (options.strictResponseValidation) {
|
|
73
|
+
const { GetPropertyListResponseSchema } = await import("../types/schemas.generated.mjs");
|
|
74
|
+
if (!GetPropertyListResponseSchema.safeParse(raw).success || response.status !== "completed" || response.identifiers.length > pageSizeForOptions(options)) {
|
|
75
|
+
throw new Error("property_list_invalid_response");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!response.list || response.list.list_id !== ref.list_id || response.identifiers !== void 0 && (!Array.isArray(response.identifiers) || response.identifiers.some(
|
|
79
|
+
(identifier) => !identifier || typeof identifier !== "object" || typeof identifier.type !== "string" || typeof identifier.value !== "string"
|
|
80
|
+
))) {
|
|
81
|
+
throw new Error("property_list_invalid_response");
|
|
82
|
+
}
|
|
68
83
|
listId = response.list.list_id;
|
|
69
84
|
identifiers.push(...response.identifiers ?? []);
|
|
70
85
|
if (typeof response.cache_valid_until === "string") {
|
|
@@ -87,6 +102,8 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
87
102
|
if (!pagination.cursor) {
|
|
88
103
|
throw new Error("property_list_invalid_pagination");
|
|
89
104
|
}
|
|
105
|
+
if (seenCursors.has(pagination.cursor)) throw new Error("property_list_invalid_pagination");
|
|
106
|
+
seenCursors.add(pagination.cursor);
|
|
90
107
|
cursor = pagination.cursor;
|
|
91
108
|
}
|
|
92
109
|
throw new Error("property_list_pagination_limit_exceeded");
|
|
@@ -83,6 +83,7 @@ function createWebhookEmitter(options) {
|
|
|
83
83
|
if (options.deliveryStore && options.idempotencyKeyStore) {
|
|
84
84
|
throw new TypeError("createWebhookEmitter: provide deliveryStore, not both deliveryStore and idempotencyKeyStore");
|
|
85
85
|
}
|
|
86
|
+
if (options.webBotAuth?.key) (0, import_web_bot_auth.assertWebBotAuthSigningKey)(options.webBotAuth.key);
|
|
86
87
|
const retryHorizonSeconds = resolveRetryHorizonSeconds(options.deliveryRetryHorizonSeconds);
|
|
87
88
|
const explicitStore = options.deliveryStore ?? options.idempotencyKeyStore;
|
|
88
89
|
const store = explicitStore ?? memoryWebhookDeliveryStore({ now: options.now });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { signWebBotAuth } from "../signing/web-bot-auth.mjs";
|
|
1
|
+
import { assertWebBotAuthSigningKey, signWebBotAuth } from "../signing/web-bot-auth.mjs";
|
|
2
2
|
import { signWebhook } from "../signing/signer.mjs";
|
|
3
3
|
import { signWebhookAsync } from "../signing/signer-async.mjs";
|
|
4
4
|
import { canonicalJsonSha256 } from "../utils/jcs.mjs";
|
|
@@ -64,6 +64,7 @@ function createWebhookEmitter(options) {
|
|
|
64
64
|
if (options.deliveryStore && options.idempotencyKeyStore) {
|
|
65
65
|
throw new TypeError("createWebhookEmitter: provide deliveryStore, not both deliveryStore and idempotencyKeyStore");
|
|
66
66
|
}
|
|
67
|
+
if (options.webBotAuth?.key) assertWebBotAuthSigningKey(options.webBotAuth.key);
|
|
67
68
|
const retryHorizonSeconds = resolveRetryHorizonSeconds(options.deliveryRetryHorizonSeconds);
|
|
68
69
|
const explicitStore = options.deliveryStore ?? options.idempotencyKeyStore;
|
|
69
70
|
const store = explicitStore ?? memoryWebhookDeliveryStore({ now: options.now });
|
|
@@ -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 when available. */
|
|
18
|
+
/** {@link signWithPrivateJwk}, preferring WebCrypto for ES256 and RSA-PSS 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 when available. */
|
|
18
|
+
/** {@link signWithPrivateJwk}, preferring WebCrypto for ES256 and RSA-PSS when available (workerd, #3243). */
|
|
19
19
|
export declare function signWithPrivateJwkAsync(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Promise<Uint8Array>;
|
|
@@ -87,15 +87,36 @@ function privateP256Jwk(jwk) {
|
|
|
87
87
|
async function verifySignatureAsync(alg, publicKey, data, signature) {
|
|
88
88
|
const subtle = subtleCrypto();
|
|
89
89
|
const keyObject = () => isKeyObject(publicKey) ? publicKey : jwkToPublicKey(publicKey);
|
|
90
|
-
if (alg !== "ecdsa-p256-sha256"
|
|
90
|
+
if (alg !== "ecdsa-p256-sha256" && alg !== "rsa-pss-sha512" || !subtle)
|
|
91
|
+
return verifySignature(alg, keyObject(), data, signature);
|
|
91
92
|
try {
|
|
92
93
|
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
|
+
}
|
|
93
98
|
const key = await importP256VerifyKey(subtle, jwk);
|
|
94
99
|
return await subtle.verify(P256_SHA256, key, toArrayBuffer(signature), toArrayBuffer(data));
|
|
95
100
|
} catch {
|
|
96
101
|
return false;
|
|
97
102
|
}
|
|
98
103
|
}
|
|
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
|
+
}
|
|
99
120
|
function isKeyObject(value) {
|
|
100
121
|
return typeof value?.export === "function" && "asymmetricKeyType" in value;
|
|
101
122
|
}
|
|
@@ -118,11 +139,25 @@ function signWithPrivateJwk(alg, privateJwk, data) {
|
|
|
118
139
|
return new Uint8Array((0, import_crypto.sign)(null, data, (0, import_crypto.createPrivateKey)({ key: privateJwk, format: "jwk" })));
|
|
119
140
|
if (alg === "ecdsa-p256-sha256")
|
|
120
141
|
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
|
+
);
|
|
121
150
|
throw new TypeError(`Unsupported signing algorithm: ${alg}`);
|
|
122
151
|
}
|
|
123
152
|
async function signWithPrivateJwkAsync(alg, privateJwk, data) {
|
|
124
153
|
const subtle = subtleCrypto();
|
|
125
|
-
if (alg !== "ecdsa-p256-sha256"
|
|
154
|
+
if (alg !== "ecdsa-p256-sha256" && alg !== "rsa-pss-sha512" || !subtle)
|
|
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
|
+
}
|
|
126
161
|
const key = await subtle.importKey("jwk", privateP256Jwk(privateJwk), P256, false, ["sign"]);
|
|
127
162
|
return new Uint8Array(await subtle.sign(P256_SHA256, key, toArrayBuffer(data)));
|
|
128
163
|
}
|
|
@@ -66,15 +66,36 @@ function privateP256Jwk(jwk) {
|
|
|
66
66
|
async function verifySignatureAsync(alg, publicKey, data, signature) {
|
|
67
67
|
const subtle = subtleCrypto();
|
|
68
68
|
const keyObject = () => isKeyObject(publicKey) ? publicKey : jwkToPublicKey(publicKey);
|
|
69
|
-
if (alg !== "ecdsa-p256-sha256"
|
|
69
|
+
if (alg !== "ecdsa-p256-sha256" && alg !== "rsa-pss-sha512" || !subtle)
|
|
70
|
+
return verifySignature(alg, keyObject(), data, signature);
|
|
70
71
|
try {
|
|
71
72
|
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
|
+
}
|
|
72
77
|
const key = await importP256VerifyKey(subtle, jwk);
|
|
73
78
|
return await subtle.verify(P256_SHA256, key, toArrayBuffer(signature), toArrayBuffer(data));
|
|
74
79
|
} catch {
|
|
75
80
|
return false;
|
|
76
81
|
}
|
|
77
82
|
}
|
|
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
|
+
}
|
|
78
99
|
function isKeyObject(value) {
|
|
79
100
|
return typeof value?.export === "function" && "asymmetricKeyType" in value;
|
|
80
101
|
}
|
|
@@ -97,11 +118,25 @@ function signWithPrivateJwk(alg, privateJwk, data) {
|
|
|
97
118
|
return new Uint8Array(nodeSign(null, data, createPrivateKey({ key: privateJwk, format: "jwk" })));
|
|
98
119
|
if (alg === "ecdsa-p256-sha256")
|
|
99
120
|
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
|
+
);
|
|
100
129
|
throw new TypeError(`Unsupported signing algorithm: ${alg}`);
|
|
101
130
|
}
|
|
102
131
|
async function signWithPrivateJwkAsync(alg, privateJwk, data) {
|
|
103
132
|
const subtle = subtleCrypto();
|
|
104
|
-
if (alg !== "ecdsa-p256-sha256"
|
|
133
|
+
if (alg !== "ecdsa-p256-sha256" && alg !== "rsa-pss-sha512" || !subtle)
|
|
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
|
+
}
|
|
105
140
|
const key = await subtle.importKey("jwk", privateP256Jwk(privateJwk), P256, false, ["sign"]);
|
|
106
141
|
return new Uint8Array(await subtle.sign(P256_SHA256, key, toArrayBuffer(data)));
|
|
107
142
|
}
|
|
@@ -24,6 +24,12 @@ export interface ParsedSignature {
|
|
|
24
24
|
bytes: Uint8Array;
|
|
25
25
|
}
|
|
26
26
|
export declare function parseSignatureInput(headerValue: string, expectedLabel?: string): ParsedSignatureInput;
|
|
27
|
+
/**
|
|
28
|
+
* {@link parseSignatureInput} for one member of an already parsed (and
|
|
29
|
+
* duplicate-checked) `Signature-Input` dictionary, so a caller that needs
|
|
30
|
+
* every label parses the field once.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseSignatureInputMember(label: string, entry: unknown): ParsedSignatureInput;
|
|
27
33
|
export declare function parseSignature(headerValue: string, expectedLabel: string, encoding?: SfBinaryEncoding): ParsedSignature;
|
|
28
34
|
/**
|
|
29
35
|
* RFC 8941 / RFC 9651 parsers deduplicate dictionary keys and parameter keys
|
|
@@ -24,6 +24,12 @@ export interface ParsedSignature {
|
|
|
24
24
|
bytes: Uint8Array;
|
|
25
25
|
}
|
|
26
26
|
export declare function parseSignatureInput(headerValue: string, expectedLabel?: string): ParsedSignatureInput;
|
|
27
|
+
/**
|
|
28
|
+
* {@link parseSignatureInput} for one member of an already parsed (and
|
|
29
|
+
* duplicate-checked) `Signature-Input` dictionary, so a caller that needs
|
|
30
|
+
* every label parses the field once.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseSignatureInputMember(label: string, entry: unknown): ParsedSignatureInput;
|
|
27
33
|
export declare function parseSignature(headerValue: string, expectedLabel: string, encoding?: SfBinaryEncoding): ParsedSignature;
|
|
28
34
|
/**
|
|
29
35
|
* RFC 8941 / RFC 9651 parsers deduplicate dictionary keys and parameter keys
|
|
@@ -20,6 +20,7 @@ var parser_exports = {};
|
|
|
20
20
|
__export(parser_exports, {
|
|
21
21
|
parseSignature: () => parseSignature,
|
|
22
22
|
parseSignatureInput: () => parseSignatureInput,
|
|
23
|
+
parseSignatureInputMember: () => parseSignatureInputMember,
|
|
23
24
|
rejectDuplicateDictionaryKeys: () => rejectDuplicateDictionaryKeys
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(parser_exports);
|
|
@@ -43,7 +44,9 @@ function parseSignatureInput(headerValue, expectedLabel) {
|
|
|
43
44
|
if (dict.size === 0) malformed("Signature-Input header is empty");
|
|
44
45
|
const label = expectedLabel ?? (dict.has("sig1") ? "sig1" : dict.keys().next().value);
|
|
45
46
|
if (!dict.has(label)) malformed("Signature-Input label is missing");
|
|
46
|
-
|
|
47
|
+
return parseSignatureInputMember(label, dict.get(label));
|
|
48
|
+
}
|
|
49
|
+
function parseSignatureInputMember(label, entry) {
|
|
47
50
|
if (!isInnerList(entry)) {
|
|
48
51
|
malformed("Signature-Input value must be a parenthesized component list");
|
|
49
52
|
}
|
|
@@ -83,10 +86,10 @@ function parseSignature(headerValue, expectedLabel, encoding = "legacy-base64url
|
|
|
83
86
|
if (!rawBytes) malformed(`Signature header does not contain a byte sequence for label "${expectedLabel}"`);
|
|
84
87
|
if (encoding === "rfc8941-base64") {
|
|
85
88
|
if (!(0, import_content_digest.isPaddedStandardBase64)(rawBytes)) {
|
|
86
|
-
malformed("Signature value must use padded standard Base64 for
|
|
89
|
+
malformed("Signature value must use padded standard Base64 for the selected signing profile");
|
|
87
90
|
}
|
|
88
91
|
} else if (!/^[A-Za-z0-9_-]+$/.test(rawBytes)) {
|
|
89
|
-
malformed("Signature value must use unpadded Base64URL for
|
|
92
|
+
malformed("Signature value must use unpadded Base64URL for the selected signing profile");
|
|
90
93
|
}
|
|
91
94
|
let dict;
|
|
92
95
|
try {
|
|
@@ -255,5 +258,6 @@ function normalizeByteSequenceBase64(input) {
|
|
|
255
258
|
0 && (module.exports = {
|
|
256
259
|
parseSignature,
|
|
257
260
|
parseSignatureInput,
|
|
261
|
+
parseSignatureInputMember,
|
|
258
262
|
rejectDuplicateDictionaryKeys
|
|
259
263
|
});
|
|
@@ -18,7 +18,9 @@ function parseSignatureInput(headerValue, expectedLabel) {
|
|
|
18
18
|
if (dict.size === 0) malformed("Signature-Input header is empty");
|
|
19
19
|
const label = expectedLabel ?? (dict.has("sig1") ? "sig1" : dict.keys().next().value);
|
|
20
20
|
if (!dict.has(label)) malformed("Signature-Input label is missing");
|
|
21
|
-
|
|
21
|
+
return parseSignatureInputMember(label, dict.get(label));
|
|
22
|
+
}
|
|
23
|
+
function parseSignatureInputMember(label, entry) {
|
|
22
24
|
if (!isInnerList(entry)) {
|
|
23
25
|
malformed("Signature-Input value must be a parenthesized component list");
|
|
24
26
|
}
|
|
@@ -58,10 +60,10 @@ function parseSignature(headerValue, expectedLabel, encoding = "legacy-base64url
|
|
|
58
60
|
if (!rawBytes) malformed(`Signature header does not contain a byte sequence for label "${expectedLabel}"`);
|
|
59
61
|
if (encoding === "rfc8941-base64") {
|
|
60
62
|
if (!isPaddedStandardBase64(rawBytes)) {
|
|
61
|
-
malformed("Signature value must use padded standard Base64 for
|
|
63
|
+
malformed("Signature value must use padded standard Base64 for the selected signing profile");
|
|
62
64
|
}
|
|
63
65
|
} else if (!/^[A-Za-z0-9_-]+$/.test(rawBytes)) {
|
|
64
|
-
malformed("Signature value must use unpadded Base64URL for
|
|
66
|
+
malformed("Signature value must use unpadded Base64URL for the selected signing profile");
|
|
65
67
|
}
|
|
66
68
|
let dict;
|
|
67
69
|
try {
|
|
@@ -229,5 +231,6 @@ function normalizeByteSequenceBase64(input) {
|
|
|
229
231
|
export {
|
|
230
232
|
parseSignature,
|
|
231
233
|
parseSignatureInput,
|
|
234
|
+
parseSignatureInputMember,
|
|
232
235
|
rejectDuplicateDictionaryKeys
|
|
233
236
|
};
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
export type { SsrfDnsLookup } from '../net/index.mjs';
|
|
12
12
|
export { buildResponseSignatureBase, buildSignatureBase, canonicalAuthority, canonicalMethod, canonicalTargetUri, formatSignatureParams, getHeaderValue, type RequestLike, type RequestCanonicalizationProfile, type ResponseLike, type SignatureParams, } from './canonicalize.mjs';
|
|
13
|
-
export { computeContentDigest, contentDigestMatches, parseContentDigest } from './content-digest.mjs';
|
|
13
|
+
export { computeContentDigest, contentDigestMatches, parseContentDigest, type SfBinaryEncoding, } from './content-digest.mjs';
|
|
14
14
|
export { requestContextFromExpress, requestContextFromFetch, requestContextFromLambda, type ExpressRequestLike, type FetchRequestLike, type LambdaRequestEvent, type RequestContextFromExpressOptions, type RequestContextFromLambdaOptions, } from './request-context.mjs';
|
|
15
15
|
export { jwkToPublicKey, verifySignature, verifySignatureAsync } from './crypto.mjs';
|
|
16
16
|
export { RequestSignatureError, RequestSigningErrorCodeMetadata, type RequestSignatureErrorCode, ResponseSignatureError, type ResponseSignatureErrorCode, WebhookSignatureError, type WebhookSignatureErrorCode, } from './errors.mjs';
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
export type { SsrfDnsLookup } from '../net';
|
|
12
12
|
export { buildResponseSignatureBase, buildSignatureBase, canonicalAuthority, canonicalMethod, canonicalTargetUri, formatSignatureParams, getHeaderValue, type RequestLike, type RequestCanonicalizationProfile, type ResponseLike, type SignatureParams, } from './canonicalize';
|
|
13
|
-
export { computeContentDigest, contentDigestMatches, parseContentDigest } from './content-digest';
|
|
13
|
+
export { computeContentDigest, contentDigestMatches, parseContentDigest, type SfBinaryEncoding, } from './content-digest';
|
|
14
14
|
export { requestContextFromExpress, requestContextFromFetch, requestContextFromLambda, type ExpressRequestLike, type FetchRequestLike, type LambdaRequestEvent, type RequestContextFromExpressOptions, type RequestContextFromLambdaOptions, } from './request-context';
|
|
15
15
|
export { jwkToPublicKey, verifySignature, verifySignatureAsync } from './crypto';
|
|
16
16
|
export { RequestSignatureError, RequestSigningErrorCodeMetadata, type RequestSignatureErrorCode, ResponseSignatureError, type ResponseSignatureErrorCode, WebhookSignatureError, type WebhookSignatureErrorCode, } from './errors';
|
|
@@ -7,7 +7,11 @@ import {
|
|
|
7
7
|
formatSignatureParams,
|
|
8
8
|
getHeaderValue
|
|
9
9
|
} from "./canonicalize.mjs";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
computeContentDigest,
|
|
12
|
+
contentDigestMatches,
|
|
13
|
+
parseContentDigest
|
|
14
|
+
} from "./content-digest.mjs";
|
|
11
15
|
import {
|
|
12
16
|
requestContextFromExpress,
|
|
13
17
|
requestContextFromFetch,
|