mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
refactor(server): share one proxy-header check across the local gates
localRequestGate.mjs owns the reverse-proxy header list and hasProxySignals; Provider Settings, the cross-site gate and /mcp all use it instead of two copies of the same nine names. The changelog credits the cross-site gate. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
bbf4976f5e
commit
6cdd6c8af9
5 files changed
+34
-34
No files matched your search
@@ -2,6 +2,13 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Refuse cross-site browser requests to the cost-bearing and log endpoints
|
||||
(`/api/realtime/token`, `/api/openai/hud-summary`,
|
||||
`/api/google/nearby-places`, `/api/realtime/debug-log`): a foreign or opaque
|
||||
Origin, a cross-site `Sec-Fetch-Site`, or proxy forwarding headers get 403,
|
||||
while loopback tools and LAN use keep working. The dev and preview servers
|
||||
send one shared Content-Security-Policy (James Sumpter, #242).
|
||||
|
||||
- The voice debug log records the server's own time: a record can no longer
|
||||
supply its `loggedAt`. The dev and preview servers also send
|
||||
`X-Content-Type-Options: nosniff` (findings by Sunil, #710).
|
||||
|
||||
@@ -306,6 +306,7 @@
|
||||
"server/providers/common/source-root.js",
|
||||
"server/standalone/key-setup.js",
|
||||
"src/keySetupCore.mjs",
|
||||
"src/localRequestGate.mjs",
|
||||
"server/standalone/key-setup-hardening.mjs"
|
||||
],
|
||||
"external": []
|
||||
@@ -390,7 +391,8 @@
|
||||
"src/ui/mapSource.js",
|
||||
"src/ui/mapSourceControls.js",
|
||||
"src/mapStackChips.js",
|
||||
"src/keySetupCore.mjs"
|
||||
"src/keySetupCore.mjs",
|
||||
"src/localRequestGate.mjs"
|
||||
],
|
||||
"external": []
|
||||
},
|
||||
@@ -409,6 +411,7 @@
|
||||
"src/loadingFeedback.js",
|
||||
"src/data/installationFeedback.js",
|
||||
"src/keySetupCore.mjs",
|
||||
"src/localRequestGate.mjs",
|
||||
"src/data/feedState.js",
|
||||
"src/data/layerSnapshot.js"
|
||||
],
|
||||
@@ -529,6 +532,7 @@
|
||||
"src/data/militaryAwarenessEngine.js",
|
||||
"src/data/scenePick.js",
|
||||
"src/keySetupCore.mjs",
|
||||
"src/localRequestGate.mjs",
|
||||
"src/loadingFeedback.js",
|
||||
"src/locationStatus.js",
|
||||
"src/mapStackChips.js",
|
||||
@@ -1266,6 +1270,7 @@
|
||||
"src/maps/terrain.js",
|
||||
"src/maps/terrainRetry.js",
|
||||
"src/keySetupCore.mjs",
|
||||
"src/localRequestGate.mjs",
|
||||
"src/maps/imageryHost.js"
|
||||
],
|
||||
"external": ["cesium"]
|
||||
@@ -1511,6 +1516,7 @@
|
||||
"src/hudSummaryResponse.js",
|
||||
"src/keySetup.js",
|
||||
"src/keySetupCore.mjs",
|
||||
"src/localRequestGate.mjs",
|
||||
"src/keylessGeocoder.js",
|
||||
"src/layers/aircraft/classification.js",
|
||||
"src/layers/alpr/index.js",
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
* rebinding) and, when a browser sends an Origin, come from that same host.
|
||||
*/
|
||||
|
||||
import { hasProxySignals, isSharingEnabled } from '../../src/keySetupCore.mjs';
|
||||
import { isSharingEnabled } from '../../src/keySetupCore.mjs';
|
||||
import { hasProxySignals } from '../../src/localRequestGate.mjs';
|
||||
import { createMcpHttpHandler } from '../../src/tools/mcp/index.js';
|
||||
import { createLocalMcpServer } from './server.js';
|
||||
|
||||
|
||||
+4
-25
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Key setup ("POWER UP") — the pure core.
|
||||
*
|
||||
* One registry, three pure functions, zero dependencies. The dev server's
|
||||
* One registry and pure functions; its only import is the proxy-header check
|
||||
* shared with the other local gates (localRequestGate.mjs). The dev server's
|
||||
* /api/setup endpoints (vite.config.js) and the in-app panel (keySetup.js)
|
||||
* are both thin shells over this module, so what a key is called, what it
|
||||
* unlocks, and how a .env line is written each live in exactly one place.
|
||||
@@ -11,6 +12,8 @@
|
||||
* behavior below unit-testable.
|
||||
*/
|
||||
|
||||
import { hasProxySignals } from './localRequestGate.mjs';
|
||||
|
||||
/** Longest accepted key/token value. Real provider keys are all far shorter. */
|
||||
export const KEY_SETUP_VALUE_LIMIT = 512;
|
||||
|
||||
@@ -184,30 +187,6 @@ export function parseWindowsUserSid(stdout) {
|
||||
: null;
|
||||
}
|
||||
|
||||
/** Headers that reverse proxies, tunnels and CDNs add to a request. */
|
||||
export const PROXY_SIGNAL_HEADERS = Object.freeze([
|
||||
'forwarded',
|
||||
'via',
|
||||
'x-forwarded-for',
|
||||
'x-forwarded-host',
|
||||
'x-forwarded-port',
|
||||
'x-forwarded-proto',
|
||||
'x-real-ip',
|
||||
'cf-connecting-ip',
|
||||
'cf-ray',
|
||||
]);
|
||||
|
||||
/**
|
||||
* Whether a request carries reverse-proxy or CDN forwarding headers, so it
|
||||
* did not originate on this machine whatever its socket says. `headers` is
|
||||
* keyed by lower-case header name.
|
||||
*/
|
||||
export function hasProxySignals(headers = {}) {
|
||||
return PROXY_SIGNAL_HEADERS.some(
|
||||
(name) => String(headers[name] || '').trim() !== '',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the launcher has sharing on. Every sharing signal the launcher
|
||||
* recognizes (scripts/pinokio-preflight.mjs) counts, so the two sets cannot
|
||||
|
||||
@@ -21,10 +21,9 @@
|
||||
*/
|
||||
/**
|
||||
* Reverse-proxy / CDN forwarding headers. Their presence means the request did
|
||||
* not originate on this machine, whatever its socket says. Kept as this
|
||||
* module's own list (keySetupCore.mjs carries the same nine names for the
|
||||
* credential panel) so the gate has no imports and can sit in any package
|
||||
* boundary.
|
||||
* not originate on this machine, whatever its socket says. This module owns
|
||||
* the list for every local gate (the credential panel and /mcp import
|
||||
* `hasProxySignals`), and has no imports so it can sit in any package boundary.
|
||||
*/
|
||||
export const PROXY_SIGNALS = Object.freeze([
|
||||
'forwarded',
|
||||
@@ -38,6 +37,16 @@ export const PROXY_SIGNALS = Object.freeze([
|
||||
'cf-ray',
|
||||
]);
|
||||
|
||||
/**
|
||||
* Whether a request carries reverse-proxy or CDN forwarding headers. `headers`
|
||||
* is keyed by lower-case header name.
|
||||
*/
|
||||
export function hasProxySignals(headers = {}) {
|
||||
return PROXY_SIGNALS.some(
|
||||
(name) => String(headers[name] || '').trim() !== '',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a request's own authority (an origin string) from its protocol and
|
||||
* Host header. Unlike the credential-panel gate's localhost-restricted
|
||||
@@ -90,9 +99,7 @@ export function admitSameSiteRequest({
|
||||
} = {}) {
|
||||
// (1) A request carrying reverse-proxy / CDN forwarding headers did not
|
||||
// originate on this machine, whatever its socket says.
|
||||
if (
|
||||
PROXY_SIGNALS.some((name) => String(proxyHeaders[name] || '').trim() !== '')
|
||||
) {
|
||||
if (hasProxySignals(proxyHeaders)) {
|
||||
return {
|
||||
ok: false,
|
||||
status: 403,
|
||||
|
||||
Reference in new issue
Block a user