refactor(gateway): harden proxy client ip resolution

This commit is contained in:
Peter Steinberger
2026-02-21 13:32:25 +01:00
parent 8b1fe0d1e2
commit be7f825006
15 changed files with 246 additions and 87 deletions

View File

@@ -133,17 +133,26 @@ async function authorizeCanvasRequest(params: {
req: IncomingMessage;
auth: ResolvedGatewayAuth;
trustedProxies: string[];
allowRealIpFallback: boolean;
clients: Set<GatewayWsClient>;
canvasCapability?: string;
malformedScopedPath?: boolean;
rateLimiter?: AuthRateLimiter;
}): Promise<GatewayAuthResult> {
const { req, auth, trustedProxies, clients, canvasCapability, malformedScopedPath, rateLimiter } =
params;
const {
req,
auth,
trustedProxies,
allowRealIpFallback,
clients,
canvasCapability,
malformedScopedPath,
rateLimiter,
} = params;
if (malformedScopedPath) {
return { ok: false, reason: "unauthorized" };
}
if (isLocalDirectRequest(req, trustedProxies)) {
if (isLocalDirectRequest(req, trustedProxies, allowRealIpFallback)) {
return { ok: true };
}
@@ -155,6 +164,7 @@ async function authorizeCanvasRequest(params: {
connectAuth: { token, password: token },
req,
trustedProxies,
allowRealIpFallback,
rateLimiter,
});
if (authResult.ok) {
@@ -497,6 +507,7 @@ export function createGatewayHttpServer(opts: {
try {
const configSnapshot = loadConfig();
const trustedProxies = configSnapshot.gateway?.trustedProxies ?? [];
const allowRealIpFallback = configSnapshot.gateway?.allowRealIpFallback === true;
const scopedCanvas = normalizeCanvasScopedUrl(req.url ?? "/");
if (scopedCanvas.malformedScopedPath) {
sendGatewayAuthFailure(res, { ok: false, reason: "unauthorized" });
@@ -513,6 +524,7 @@ export function createGatewayHttpServer(opts: {
await handleToolsInvokeHttpRequest(req, res, {
auth: resolvedAuth,
trustedProxies,
allowRealIpFallback,
rateLimiter,
})
) {
@@ -532,6 +544,7 @@ export function createGatewayHttpServer(opts: {
connectAuth: token ? { token, password: token } : null,
req,
trustedProxies,
allowRealIpFallback,
rateLimiter,
});
if (!authResult.ok) {
@@ -549,6 +562,7 @@ export function createGatewayHttpServer(opts: {
auth: resolvedAuth,
config: openResponsesConfig,
trustedProxies,
allowRealIpFallback,
rateLimiter,
})
) {
@@ -560,6 +574,7 @@ export function createGatewayHttpServer(opts: {
await handleOpenAiHttpRequest(req, res, {
auth: resolvedAuth,
trustedProxies,
allowRealIpFallback,
rateLimiter,
})
) {
@@ -572,6 +587,7 @@ export function createGatewayHttpServer(opts: {
req,
auth: resolvedAuth,
trustedProxies,
allowRealIpFallback,
clients,
canvasCapability: scopedCanvas.capability,
malformedScopedPath: scopedCanvas.malformedScopedPath,
@@ -648,10 +664,12 @@ export function attachGatewayUpgradeHandler(opts: {
if (url.pathname === CANVAS_WS_PATH) {
const configSnapshot = loadConfig();
const trustedProxies = configSnapshot.gateway?.trustedProxies ?? [];
const allowRealIpFallback = configSnapshot.gateway?.allowRealIpFallback === true;
const ok = await authorizeCanvasRequest({
req,
auth: resolvedAuth,
trustedProxies,
allowRealIpFallback,
clients,
canvasCapability: scopedCanvas.capability,
malformedScopedPath: scopedCanvas.malformedScopedPath,