@astrasyncai/verification-gateway 4.3.0 → 4.5.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/dist/adapters/express.js +104 -28
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +104 -28
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.js +63 -21
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +63 -21
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.js +103 -27
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +103 -27
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.js +33 -12
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +33 -12
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.js +24 -3
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +24 -3
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +31 -10
- package/dist/bin/astrasync-codex-hook.js +31 -10
- package/dist/bin/astrasync-guard.js +35 -14
- package/dist/bin/astrasync.js +75 -29
- package/dist/browser/background.js +31 -10
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +31 -10
- package/dist/browser/background.mjs.map +1 -1
- package/dist/cli/index.js +23 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +23 -2
- package/dist/cli/index.mjs.map +1 -1
- package/dist/codex/index.js +31 -10
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +31 -10
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +31 -10
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +31 -10
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +11 -4
- package/dist/edge-config.d.ts +11 -4
- package/dist/edge-config.js +24 -1
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs +22 -1
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.d.mts +21 -7
- package/dist/edge-core/index.d.ts +21 -7
- package/dist/edge-core/index.js +170 -25
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +170 -25
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.js +31 -10
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +31 -10
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/index.d.mts +51 -2
- package/dist/index.d.ts +51 -2
- package/dist/index.js +169 -40
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +165 -40
- package/dist/index.mjs.map +1 -1
- package/dist/metadata-capture.d.mts +17 -0
- package/dist/metadata-capture.d.ts +17 -0
- package/dist/metadata-capture.js +25 -4
- package/dist/metadata-capture.js.map +1 -1
- package/dist/metadata-capture.mjs +25 -4
- package/dist/metadata-capture.mjs.map +1 -1
- package/dist/platform-signatures.d.mts +18 -1
- package/dist/platform-signatures.d.ts +18 -1
- package/dist/platform-signatures.js +35 -2
- package/dist/platform-signatures.js.map +1 -1
- package/dist/platform-signatures.mjs +35 -2
- package/dist/platform-signatures.mjs.map +1 -1
- package/dist/registration/index.js +25 -4
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +25 -4
- package/dist/registration/index.mjs.map +1 -1
- package/dist/transport/index.js +22 -1
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +22 -1
- package/dist/transport/index.mjs.map +1 -1
- package/dist/verify.js +38 -17
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +38 -17
- package/dist/verify.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -126,7 +126,25 @@ function getCapabilities(accessLevel) {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
// src/version.ts
|
|
129
|
-
var SDK_VERSION = "4.
|
|
129
|
+
var SDK_VERSION = "4.5.0";
|
|
130
|
+
|
|
131
|
+
// src/http.ts
|
|
132
|
+
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
133
|
+
function withUserAgent(initHeaders) {
|
|
134
|
+
if (!initHeaders) return { "user-agent": SDK_USER_AGENT };
|
|
135
|
+
if (initHeaders instanceof Headers) {
|
|
136
|
+
const copy = new Headers(initHeaders);
|
|
137
|
+
if (!copy.has("user-agent")) copy.set("user-agent", SDK_USER_AGENT);
|
|
138
|
+
return copy;
|
|
139
|
+
}
|
|
140
|
+
if (Array.isArray(initHeaders)) {
|
|
141
|
+
const has2 = initHeaders.some(([name]) => name.toLowerCase() === "user-agent");
|
|
142
|
+
return has2 ? initHeaders : [...initHeaders, ["user-agent", SDK_USER_AGENT]];
|
|
143
|
+
}
|
|
144
|
+
const has = Object.keys(initHeaders).some((name) => name.toLowerCase() === "user-agent");
|
|
145
|
+
return has ? initHeaders : { "user-agent": SDK_USER_AGENT, ...initHeaders };
|
|
146
|
+
}
|
|
147
|
+
var sdkFetch = (input, init) => fetch(input, { ...init, headers: withUserAgent(init?.headers) });
|
|
130
148
|
|
|
131
149
|
// src/well-known.ts
|
|
132
150
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -138,7 +156,7 @@ function wellKnownUrl(apiBaseUrl) {
|
|
|
138
156
|
}
|
|
139
157
|
async function fetchWellKnown(apiBaseUrl) {
|
|
140
158
|
const url = wellKnownUrl(apiBaseUrl);
|
|
141
|
-
const response = await
|
|
159
|
+
const response = await sdkFetch(url, {
|
|
142
160
|
method: "GET",
|
|
143
161
|
headers: { Accept: "application/json" },
|
|
144
162
|
signal: AbortSignal.timeout(5e3)
|
|
@@ -208,7 +226,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
|
|
|
208
226
|
initCheckPerformed = true;
|
|
209
227
|
try {
|
|
210
228
|
const probeUrl = `${apiBaseUrl}/agents/verify-access`;
|
|
211
|
-
const response = await
|
|
229
|
+
const response = await sdkFetch(probeUrl, { method: "HEAD" });
|
|
212
230
|
const contentType = response.headers.get("content-type") ?? "";
|
|
213
231
|
if (contentType.startsWith("text/html")) {
|
|
214
232
|
const message = `[VerificationGateway] apiBaseUrl '${apiBaseUrl}' returned HTML (content-type: ${contentType}). This usually means apiBaseUrl is pointing at a marketing site instead of the API. Expected: 'https://astrasync.ai/api' (prod) or 'https://staging.astrasync.ai/api' (staging).`;
|
|
@@ -222,7 +240,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
|
|
|
222
240
|
);
|
|
223
241
|
}
|
|
224
242
|
if (apiKey) {
|
|
225
|
-
const selfCheck = await
|
|
243
|
+
const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
|
|
226
244
|
headers: { Authorization: `Bearer ${apiKey}` }
|
|
227
245
|
});
|
|
228
246
|
if (selfCheck.status === 401) {
|
|
@@ -475,7 +493,7 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
475
493
|
headers["X-API-Key"] = config.apiKey;
|
|
476
494
|
}
|
|
477
495
|
try {
|
|
478
|
-
const response = await
|
|
496
|
+
const response = await sdkFetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
479
497
|
method: "POST",
|
|
480
498
|
headers,
|
|
481
499
|
body: JSON.stringify(body),
|
|
@@ -657,12 +675,15 @@ async function verify(config, request, options) {
|
|
|
657
675
|
const verificationContext = apiResponse.verificationContext;
|
|
658
676
|
const accessLevel = apiResponse.access?.accessLevel ?? "standard";
|
|
659
677
|
const result = {
|
|
660
|
-
//
|
|
661
|
-
//
|
|
662
|
-
//
|
|
663
|
-
//
|
|
664
|
-
//
|
|
665
|
-
|
|
678
|
+
// 4.5.0 (probe F1): read idVerified from verificationContext with the
|
|
679
|
+
// SAME absent⇒false default as the deny branch. The previous `!== false`
|
|
680
|
+
// default manufactured `identityVerified: true` for anonymous
|
|
681
|
+
// allow_full/allow_partial/audit responses (which allow access but omit
|
|
682
|
+
// verificationContext entirely) — the "anonymous caller labelled
|
|
683
|
+
// verified" defect. Every authenticated success response has carried
|
|
684
|
+
// `verificationContext.idVerified: true` since v2.2.4, so a truth claim
|
|
685
|
+
// this load-bearing must never be defaulted on.
|
|
686
|
+
identityVerified: apiResponse.verificationContext?.idVerified === true,
|
|
666
687
|
policyAllowed: true,
|
|
667
688
|
accessLevel,
|
|
668
689
|
agent,
|
|
@@ -718,7 +739,7 @@ async function recordDecision(config, sessionId, decision, reason) {
|
|
|
718
739
|
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
719
740
|
headers["X-API-Key"] = config.apiKey;
|
|
720
741
|
}
|
|
721
|
-
await
|
|
742
|
+
await sdkFetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
|
|
722
743
|
method: "POST",
|
|
723
744
|
headers,
|
|
724
745
|
body: JSON.stringify({ decision, reason })
|
|
@@ -736,7 +757,7 @@ async function reportAttempt(config, report) {
|
|
|
736
757
|
...report,
|
|
737
758
|
...!report.counterpartyId && config.counterpartyId && { counterpartyId: config.counterpartyId }
|
|
738
759
|
};
|
|
739
|
-
await
|
|
760
|
+
await sdkFetch(`${apiBaseUrl}/agents/verify-access/attempt-report`, {
|
|
740
761
|
method: "POST",
|
|
741
762
|
headers,
|
|
742
763
|
body: JSON.stringify(body)
|
|
@@ -751,7 +772,7 @@ async function fetchRoutes(config, counterpartyId) {
|
|
|
751
772
|
headers["X-API-Key"] = config.apiKey;
|
|
752
773
|
}
|
|
753
774
|
try {
|
|
754
|
-
const response = await
|
|
775
|
+
const response = await sdkFetch(
|
|
755
776
|
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,
|
|
756
777
|
{ method: "GET", headers }
|
|
757
778
|
);
|
|
@@ -770,7 +791,7 @@ async function reportUnregisteredAttempt(config, data) {
|
|
|
770
791
|
...counterpartyUrl && { counterpartyUrl },
|
|
771
792
|
...config.counterpartyId && { counterpartyId: config.counterpartyId }
|
|
772
793
|
};
|
|
773
|
-
await
|
|
794
|
+
await sdkFetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
|
|
774
795
|
method: "POST",
|
|
775
796
|
headers: { "Content-Type": "application/json" },
|
|
776
797
|
body: JSON.stringify(body)
|
|
@@ -779,7 +800,7 @@ async function reportUnregisteredAttempt(config, data) {
|
|
|
779
800
|
}
|
|
780
801
|
async function reportCounterpartyPreCheckFailure(config, data) {
|
|
781
802
|
const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
|
|
782
|
-
await
|
|
803
|
+
await sdkFetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
|
|
783
804
|
method: "POST",
|
|
784
805
|
headers: { "Content-Type": "application/json" },
|
|
785
806
|
body: JSON.stringify(data)
|
|
@@ -813,7 +834,7 @@ function resolvePollUrl(config, pollUrl) {
|
|
|
813
834
|
async function pollStepUpStatus(config, approval) {
|
|
814
835
|
if (!approval.pollUrl) return null;
|
|
815
836
|
try {
|
|
816
|
-
const res = await
|
|
837
|
+
const res = await sdkFetch(resolvePollUrl(config, approval.pollUrl), {
|
|
817
838
|
method: "GET",
|
|
818
839
|
signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS)
|
|
819
840
|
});
|
|
@@ -1188,7 +1209,13 @@ var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
|
1188
1209
|
"x-agent-card-url",
|
|
1189
1210
|
"x-agent-provider"
|
|
1190
1211
|
]);
|
|
1191
|
-
var PLATFORM_HEADER_PREFIXES = [
|
|
1212
|
+
var PLATFORM_HEADER_PREFIXES = [
|
|
1213
|
+
"x-goog-",
|
|
1214
|
+
"x-stainless-",
|
|
1215
|
+
"x-anthropic-",
|
|
1216
|
+
"x-openai-",
|
|
1217
|
+
"sec-ch-"
|
|
1218
|
+
];
|
|
1192
1219
|
var KEY_FORMAT_PREFIXES = [
|
|
1193
1220
|
"sk-ant-api03",
|
|
1194
1221
|
"sk-ant-api",
|
|
@@ -1260,6 +1287,7 @@ function sanitizeHeaders(raw) {
|
|
|
1260
1287
|
const headers = {};
|
|
1261
1288
|
const platformHeaders = {};
|
|
1262
1289
|
let apiKeyFormat;
|
|
1290
|
+
let cookieCount;
|
|
1263
1291
|
let totalBytes = 0;
|
|
1264
1292
|
let count = 0;
|
|
1265
1293
|
if (!raw) return { headers };
|
|
@@ -1274,6 +1302,9 @@ function sanitizeHeaders(raw) {
|
|
|
1274
1302
|
if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
|
|
1275
1303
|
continue;
|
|
1276
1304
|
}
|
|
1305
|
+
if (name === "cookie") {
|
|
1306
|
+
cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
|
|
1307
|
+
}
|
|
1277
1308
|
if (isSecretHeader(name)) continue;
|
|
1278
1309
|
let value = joined;
|
|
1279
1310
|
if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
|
|
@@ -1289,6 +1320,7 @@ function sanitizeHeaders(raw) {
|
|
|
1289
1320
|
const result = { headers };
|
|
1290
1321
|
if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
|
|
1291
1322
|
if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
|
|
1323
|
+
if (cookieCount !== void 0) result.cookieCount = cookieCount;
|
|
1292
1324
|
return result;
|
|
1293
1325
|
}
|
|
1294
1326
|
function extractPlatformHeaders(sanitized) {
|
|
@@ -1308,6 +1340,9 @@ var CONNECTION_HEADER_SOURCES = [
|
|
|
1308
1340
|
["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
|
|
1309
1341
|
["countryRegionName", ["cloudfront-viewer-country-region-name"]],
|
|
1310
1342
|
["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
|
|
1343
|
+
["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
|
|
1344
|
+
["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
|
|
1345
|
+
["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
|
|
1311
1346
|
["asn", ["cloudfront-viewer-asn"]],
|
|
1312
1347
|
["tlsVersion", ["cloudfront-viewer-tls"]],
|
|
1313
1348
|
["httpVersion", ["cloudfront-viewer-http-version"]],
|
|
@@ -1342,19 +1377,25 @@ function deriveConnectionFromHeaders(headers) {
|
|
|
1342
1377
|
}
|
|
1343
1378
|
}
|
|
1344
1379
|
}
|
|
1345
|
-
|
|
1380
|
+
{
|
|
1346
1381
|
const addr = lower["cloudfront-viewer-address"]?.trim();
|
|
1347
|
-
|
|
1382
|
+
const portMatch = addr?.match(/:(\d+)$/);
|
|
1383
|
+
if (portMatch) connection.sourcePort = portMatch[1];
|
|
1384
|
+
if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
|
|
1348
1385
|
}
|
|
1349
1386
|
if (!connection.ip) {
|
|
1350
1387
|
const xff = lower["x-forwarded-for"];
|
|
1351
1388
|
const client = xff?.split(",")[0]?.trim();
|
|
1352
1389
|
if (client) connection.ip = client;
|
|
1353
1390
|
}
|
|
1391
|
+
if (!connection.tlsCipher) {
|
|
1392
|
+
const cipher = connection.tlsVersion?.split(":")[1];
|
|
1393
|
+
if (cipher) connection.tlsCipher = cipher;
|
|
1394
|
+
}
|
|
1354
1395
|
return Object.keys(connection).length > 0 ? connection : void 0;
|
|
1355
1396
|
}
|
|
1356
1397
|
function buildSdkObservedMetadata(rawHeaders) {
|
|
1357
|
-
const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
|
|
1398
|
+
const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
|
|
1358
1399
|
const flat = {};
|
|
1359
1400
|
if (rawHeaders) {
|
|
1360
1401
|
for (const name of Object.keys(rawHeaders)) {
|
|
@@ -1369,6 +1410,7 @@ function buildSdkObservedMetadata(rawHeaders) {
|
|
|
1369
1410
|
...apiKeyFormat && { apiKeyFormat },
|
|
1370
1411
|
...platformHeaders && { platformHeaders },
|
|
1371
1412
|
...connection && { connection },
|
|
1413
|
+
...cookieCount !== void 0 && { cookieCount },
|
|
1372
1414
|
schemaVersion: CAPTURE_SCHEMA_VERSION
|
|
1373
1415
|
};
|
|
1374
1416
|
}
|
|
@@ -1413,7 +1455,7 @@ async function fetchEdgeConfig(config, counterpartyId, opts) {
|
|
|
1413
1455
|
}
|
|
1414
1456
|
if (opts?.etag) headers["If-None-Match"] = opts.etag;
|
|
1415
1457
|
try {
|
|
1416
|
-
const response = await
|
|
1458
|
+
const response = await sdkFetch(
|
|
1417
1459
|
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
|
|
1418
1460
|
{ method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
|
|
1419
1461
|
);
|
|
@@ -1539,12 +1581,43 @@ var PLATFORM_AGENT_SIGNATURES = [
|
|
|
1539
1581
|
uaPatterns: [/perplexity/i],
|
|
1540
1582
|
agentCardPatterns: [/perplexity\.ai/i],
|
|
1541
1583
|
apiKeyFormatPatterns: [/^pplx-/i]
|
|
1584
|
+
},
|
|
1585
|
+
// Agentic browsers — versioned-token patterns ONLY (a stock Chrome UA must
|
|
1586
|
+
// never match). Distinct vendor keys (not 'chatgpt'/'perplexity'): the
|
|
1587
|
+
// browser product is a different surface than the assistant service, and
|
|
1588
|
+
// the DB registry mirrors one row per vendor. These sit after the primary
|
|
1589
|
+
// vendor entries so a UA carrying an explicit vendor token keeps its
|
|
1590
|
+
// primary attribution; a browser-shaped UA with the agentic token is
|
|
1591
|
+
// caught here BEFORE classify's human tier, which is what makes these
|
|
1592
|
+
// visits observable at all. Token drift is real (some builds mimic Chrome
|
|
1593
|
+
// outright) — re-verify against captured events when a new browser ships,
|
|
1594
|
+
// and check `sec-ch-ua` platformHeaders for the real brand.
|
|
1595
|
+
{
|
|
1596
|
+
vendor: "chatgpt-atlas",
|
|
1597
|
+
displayName: "ChatGPT Atlas browser",
|
|
1598
|
+
uaPatterns: [/\batlas\/\d/i],
|
|
1599
|
+
headerPatterns: [/^sec-ch-ua: .*atlas/i]
|
|
1600
|
+
},
|
|
1601
|
+
{
|
|
1602
|
+
vendor: "perplexity-comet",
|
|
1603
|
+
displayName: "Perplexity Comet browser",
|
|
1604
|
+
uaPatterns: [/\bcomet\/\d/i],
|
|
1605
|
+
headerPatterns: [/^sec-ch-ua: .*comet/i]
|
|
1606
|
+
},
|
|
1607
|
+
// Our own SDK self-identifies (sdkFetch stamps this UA) — first-party
|
|
1608
|
+
// traffic must never pollute the unknown/anonymous pool it exists to audit.
|
|
1609
|
+
{
|
|
1610
|
+
vendor: "astrasync-sdk",
|
|
1611
|
+
displayName: "AstraSync SDK",
|
|
1612
|
+
uaPatterns: [/^astrasync-sdk\//i]
|
|
1542
1613
|
}
|
|
1543
1614
|
];
|
|
1544
1615
|
function matchPlatformSignature(signatures, input) {
|
|
1545
1616
|
const ua = input.userAgent ?? "";
|
|
1546
1617
|
const cardUrl = input.agentCardUrl ?? "";
|
|
1547
1618
|
const apiKeyFormat = input.apiKeyFormat ?? "";
|
|
1619
|
+
const ja4 = input.ja4 ?? "";
|
|
1620
|
+
const asn = input.asn ?? "";
|
|
1548
1621
|
const headerLines = [];
|
|
1549
1622
|
if (input.platformHeaders) {
|
|
1550
1623
|
for (const [name, value] of Object.entries(input.platformHeaders)) {
|
|
@@ -1556,7 +1629,9 @@ function matchPlatformSignature(signatures, input) {
|
|
|
1556
1629
|
const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
|
|
1557
1630
|
const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
|
|
1558
1631
|
const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
|
|
1559
|
-
|
|
1632
|
+
const ja4Match = ja4.length > 0 && sig.ja4Patterns?.some((p) => p.test(ja4));
|
|
1633
|
+
const asnMatch = asn.length > 0 && sig.asnList?.includes(asn);
|
|
1634
|
+
if (uaMatch || cardMatch || keyMatch || headerMatch || ja4Match || asnMatch) {
|
|
1560
1635
|
const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
|
|
1561
1636
|
const cardHost = (() => {
|
|
1562
1637
|
try {
|
|
@@ -1565,7 +1640,7 @@ function matchPlatformSignature(signatures, input) {
|
|
|
1565
1640
|
return "";
|
|
1566
1641
|
}
|
|
1567
1642
|
})();
|
|
1568
|
-
const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
|
|
1643
|
+
const keyBasis = uaBase || cardHost || apiKeyFormat || ja4 || asn && `asn${asn}` || "unknown";
|
|
1569
1644
|
return {
|
|
1570
1645
|
vendor: sig.vendor,
|
|
1571
1646
|
fingerprintKey: `${sig.vendor}:${keyBasis}`,
|
|
@@ -1581,9 +1656,10 @@ function detectPlatformFingerprint(input) {
|
|
|
1581
1656
|
|
|
1582
1657
|
// src/edge-core/classify.ts
|
|
1583
1658
|
var STATIC_EXTENSIONS = /\.(css|js|mjs|map|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm|pdf|txt|xml)$/i;
|
|
1659
|
+
var SELF_UA_PATTERN = /^astrasync-sdk\//i;
|
|
1584
1660
|
var BOT_UA_PATTERN = /curl|wget|python-requests|python-urllib|node-fetch|axios|got|okhttp|go-http-client|libwww|httpie|java\/|ruby|php|scrapy|headless|phantomjs|selenium|playwright|puppeteer|bot|crawler|spider|slurp/i;
|
|
1585
1661
|
var BROWSER_UA_PATTERN = /mozilla\/\d/i;
|
|
1586
|
-
var _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN };
|
|
1662
|
+
var _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN, SELF_UA_PATTERN };
|
|
1587
1663
|
|
|
1588
1664
|
// src/edge-core/events.ts
|
|
1589
1665
|
function sampled(rate, random = Math.random) {
|
|
@@ -2003,7 +2079,7 @@ function createMiddleware(options) {
|
|
|
2003
2079
|
let result = await verify(config, verificationRequest);
|
|
2004
2080
|
req.agentVerification = result;
|
|
2005
2081
|
let sessionId = result.sessionId;
|
|
2006
|
-
if (config.stepUpMaxWaitMs !== void 0 && result.
|
|
2082
|
+
if (config.stepUpMaxWaitMs !== void 0 && result.policyAllowed && requiresHumanApproval(result) && result.stepUpApproval?.pollUrl) {
|
|
2007
2083
|
const outcome = await awaitStepUpApproval(config, result.stepUpApproval);
|
|
2008
2084
|
res.setHeader("X-Astra-Step-Up", outcome);
|
|
2009
2085
|
if (outcome === "approved") {
|
|
@@ -2014,7 +2090,7 @@ function createMiddleware(options) {
|
|
|
2014
2090
|
result.stepUpOutcome = outcome;
|
|
2015
2091
|
}
|
|
2016
2092
|
}
|
|
2017
|
-
if (!result.
|
|
2093
|
+
if (!result.policyAllowed) {
|
|
2018
2094
|
if (shouldRecordDecisions && sessionId) {
|
|
2019
2095
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
2020
2096
|
});
|
|
@@ -2515,7 +2591,7 @@ function createMiddleware2(options) {
|
|
|
2515
2591
|
};
|
|
2516
2592
|
let result = await verify(config, verificationRequest);
|
|
2517
2593
|
let stepUpHoldOutcome;
|
|
2518
|
-
if (config.stepUpMaxWaitMs !== void 0 && result.
|
|
2594
|
+
if (config.stepUpMaxWaitMs !== void 0 && result.policyAllowed && requiresHumanApproval(result) && result.stepUpApproval?.pollUrl) {
|
|
2519
2595
|
stepUpHoldOutcome = await awaitStepUpApproval(config, result.stepUpApproval);
|
|
2520
2596
|
if (stepUpHoldOutcome === "approved") {
|
|
2521
2597
|
result = await verify(config, verificationRequest, { bypassCache: true });
|
|
@@ -2523,9 +2599,9 @@ function createMiddleware2(options) {
|
|
|
2523
2599
|
result.stepUpOutcome = stepUpHoldOutcome;
|
|
2524
2600
|
}
|
|
2525
2601
|
}
|
|
2526
|
-
const approvalRequired = result.
|
|
2602
|
+
const approvalRequired = result.policyAllowed && requiresHumanApproval(result);
|
|
2527
2603
|
if (approvalRequired) annotateApprovalRequired(result);
|
|
2528
|
-
if (!result.
|
|
2604
|
+
if (!result.policyAllowed || approvalRequired) {
|
|
2529
2605
|
if (result.misconfigured && pathname.startsWith("/api/")) {
|
|
2530
2606
|
return NextResponse.json(
|
|
2531
2607
|
{
|
|
@@ -3396,7 +3472,7 @@ async function fetchUCPManifest(manifestUrl, options = {}) {
|
|
|
3396
3472
|
const controller = new AbortController();
|
|
3397
3473
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3398
3474
|
try {
|
|
3399
|
-
const res = await
|
|
3475
|
+
const res = await sdkFetch(manifestUrl, { signal: controller.signal });
|
|
3400
3476
|
if (!res.ok) return null;
|
|
3401
3477
|
return await res.json();
|
|
3402
3478
|
} catch {
|
|
@@ -5661,7 +5737,7 @@ function createMcpMiddleware(options) {
|
|
|
5661
5737
|
let result = await verify(config, verificationRequest);
|
|
5662
5738
|
req.agentVerification = result;
|
|
5663
5739
|
let sessionId = result.sessionId;
|
|
5664
|
-
if (config.stepUpMaxWaitMs !== void 0 && result.
|
|
5740
|
+
if (config.stepUpMaxWaitMs !== void 0 && result.policyAllowed && requiresHumanApproval(result) && result.stepUpApproval?.pollUrl) {
|
|
5665
5741
|
const outcome = await awaitStepUpApproval(config, result.stepUpApproval);
|
|
5666
5742
|
res.setHeader("X-Astra-Step-Up", outcome);
|
|
5667
5743
|
if (outcome === "approved") {
|
|
@@ -5672,7 +5748,7 @@ function createMcpMiddleware(options) {
|
|
|
5672
5748
|
result.stepUpOutcome = outcome;
|
|
5673
5749
|
}
|
|
5674
5750
|
}
|
|
5675
|
-
if (!result.
|
|
5751
|
+
if (!result.policyAllowed) {
|
|
5676
5752
|
if (shouldRecordDecisions && sessionId) {
|
|
5677
5753
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
5678
5754
|
});
|
|
@@ -5944,7 +6020,7 @@ var AstraSync = class {
|
|
|
5944
6020
|
*/
|
|
5945
6021
|
async pollRegistration(requestId) {
|
|
5946
6022
|
const url = `${this.baseUrl}/api/agents/request-registration/${requestId}`;
|
|
5947
|
-
const res = await
|
|
6023
|
+
const res = await sdkFetch(url, { headers: { Accept: "application/json" } });
|
|
5948
6024
|
if (!res.ok) {
|
|
5949
6025
|
const errBody = await res.json().catch(() => ({}));
|
|
5950
6026
|
throw new AstraSyncError(
|
|
@@ -6001,7 +6077,7 @@ var AstraSync = class {
|
|
|
6001
6077
|
* Check API health.
|
|
6002
6078
|
*/
|
|
6003
6079
|
async health() {
|
|
6004
|
-
const res = await
|
|
6080
|
+
const res = await sdkFetch(`${this.baseUrl}/api/health/`);
|
|
6005
6081
|
if (!res.ok) {
|
|
6006
6082
|
throw new AstraSyncError(`Health check failed: ${res.status}`, res.status);
|
|
6007
6083
|
}
|
|
@@ -6028,7 +6104,7 @@ var AstraSync = class {
|
|
|
6028
6104
|
const signature = await this.signRequest(method, endpoint, body || {});
|
|
6029
6105
|
headers["X-AstraSync-Signature"] = signature;
|
|
6030
6106
|
}
|
|
6031
|
-
const res = await
|
|
6107
|
+
const res = await sdkFetch(url, {
|
|
6032
6108
|
method,
|
|
6033
6109
|
headers,
|
|
6034
6110
|
...body ? { body: JSON.stringify(body) } : {}
|
|
@@ -6053,7 +6129,7 @@ var AstraSync = class {
|
|
|
6053
6129
|
if (this.cachedJwt && this.jwtExpiresAt && Date.now() < this.jwtExpiresAt) {
|
|
6054
6130
|
return this.cachedJwt;
|
|
6055
6131
|
}
|
|
6056
|
-
const res = await
|
|
6132
|
+
const res = await sdkFetch(`${this.baseUrl}/api/auth/login`, {
|
|
6057
6133
|
method: "POST",
|
|
6058
6134
|
headers: { "Content-Type": "application/json" },
|
|
6059
6135
|
body: JSON.stringify({ email: this.email, password: this.password })
|
|
@@ -6196,7 +6272,7 @@ var AgentClient = class _AgentClient {
|
|
|
6196
6272
|
const url = `${this.apiBaseUrl.replace(/\/+$/, "")}/api/agents/${encodeURIComponent(
|
|
6197
6273
|
this.credentials.agentId
|
|
6198
6274
|
)}/ownership`;
|
|
6199
|
-
const resp = await
|
|
6275
|
+
const resp = await sdkFetch(url, {
|
|
6200
6276
|
method: "GET",
|
|
6201
6277
|
headers: {
|
|
6202
6278
|
Authorization: `Bearer ${this.apiKey}`,
|
|
@@ -6234,7 +6310,7 @@ var AgentClient = class _AgentClient {
|
|
|
6234
6310
|
}
|
|
6235
6311
|
}
|
|
6236
6312
|
const enrichedHeaders = setHttpHeaders(existingHeaders, creds);
|
|
6237
|
-
return
|
|
6313
|
+
return sdkFetch(url, {
|
|
6238
6314
|
...fetchOptions,
|
|
6239
6315
|
headers: enrichedHeaders
|
|
6240
6316
|
});
|
|
@@ -6423,7 +6499,7 @@ async function recordDecision2(config, params) {
|
|
|
6423
6499
|
if (config.customHeaders) {
|
|
6424
6500
|
Object.assign(headers, config.customHeaders);
|
|
6425
6501
|
}
|
|
6426
|
-
const response = await
|
|
6502
|
+
const response = await sdkFetch(url, {
|
|
6427
6503
|
method: "POST",
|
|
6428
6504
|
headers,
|
|
6429
6505
|
body: JSON.stringify(body)
|
|
@@ -6440,6 +6516,51 @@ async function recordDecision2(config, params) {
|
|
|
6440
6516
|
blockchainTxHash: result.blockchainTxHash
|
|
6441
6517
|
};
|
|
6442
6518
|
}
|
|
6519
|
+
|
|
6520
|
+
// src/runtime-signatures.ts
|
|
6521
|
+
var RUNTIME_SIGNATURES = [
|
|
6522
|
+
{
|
|
6523
|
+
runtime: "browser-automation",
|
|
6524
|
+
displayName: "Browser automation",
|
|
6525
|
+
uaPatterns: [/headless/i, /phantomjs/i, /selenium/i, /playwright/i, /puppeteer/i]
|
|
6526
|
+
},
|
|
6527
|
+
{
|
|
6528
|
+
runtime: "nodejs",
|
|
6529
|
+
displayName: "Node.js runtime",
|
|
6530
|
+
// `node` exactly is the global-fetch default UA; the token forms cover
|
|
6531
|
+
// the common Node HTTP libraries.
|
|
6532
|
+
uaPatterns: [/^node$/i, /^undici/i, /node-fetch/i, /^axios/i, /^got\b/i, /needle/i]
|
|
6533
|
+
},
|
|
6534
|
+
{
|
|
6535
|
+
runtime: "python",
|
|
6536
|
+
displayName: "Python runtime",
|
|
6537
|
+
uaPatterns: [/python-requests/i, /python-urllib/i, /^python\b/i, /httpx/i, /aiohttp/i]
|
|
6538
|
+
},
|
|
6539
|
+
{ runtime: "go", displayName: "Go runtime", uaPatterns: [/go-http-client/i] },
|
|
6540
|
+
{
|
|
6541
|
+
runtime: "java",
|
|
6542
|
+
displayName: "Java runtime",
|
|
6543
|
+
uaPatterns: [/^java\//i, /okhttp/i, /apache-httpclient/i]
|
|
6544
|
+
},
|
|
6545
|
+
{ runtime: "curl", displayName: "curl", uaPatterns: [/^curl\//i] },
|
|
6546
|
+
{ runtime: "wget", displayName: "wget", uaPatterns: [/^wget\//i] },
|
|
6547
|
+
{ runtime: "ruby", displayName: "Ruby runtime", uaPatterns: [/^ruby\b/i, /faraday/i] },
|
|
6548
|
+
{
|
|
6549
|
+
runtime: "php",
|
|
6550
|
+
displayName: "PHP runtime",
|
|
6551
|
+
uaPatterns: [/^php\b/i, /guzzlehttp/i, /^symfony/i]
|
|
6552
|
+
},
|
|
6553
|
+
{ runtime: "dotnet", displayName: ".NET runtime", uaPatterns: [/^dotnet/i, /httpclient/i] },
|
|
6554
|
+
{ runtime: "dart", displayName: "Dart runtime", uaPatterns: [/^dart/i] }
|
|
6555
|
+
];
|
|
6556
|
+
function detectRuntime(userAgent) {
|
|
6557
|
+
if (!userAgent) return void 0;
|
|
6558
|
+
const ua = userAgent.trim();
|
|
6559
|
+
for (const sig of RUNTIME_SIGNATURES) {
|
|
6560
|
+
if (sig.uaPatterns.some((p) => p.test(ua))) return sig.displayName;
|
|
6561
|
+
}
|
|
6562
|
+
return void 0;
|
|
6563
|
+
}
|
|
6443
6564
|
export {
|
|
6444
6565
|
ACCESS_LEVEL_DESCRIPTIONS,
|
|
6445
6566
|
ACCESS_LEVEL_HIERARCHY,
|
|
@@ -6456,9 +6577,11 @@ export {
|
|
|
6456
6577
|
MAX_HEADER_VALUE_BYTES,
|
|
6457
6578
|
MAX_TOTAL_BYTES,
|
|
6458
6579
|
PLATFORM_AGENT_SIGNATURES,
|
|
6580
|
+
RUNTIME_SIGNATURES,
|
|
6459
6581
|
RegistrationDeniedError,
|
|
6460
6582
|
RegistrationExpiredError,
|
|
6461
6583
|
RegistrationTimeoutError,
|
|
6584
|
+
SDK_USER_AGENT,
|
|
6462
6585
|
TRUST_LEVEL_RANGES,
|
|
6463
6586
|
SDK_VERSION as VERSION,
|
|
6464
6587
|
_resetEdgeConfigCache,
|
|
@@ -6472,6 +6595,7 @@ export {
|
|
|
6472
6595
|
degradeToObserve,
|
|
6473
6596
|
deriveConnectionFromHeaders,
|
|
6474
6597
|
detectPlatformFingerprint,
|
|
6598
|
+
detectRuntime,
|
|
6475
6599
|
determineAccessLevel,
|
|
6476
6600
|
express_exports as express,
|
|
6477
6601
|
extractApiKeyFormat,
|
|
@@ -6500,6 +6624,7 @@ export {
|
|
|
6500
6624
|
reportUnregisteredAttempt,
|
|
6501
6625
|
sanitizeHeaders,
|
|
6502
6626
|
sdk_exports as sdk,
|
|
6627
|
+
sdkFetch,
|
|
6503
6628
|
setMcpMeta,
|
|
6504
6629
|
transport_exports as transport,
|
|
6505
6630
|
verify
|