@astrasyncai/verification-gateway 5.14.0 → 5.15.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 +27 -17
- package/dist/adapters/express.d.mts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +477 -240
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +477 -240
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +1 -1
- package/dist/adapters/mcp.d.ts +1 -1
- package/dist/adapters/mcp.js +20 -6
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +20 -6
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +1 -1
- package/dist/adapters/nextjs.d.ts +1 -1
- package/dist/adapters/nextjs.js +460 -239
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +460 -239
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +18 -10
- package/dist/adapters/sdk.d.ts +18 -10
- package/dist/adapters/sdk.js +80 -23
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +80 -23
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +1 -1
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +55 -11
- package/dist/bin/astrasync-codex-hook.js +55 -11
- package/dist/bin/astrasync-guard.js +55 -11
- package/dist/bin/astrasync.js +288 -33
- package/dist/browser/background.js +50 -6
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +60 -6
- package/dist/browser/background.mjs.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/cli/index.mjs.map +1 -1
- package/dist/codex/index.js +55 -11
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +65 -11
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +55 -11
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +65 -11
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +31 -2
- package/dist/edge-config.d.ts +31 -2
- package/dist/edge-config.js +35 -5
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs +32 -4
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.d.mts +11 -2
- package/dist/edge-core/index.d.ts +11 -2
- package/dist/edge-core/index.js +93 -10
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +91 -10
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.js +50 -6
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +60 -6
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +1 -1
- package/dist/git-trigger/git-hooks.d.ts +1 -1
- package/dist/index.d.mts +1314 -34
- package/dist/index.d.ts +1314 -34
- package/dist/index.js +5116 -2612
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5063 -2614
- package/dist/index.mjs.map +1 -1
- package/dist/registration/index.d.mts +28 -2
- package/dist/registration/index.d.ts +28 -2
- package/dist/registration/index.js +18 -3
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +15 -2
- package/dist/registration/index.mjs.map +1 -1
- package/dist/transport/index.d.mts +7 -5
- package/dist/transport/index.d.ts +7 -5
- package/dist/transport/index.js +61 -5
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +67 -11
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-C_b4QTyO.d.ts → types-DtJjlW4O.d.ts} +104 -10
- package/dist/{types-BCkwBA84.d.mts → types-Dxf9DBpr.d.mts} +106 -12
- package/dist/{types-BCkwBA84.d.ts → types-Dxf9DBpr.d.ts} +106 -12
- package/dist/{types-DlshIIR-.d.mts → types-Eg6VoBNH.d.mts} +104 -10
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +1 -1
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js +20 -6
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +20 -6
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
package/dist/adapters/express.js
CHANGED
|
@@ -25,8 +25,440 @@ __export(express_exports, {
|
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(express_exports);
|
|
27
27
|
|
|
28
|
+
// src/metadata-capture.ts
|
|
29
|
+
var CAPTURE_SCHEMA_VERSION = 1;
|
|
30
|
+
var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
31
|
+
"cookie",
|
|
32
|
+
"set-cookie",
|
|
33
|
+
"x-csrf-token",
|
|
34
|
+
"proxy-authorization",
|
|
35
|
+
"x-astrasync-signature",
|
|
36
|
+
"x-astrasync-secret",
|
|
37
|
+
"x-hub-signature",
|
|
38
|
+
"x-hub-signature-256",
|
|
39
|
+
// Short-lived verify dedupe token — must never persist in stored metadata.
|
|
40
|
+
"x-astra-verified-hop"
|
|
41
|
+
]);
|
|
42
|
+
var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
|
|
43
|
+
var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
44
|
+
"authorization",
|
|
45
|
+
"x-api-key",
|
|
46
|
+
"x-goog-api-key",
|
|
47
|
+
"api-key"
|
|
48
|
+
]);
|
|
49
|
+
function isSignatureHeader(name) {
|
|
50
|
+
return name === "signature" || name.endsWith("-signature") || name.endsWith("-signature-256");
|
|
51
|
+
}
|
|
52
|
+
var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
53
|
+
"openai-organization",
|
|
54
|
+
"openai-project",
|
|
55
|
+
"openai-version",
|
|
56
|
+
"openai-processing-ms",
|
|
57
|
+
"anthropic-version",
|
|
58
|
+
"anthropic-beta",
|
|
59
|
+
"x-goog-user-project",
|
|
60
|
+
"x-goog-api-client",
|
|
61
|
+
"user-agent",
|
|
62
|
+
"x-agent-card-url",
|
|
63
|
+
"x-agent-provider"
|
|
64
|
+
]);
|
|
65
|
+
var PLATFORM_HEADER_PREFIXES = [
|
|
66
|
+
"x-goog-",
|
|
67
|
+
"x-stainless-",
|
|
68
|
+
"x-anthropic-",
|
|
69
|
+
"x-openai-",
|
|
70
|
+
"sec-ch-"
|
|
71
|
+
];
|
|
72
|
+
var KEY_FORMAT_PREFIXES = [
|
|
73
|
+
"sk-ant-api03",
|
|
74
|
+
"sk-ant-api",
|
|
75
|
+
"sk-ant",
|
|
76
|
+
"sk-proj",
|
|
77
|
+
"sk-svcacct",
|
|
78
|
+
"sk-or-v1",
|
|
79
|
+
"sk-or",
|
|
80
|
+
"sk-lf",
|
|
81
|
+
"sk-",
|
|
82
|
+
"gsk_",
|
|
83
|
+
"aiza",
|
|
84
|
+
"ya29",
|
|
85
|
+
"ghp_",
|
|
86
|
+
"gho_",
|
|
87
|
+
"github_pat_",
|
|
88
|
+
"xai-",
|
|
89
|
+
"pplx-",
|
|
90
|
+
"r8_",
|
|
91
|
+
"hf_",
|
|
92
|
+
"astra-",
|
|
93
|
+
"astrae-"
|
|
94
|
+
];
|
|
95
|
+
var MAX_HEADERS = 64;
|
|
96
|
+
var MAX_HEADER_VALUE_BYTES = 1024;
|
|
97
|
+
var MAX_TOTAL_BYTES = 16 * 1024;
|
|
98
|
+
function byteLength(s) {
|
|
99
|
+
let bytes = 0;
|
|
100
|
+
for (let i = 0; i < s.length; i++) {
|
|
101
|
+
const code = s.charCodeAt(i);
|
|
102
|
+
if (code < 128) bytes += 1;
|
|
103
|
+
else if (code < 2048) bytes += 2;
|
|
104
|
+
else if (code >= 55296 && code <= 56319) {
|
|
105
|
+
bytes += 4;
|
|
106
|
+
i++;
|
|
107
|
+
} else bytes += 3;
|
|
108
|
+
}
|
|
109
|
+
return bytes;
|
|
110
|
+
}
|
|
111
|
+
function extractApiKeyFormat(rawValue) {
|
|
112
|
+
if (!rawValue) return void 0;
|
|
113
|
+
let value = rawValue.trim();
|
|
114
|
+
const spaceIdx = value.indexOf(" ");
|
|
115
|
+
if (spaceIdx > 0) {
|
|
116
|
+
const scheme = value.slice(0, spaceIdx).toLowerCase();
|
|
117
|
+
if (scheme === "bearer" || scheme === "basic" || scheme === "token") {
|
|
118
|
+
value = value.slice(spaceIdx + 1).trim();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const lower = value.toLowerCase();
|
|
122
|
+
for (const prefix of KEY_FORMAT_PREFIXES) {
|
|
123
|
+
if (lower.startsWith(prefix)) {
|
|
124
|
+
return prefix;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return void 0;
|
|
128
|
+
}
|
|
129
|
+
function isSecretHeader(name) {
|
|
130
|
+
if (SECRET_HEADER_NAMES.has(name)) return true;
|
|
131
|
+
if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;
|
|
132
|
+
if (isSignatureHeader(name)) return true;
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
function isPlatformHeader(name) {
|
|
136
|
+
if (PLATFORM_HEADER_NAMES.has(name)) return true;
|
|
137
|
+
return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));
|
|
138
|
+
}
|
|
139
|
+
function sanitizeHeaders(raw) {
|
|
140
|
+
const headers = {};
|
|
141
|
+
const platformHeaders = {};
|
|
142
|
+
let apiKeyFormat;
|
|
143
|
+
let cookieCount;
|
|
144
|
+
let totalBytes = 0;
|
|
145
|
+
let count = 0;
|
|
146
|
+
if (!raw) return { headers };
|
|
147
|
+
for (const rawName of Object.keys(raw)) {
|
|
148
|
+
if (count >= MAX_HEADERS) break;
|
|
149
|
+
const name = rawName.toLowerCase();
|
|
150
|
+
const rawValue = raw[rawName];
|
|
151
|
+
if (rawValue === void 0) continue;
|
|
152
|
+
const joined = Array.isArray(rawValue) ? rawValue.join(", ") : String(rawValue);
|
|
153
|
+
if (CREDENTIAL_HEADER_NAMES.has(name)) {
|
|
154
|
+
const fmt = extractApiKeyFormat(joined);
|
|
155
|
+
if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (name === "cookie") {
|
|
159
|
+
cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
|
|
160
|
+
}
|
|
161
|
+
if (isSecretHeader(name)) continue;
|
|
162
|
+
let value = joined;
|
|
163
|
+
if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
|
|
164
|
+
value = value.slice(0, MAX_HEADER_VALUE_BYTES);
|
|
165
|
+
}
|
|
166
|
+
const entryBytes = byteLength(name) + byteLength(value);
|
|
167
|
+
if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;
|
|
168
|
+
totalBytes += entryBytes;
|
|
169
|
+
count++;
|
|
170
|
+
headers[name] = value;
|
|
171
|
+
if (isPlatformHeader(name)) platformHeaders[name] = value;
|
|
172
|
+
}
|
|
173
|
+
const result = { headers };
|
|
174
|
+
if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
|
|
175
|
+
if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
|
|
176
|
+
if (cookieCount !== void 0) result.cookieCount = cookieCount;
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
var CONNECTION_HEADER_SOURCES = [
|
|
180
|
+
["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
|
|
181
|
+
[
|
|
182
|
+
"country",
|
|
183
|
+
["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
|
|
184
|
+
],
|
|
185
|
+
["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
|
|
186
|
+
["countryRegionName", ["cloudfront-viewer-country-region-name"]],
|
|
187
|
+
["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
|
|
188
|
+
["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
|
|
189
|
+
["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
|
|
190
|
+
["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
|
|
191
|
+
["asn", ["cloudfront-viewer-asn"]],
|
|
192
|
+
["tlsVersion", ["cloudfront-viewer-tls"]],
|
|
193
|
+
["httpVersion", ["cloudfront-viewer-http-version"]],
|
|
194
|
+
["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
|
|
195
|
+
["metroCode", ["cloudfront-viewer-metro-code"]],
|
|
196
|
+
// TLS fingerprints can only be computed where TLS terminates. When a CDN
|
|
197
|
+
// terminates TLS in front of the merchant, its fingerprint headers ARE the
|
|
198
|
+
// connection-layer truth — normalising them here is the permanent design.
|
|
199
|
+
// CloudFront delivers JA3/JA4 only via an origin request policy and only
|
|
200
|
+
// for HTTPS viewer connections.
|
|
201
|
+
["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
|
|
202
|
+
["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
|
|
203
|
+
// Header-structure fingerprint: browser/SDK-distinctive header ordering.
|
|
204
|
+
["headerOrder", ["cloudfront-viewer-header-order"]],
|
|
205
|
+
["headerCount", ["cloudfront-viewer-header-count"]]
|
|
206
|
+
];
|
|
207
|
+
var MAX_CONNECTION_VALUE_CHARS = 256;
|
|
208
|
+
function deriveConnectionFromHeaders(headers) {
|
|
209
|
+
if (!headers) return void 0;
|
|
210
|
+
const lower = {};
|
|
211
|
+
for (const name of Object.keys(headers)) {
|
|
212
|
+
const value = headers[name];
|
|
213
|
+
if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
|
|
214
|
+
}
|
|
215
|
+
const connection = {};
|
|
216
|
+
for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
|
|
217
|
+
for (const source of sources) {
|
|
218
|
+
const value = lower[source]?.trim();
|
|
219
|
+
if (value) {
|
|
220
|
+
connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
{
|
|
226
|
+
const addr = lower["cloudfront-viewer-address"]?.trim();
|
|
227
|
+
const portMatch = addr?.match(/:(\d+)$/);
|
|
228
|
+
if (portMatch) connection.sourcePort = portMatch[1];
|
|
229
|
+
if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
|
|
230
|
+
}
|
|
231
|
+
if (!connection.ip) {
|
|
232
|
+
const xff = lower["x-forwarded-for"];
|
|
233
|
+
const client = xff?.split(",")[0]?.trim();
|
|
234
|
+
if (client) connection.ip = client;
|
|
235
|
+
}
|
|
236
|
+
if (!connection.tlsCipher) {
|
|
237
|
+
const cipher = connection.tlsVersion?.split(":")[1];
|
|
238
|
+
if (cipher) connection.tlsCipher = cipher;
|
|
239
|
+
}
|
|
240
|
+
return Object.keys(connection).length > 0 ? connection : void 0;
|
|
241
|
+
}
|
|
242
|
+
function buildSdkObservedMetadata(rawHeaders) {
|
|
243
|
+
const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
|
|
244
|
+
const flat = {};
|
|
245
|
+
if (rawHeaders) {
|
|
246
|
+
for (const name of Object.keys(rawHeaders)) {
|
|
247
|
+
const value = rawHeaders[name];
|
|
248
|
+
if (value === void 0) continue;
|
|
249
|
+
flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const connection = deriveConnectionFromHeaders(flat);
|
|
253
|
+
return {
|
|
254
|
+
headers,
|
|
255
|
+
...apiKeyFormat && { apiKeyFormat },
|
|
256
|
+
...platformHeaders && { platformHeaders },
|
|
257
|
+
...connection && { connection },
|
|
258
|
+
...cookieCount !== void 0 && { cookieCount },
|
|
259
|
+
schemaVersion: CAPTURE_SCHEMA_VERSION
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// src/edge-core/request.ts
|
|
264
|
+
function headerValue(req, name) {
|
|
265
|
+
return req.headers[name.toLowerCase()];
|
|
266
|
+
}
|
|
267
|
+
function requestUrl(req, host) {
|
|
268
|
+
const qs = req.querystring ? `?${req.querystring}` : "";
|
|
269
|
+
return `https://${host}${req.uri}${qs}`;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// src/edge-core/detect.ts
|
|
273
|
+
var SD_JWT_PATTERN = /^eyJ[\w-]+\.[\w-]*\.[\w-]+~/;
|
|
274
|
+
function decodeBase64Url(seg) {
|
|
275
|
+
const b64 = seg.replace(/-/g, "+").replace(/_/g, "/");
|
|
276
|
+
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
277
|
+
const binary = atob(padded);
|
|
278
|
+
const bytes = new Uint8Array(binary.length);
|
|
279
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
280
|
+
return new TextDecoder().decode(bytes);
|
|
281
|
+
}
|
|
282
|
+
function sniffJwtHeader(compact) {
|
|
283
|
+
try {
|
|
284
|
+
const seg = compact.split(".")[0];
|
|
285
|
+
return JSON.parse(decodeBase64Url(seg));
|
|
286
|
+
} catch {
|
|
287
|
+
return void 0;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function parseJsonBody(bodyText) {
|
|
291
|
+
if (!bodyText) return void 0;
|
|
292
|
+
try {
|
|
293
|
+
const parsed = JSON.parse(bodyText);
|
|
294
|
+
return typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
295
|
+
} catch {
|
|
296
|
+
return void 0;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function detectCommerce(req, host) {
|
|
300
|
+
const url = requestUrl(req, host);
|
|
301
|
+
const method = req.method;
|
|
302
|
+
const headers = req.headers;
|
|
303
|
+
const jsonBody = parseJsonBody(req.bodyText);
|
|
304
|
+
const truncated = req.bodyTruncated ? { bodyTruncated: true } : {};
|
|
305
|
+
const authHeader = headerValue(req, "authorization");
|
|
306
|
+
const bearer = authHeader?.replace(/^Bearer\s+/i, "");
|
|
307
|
+
const mandateHeader = headerValue(req, "x-payment-mandate") ?? headerValue(req, "payment-mandate");
|
|
308
|
+
const sdJwtCandidate = [mandateHeader, bearer].find((v) => v && SD_JWT_PATTERN.test(v));
|
|
309
|
+
if (sdJwtCandidate) {
|
|
310
|
+
const typ = sniffJwtHeader(sdJwtCandidate)?.typ;
|
|
311
|
+
return {
|
|
312
|
+
protocol: "vi-sd-jwt",
|
|
313
|
+
artifacts: { viSdJwt: sdJwtCandidate },
|
|
314
|
+
evidence: { typ, ...truncated }
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
const signature = headerValue(req, "signature");
|
|
318
|
+
const signatureInput = headerValue(req, "signature-input");
|
|
319
|
+
if (signature && signatureInput) {
|
|
320
|
+
const signatureAgent = headerValue(req, "signature-agent");
|
|
321
|
+
const registryHint = headerValue(req, "x-agent-registry");
|
|
322
|
+
const lowerInput = signatureInput.toLowerCase();
|
|
323
|
+
const protocol = signatureAgent ? "rfc9421-web-bot-auth" : registryHint?.toLowerCase().includes("visa") || lowerInput.includes("visa") ? "rfc9421-tap" : registryHint?.toLowerCase().includes("mastercard") || lowerInput.includes("mastercard") ? "rfc9421-agent-pay" : "rfc9421";
|
|
324
|
+
return {
|
|
325
|
+
protocol,
|
|
326
|
+
artifacts: {
|
|
327
|
+
rfc9421: { headers, method, url, ...req.bodyText && { body: req.bodyText } }
|
|
328
|
+
},
|
|
329
|
+
evidence: {
|
|
330
|
+
...signatureAgent && { signatureAgent },
|
|
331
|
+
...registryHint && { registryHint },
|
|
332
|
+
keyid: signatureInput.match(/keyid="([^"]+)"/)?.[1],
|
|
333
|
+
...truncated
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
const acpTimestamp = headerValue(req, "timestamp");
|
|
338
|
+
if (signature && !signatureInput && (acpTimestamp || headerValue(req, "idempotency-key"))) {
|
|
339
|
+
return {
|
|
340
|
+
protocol: "acp",
|
|
341
|
+
artifacts: {
|
|
342
|
+
acpRequest: {
|
|
343
|
+
method,
|
|
344
|
+
url,
|
|
345
|
+
headers,
|
|
346
|
+
...req.bodyText && { rawBody: req.bodyText },
|
|
347
|
+
...jsonBody && { body: jsonBody }
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
evidence: { hasTimestamp: Boolean(acpTimestamp), ...truncated }
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
if (/\/checkout[-_]sessions(\/|$)/.test(req.uri)) {
|
|
354
|
+
return {
|
|
355
|
+
protocol: "ucp",
|
|
356
|
+
artifacts: { ucpRequest: { method, url, ...jsonBody && { body: jsonBody } } },
|
|
357
|
+
evidence: { path: req.uri, ...truncated }
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
if (jsonBody) {
|
|
361
|
+
const intent = jsonBody.intent_mandate ?? jsonBody.intentMandate;
|
|
362
|
+
const cart = jsonBody.cart_mandate ?? jsonBody.cartMandate;
|
|
363
|
+
const payment = jsonBody.payment_mandate ?? jsonBody.paymentMandate;
|
|
364
|
+
if (typeof intent === "string" || typeof cart === "string" || typeof payment === "string") {
|
|
365
|
+
return {
|
|
366
|
+
protocol: "ap2",
|
|
367
|
+
artifacts: {
|
|
368
|
+
ap2Mandates: {
|
|
369
|
+
...typeof intent === "string" && { intent },
|
|
370
|
+
...typeof cart === "string" && { cart },
|
|
371
|
+
...typeof payment === "string" && { payment }
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
evidence: {
|
|
375
|
+
mandatesPresent: [
|
|
376
|
+
typeof intent === "string" && "intent",
|
|
377
|
+
typeof cart === "string" && "cart",
|
|
378
|
+
typeof payment === "string" && "payment"
|
|
379
|
+
].filter(Boolean),
|
|
380
|
+
...truncated
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (authHeader && /^Payment\s+/i.test(authHeader) || headerValue(req, "payment-authorization")) {
|
|
386
|
+
return {
|
|
387
|
+
protocol: "mpp",
|
|
388
|
+
artifacts: {
|
|
389
|
+
mppRequest: {
|
|
390
|
+
method,
|
|
391
|
+
url,
|
|
392
|
+
headers,
|
|
393
|
+
...req.bodyText && { rawBody: req.bodyText },
|
|
394
|
+
...jsonBody && { body: jsonBody }
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
evidence: truncated
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
if (headerValue(req, "payment-signature") || headerValue(req, "x-payment")) {
|
|
401
|
+
return {
|
|
402
|
+
protocol: "x402",
|
|
403
|
+
artifacts: {
|
|
404
|
+
x402Request: { method, url, headers, ...jsonBody && { body: jsonBody } }
|
|
405
|
+
},
|
|
406
|
+
evidence: truncated
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
return void 0;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// src/adapters/commerce-detect.ts
|
|
413
|
+
var MAX_BODY_BYTES = 64 * 1024;
|
|
414
|
+
function lowerHeaders(headers) {
|
|
415
|
+
const out = {};
|
|
416
|
+
if (typeof Headers !== "undefined" && headers instanceof Headers) {
|
|
417
|
+
headers.forEach((v, k) => out[k.toLowerCase()] = v);
|
|
418
|
+
return out;
|
|
419
|
+
}
|
|
420
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
421
|
+
if (v === void 0) continue;
|
|
422
|
+
out[k.toLowerCase()] = Array.isArray(v) ? v.join(", ") : v;
|
|
423
|
+
}
|
|
424
|
+
return out;
|
|
425
|
+
}
|
|
426
|
+
function detect(req, host) {
|
|
427
|
+
try {
|
|
428
|
+
return detectCommerce(req, host)?.artifacts;
|
|
429
|
+
} catch {
|
|
430
|
+
return void 0;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
function detectExpressCommerce(req) {
|
|
434
|
+
const headers = lowerHeaders(req.headers);
|
|
435
|
+
const [uri, query = ""] = (req.originalUrl ?? req.url).split("?");
|
|
436
|
+
let bodyText;
|
|
437
|
+
if (req.rawBody !== void 0) {
|
|
438
|
+
bodyText = typeof req.rawBody === "string" ? req.rawBody : req.rawBody.toString("utf8");
|
|
439
|
+
} else if (typeof req.body === "string") {
|
|
440
|
+
bodyText = req.body;
|
|
441
|
+
} else if (req.body && typeof req.body === "object" && Object.keys(req.body).length > 0) {
|
|
442
|
+
bodyText = JSON.stringify(req.body);
|
|
443
|
+
}
|
|
444
|
+
const truncated = bodyText !== void 0 && bodyText.length > MAX_BODY_BYTES;
|
|
445
|
+
return detect(
|
|
446
|
+
{
|
|
447
|
+
method: req.method,
|
|
448
|
+
uri,
|
|
449
|
+
querystring: query,
|
|
450
|
+
headers,
|
|
451
|
+
...bodyText !== void 0 && {
|
|
452
|
+
bodyText: truncated ? bodyText.slice(0, MAX_BODY_BYTES) : bodyText,
|
|
453
|
+
bodyTruncated: truncated
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
headers["x-forwarded-host"] ?? headers.host ?? "localhost"
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
|
|
28
460
|
// src/version.ts
|
|
29
|
-
var SDK_VERSION = "5.
|
|
461
|
+
var SDK_VERSION = "5.15.0";
|
|
30
462
|
|
|
31
463
|
// src/http.ts
|
|
32
464
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -542,6 +974,7 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
542
974
|
if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
|
|
543
975
|
if (requestData.commercePhase) body.commercePhase = requestData.commercePhase;
|
|
544
976
|
if (requestData.checkoutSessionId) body.checkoutSessionId = requestData.checkoutSessionId;
|
|
977
|
+
if (requestData.checkoutJwt) body.checkoutJwt = requestData.checkoutJwt;
|
|
545
978
|
if (requestData.checkoutItems) body.checkoutItems = requestData.checkoutItems;
|
|
546
979
|
if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
|
|
547
980
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
@@ -692,7 +1125,8 @@ async function verify(config, request, options) {
|
|
|
692
1125
|
"[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access decisions (verified ID + runtime challenge + PDLSS + trust score). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side."
|
|
693
1126
|
);
|
|
694
1127
|
}
|
|
695
|
-
|
|
1128
|
+
const uncacheable = Boolean(request.commerceArtifacts);
|
|
1129
|
+
if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
|
|
696
1130
|
const cached = getCachedResult(request, mergedConfig.counterpartyId);
|
|
697
1131
|
if (cached) {
|
|
698
1132
|
if (mergedConfig.debug) {
|
|
@@ -773,7 +1207,10 @@ async function verify(config, request, options) {
|
|
|
773
1207
|
// MERCHANT caller only (bridge callers strip it before the agent plane).
|
|
774
1208
|
settlementToken: apiResponse.settlementToken,
|
|
775
1209
|
// 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
|
|
776
|
-
fulfilment: apiResponse.fulfilment
|
|
1210
|
+
fulfilment: apiResponse.fulfilment,
|
|
1211
|
+
mandates: apiResponse.mandates,
|
|
1212
|
+
kyaToken: apiResponse.kyaToken,
|
|
1213
|
+
aep: apiResponse.aep
|
|
777
1214
|
};
|
|
778
1215
|
return result2;
|
|
779
1216
|
}
|
|
@@ -783,7 +1220,10 @@ async function verify(config, request, options) {
|
|
|
783
1220
|
trustScore: apiResponse.agent.trustScore,
|
|
784
1221
|
trustLevel: getTrustLevel(apiResponse.agent.trustScore),
|
|
785
1222
|
blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
|
|
786
|
-
status: apiResponse.agent.agentStatus
|
|
1223
|
+
status: apiResponse.agent.agentStatus,
|
|
1224
|
+
...apiResponse.agent.protocolIdentities && {
|
|
1225
|
+
protocolIdentities: apiResponse.agent.protocolIdentities
|
|
1226
|
+
}
|
|
787
1227
|
} : void 0;
|
|
788
1228
|
const developer = apiResponse.developer ? {
|
|
789
1229
|
astradId: apiResponse.developer.kyaOwnerId,
|
|
@@ -834,7 +1274,11 @@ async function verify(config, request, options) {
|
|
|
834
1274
|
settlementOutcome: apiResponse.settlementOutcome,
|
|
835
1275
|
settlementToken: apiResponse.settlementToken,
|
|
836
1276
|
// 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
|
|
837
|
-
fulfilment: apiResponse.fulfilment
|
|
1277
|
+
fulfilment: apiResponse.fulfilment,
|
|
1278
|
+
// 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
|
|
1279
|
+
mandates: apiResponse.mandates,
|
|
1280
|
+
kyaToken: apiResponse.kyaToken,
|
|
1281
|
+
aep: apiResponse.aep
|
|
838
1282
|
};
|
|
839
1283
|
if (result.recommendation === "deny") {
|
|
840
1284
|
result.policyAllowed = false;
|
|
@@ -854,7 +1298,9 @@ async function verify(config, request, options) {
|
|
|
854
1298
|
}
|
|
855
1299
|
const escalates = result.requiresStepUp === true || result.requiresApproval === true || result.recommendation === "step_up_required";
|
|
856
1300
|
if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny" && !escalates) {
|
|
857
|
-
|
|
1301
|
+
if (!uncacheable) {
|
|
1302
|
+
cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
|
|
1303
|
+
}
|
|
858
1304
|
}
|
|
859
1305
|
return result;
|
|
860
1306
|
}
|
|
@@ -1138,239 +1584,30 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
|
|
|
1138
1584
|
return failures;
|
|
1139
1585
|
}
|
|
1140
1586
|
|
|
1141
|
-
// src/
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
]);
|
|
1155
|
-
var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
|
|
1156
|
-
var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
1157
|
-
"authorization",
|
|
1158
|
-
"x-api-key",
|
|
1159
|
-
"x-goog-api-key",
|
|
1160
|
-
"api-key"
|
|
1161
|
-
]);
|
|
1162
|
-
function isSignatureHeader(name) {
|
|
1163
|
-
return name === "signature" || name.endsWith("-signature") || name.endsWith("-signature-256");
|
|
1164
|
-
}
|
|
1165
|
-
var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
1166
|
-
"openai-organization",
|
|
1167
|
-
"openai-project",
|
|
1168
|
-
"openai-version",
|
|
1169
|
-
"openai-processing-ms",
|
|
1170
|
-
"anthropic-version",
|
|
1171
|
-
"anthropic-beta",
|
|
1172
|
-
"x-goog-user-project",
|
|
1173
|
-
"x-goog-api-client",
|
|
1174
|
-
"user-agent",
|
|
1175
|
-
"x-agent-card-url",
|
|
1176
|
-
"x-agent-provider"
|
|
1177
|
-
]);
|
|
1178
|
-
var PLATFORM_HEADER_PREFIXES = [
|
|
1179
|
-
"x-goog-",
|
|
1180
|
-
"x-stainless-",
|
|
1181
|
-
"x-anthropic-",
|
|
1182
|
-
"x-openai-",
|
|
1183
|
-
"sec-ch-"
|
|
1184
|
-
];
|
|
1185
|
-
var KEY_FORMAT_PREFIXES = [
|
|
1186
|
-
"sk-ant-api03",
|
|
1187
|
-
"sk-ant-api",
|
|
1188
|
-
"sk-ant",
|
|
1189
|
-
"sk-proj",
|
|
1190
|
-
"sk-svcacct",
|
|
1191
|
-
"sk-or-v1",
|
|
1192
|
-
"sk-or",
|
|
1193
|
-
"sk-lf",
|
|
1194
|
-
"sk-",
|
|
1195
|
-
"gsk_",
|
|
1196
|
-
"aiza",
|
|
1197
|
-
"ya29",
|
|
1198
|
-
"ghp_",
|
|
1199
|
-
"gho_",
|
|
1200
|
-
"github_pat_",
|
|
1201
|
-
"xai-",
|
|
1202
|
-
"pplx-",
|
|
1203
|
-
"r8_",
|
|
1204
|
-
"hf_",
|
|
1205
|
-
"astra-",
|
|
1206
|
-
"astrae-"
|
|
1207
|
-
];
|
|
1208
|
-
var MAX_HEADERS = 64;
|
|
1209
|
-
var MAX_HEADER_VALUE_BYTES = 1024;
|
|
1210
|
-
var MAX_TOTAL_BYTES = 16 * 1024;
|
|
1211
|
-
function byteLength(s) {
|
|
1212
|
-
let bytes = 0;
|
|
1213
|
-
for (let i = 0; i < s.length; i++) {
|
|
1214
|
-
const code = s.charCodeAt(i);
|
|
1215
|
-
if (code < 128) bytes += 1;
|
|
1216
|
-
else if (code < 2048) bytes += 2;
|
|
1217
|
-
else if (code >= 55296 && code <= 56319) {
|
|
1218
|
-
bytes += 4;
|
|
1219
|
-
i++;
|
|
1220
|
-
} else bytes += 3;
|
|
1221
|
-
}
|
|
1222
|
-
return bytes;
|
|
1223
|
-
}
|
|
1224
|
-
function extractApiKeyFormat(rawValue) {
|
|
1225
|
-
if (!rawValue) return void 0;
|
|
1226
|
-
let value = rawValue.trim();
|
|
1227
|
-
const spaceIdx = value.indexOf(" ");
|
|
1228
|
-
if (spaceIdx > 0) {
|
|
1229
|
-
const scheme = value.slice(0, spaceIdx).toLowerCase();
|
|
1230
|
-
if (scheme === "bearer" || scheme === "basic" || scheme === "token") {
|
|
1231
|
-
value = value.slice(spaceIdx + 1).trim();
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
const lower = value.toLowerCase();
|
|
1235
|
-
for (const prefix of KEY_FORMAT_PREFIXES) {
|
|
1236
|
-
if (lower.startsWith(prefix)) {
|
|
1237
|
-
return prefix;
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
return void 0;
|
|
1241
|
-
}
|
|
1242
|
-
function isSecretHeader(name) {
|
|
1243
|
-
if (SECRET_HEADER_NAMES.has(name)) return true;
|
|
1244
|
-
if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;
|
|
1245
|
-
if (isSignatureHeader(name)) return true;
|
|
1246
|
-
return false;
|
|
1247
|
-
}
|
|
1248
|
-
function isPlatformHeader(name) {
|
|
1249
|
-
if (PLATFORM_HEADER_NAMES.has(name)) return true;
|
|
1250
|
-
return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));
|
|
1251
|
-
}
|
|
1252
|
-
function sanitizeHeaders(raw) {
|
|
1253
|
-
const headers = {};
|
|
1254
|
-
const platformHeaders = {};
|
|
1255
|
-
let apiKeyFormat;
|
|
1256
|
-
let cookieCount;
|
|
1257
|
-
let totalBytes = 0;
|
|
1258
|
-
let count = 0;
|
|
1259
|
-
if (!raw) return { headers };
|
|
1260
|
-
for (const rawName of Object.keys(raw)) {
|
|
1261
|
-
if (count >= MAX_HEADERS) break;
|
|
1262
|
-
const name = rawName.toLowerCase();
|
|
1263
|
-
const rawValue = raw[rawName];
|
|
1264
|
-
if (rawValue === void 0) continue;
|
|
1265
|
-
const joined = Array.isArray(rawValue) ? rawValue.join(", ") : String(rawValue);
|
|
1266
|
-
if (CREDENTIAL_HEADER_NAMES.has(name)) {
|
|
1267
|
-
const fmt = extractApiKeyFormat(joined);
|
|
1268
|
-
if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
|
|
1269
|
-
continue;
|
|
1270
|
-
}
|
|
1271
|
-
if (name === "cookie") {
|
|
1272
|
-
cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
|
|
1273
|
-
}
|
|
1274
|
-
if (isSecretHeader(name)) continue;
|
|
1275
|
-
let value = joined;
|
|
1276
|
-
if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
|
|
1277
|
-
value = value.slice(0, MAX_HEADER_VALUE_BYTES);
|
|
1278
|
-
}
|
|
1279
|
-
const entryBytes = byteLength(name) + byteLength(value);
|
|
1280
|
-
if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;
|
|
1281
|
-
totalBytes += entryBytes;
|
|
1282
|
-
count++;
|
|
1283
|
-
headers[name] = value;
|
|
1284
|
-
if (isPlatformHeader(name)) platformHeaders[name] = value;
|
|
1285
|
-
}
|
|
1286
|
-
const result = { headers };
|
|
1287
|
-
if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
|
|
1288
|
-
if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
|
|
1289
|
-
if (cookieCount !== void 0) result.cookieCount = cookieCount;
|
|
1290
|
-
return result;
|
|
1291
|
-
}
|
|
1292
|
-
var CONNECTION_HEADER_SOURCES = [
|
|
1293
|
-
["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
|
|
1294
|
-
[
|
|
1295
|
-
"country",
|
|
1296
|
-
["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
|
|
1297
|
-
],
|
|
1298
|
-
["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
|
|
1299
|
-
["countryRegionName", ["cloudfront-viewer-country-region-name"]],
|
|
1300
|
-
["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
|
|
1301
|
-
["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
|
|
1302
|
-
["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
|
|
1303
|
-
["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
|
|
1304
|
-
["asn", ["cloudfront-viewer-asn"]],
|
|
1305
|
-
["tlsVersion", ["cloudfront-viewer-tls"]],
|
|
1306
|
-
["httpVersion", ["cloudfront-viewer-http-version"]],
|
|
1307
|
-
["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
|
|
1308
|
-
["metroCode", ["cloudfront-viewer-metro-code"]],
|
|
1309
|
-
// TLS fingerprints can only be computed where TLS terminates. When a CDN
|
|
1310
|
-
// terminates TLS in front of the merchant, its fingerprint headers ARE the
|
|
1311
|
-
// connection-layer truth — normalising them here is the permanent design.
|
|
1312
|
-
// CloudFront delivers JA3/JA4 only via an origin request policy and only
|
|
1313
|
-
// for HTTPS viewer connections.
|
|
1314
|
-
["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
|
|
1315
|
-
["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
|
|
1316
|
-
// Header-structure fingerprint: browser/SDK-distinctive header ordering.
|
|
1317
|
-
["headerOrder", ["cloudfront-viewer-header-order"]],
|
|
1318
|
-
["headerCount", ["cloudfront-viewer-header-count"]]
|
|
1319
|
-
];
|
|
1320
|
-
var MAX_CONNECTION_VALUE_CHARS = 256;
|
|
1321
|
-
function deriveConnectionFromHeaders(headers) {
|
|
1322
|
-
if (!headers) return void 0;
|
|
1323
|
-
const lower = {};
|
|
1324
|
-
for (const name of Object.keys(headers)) {
|
|
1325
|
-
const value = headers[name];
|
|
1326
|
-
if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
|
|
1327
|
-
}
|
|
1328
|
-
const connection = {};
|
|
1329
|
-
for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
|
|
1330
|
-
for (const source of sources) {
|
|
1331
|
-
const value = lower[source]?.trim();
|
|
1332
|
-
if (value) {
|
|
1333
|
-
connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
|
|
1334
|
-
break;
|
|
1335
|
-
}
|
|
1587
|
+
// src/route-pattern.ts
|
|
1588
|
+
function routePatternToRegExp(pattern, opts = {}) {
|
|
1589
|
+
let source = "";
|
|
1590
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
1591
|
+
const ch = pattern[i];
|
|
1592
|
+
if (ch === "*") {
|
|
1593
|
+
source += ".*";
|
|
1594
|
+
} else if (ch === ":" && /[A-Za-z_]/.test(pattern[i + 1] ?? "") && (i === 0 || pattern[i - 1] === "/")) {
|
|
1595
|
+
let j = i + 1;
|
|
1596
|
+
while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) j++;
|
|
1597
|
+
source += "[^/]+";
|
|
1598
|
+
i = j - 1;
|
|
1599
|
+
} else {
|
|
1600
|
+
source += ch.replace(/[.+?^${}()|[\]\\/]/g, "\\$&");
|
|
1336
1601
|
}
|
|
1337
1602
|
}
|
|
1338
|
-
{
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
|
|
1343
|
-
}
|
|
1344
|
-
if (!connection.ip) {
|
|
1345
|
-
const xff = lower["x-forwarded-for"];
|
|
1346
|
-
const client = xff?.split(",")[0]?.trim();
|
|
1347
|
-
if (client) connection.ip = client;
|
|
1348
|
-
}
|
|
1349
|
-
if (!connection.tlsCipher) {
|
|
1350
|
-
const cipher = connection.tlsVersion?.split(":")[1];
|
|
1351
|
-
if (cipher) connection.tlsCipher = cipher;
|
|
1603
|
+
try {
|
|
1604
|
+
return new RegExp(`^${source}$`, opts.caseInsensitive ? "i" : "");
|
|
1605
|
+
} catch {
|
|
1606
|
+
return null;
|
|
1352
1607
|
}
|
|
1353
|
-
return Object.keys(connection).length > 0 ? connection : void 0;
|
|
1354
1608
|
}
|
|
1355
|
-
function
|
|
1356
|
-
|
|
1357
|
-
const flat = {};
|
|
1358
|
-
if (rawHeaders) {
|
|
1359
|
-
for (const name of Object.keys(rawHeaders)) {
|
|
1360
|
-
const value = rawHeaders[name];
|
|
1361
|
-
if (value === void 0) continue;
|
|
1362
|
-
flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
const connection = deriveConnectionFromHeaders(flat);
|
|
1366
|
-
return {
|
|
1367
|
-
headers,
|
|
1368
|
-
...apiKeyFormat && { apiKeyFormat },
|
|
1369
|
-
...platformHeaders && { platformHeaders },
|
|
1370
|
-
...connection && { connection },
|
|
1371
|
-
...cookieCount !== void 0 && { cookieCount },
|
|
1372
|
-
schemaVersion: CAPTURE_SCHEMA_VERSION
|
|
1373
|
-
};
|
|
1609
|
+
function matchRoutePattern(pattern, path, opts = {}) {
|
|
1610
|
+
return routePatternToRegExp(pattern, opts)?.test(path) ?? false;
|
|
1374
1611
|
}
|
|
1375
1612
|
|
|
1376
1613
|
// src/edge-config.ts
|
|
@@ -1405,6 +1642,7 @@ function isEdgeConfig(value) {
|
|
|
1405
1642
|
if (r.sampling !== void 0 && !isSamplingShape(r.sampling)) return false;
|
|
1406
1643
|
}
|
|
1407
1644
|
if (!isSamplingShape(v.sampling)) return false;
|
|
1645
|
+
if (v.minTls !== void 0 && v.minTls !== "1.2" && v.minTls !== "1.3") return false;
|
|
1408
1646
|
if (v.queryValueAllowlist !== void 0) {
|
|
1409
1647
|
if (!Array.isArray(v.queryValueAllowlist) || v.queryValueAllowlist.length > 16 || !v.queryValueAllowlist.every((e) => typeof e === "string" && e.length > 0 && e.length <= 64)) {
|
|
1410
1648
|
return false;
|
|
@@ -1992,14 +2230,11 @@ function resolveRequestPdlss(req, routeConfig, customExtractPurpose, customExtra
|
|
|
1992
2230
|
});
|
|
1993
2231
|
}
|
|
1994
2232
|
function matchRoute(pattern, path, opts) {
|
|
1995
|
-
const
|
|
1996
|
-
const caseSensitiveRegex = new RegExp(`^${regexPattern}$`);
|
|
1997
|
-
const caseSensitiveResult = caseSensitiveRegex.test(path);
|
|
2233
|
+
const caseSensitiveResult = matchRoutePattern(pattern, path);
|
|
1998
2234
|
if (!opts?.caseInsensitive && !opts?.logShadowDivergence) {
|
|
1999
2235
|
return caseSensitiveResult;
|
|
2000
2236
|
}
|
|
2001
|
-
const
|
|
2002
|
-
const caseInsensitiveResult = caseInsensitiveRegex.test(path);
|
|
2237
|
+
const caseInsensitiveResult = matchRoutePattern(pattern, path, { caseInsensitive: true });
|
|
2003
2238
|
if (opts?.logShadowDivergence && caseSensitiveResult !== caseInsensitiveResult) {
|
|
2004
2239
|
console.warn(
|
|
2005
2240
|
`[SHADOW] matchRoute case-insensitive would change result: pattern=${pattern} path=${path} caseSensitive=${caseSensitiveResult} caseInsensitive=${caseInsensitiveResult} correlationId=${opts.correlationId ?? "unknown"}`
|
|
@@ -2262,8 +2497,10 @@ function createMiddleware(options) {
|
|
|
2262
2497
|
}
|
|
2263
2498
|
const attemptHeader = req.headers["x-astra-attempt-id"];
|
|
2264
2499
|
const inboundAttemptId = typeof attemptHeader === "string" && /^att_[0-9a-f]{32}$/.test(attemptHeader) ? attemptHeader : void 0;
|
|
2500
|
+
const commerceArtifacts = detectExpressCommerce(req);
|
|
2265
2501
|
const verificationRequest = {
|
|
2266
2502
|
credentials,
|
|
2503
|
+
...commerceArtifacts && { commerceArtifacts },
|
|
2267
2504
|
purpose,
|
|
2268
2505
|
action: pdlssPair.action,
|
|
2269
2506
|
resource: req.path,
|