@astrasyncai/verification-gateway 4.2.0 → 4.3.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 +56 -4
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +56 -4
- 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 +22 -5
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +22 -5
- 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 +54 -4
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +54 -4
- 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/agent/index.d.mts +2 -2
- package/dist/agent/index.d.ts +2 -2
- package/dist/agent/index.js +2 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +2 -2
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +2 -2
- package/dist/bin/astrasync-codex-hook.js +2 -2
- package/dist/bin/astrasync-guard.js +2 -2
- package/dist/bin/astrasync.js +14 -4
- package/dist/browser/background.js +2 -2
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +2 -2
- 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/codex/index.d.mts +2 -2
- package/dist/codex/index.d.ts +2 -2
- package/dist/codex/index.js +2 -2
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +2 -2
- 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 +2 -2
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +2 -2
- 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-core/index.d.mts +1 -1
- package/dist/edge-core/index.d.ts +1 -1
- package/dist/edge-core/index.js +25 -5
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +25 -5
- 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 +2 -2
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +2 -2
- 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-B0YHu_SP.d.ts → index-B5Ts1WtM.d.ts} +3 -3
- package/dist/{index-T1aBoUcc.d.ts → index-BfIxCYIZ.d.ts} +1 -1
- package/dist/{index-BPEBlOsE.d.mts → index-Cub7lK-T.d.mts} +3 -3
- package/dist/{index-DQb5-_1X.d.mts → index-CwAh7Tln.d.mts} +1 -1
- package/dist/index.d.mts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +74 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +71 -32
- 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 +18 -5
- package/dist/metadata-capture.d.ts +18 -5
- package/dist/metadata-capture.js +21 -4
- package/dist/metadata-capture.js.map +1 -1
- package/dist/metadata-capture.mjs +20 -4
- 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/{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 +5 -5
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +2 -2
- 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/package.json +2 -4
package/README.md
CHANGED
|
@@ -229,20 +229,39 @@ The CLI uses the same response logic — it will print a "Sign in to approve" me
|
|
|
229
229
|
|
|
230
230
|
> A `PDLSSConfig` type exists in both `/registration` and `/agent`, with **different shapes**. `/registration`'s `PDLSSConfig` is the boundary declaration submitted at register time; `/agent`'s `PDLSSConfig` is the per-request runtime request shape. Disambiguate via the import path — the root export deliberately does not re-export either.
|
|
231
231
|
|
|
232
|
-
### Inner-hop verification (
|
|
233
|
-
|
|
234
|
-
When an
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
232
|
+
### Inner-hop verification (cross-hop dedupe with X-Astra-Verified-Hop)
|
|
233
|
+
|
|
234
|
+
When an upstream AstraSync hop and an inner gateway-protected endpoint
|
|
235
|
+
both verify the same agent in the same logical request, two verify-access
|
|
236
|
+
calls fire — audit gets noisy and you pay a doubled round-trip. The
|
|
237
|
+
`X-Astra-Verified-Hop` header marks the inner hop as already-verified by
|
|
238
|
+
the upstream so the inner middleware skips the redundant call.
|
|
239
|
+
|
|
240
|
+
Two upstreams emit the marker automatically (SDK 4.3.0+):
|
|
241
|
+
|
|
242
|
+
- the **MCP middleware**, on its outbound response (tool handlers calling
|
|
243
|
+
inner REST hops forward it on outgoing fetches — worked example below);
|
|
244
|
+
- the **edge gateway** (`adapter-lambda` / `adapter-edge`), toward the
|
|
245
|
+
origin whenever its verify-access call produced identity (authenticate /
|
|
246
|
+
authorize depth). An SDK-middleware origin behind the TAG then skips the
|
|
247
|
+
double verify by setting `trustVerifiedHop: true` — at the default
|
|
248
|
+
classify depth no marker is emitted and the origin verifies as usual.
|
|
249
|
+
|
|
250
|
+
`trustVerifiedHop` + `verifiedHopMaxAgeMs` are supported on the `express`,
|
|
251
|
+
`nextjs`, and `mcp` middleware options (all default off). The inner
|
|
252
|
+
middleware validates the marker via `parseVerifiedHop` +
|
|
253
|
+
`isVerifiedHopValidFor` and skips a duplicate verify-access only if the
|
|
254
|
+
marker is fresh AND matches the agent claimed on the inner hop. The edge
|
|
255
|
+
gateway strips any inbound `X-Astra-Verified-Hop` on evaluated passes, so
|
|
256
|
+
a viewer can never smuggle one through the TAG.
|
|
257
|
+
|
|
258
|
+
**Trust model (read before enabling):** the marker is UNSIGNED — a dedupe
|
|
259
|
+
advisory, not proof. Enable `trustVerifiedHop` only when every network
|
|
260
|
+
path to the inner hop crosses a stripping gateway (the TAG) or an
|
|
261
|
+
equivalent trusted boundary; inside that boundary a forger could reduce
|
|
262
|
+
verify-access from "every request" to "once per freshness window" for an
|
|
263
|
+
agent id it already presents. This is the same trust model as the
|
|
264
|
+
unsigned `X-AstraSync-*` attestation headers.
|
|
246
265
|
|
|
247
266
|
**Worked example — upstream MCP → inner REST hop:**
|
|
248
267
|
|
|
@@ -589,13 +608,18 @@ The **Trusted Agent Gateway (TAG)** is AstraSync's verification gateway at the C
|
|
|
589
608
|
|
|
590
609
|
Both consume the same dashboard-managed policy (`./edge-config`), the same platform fingerprint registry (`./platform-signatures`), and the same header sanitiser (`./metadata-capture`) as this SDK — one classification everywhere.
|
|
591
610
|
|
|
592
|
-
### What each integration captures
|
|
611
|
+
### What each integration captures (canonical capture matrix)
|
|
612
|
+
|
|
613
|
+
Header-level capture (`ObservedMetadata.headers` etc.) is identical everywhere: **automatic on every verify** for the edge adapters and the `express` / `nextjs` / `mcp` SDK adapters (no config, no opt-out). What differs is the **connection layer** — and the deciding variable is _who operates the CDN in front of your origin_:
|
|
614
|
+
|
|
615
|
+
| Integration | Connection layer | TLS fingerprint (JA3/JA4) |
|
|
616
|
+
| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
617
|
+
| **Edge adapter** (`adapter-lambda`, `adapter-edge`) | **Full** — native platform signals (IP, ASN, geo, TLS, HTTP version, device class, header structure) | CloudFront: **JA3 + JA4** (2.2.0+, via the template's origin request policy). Cloudflare Workers: Bot Management zones only. Vercel: JA4 with BotID. Fastly: none |
|
|
618
|
+
| **SDK behind a CDN you control** (your own Cloudflare / Fastly / Vercel / CloudFront distribution) | **Derived** — geo/ASN/TLS promoted from the CDN's injected headers (`deriveConnectionFromHeaders`) | Cloudflare: JA3 + JA4 (`cf-ja3-hash` / `cf-ja4`, plan-dependent). CloudFront: JA3 + JA4 — add the `CloudFront-Viewer-JA3/JA4-Fingerprint` headers to your origin request policy |
|
|
619
|
+
| **SDK behind a platform-managed CDN** (Railway, Render, Fly, Heroku, …) | **IP only** — platform CDNs forward `x-forwarded-for` but NOT their provider-specific geo/TLS headers to customer origins | None — no fingerprint header reaches your origin |
|
|
620
|
+
| **SDK, no CDN** | Absent (IP from `x-forwarded-for` when a proxy sets it) | None |
|
|
593
621
|
|
|
594
|
-
|
|
595
|
-
| ------------------------------------------------ | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
596
|
-
| Edge adapters (`adapter-lambda`, `adapter-edge`) | Yes | **Yes** — native platform signals (the authoritative source) |
|
|
597
|
-
| `express` + `nextjs` SDK adapters | Yes — **automatic on every verify** (no config, no opt-out) | Derived from CDN-injected headers when your origin sits behind Cloudflare / Fastly / Vercel / CloudFront (`deriveConnectionFromHeaders`, from 4.1.0); absent otherwise |
|
|
598
|
-
| `mcp` SDK adapter | Yes — from 4.1.0 | Same CDN-header derivation as express/nextjs |
|
|
622
|
+
> "Behind Fastly" ≠ "receives Fastly's headers": platform-managed CDNs are operated by the platform, and they do not forward `Fastly-Client-IP`-style headers to your origin. If connection-layer signals or fingerprints matter to you on a managed platform, deploy the edge adapter in front (bucket 1) — that is the whole point of the TAG.
|
|
599
623
|
|
|
600
624
|
> **Note:** `runCommercePipeline` (on the `./transport` subpath) is the **server-side** orchestrator of commerce-protocol verification — it runs inside the AstraSync verify-access service. The edge adapters forward raw commerce artifacts to verify-access and never bundle or call the pipeline themselves.
|
|
601
625
|
|
|
@@ -622,7 +646,7 @@ The ONE sanitiser deciding what is safe to store from an inbound agent's request
|
|
|
622
646
|
- `sanitizeHeaders(raw)` → `{ headers, apiKeyFormat?, platformHeaders? }` — drops genuine secrets (cookies, signatures, AstraSync credential headers), reduces credential headers to a safe **format prefix** (e.g. `sk-ant-api03` — a platform signal, never the key), keeps everything else verbatim, and enforces size caps (`MAX_HEADERS`, `MAX_HEADER_VALUE_BYTES`, `MAX_TOTAL_BYTES`).
|
|
623
647
|
- `extractApiKeyFormat(value)` — the safe key-format prefix of a credential header value, or `undefined` for unrecognised/opaque tokens.
|
|
624
648
|
- `extractPlatformHeaders(sanitized)` — the platform-signal subset (`openai-organization`, `anthropic-version`, `x-goog-user-project`, …) of an already-sanitised map.
|
|
625
|
-
- `deriveConnectionFromHeaders(headers)` — promotes CDN-injected headers (Cloudflare / Fastly / Vercel / CloudFront geo, client-IP,
|
|
649
|
+
- `deriveConnectionFromHeaders(headers)` — promotes CDN-injected headers (Cloudflare / Fastly / Vercel / CloudFront geo, client-IP, TLS-fingerprint, and header-structure headers — incl. `cf-ja3-hash` / `cf-ja4` and `cloudfront-viewer-ja3-fingerprint` / `-ja4-fingerprint` from 4.3.0) into the `connection` block, so SDK-only deployments behind a CDN **you control** still get connection-layer attribution (see the capture matrix for the platform-managed-CDN caveat). Values are truncated to `MAX_CONNECTION_VALUE_CHARS` (256 — the platform bound). Native edge signals remain authoritative; this is the SDK-level fallback.
|
|
626
650
|
- `buildSdkObservedMetadata(rawHeaders)` — the one builder the express / nextjs / mcp adapters share: sanitised headers + `apiKeyFormat` + `platformHeaders` + derived `connection` + `schemaVersion`.
|
|
627
651
|
- `CAPTURE_SCHEMA_VERSION` — the capture-semantics version stamped on every `ObservedMetadata` (currently `1`). Capture semantics are **frozen within a major version**: `schemaVersion` bumps only on a semantic change to what is kept/dropped/derived, never for additive signals. The verify body's `sdkVersion` disambiguates builds.
|
|
628
652
|
- Types: `ObservedMetadata` (`{ headers, apiKeyFormat?, platformHeaders?, connection?, schemaVersion? }` — `connection` is populated natively by edge adapters and via CDN-header derivation by SDK adapters), `SanitizeHeadersResult`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AstraSyncGateway } from '../gateway/gateway.mjs';
|
|
2
|
-
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-
|
|
3
|
-
import '../types-
|
|
2
|
+
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-C7Rb-w0d.mjs';
|
|
3
|
+
import '../types-C0zfSXMB.mjs';
|
|
4
4
|
import '../metadata-capture.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AstraSyncGateway } from '../gateway/gateway.js';
|
|
2
|
-
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-
|
|
3
|
-
import '../types-
|
|
2
|
+
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-nIh3HtuA.js';
|
|
3
|
+
import '../types-DwSfO7Sb.js';
|
|
4
4
|
import '../metadata-capture.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'express';
|
|
2
|
-
import '../types-
|
|
3
|
-
export { c as createMiddleware, a as extractAstraSyncCredentials } from '../express-
|
|
2
|
+
import '../types-C0zfSXMB.mjs';
|
|
3
|
+
export { c as createMiddleware, a as extractAstraSyncCredentials } from '../express-CR6F3njD.mjs';
|
|
4
4
|
import '../metadata-capture.mjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'express';
|
|
2
|
-
import '../types-
|
|
3
|
-
export { c as createMiddleware, a as extractAstraSyncCredentials } from '../express-
|
|
2
|
+
import '../types-DwSfO7Sb.js';
|
|
3
|
+
export { c as createMiddleware, a as extractAstraSyncCredentials } from '../express-DaqL11tx.js';
|
|
4
4
|
import '../metadata-capture.js';
|
package/dist/adapters/express.js
CHANGED
|
@@ -775,6 +775,31 @@ function extractHttpCredentials(headers) {
|
|
|
775
775
|
return credentials;
|
|
776
776
|
}
|
|
777
777
|
|
|
778
|
+
// src/verified-hop.ts
|
|
779
|
+
var MCP_VERIFIED_HOP_HEADER = "X-Astra-Verified-Hop";
|
|
780
|
+
var MCP_VERIFIED_HOP_MAX_AGE_MS = 6e4;
|
|
781
|
+
function parseVerifiedHop(value) {
|
|
782
|
+
if (!value) return null;
|
|
783
|
+
const parts = value.split(";");
|
|
784
|
+
if (parts.length !== 3) return null;
|
|
785
|
+
const [astraId, sessionId, checkedAtRaw] = parts;
|
|
786
|
+
if (!astraId) return null;
|
|
787
|
+
const checkedAt = Number(checkedAtRaw);
|
|
788
|
+
if (!Number.isFinite(checkedAt) || checkedAt <= 0) return null;
|
|
789
|
+
return {
|
|
790
|
+
astraId,
|
|
791
|
+
...sessionId ? { sessionId } : {},
|
|
792
|
+
checkedAt
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
function isVerifiedHopValidFor(marker, expectedAstraId, opts = {}) {
|
|
796
|
+
if (!marker) return false;
|
|
797
|
+
if (marker.astraId !== expectedAstraId) return false;
|
|
798
|
+
const maxAge = opts.maxAgeMs ?? MCP_VERIFIED_HOP_MAX_AGE_MS;
|
|
799
|
+
const now = opts.now ?? Date.now();
|
|
800
|
+
return now - marker.checkedAt <= maxAge && now >= marker.checkedAt;
|
|
801
|
+
}
|
|
802
|
+
|
|
778
803
|
// src/adapters/http-pdlss.ts
|
|
779
804
|
var HTTP_METHOD_ACTION_TABLE = {
|
|
780
805
|
GET: "data.read",
|
|
@@ -925,7 +950,9 @@ var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
|
925
950
|
"x-astrasync-signature",
|
|
926
951
|
"x-astrasync-secret",
|
|
927
952
|
"x-hub-signature",
|
|
928
|
-
"x-hub-signature-256"
|
|
953
|
+
"x-hub-signature-256",
|
|
954
|
+
// Short-lived verify dedupe token — must never persist in stored metadata.
|
|
955
|
+
"x-astra-verified-hop"
|
|
929
956
|
]);
|
|
930
957
|
var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
|
|
931
958
|
var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -1060,16 +1087,25 @@ var CONNECTION_HEADER_SOURCES = [
|
|
|
1060
1087
|
["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
|
|
1061
1088
|
],
|
|
1062
1089
|
["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
|
|
1090
|
+
["countryRegionName", ["cloudfront-viewer-country-region-name"]],
|
|
1063
1091
|
["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
|
|
1064
1092
|
["asn", ["cloudfront-viewer-asn"]],
|
|
1065
1093
|
["tlsVersion", ["cloudfront-viewer-tls"]],
|
|
1066
1094
|
["httpVersion", ["cloudfront-viewer-http-version"]],
|
|
1095
|
+
["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
|
|
1096
|
+
["metroCode", ["cloudfront-viewer-metro-code"]],
|
|
1067
1097
|
// TLS fingerprints can only be computed where TLS terminates. When a CDN
|
|
1068
1098
|
// terminates TLS in front of the merchant, its fingerprint headers ARE the
|
|
1069
1099
|
// connection-layer truth — normalising them here is the permanent design.
|
|
1070
|
-
|
|
1071
|
-
|
|
1100
|
+
// CloudFront delivers JA3/JA4 only via an origin request policy and only
|
|
1101
|
+
// for HTTPS viewer connections.
|
|
1102
|
+
["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
|
|
1103
|
+
["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
|
|
1104
|
+
// Header-structure fingerprint: browser/SDK-distinctive header ordering.
|
|
1105
|
+
["headerOrder", ["cloudfront-viewer-header-order"]],
|
|
1106
|
+
["headerCount", ["cloudfront-viewer-header-count"]]
|
|
1072
1107
|
];
|
|
1108
|
+
var MAX_CONNECTION_VALUE_CHARS = 256;
|
|
1073
1109
|
function deriveConnectionFromHeaders(headers) {
|
|
1074
1110
|
if (!headers) return void 0;
|
|
1075
1111
|
const lower = {};
|
|
@@ -1082,11 +1118,15 @@ function deriveConnectionFromHeaders(headers) {
|
|
|
1082
1118
|
for (const source of sources) {
|
|
1083
1119
|
const value = lower[source]?.trim();
|
|
1084
1120
|
if (value) {
|
|
1085
|
-
connection[key] = value;
|
|
1121
|
+
connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
|
|
1086
1122
|
break;
|
|
1087
1123
|
}
|
|
1088
1124
|
}
|
|
1089
1125
|
}
|
|
1126
|
+
if (!connection.ip) {
|
|
1127
|
+
const addr = lower["cloudfront-viewer-address"]?.trim();
|
|
1128
|
+
if (addr) connection.ip = addr.replace(/:\d+$/, "");
|
|
1129
|
+
}
|
|
1090
1130
|
if (!connection.ip) {
|
|
1091
1131
|
const xff = lower["x-forwarded-for"];
|
|
1092
1132
|
const client = xff?.split(",")[0]?.trim();
|
|
@@ -1527,6 +1567,8 @@ function createMiddleware(options) {
|
|
|
1527
1567
|
failOnError = "open",
|
|
1528
1568
|
caseInsensitiveRouteMatch = false,
|
|
1529
1569
|
anonymousBeacon = true,
|
|
1570
|
+
trustVerifiedHop = false,
|
|
1571
|
+
verifiedHopMaxAgeMs,
|
|
1530
1572
|
...config
|
|
1531
1573
|
} = options;
|
|
1532
1574
|
if (config.apiBaseUrl) {
|
|
@@ -1619,6 +1661,16 @@ function createMiddleware(options) {
|
|
|
1619
1661
|
beaconPassThrough?.(req);
|
|
1620
1662
|
return next();
|
|
1621
1663
|
}
|
|
1664
|
+
if (trustVerifiedHop && credentials.astraId) {
|
|
1665
|
+
const hopRaw = req.headers[MCP_VERIFIED_HOP_HEADER.toLowerCase()];
|
|
1666
|
+
const hopValue = typeof hopRaw === "string" ? hopRaw : Array.isArray(hopRaw) ? hopRaw[0] : void 0;
|
|
1667
|
+
const marker = parseVerifiedHop(hopValue);
|
|
1668
|
+
if (isVerifiedHopValidFor(marker, credentials.astraId, {
|
|
1669
|
+
...verifiedHopMaxAgeMs !== void 0 ? { maxAgeMs: verifiedHopMaxAgeMs } : {}
|
|
1670
|
+
})) {
|
|
1671
|
+
return next();
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1622
1674
|
const pdlssPair = resolveRequestPdlss(
|
|
1623
1675
|
req,
|
|
1624
1676
|
routeConfig,
|