@astrasyncai/verification-gateway 4.2.1 → 4.4.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 +45 -21
- package/dist/adapter-interface/interface.d.mts +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +2 -2
- package/dist/adapters/express.d.ts +2 -2
- package/dist/adapters/express.js +145 -21
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +145 -21
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +38 -30
- package/dist/adapters/mcp.d.ts +38 -30
- package/dist/adapters/mcp.js +72 -16
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +72 -16
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +2 -2
- package/dist/adapters/nextjs.d.ts +2 -2
- package/dist/adapters/nextjs.js +141 -19
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +141 -19
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +2 -2
- package/dist/adapters/sdk.d.ts +2 -2
- package/dist/adapters/sdk.js +24 -6
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +24 -6
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +2 -2
- package/dist/agent/index.d.ts +2 -2
- 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 +22 -4
- package/dist/bin/astrasync-codex-hook.js +22 -4
- package/dist/bin/astrasync-guard.js +26 -8
- package/dist/bin/astrasync.js +76 -23
- package/dist/browser/background.js +22 -4
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +22 -4
- package/dist/browser/background.mjs.map +1 -1
- package/dist/browser/browser-adapter.d.mts +2 -2
- package/dist/browser/browser-adapter.d.ts +2 -2
- package/dist/claude-code/claude-code-adapter.d.mts +2 -2
- package/dist/claude-code/claude-code-adapter.d.ts +2 -2
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.d.ts +2 -2
- 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.d.mts +2 -2
- package/dist/codex/index.d.ts +2 -2
- package/dist/codex/index.js +22 -4
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +22 -4
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/cursor-adapter.d.mts +2 -2
- package/dist/cursor/cursor-adapter.d.ts +2 -2
- package/dist/cursor/extension.d.mts +2 -2
- package/dist/cursor/extension.d.ts +2 -2
- package/dist/cursor/extension.js +22 -4
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +22 -4
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +1 -1
- package/dist/edge-config.d.ts +1 -1
- 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 +1 -1
- package/dist/edge-core/index.d.ts +1 -1
- package/dist/edge-core/index.js +121 -16
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +121 -16
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/{express-D_4hTn5Z.d.mts → express-CR6F3njD.d.mts} +1 -1
- package/dist/{express-BVd1_3FE.d.ts → express-DaqL11tx.d.ts} +1 -1
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +22 -4
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +22 -4
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +2 -2
- package/dist/git-trigger/git-hooks.d.ts +2 -2
- package/dist/{index-BqHKlLOU.d.ts → index-B5Ts1WtM.d.ts} +1 -1
- package/dist/{index-T1aBoUcc.d.ts → index-BfIxCYIZ.d.ts} +1 -1
- package/dist/{index-BTeQ9fgV.d.mts → index-Cub7lK-T.d.mts} +1 -1
- package/dist/{index-DQb5-_1X.d.mts → index-CwAh7Tln.d.mts} +1 -1
- package/dist/index.d.mts +58 -9
- package/dist/index.d.ts +58 -9
- package/dist/index.js +218 -54
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +214 -54
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +2 -2
- package/dist/local-evaluator/evaluator.d.ts +2 -2
- package/dist/metadata-capture.d.mts +35 -5
- package/dist/metadata-capture.d.ts +35 -5
- package/dist/metadata-capture.js +44 -6
- package/dist/metadata-capture.js.map +1 -1
- package/dist/metadata-capture.mjs +43 -6
- package/dist/metadata-capture.mjs.map +1 -1
- package/dist/{nextjs-w7RTbP1P.d.ts → nextjs-DL6uE1ye.d.ts} +1 -1
- package/dist/{nextjs-WyeVr2Kp.d.mts → nextjs-DlX6xwbU.d.mts} +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/{sdk-CbTNIkAa.d.mts → sdk-Bbh9B_dw.d.mts} +1 -1
- package/dist/{sdk-QeX0Z8Ho.d.ts → sdk-C6SASmsh.d.ts} +1 -1
- package/dist/transport/index.d.mts +2 -2
- package/dist/transport/index.d.ts +2 -2
- 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/{types-r850cOt0.d.mts → types-C0zfSXMB.d.mts} +22 -0
- package/dist/{types-DqfPU5Bl.d.mts → types-C7Rb-w0d.d.mts} +1 -1
- package/dist/{types-sMxBT-nM.d.ts → types-DwSfO7Sb.d.ts} +22 -0
- package/dist/{types-BLUx92FJ.d.ts → types-nIh3HtuA.d.ts} +1 -1
- 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 +29 -11
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +29 -11
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'next/server';
|
|
2
|
-
import '../types-
|
|
3
|
-
export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-
|
|
2
|
+
import '../types-C0zfSXMB.mjs';
|
|
3
|
+
export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-DlX6xwbU.mjs';
|
|
4
4
|
import '../metadata-capture.mjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'next/server';
|
|
2
|
-
import '../types-
|
|
3
|
-
export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-
|
|
2
|
+
import '../types-DwSfO7Sb.js';
|
|
3
|
+
export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-DL6uE1ye.js';
|
|
4
4
|
import '../metadata-capture.js';
|
package/dist/adapters/nextjs.js
CHANGED
|
@@ -35,6 +35,27 @@ __export(nextjs_exports, {
|
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(nextjs_exports);
|
|
37
37
|
|
|
38
|
+
// src/version.ts
|
|
39
|
+
var SDK_VERSION = "4.4.0";
|
|
40
|
+
|
|
41
|
+
// src/http.ts
|
|
42
|
+
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
43
|
+
function withUserAgent(initHeaders) {
|
|
44
|
+
if (!initHeaders) return { "user-agent": SDK_USER_AGENT };
|
|
45
|
+
if (initHeaders instanceof Headers) {
|
|
46
|
+
const copy = new Headers(initHeaders);
|
|
47
|
+
if (!copy.has("user-agent")) copy.set("user-agent", SDK_USER_AGENT);
|
|
48
|
+
return copy;
|
|
49
|
+
}
|
|
50
|
+
if (Array.isArray(initHeaders)) {
|
|
51
|
+
const has2 = initHeaders.some(([name]) => name.toLowerCase() === "user-agent");
|
|
52
|
+
return has2 ? initHeaders : [...initHeaders, ["user-agent", SDK_USER_AGENT]];
|
|
53
|
+
}
|
|
54
|
+
const has = Object.keys(initHeaders).some((name) => name.toLowerCase() === "user-agent");
|
|
55
|
+
return has ? initHeaders : { "user-agent": SDK_USER_AGENT, ...initHeaders };
|
|
56
|
+
}
|
|
57
|
+
var sdkFetch = (input, init) => fetch(input, { ...init, headers: withUserAgent(init?.headers) });
|
|
58
|
+
|
|
38
59
|
// src/adapters/stepup-poll.ts
|
|
39
60
|
var DEFAULT_POLL_INTERVAL_MS = 3e3;
|
|
40
61
|
var MIN_POLL_INTERVAL_MS = 250;
|
|
@@ -49,7 +70,7 @@ function resolvePollUrl(config, pollUrl) {
|
|
|
49
70
|
async function pollStepUpStatus(config, approval) {
|
|
50
71
|
if (!approval.pollUrl) return null;
|
|
51
72
|
try {
|
|
52
|
-
const res = await
|
|
73
|
+
const res = await sdkFetch(resolvePollUrl(config, approval.pollUrl), {
|
|
53
74
|
method: "GET",
|
|
54
75
|
signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS)
|
|
55
76
|
});
|
|
@@ -101,9 +122,6 @@ function getTrustLevel(score) {
|
|
|
101
122
|
return "BRONZE";
|
|
102
123
|
}
|
|
103
124
|
|
|
104
|
-
// src/version.ts
|
|
105
|
-
var SDK_VERSION = "4.1.0";
|
|
106
|
-
|
|
107
125
|
// src/well-known.ts
|
|
108
126
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
109
127
|
var cache = /* @__PURE__ */ new Map();
|
|
@@ -132,7 +150,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
|
|
|
132
150
|
initCheckPerformed = true;
|
|
133
151
|
try {
|
|
134
152
|
const probeUrl = `${apiBaseUrl}/agents/verify-access`;
|
|
135
|
-
const response = await
|
|
153
|
+
const response = await sdkFetch(probeUrl, { method: "HEAD" });
|
|
136
154
|
const contentType = response.headers.get("content-type") ?? "";
|
|
137
155
|
if (contentType.startsWith("text/html")) {
|
|
138
156
|
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).`;
|
|
@@ -146,7 +164,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
|
|
|
146
164
|
);
|
|
147
165
|
}
|
|
148
166
|
if (apiKey) {
|
|
149
|
-
const selfCheck = await
|
|
167
|
+
const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
|
|
150
168
|
headers: { Authorization: `Bearer ${apiKey}` }
|
|
151
169
|
});
|
|
152
170
|
if (selfCheck.status === 401) {
|
|
@@ -393,7 +411,7 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
393
411
|
headers["X-API-Key"] = config.apiKey;
|
|
394
412
|
}
|
|
395
413
|
try {
|
|
396
|
-
const response = await
|
|
414
|
+
const response = await sdkFetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
397
415
|
method: "POST",
|
|
398
416
|
headers,
|
|
399
417
|
body: JSON.stringify(body),
|
|
@@ -638,7 +656,7 @@ async function fetchRoutes(config, counterpartyId) {
|
|
|
638
656
|
headers["X-API-Key"] = config.apiKey;
|
|
639
657
|
}
|
|
640
658
|
try {
|
|
641
|
-
const response = await
|
|
659
|
+
const response = await sdkFetch(
|
|
642
660
|
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,
|
|
643
661
|
{ method: "GET", headers }
|
|
644
662
|
);
|
|
@@ -657,7 +675,7 @@ async function reportUnregisteredAttempt(config, data) {
|
|
|
657
675
|
...counterpartyUrl && { counterpartyUrl },
|
|
658
676
|
...config.counterpartyId && { counterpartyId: config.counterpartyId }
|
|
659
677
|
};
|
|
660
|
-
await
|
|
678
|
+
await sdkFetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
|
|
661
679
|
method: "POST",
|
|
662
680
|
headers: { "Content-Type": "application/json" },
|
|
663
681
|
body: JSON.stringify(body)
|
|
@@ -666,7 +684,7 @@ async function reportUnregisteredAttempt(config, data) {
|
|
|
666
684
|
}
|
|
667
685
|
async function reportCounterpartyPreCheckFailure(config, data) {
|
|
668
686
|
const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
|
|
669
|
-
await
|
|
687
|
+
await sdkFetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
|
|
670
688
|
method: "POST",
|
|
671
689
|
headers: { "Content-Type": "application/json" },
|
|
672
690
|
body: JSON.stringify(data)
|
|
@@ -778,7 +796,9 @@ var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
|
778
796
|
"x-astrasync-signature",
|
|
779
797
|
"x-astrasync-secret",
|
|
780
798
|
"x-hub-signature",
|
|
781
|
-
"x-hub-signature-256"
|
|
799
|
+
"x-hub-signature-256",
|
|
800
|
+
// Short-lived verify dedupe token — must never persist in stored metadata.
|
|
801
|
+
"x-astra-verified-hop"
|
|
782
802
|
]);
|
|
783
803
|
var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
|
|
784
804
|
var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -803,7 +823,13 @@ var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
|
803
823
|
"x-agent-card-url",
|
|
804
824
|
"x-agent-provider"
|
|
805
825
|
]);
|
|
806
|
-
var PLATFORM_HEADER_PREFIXES = [
|
|
826
|
+
var PLATFORM_HEADER_PREFIXES = [
|
|
827
|
+
"x-goog-",
|
|
828
|
+
"x-stainless-",
|
|
829
|
+
"x-anthropic-",
|
|
830
|
+
"x-openai-",
|
|
831
|
+
"sec-ch-"
|
|
832
|
+
];
|
|
807
833
|
var KEY_FORMAT_PREFIXES = [
|
|
808
834
|
"sk-ant-api03",
|
|
809
835
|
"sk-ant-api",
|
|
@@ -875,6 +901,7 @@ function sanitizeHeaders(raw) {
|
|
|
875
901
|
const headers = {};
|
|
876
902
|
const platformHeaders = {};
|
|
877
903
|
let apiKeyFormat;
|
|
904
|
+
let cookieCount;
|
|
878
905
|
let totalBytes = 0;
|
|
879
906
|
let count = 0;
|
|
880
907
|
if (!raw) return { headers };
|
|
@@ -889,6 +916,9 @@ function sanitizeHeaders(raw) {
|
|
|
889
916
|
if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
|
|
890
917
|
continue;
|
|
891
918
|
}
|
|
919
|
+
if (name === "cookie") {
|
|
920
|
+
cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
|
|
921
|
+
}
|
|
892
922
|
if (isSecretHeader(name)) continue;
|
|
893
923
|
let value = joined;
|
|
894
924
|
if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
|
|
@@ -904,6 +934,7 @@ function sanitizeHeaders(raw) {
|
|
|
904
934
|
const result = { headers };
|
|
905
935
|
if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
|
|
906
936
|
if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
|
|
937
|
+
if (cookieCount !== void 0) result.cookieCount = cookieCount;
|
|
907
938
|
return result;
|
|
908
939
|
}
|
|
909
940
|
var CONNECTION_HEADER_SOURCES = [
|
|
@@ -913,16 +944,28 @@ var CONNECTION_HEADER_SOURCES = [
|
|
|
913
944
|
["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
|
|
914
945
|
],
|
|
915
946
|
["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
|
|
947
|
+
["countryRegionName", ["cloudfront-viewer-country-region-name"]],
|
|
916
948
|
["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
|
|
949
|
+
["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
|
|
950
|
+
["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
|
|
951
|
+
["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
|
|
917
952
|
["asn", ["cloudfront-viewer-asn"]],
|
|
918
953
|
["tlsVersion", ["cloudfront-viewer-tls"]],
|
|
919
954
|
["httpVersion", ["cloudfront-viewer-http-version"]],
|
|
955
|
+
["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
|
|
956
|
+
["metroCode", ["cloudfront-viewer-metro-code"]],
|
|
920
957
|
// TLS fingerprints can only be computed where TLS terminates. When a CDN
|
|
921
958
|
// terminates TLS in front of the merchant, its fingerprint headers ARE the
|
|
922
959
|
// connection-layer truth — normalising them here is the permanent design.
|
|
923
|
-
|
|
924
|
-
|
|
960
|
+
// CloudFront delivers JA3/JA4 only via an origin request policy and only
|
|
961
|
+
// for HTTPS viewer connections.
|
|
962
|
+
["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
|
|
963
|
+
["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
|
|
964
|
+
// Header-structure fingerprint: browser/SDK-distinctive header ordering.
|
|
965
|
+
["headerOrder", ["cloudfront-viewer-header-order"]],
|
|
966
|
+
["headerCount", ["cloudfront-viewer-header-count"]]
|
|
925
967
|
];
|
|
968
|
+
var MAX_CONNECTION_VALUE_CHARS = 256;
|
|
926
969
|
function deriveConnectionFromHeaders(headers) {
|
|
927
970
|
if (!headers) return void 0;
|
|
928
971
|
const lower = {};
|
|
@@ -935,20 +978,30 @@ function deriveConnectionFromHeaders(headers) {
|
|
|
935
978
|
for (const source of sources) {
|
|
936
979
|
const value = lower[source]?.trim();
|
|
937
980
|
if (value) {
|
|
938
|
-
connection[key] = value;
|
|
981
|
+
connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
|
|
939
982
|
break;
|
|
940
983
|
}
|
|
941
984
|
}
|
|
942
985
|
}
|
|
986
|
+
{
|
|
987
|
+
const addr = lower["cloudfront-viewer-address"]?.trim();
|
|
988
|
+
const portMatch = addr?.match(/:(\d+)$/);
|
|
989
|
+
if (portMatch) connection.sourcePort = portMatch[1];
|
|
990
|
+
if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
|
|
991
|
+
}
|
|
943
992
|
if (!connection.ip) {
|
|
944
993
|
const xff = lower["x-forwarded-for"];
|
|
945
994
|
const client = xff?.split(",")[0]?.trim();
|
|
946
995
|
if (client) connection.ip = client;
|
|
947
996
|
}
|
|
997
|
+
if (!connection.tlsCipher) {
|
|
998
|
+
const cipher = connection.tlsVersion?.split(":")[1];
|
|
999
|
+
if (cipher) connection.tlsCipher = cipher;
|
|
1000
|
+
}
|
|
948
1001
|
return Object.keys(connection).length > 0 ? connection : void 0;
|
|
949
1002
|
}
|
|
950
1003
|
function buildSdkObservedMetadata(rawHeaders) {
|
|
951
|
-
const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
|
|
1004
|
+
const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
|
|
952
1005
|
const flat = {};
|
|
953
1006
|
if (rawHeaders) {
|
|
954
1007
|
for (const name of Object.keys(rawHeaders)) {
|
|
@@ -963,6 +1016,7 @@ function buildSdkObservedMetadata(rawHeaders) {
|
|
|
963
1016
|
...apiKeyFormat && { apiKeyFormat },
|
|
964
1017
|
...platformHeaders && { platformHeaders },
|
|
965
1018
|
...connection && { connection },
|
|
1019
|
+
...cookieCount !== void 0 && { cookieCount },
|
|
966
1020
|
schemaVersion: CAPTURE_SCHEMA_VERSION
|
|
967
1021
|
};
|
|
968
1022
|
}
|
|
@@ -1007,7 +1061,7 @@ async function fetchEdgeConfig(config, counterpartyId, opts) {
|
|
|
1007
1061
|
}
|
|
1008
1062
|
if (opts?.etag) headers["If-None-Match"] = opts.etag;
|
|
1009
1063
|
try {
|
|
1010
|
-
const response = await
|
|
1064
|
+
const response = await sdkFetch(
|
|
1011
1065
|
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
|
|
1012
1066
|
{ method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
|
|
1013
1067
|
);
|
|
@@ -1119,12 +1173,43 @@ var PLATFORM_AGENT_SIGNATURES = [
|
|
|
1119
1173
|
uaPatterns: [/perplexity/i],
|
|
1120
1174
|
agentCardPatterns: [/perplexity\.ai/i],
|
|
1121
1175
|
apiKeyFormatPatterns: [/^pplx-/i]
|
|
1176
|
+
},
|
|
1177
|
+
// Agentic browsers — versioned-token patterns ONLY (a stock Chrome UA must
|
|
1178
|
+
// never match). Distinct vendor keys (not 'chatgpt'/'perplexity'): the
|
|
1179
|
+
// browser product is a different surface than the assistant service, and
|
|
1180
|
+
// the DB registry mirrors one row per vendor. These sit after the primary
|
|
1181
|
+
// vendor entries so a UA carrying an explicit vendor token keeps its
|
|
1182
|
+
// primary attribution; a browser-shaped UA with the agentic token is
|
|
1183
|
+
// caught here BEFORE classify's human tier, which is what makes these
|
|
1184
|
+
// visits observable at all. Token drift is real (some builds mimic Chrome
|
|
1185
|
+
// outright) — re-verify against captured events when a new browser ships,
|
|
1186
|
+
// and check `sec-ch-ua` platformHeaders for the real brand.
|
|
1187
|
+
{
|
|
1188
|
+
vendor: "chatgpt-atlas",
|
|
1189
|
+
displayName: "ChatGPT Atlas browser",
|
|
1190
|
+
uaPatterns: [/\batlas\/\d/i],
|
|
1191
|
+
headerPatterns: [/^sec-ch-ua: .*atlas/i]
|
|
1192
|
+
},
|
|
1193
|
+
{
|
|
1194
|
+
vendor: "perplexity-comet",
|
|
1195
|
+
displayName: "Perplexity Comet browser",
|
|
1196
|
+
uaPatterns: [/\bcomet\/\d/i],
|
|
1197
|
+
headerPatterns: [/^sec-ch-ua: .*comet/i]
|
|
1198
|
+
},
|
|
1199
|
+
// Our own SDK self-identifies (sdkFetch stamps this UA) — first-party
|
|
1200
|
+
// traffic must never pollute the unknown/anonymous pool it exists to audit.
|
|
1201
|
+
{
|
|
1202
|
+
vendor: "astrasync-sdk",
|
|
1203
|
+
displayName: "AstraSync SDK",
|
|
1204
|
+
uaPatterns: [/^astrasync-sdk\//i]
|
|
1122
1205
|
}
|
|
1123
1206
|
];
|
|
1124
1207
|
function matchPlatformSignature(signatures, input) {
|
|
1125
1208
|
const ua = input.userAgent ?? "";
|
|
1126
1209
|
const cardUrl = input.agentCardUrl ?? "";
|
|
1127
1210
|
const apiKeyFormat = input.apiKeyFormat ?? "";
|
|
1211
|
+
const ja4 = input.ja4 ?? "";
|
|
1212
|
+
const asn = input.asn ?? "";
|
|
1128
1213
|
const headerLines = [];
|
|
1129
1214
|
if (input.platformHeaders) {
|
|
1130
1215
|
for (const [name, value] of Object.entries(input.platformHeaders)) {
|
|
@@ -1136,7 +1221,9 @@ function matchPlatformSignature(signatures, input) {
|
|
|
1136
1221
|
const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
|
|
1137
1222
|
const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
|
|
1138
1223
|
const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
|
|
1139
|
-
|
|
1224
|
+
const ja4Match = ja4.length > 0 && sig.ja4Patterns?.some((p) => p.test(ja4));
|
|
1225
|
+
const asnMatch = asn.length > 0 && sig.asnList?.includes(asn);
|
|
1226
|
+
if (uaMatch || cardMatch || keyMatch || headerMatch || ja4Match || asnMatch) {
|
|
1140
1227
|
const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
|
|
1141
1228
|
const cardHost = (() => {
|
|
1142
1229
|
try {
|
|
@@ -1145,7 +1232,7 @@ function matchPlatformSignature(signatures, input) {
|
|
|
1145
1232
|
return "";
|
|
1146
1233
|
}
|
|
1147
1234
|
})();
|
|
1148
|
-
const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
|
|
1235
|
+
const keyBasis = uaBase || cardHost || apiKeyFormat || ja4 || asn && `asn${asn}` || "unknown";
|
|
1149
1236
|
return {
|
|
1150
1237
|
vendor: sig.vendor,
|
|
1151
1238
|
fingerprintKey: `${sig.vendor}:${keyBasis}`,
|
|
@@ -1352,6 +1439,31 @@ function annotateApprovalRequired(result) {
|
|
|
1352
1439
|
result.denialReasons = [APPROVAL_REASON, ...result.denialReasons ?? []];
|
|
1353
1440
|
}
|
|
1354
1441
|
|
|
1442
|
+
// src/verified-hop.ts
|
|
1443
|
+
var MCP_VERIFIED_HOP_HEADER = "X-Astra-Verified-Hop";
|
|
1444
|
+
var MCP_VERIFIED_HOP_MAX_AGE_MS = 6e4;
|
|
1445
|
+
function parseVerifiedHop(value) {
|
|
1446
|
+
if (!value) return null;
|
|
1447
|
+
const parts = value.split(";");
|
|
1448
|
+
if (parts.length !== 3) return null;
|
|
1449
|
+
const [astraId, sessionId, checkedAtRaw] = parts;
|
|
1450
|
+
if (!astraId) return null;
|
|
1451
|
+
const checkedAt = Number(checkedAtRaw);
|
|
1452
|
+
if (!Number.isFinite(checkedAt) || checkedAt <= 0) return null;
|
|
1453
|
+
return {
|
|
1454
|
+
astraId,
|
|
1455
|
+
...sessionId ? { sessionId } : {},
|
|
1456
|
+
checkedAt
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
function isVerifiedHopValidFor(marker, expectedAstraId, opts = {}) {
|
|
1460
|
+
if (!marker) return false;
|
|
1461
|
+
if (marker.astraId !== expectedAstraId) return false;
|
|
1462
|
+
const maxAge = opts.maxAgeMs ?? MCP_VERIFIED_HOP_MAX_AGE_MS;
|
|
1463
|
+
const now = opts.now ?? Date.now();
|
|
1464
|
+
return now - marker.checkedAt <= maxAge && now >= marker.checkedAt;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1355
1467
|
// src/adapters/nextjs.ts
|
|
1356
1468
|
function escapeHtml(value) {
|
|
1357
1469
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -1590,6 +1702,8 @@ function createMiddleware(options) {
|
|
|
1590
1702
|
enableRuntimeChallenge = true,
|
|
1591
1703
|
routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
|
|
1592
1704
|
anonymousBeacon = true,
|
|
1705
|
+
trustVerifiedHop = false,
|
|
1706
|
+
verifiedHopMaxAgeMs,
|
|
1593
1707
|
...config
|
|
1594
1708
|
} = options;
|
|
1595
1709
|
const interstitialEnabled = showInterstitial ?? showCommerceShield ?? true;
|
|
@@ -1652,6 +1766,14 @@ function createMiddleware(options) {
|
|
|
1652
1766
|
return NextResponse.next();
|
|
1653
1767
|
}
|
|
1654
1768
|
const credentials = extractCredentialsFromNextRequest(request);
|
|
1769
|
+
if (trustVerifiedHop && credentials.astraId) {
|
|
1770
|
+
const marker = parseVerifiedHop(request.headers.get(MCP_VERIFIED_HOP_HEADER) ?? void 0);
|
|
1771
|
+
if (isVerifiedHopValidFor(marker, credentials.astraId, {
|
|
1772
|
+
...verifiedHopMaxAgeMs !== void 0 ? { maxAgeMs: verifiedHopMaxAgeMs } : {}
|
|
1773
|
+
})) {
|
|
1774
|
+
return NextResponse.next();
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1655
1777
|
const counterpartyUrl = config.counterpartyUrl || request.nextUrl.origin;
|
|
1656
1778
|
const pdlssPair = resolveNextPdlss(request, routeConfig);
|
|
1657
1779
|
const purpose = pdlssPair.purpose;
|