@astrasyncai/verification-gateway 5.21.2 → 5.22.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/CHANGELOG.md +9 -0
- package/README.md +19 -7
- package/dist/adapters/express.js +60 -11
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +60 -11
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.js +34 -3
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +34 -3
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.js +60 -11
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +60 -11
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.js +1 -1
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +1 -1
- 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 +1 -1
- package/dist/bin/astrasync-codex-hook.js +1 -1
- package/dist/bin/astrasync-guard.js +1 -1
- package/dist/bin/astrasync.js +1 -1
- package/dist/browser/background.js +1 -1
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +1 -1
- 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 +1 -1
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +1 -1
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +1 -1
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +1 -1
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.js +1 -1
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs +1 -1
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.d.mts +4 -1
- package/dist/edge-core/index.d.ts +4 -1
- package/dist/edge-core/index.js +45 -15
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +45 -15
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.js +1 -1
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +1 -1
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/index.d.mts +20 -5
- package/dist/index.d.ts +20 -5
- package/dist/index.js +60 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +60 -11
- package/dist/index.mjs.map +1 -1
- package/dist/metadata-capture.d.mts +5 -3
- package/dist/metadata-capture.d.ts +5 -3
- package/dist/metadata-capture.js +33 -2
- package/dist/metadata-capture.js.map +1 -1
- package/dist/metadata-capture.mjs +33 -2
- package/dist/metadata-capture.mjs.map +1 -1
- package/dist/platform-signatures.d.mts +13 -0
- package/dist/platform-signatures.d.ts +13 -0
- package/dist/platform-signatures.js +26 -8
- package/dist/platform-signatures.js.map +1 -1
- package/dist/platform-signatures.mjs +26 -8
- package/dist/platform-signatures.mjs.map +1 -1
- package/dist/registration/index.js +1 -1
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +1 -1
- package/dist/registration/index.mjs.map +1 -1
- package/dist/transport/index.js +1 -1
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +1 -1
- package/dist/transport/index.mjs.map +1 -1
- package/dist/verify.js +1 -1
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +1 -1
- package/dist/verify.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -155,9 +155,11 @@ declare function extractPlatformHeaders(sanitized: Record<string, string> | unde
|
|
|
155
155
|
* `connection` keys the edge adapters populate natively, so SDK-only
|
|
156
156
|
* deployments still get IP / geo / TLS attribution. Precedence per key:
|
|
157
157
|
*
|
|
158
|
-
* - `ip`: `cf-connecting-ip` > `fastly-client-ip` > `
|
|
159
|
-
* `
|
|
160
|
-
* `x-forwarded-for`
|
|
158
|
+
* - `ip`: `cf-connecting-ip` > `fastly-client-ip` > `incap-client-ip`
|
|
159
|
+
* (Imperva) > `true-client-ip` (Akamai et al.) > `x-real-ip` >
|
|
160
|
+
* `cloudfront-viewer-address` (port stripped) > leftmost `x-forwarded-for`
|
|
161
|
+
* - Akamai `x-akamai-edgescape` fills country / region / city / lat / long /
|
|
162
|
+
* timeZone / asn / continent where no header above supplied them
|
|
161
163
|
* - `country`: `cf-ipcountry` > `x-vercel-ip-country` >
|
|
162
164
|
* `cloudfront-viewer-country` > `fastly-geo-country`
|
|
163
165
|
* - `region` / `city` / `timeZone`: Vercel then CloudFront viewer headers
|
|
@@ -5358,6 +5360,13 @@ interface PlatformDetectionInput {
|
|
|
5358
5360
|
* provider — registry validation rejects ASN-only signatures.
|
|
5359
5361
|
*/
|
|
5360
5362
|
asn?: string;
|
|
5363
|
+
/**
|
|
5364
|
+
* Round 31 — bot labels a customer's WAF attached to the request (AWS Bot
|
|
5365
|
+
* Control `…:bot:name:x`, Akamai Bot Manager bot name, Cloudflare
|
|
5366
|
+
* verified-bot category, Imperva client classification). Present only on
|
|
5367
|
+
* rows read from WAF security logs. Matched against `wafLabelPatterns`.
|
|
5368
|
+
*/
|
|
5369
|
+
wafLabels?: string[];
|
|
5361
5370
|
}
|
|
5362
5371
|
/**
|
|
5363
5372
|
* A signature definition, generic over the vendor key. The seed constant
|
|
@@ -5386,6 +5395,8 @@ interface PlatformSignatureDef<V extends string = string> {
|
|
|
5386
5395
|
ja4Patterns?: RegExp[];
|
|
5387
5396
|
/** Exact ASN strings this signature matches (never regex). */
|
|
5388
5397
|
asnList?: string[];
|
|
5398
|
+
/** Patterns tested against each WAF bot label (round 31; see PlatformDetectionInput.wafLabels). */
|
|
5399
|
+
wafLabelPatterns?: RegExp[];
|
|
5389
5400
|
}
|
|
5390
5401
|
/**
|
|
5391
5402
|
* A fingerprint whose vendor may be a dynamically-promoted (non-seed) key.
|
|
@@ -5403,6 +5414,10 @@ interface DynamicPlatformFingerprint {
|
|
|
5403
5414
|
* platform UA strings drift between versions. False positives are tolerable —
|
|
5404
5415
|
* the orphan record is informational, not enforcement.
|
|
5405
5416
|
*
|
|
5417
|
+
* Round 31: `wafLabelPatterns` attribute rows read from a customer's WAF
|
|
5418
|
+
* security logs by the bot name THEIR WAF assigned; they never match inline
|
|
5419
|
+
* traffic (no labels there).
|
|
5420
|
+
*
|
|
5406
5421
|
* NOT detectable here, by design (Oct 2026): Meta's Muse and OpenAI's Dots
|
|
5407
5422
|
* publish no user agent and browse through real Chromium sessions that are
|
|
5408
5423
|
* indistinguishable from a person's. There is no signature to find — don't
|
|
@@ -5472,7 +5487,7 @@ declare function detectRuntime(userAgent: string | undefined | null): string | u
|
|
|
5472
5487
|
* silently (never throwing), so this is a no-op there — which is correct:
|
|
5473
5488
|
* in a browser the page's real UA is the honest identity.
|
|
5474
5489
|
*/
|
|
5475
|
-
declare const SDK_USER_AGENT = "astrasync-sdk/5.
|
|
5490
|
+
declare const SDK_USER_AGENT = "astrasync-sdk/5.22.0";
|
|
5476
5491
|
declare const sdkFetch: typeof fetch;
|
|
5477
5492
|
|
|
5478
5493
|
interface LocalPolicy {
|
|
@@ -5590,7 +5605,7 @@ declare function parseYaml(yamlContent: string): ParseResult;
|
|
|
5590
5605
|
* is fine — bumping both in the release-ceremony commit keeps them
|
|
5591
5606
|
* lockstep.
|
|
5592
5607
|
*/
|
|
5593
|
-
declare const SDK_VERSION = "5.
|
|
5608
|
+
declare const SDK_VERSION = "5.22.0";
|
|
5594
5609
|
|
|
5595
5610
|
/**
|
|
5596
5611
|
* 5.15.0 — the `UCP-Agent` request header (UCP 2026-08-25): an RFC 8941
|
package/dist/index.d.ts
CHANGED
|
@@ -155,9 +155,11 @@ declare function extractPlatformHeaders(sanitized: Record<string, string> | unde
|
|
|
155
155
|
* `connection` keys the edge adapters populate natively, so SDK-only
|
|
156
156
|
* deployments still get IP / geo / TLS attribution. Precedence per key:
|
|
157
157
|
*
|
|
158
|
-
* - `ip`: `cf-connecting-ip` > `fastly-client-ip` > `
|
|
159
|
-
* `
|
|
160
|
-
* `x-forwarded-for`
|
|
158
|
+
* - `ip`: `cf-connecting-ip` > `fastly-client-ip` > `incap-client-ip`
|
|
159
|
+
* (Imperva) > `true-client-ip` (Akamai et al.) > `x-real-ip` >
|
|
160
|
+
* `cloudfront-viewer-address` (port stripped) > leftmost `x-forwarded-for`
|
|
161
|
+
* - Akamai `x-akamai-edgescape` fills country / region / city / lat / long /
|
|
162
|
+
* timeZone / asn / continent where no header above supplied them
|
|
161
163
|
* - `country`: `cf-ipcountry` > `x-vercel-ip-country` >
|
|
162
164
|
* `cloudfront-viewer-country` > `fastly-geo-country`
|
|
163
165
|
* - `region` / `city` / `timeZone`: Vercel then CloudFront viewer headers
|
|
@@ -5358,6 +5360,13 @@ interface PlatformDetectionInput {
|
|
|
5358
5360
|
* provider — registry validation rejects ASN-only signatures.
|
|
5359
5361
|
*/
|
|
5360
5362
|
asn?: string;
|
|
5363
|
+
/**
|
|
5364
|
+
* Round 31 — bot labels a customer's WAF attached to the request (AWS Bot
|
|
5365
|
+
* Control `…:bot:name:x`, Akamai Bot Manager bot name, Cloudflare
|
|
5366
|
+
* verified-bot category, Imperva client classification). Present only on
|
|
5367
|
+
* rows read from WAF security logs. Matched against `wafLabelPatterns`.
|
|
5368
|
+
*/
|
|
5369
|
+
wafLabels?: string[];
|
|
5361
5370
|
}
|
|
5362
5371
|
/**
|
|
5363
5372
|
* A signature definition, generic over the vendor key. The seed constant
|
|
@@ -5386,6 +5395,8 @@ interface PlatformSignatureDef<V extends string = string> {
|
|
|
5386
5395
|
ja4Patterns?: RegExp[];
|
|
5387
5396
|
/** Exact ASN strings this signature matches (never regex). */
|
|
5388
5397
|
asnList?: string[];
|
|
5398
|
+
/** Patterns tested against each WAF bot label (round 31; see PlatformDetectionInput.wafLabels). */
|
|
5399
|
+
wafLabelPatterns?: RegExp[];
|
|
5389
5400
|
}
|
|
5390
5401
|
/**
|
|
5391
5402
|
* A fingerprint whose vendor may be a dynamically-promoted (non-seed) key.
|
|
@@ -5403,6 +5414,10 @@ interface DynamicPlatformFingerprint {
|
|
|
5403
5414
|
* platform UA strings drift between versions. False positives are tolerable —
|
|
5404
5415
|
* the orphan record is informational, not enforcement.
|
|
5405
5416
|
*
|
|
5417
|
+
* Round 31: `wafLabelPatterns` attribute rows read from a customer's WAF
|
|
5418
|
+
* security logs by the bot name THEIR WAF assigned; they never match inline
|
|
5419
|
+
* traffic (no labels there).
|
|
5420
|
+
*
|
|
5406
5421
|
* NOT detectable here, by design (Oct 2026): Meta's Muse and OpenAI's Dots
|
|
5407
5422
|
* publish no user agent and browse through real Chromium sessions that are
|
|
5408
5423
|
* indistinguishable from a person's. There is no signature to find — don't
|
|
@@ -5472,7 +5487,7 @@ declare function detectRuntime(userAgent: string | undefined | null): string | u
|
|
|
5472
5487
|
* silently (never throwing), so this is a no-op there — which is correct:
|
|
5473
5488
|
* in a browser the page's real UA is the honest identity.
|
|
5474
5489
|
*/
|
|
5475
|
-
declare const SDK_USER_AGENT = "astrasync-sdk/5.
|
|
5490
|
+
declare const SDK_USER_AGENT = "astrasync-sdk/5.22.0";
|
|
5476
5491
|
declare const sdkFetch: typeof fetch;
|
|
5477
5492
|
|
|
5478
5493
|
interface LocalPolicy {
|
|
@@ -5590,7 +5605,7 @@ declare function parseYaml(yamlContent: string): ParseResult;
|
|
|
5590
5605
|
* is fine — bumping both in the release-ceremony commit keeps them
|
|
5591
5606
|
* lockstep.
|
|
5592
5607
|
*/
|
|
5593
|
-
declare const SDK_VERSION = "5.
|
|
5608
|
+
declare const SDK_VERSION = "5.22.0";
|
|
5594
5609
|
|
|
5595
5610
|
/**
|
|
5596
5611
|
* 5.15.0 — the `UCP-Agent` request header (UCP 2026-08-25): an RFC 8941
|
package/dist/index.js
CHANGED
|
@@ -229,7 +229,7 @@ function getTrustLevel(score) {
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
// src/version.ts
|
|
232
|
-
var SDK_VERSION = "5.
|
|
232
|
+
var SDK_VERSION = "5.22.0";
|
|
233
233
|
|
|
234
234
|
// src/http.ts
|
|
235
235
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -1404,7 +1404,11 @@ var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
|
1404
1404
|
"x-goog-api-client",
|
|
1405
1405
|
"user-agent",
|
|
1406
1406
|
"x-agent-card-url",
|
|
1407
|
-
"x-agent-provider"
|
|
1407
|
+
"x-agent-provider",
|
|
1408
|
+
// Round 31 — Web Bot Auth's Signature-Agent names the signing agent's
|
|
1409
|
+
// directory host (a public URL, never a secret). It attributes a signed
|
|
1410
|
+
// agent even when its UA is stock Chrome.
|
|
1411
|
+
"signature-agent"
|
|
1408
1412
|
]);
|
|
1409
1413
|
var PLATFORM_HEADER_PREFIXES = [
|
|
1410
1414
|
"x-goog-",
|
|
@@ -1535,7 +1539,12 @@ function extractPlatformHeaders(sanitized) {
|
|
|
1535
1539
|
return out;
|
|
1536
1540
|
}
|
|
1537
1541
|
var CONNECTION_HEADER_SOURCES = [
|
|
1538
|
-
|
|
1542
|
+
// Round 31: `incap-client-ip` = Imperva Cloud WAF; `true-client-ip` is
|
|
1543
|
+
// also Akamai's client-IP header when the property enables it.
|
|
1544
|
+
[
|
|
1545
|
+
"ip",
|
|
1546
|
+
["cf-connecting-ip", "fastly-client-ip", "incap-client-ip", "true-client-ip", "x-real-ip"]
|
|
1547
|
+
],
|
|
1539
1548
|
[
|
|
1540
1549
|
"country",
|
|
1541
1550
|
["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
|
|
@@ -1586,6 +1595,28 @@ function deriveConnectionFromHeaders(headers) {
|
|
|
1586
1595
|
if (portMatch) connection.sourcePort = portMatch[1];
|
|
1587
1596
|
if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
|
|
1588
1597
|
}
|
|
1598
|
+
{
|
|
1599
|
+
const edgescape = (lower["x-akamai-edgescape"] ?? lower["akamai-edgescape"])?.trim();
|
|
1600
|
+
if (edgescape) {
|
|
1601
|
+
const fields = /* @__PURE__ */ new Map();
|
|
1602
|
+
for (const pair of edgescape.split(",")) {
|
|
1603
|
+
const i = pair.indexOf("=");
|
|
1604
|
+
if (i > 0) fields.set(pair.slice(0, i).trim().toLowerCase(), pair.slice(i + 1).trim());
|
|
1605
|
+
}
|
|
1606
|
+
const fill = (key, field) => {
|
|
1607
|
+
const v = fields.get(field);
|
|
1608
|
+
if (v && !connection[key]) connection[key] = v.slice(0, MAX_CONNECTION_VALUE_CHARS);
|
|
1609
|
+
};
|
|
1610
|
+
fill("country", "country_code");
|
|
1611
|
+
fill("region", "region_code");
|
|
1612
|
+
fill("city", "city");
|
|
1613
|
+
fill("latitude", "lat");
|
|
1614
|
+
fill("longitude", "long");
|
|
1615
|
+
fill("timeZone", "timezone");
|
|
1616
|
+
fill("asn", "asnum");
|
|
1617
|
+
fill("continent", "continent");
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1589
1620
|
if (!connection.ip) {
|
|
1590
1621
|
const xff = lower["x-forwarded-for"];
|
|
1591
1622
|
const client = xff?.split(",")[0]?.trim();
|
|
@@ -2284,7 +2315,8 @@ var PLATFORM_AGENT_SIGNATURES = [
|
|
|
2284
2315
|
uaPatterns: [/claude/i, /anthropic/i],
|
|
2285
2316
|
agentCardPatterns: [/anthropic\.com/i, /claude\.ai/i],
|
|
2286
2317
|
apiKeyFormatPatterns: [/^sk-ant/i],
|
|
2287
|
-
headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i]
|
|
2318
|
+
headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i],
|
|
2319
|
+
wafLabelPatterns: [/\bclaude/i, /\banthropic/i]
|
|
2288
2320
|
},
|
|
2289
2321
|
{
|
|
2290
2322
|
vendor: "chatgpt",
|
|
@@ -2295,7 +2327,14 @@ var PLATFORM_AGENT_SIGNATURES = [
|
|
|
2295
2327
|
uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\d/i, /\bGPTBot\b/i, /\bOAI-SearchBot\b/i],
|
|
2296
2328
|
agentCardPatterns: [/openai\.com/i, /chatgpt\.com/i],
|
|
2297
2329
|
apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],
|
|
2298
|
-
headerPatterns: [
|
|
2330
|
+
headerPatterns: [
|
|
2331
|
+
/^openai-organization/i,
|
|
2332
|
+
/^openai-project/i,
|
|
2333
|
+
/^openai-version/i,
|
|
2334
|
+
// ChatGPT agent signs with Web Bot Auth under this directory host.
|
|
2335
|
+
/^signature-agent: "?https:\/\/chatgpt\.com/i
|
|
2336
|
+
],
|
|
2337
|
+
wafLabelPatterns: [/\bgptbot\b/i, /\bchatgpt/i, /\boai-searchbot\b/i, /\bopenai/i]
|
|
2299
2338
|
},
|
|
2300
2339
|
{
|
|
2301
2340
|
vendor: "gemini",
|
|
@@ -2316,7 +2355,8 @@ var PLATFORM_AGENT_SIGNATURES = [
|
|
|
2316
2355
|
],
|
|
2317
2356
|
agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
|
|
2318
2357
|
apiKeyFormatPatterns: [/^aiza/i],
|
|
2319
|
-
headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
|
|
2358
|
+
headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i],
|
|
2359
|
+
wafLabelPatterns: [/\bgoogle-extended\b/i, /\bgoogleother\b/i, /\bgemini/i]
|
|
2320
2360
|
},
|
|
2321
2361
|
{
|
|
2322
2362
|
vendor: "cursor",
|
|
@@ -2335,7 +2375,8 @@ var PLATFORM_AGENT_SIGNATURES = [
|
|
|
2335
2375
|
displayName: "Perplexity",
|
|
2336
2376
|
uaPatterns: [/perplexity/i],
|
|
2337
2377
|
agentCardPatterns: [/perplexity\.ai/i],
|
|
2338
|
-
apiKeyFormatPatterns: [/^pplx-/i]
|
|
2378
|
+
apiKeyFormatPatterns: [/^pplx-/i],
|
|
2379
|
+
wafLabelPatterns: [/\bperplexity/i]
|
|
2339
2380
|
},
|
|
2340
2381
|
// Round 30.1: xAI's documented crawlers (GrokBot/1.0, xAI-Grok/1.0,
|
|
2341
2382
|
// Grok-DeepSearch/1.0). Anchored, versioned tokens — never in a stock UA.
|
|
@@ -2344,7 +2385,8 @@ var PLATFORM_AGENT_SIGNATURES = [
|
|
|
2344
2385
|
displayName: "xAI Grok",
|
|
2345
2386
|
uaPatterns: [/\bGrokBot\//i, /\bxAI-Grok\//i, /\bGrok-DeepSearch\//i],
|
|
2346
2387
|
agentCardPatterns: [/\bx\.ai\b/i, /grok\.com/i],
|
|
2347
|
-
apiKeyFormatPatterns: [/^xai-/i]
|
|
2388
|
+
apiKeyFormatPatterns: [/^xai-/i],
|
|
2389
|
+
wafLabelPatterns: [/\bgrok/i, /\bxai\b/i]
|
|
2348
2390
|
},
|
|
2349
2391
|
// Round 30.1: Meta AI's index and fetch crawlers. facebookexternalhit
|
|
2350
2392
|
// (link previews) is deliberately NOT here — it stays a generic crawler.
|
|
@@ -2352,7 +2394,12 @@ var PLATFORM_AGENT_SIGNATURES = [
|
|
|
2352
2394
|
vendor: "meta-ai",
|
|
2353
2395
|
displayName: "Meta AI",
|
|
2354
2396
|
uaPatterns: [/\bMeta-WebIndexer\b/i, /\bMeta-ExternalFetcher\b/i],
|
|
2355
|
-
agentCardPatterns: [/meta\.ai/i]
|
|
2397
|
+
agentCardPatterns: [/meta\.ai/i],
|
|
2398
|
+
wafLabelPatterns: [
|
|
2399
|
+
/\bmeta-webindexer\b/i,
|
|
2400
|
+
/\bmeta-externalfetcher\b/i,
|
|
2401
|
+
/\bmeta-externalagent\b/i
|
|
2402
|
+
]
|
|
2356
2403
|
},
|
|
2357
2404
|
// Agentic browsers — versioned-token patterns ONLY (a stock Chrome UA must
|
|
2358
2405
|
// never match). Distinct vendor keys (not 'chatgpt'/'perplexity'): the
|
|
@@ -2400,6 +2447,7 @@ function matchPlatformSignature(signatures, input) {
|
|
|
2400
2447
|
const apiKeyFormat = input.apiKeyFormat ?? "";
|
|
2401
2448
|
const ja4 = input.ja4 ?? "";
|
|
2402
2449
|
const asn = input.asn ?? "";
|
|
2450
|
+
const wafLabels = input.wafLabels ?? [];
|
|
2403
2451
|
const headerLines = [];
|
|
2404
2452
|
if (input.platformHeaders) {
|
|
2405
2453
|
for (const [name, value] of Object.entries(input.platformHeaders)) {
|
|
@@ -2413,7 +2461,8 @@ function matchPlatformSignature(signatures, input) {
|
|
|
2413
2461
|
const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
|
|
2414
2462
|
const ja4Match = ja4.length > 0 && sig.ja4Patterns?.some((p) => p.test(ja4));
|
|
2415
2463
|
const asnMatch = asn.length > 0 && sig.asnList?.includes(asn);
|
|
2416
|
-
|
|
2464
|
+
const wafMatch = wafLabels.length > 0 && sig.wafLabelPatterns?.some((p) => wafLabels.some((label) => p.test(label)));
|
|
2465
|
+
if (uaMatch || cardMatch || keyMatch || headerMatch || ja4Match || asnMatch || wafMatch) {
|
|
2417
2466
|
const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
|
|
2418
2467
|
const cardHost = (() => {
|
|
2419
2468
|
try {
|
|
@@ -2422,7 +2471,7 @@ function matchPlatformSignature(signatures, input) {
|
|
|
2422
2471
|
return "";
|
|
2423
2472
|
}
|
|
2424
2473
|
})();
|
|
2425
|
-
const keyBasis = uaBase || cardHost || apiKeyFormat || ja4 || asn && `asn${asn}` || "unknown";
|
|
2474
|
+
const keyBasis = uaBase || cardHost || apiKeyFormat || ja4 || asn && `asn${asn}` || wafMatch && `waf:${wafLabels[0]?.toLowerCase()}` || "unknown";
|
|
2426
2475
|
return {
|
|
2427
2476
|
vendor: sig.vendor,
|
|
2428
2477
|
fingerprintKey: `${sig.vendor}:${keyBasis}`,
|