diff --git a/src/gateway/server-http.ts b/src/gateway/server-http.ts index fea650fd3..ad3a0e305 100644 --- a/src/gateway/server-http.ts +++ b/src/gateway/server-http.ts @@ -80,6 +80,11 @@ type HookDispatchers = { dispatchAgentHook: (value: HookAgentDispatchPayload) => string; }; +export type HookClientIpConfig = Readonly<{ + trustedProxies?: string[]; + allowRealIpFallback?: boolean; +}>; + function sendJson(res: ServerResponse, status: number, body: unknown) { res.statusCode = status; res.setHeader("Content-Type", "application/json; charset=utf-8"); @@ -352,10 +357,7 @@ export function createHooksRequestHandler( bindHost: string; port: number; logHooks: SubsystemLogger; - getClientIpConfig?: () => { - trustedProxies?: string[]; - allowRealIpFallback?: boolean; - }; + getClientIpConfig?: () => HookClientIpConfig; } & HookDispatchers, ): HooksRequestHandler { const { getHooksConfig, logHooks, dispatchAgentHook, dispatchWakeHook, getClientIpConfig } = opts; diff --git a/src/gateway/server-reload-handlers.ts b/src/gateway/server-reload-handlers.ts index 73e8129e1..f9cfb9111 100644 --- a/src/gateway/server-reload-handlers.ts +++ b/src/gateway/server-reload-handlers.ts @@ -22,9 +22,12 @@ import type { GatewayReloadPlan } from "./config-reload.js"; import { resolveHooksConfig } from "./hooks.js"; import { startBrowserControlServerIfEnabled } from "./server-browser.js"; import { buildGatewayCronService, type GatewayCronState } from "./server-cron.js"; +import type { HookClientIpConfig } from "./server-http.js"; +import { resolveHookClientIpConfig } from "./server/hooks.js"; type GatewayHotReloadState = { hooksConfig: ReturnType; + hookClientIpConfig: HookClientIpConfig; heartbeatRunner: HeartbeatRunner; cronState: GatewayCronState; browserControl: Awaited> | null; @@ -64,6 +67,7 @@ export function createGatewayReloadHandlers(params: { params.logHooks.warn(`hooks config reload failed: ${String(err)}`); } } + nextState.hookClientIpConfig = resolveHookClientIpConfig(nextConfig); if (plan.restartHeartbeat) { nextState.heartbeatRunner.updateConfig(nextConfig); diff --git a/src/gateway/server-runtime-state.ts b/src/gateway/server-runtime-state.ts index 52832de93..a569b896e 100644 --- a/src/gateway/server-runtime-state.ts +++ b/src/gateway/server-runtime-state.ts @@ -23,7 +23,11 @@ import { createToolEventRecipientRegistry, } from "./server-chat.js"; import { MAX_PREAUTH_PAYLOAD_BYTES } from "./server-constants.js"; -import { attachGatewayUpgradeHandler, createGatewayHttpServer } from "./server-http.js"; +import { + attachGatewayUpgradeHandler, + createGatewayHttpServer, + type HookClientIpConfig, +} from "./server-http.js"; import type { DedupeEntry } from "./server-shared.js"; import { createGatewayHooksRequestHandler } from "./server/hooks.js"; import { listenGatewayHttpServer } from "./server/http-listen.js"; @@ -53,6 +57,7 @@ export async function createGatewayRuntimeState(params: { rateLimiter?: AuthRateLimiter; gatewayTls?: GatewayTlsRuntime; hooksConfig: () => HooksConfigResolved | null; + getHookClientIpConfig: () => HookClientIpConfig; pluginRegistry: PluginRegistry; deps: CliDeps; canvasRuntime: RuntimeEnv; @@ -113,6 +118,7 @@ export async function createGatewayRuntimeState(params: { const handleHooksRequest = createGatewayHooksRequestHandler({ deps: params.deps, getHooksConfig: params.hooksConfig, + getClientIpConfig: params.getHookClientIpConfig, bindHost: params.bindHost, port: params.port, logHooks: params.logHooks, diff --git a/src/gateway/server.impl.ts b/src/gateway/server.impl.ts index 898cdc6fe..9b3941d14 100644 --- a/src/gateway/server.impl.ts +++ b/src/gateway/server.impl.ts @@ -107,6 +107,7 @@ import { incrementPresenceVersion, refreshGatewayHealthSnapshot, } from "./server/health-state.js"; +import { resolveHookClientIpConfig } from "./server/hooks.js"; import { createReadinessChecker } from "./server/readiness.js"; import { loadGatewayTlsRuntime } from "./server/tls.js"; import { @@ -511,6 +512,7 @@ export async function startGatewayServer( tailscaleMode, } = runtimeConfig; let hooksConfig = runtimeConfig.hooksConfig; + let hookClientIpConfig = resolveHookClientIpConfig(cfgAtStart); const canvasHostEnabled = runtimeConfig.canvasHostEnabled; // Create auth rate limiters used by connect/auth flows. @@ -613,6 +615,7 @@ export async function startGatewayServer( rateLimiter: authRateLimiter, gatewayTls, hooksConfig: () => hooksConfig, + getHookClientIpConfig: () => hookClientIpConfig, pluginRegistry, deps, canvasRuntime, @@ -954,6 +957,7 @@ export async function startGatewayServer( broadcast, getState: () => ({ hooksConfig, + hookClientIpConfig, heartbeatRunner, cronState, browserControl, @@ -961,6 +965,7 @@ export async function startGatewayServer( }), setState: (nextState) => { hooksConfig = nextState.hooksConfig; + hookClientIpConfig = nextState.hookClientIpConfig; heartbeatRunner = nextState.heartbeatRunner; cronState = nextState.cronState; cron = cronState.cron; diff --git a/src/gateway/server/hooks.ts b/src/gateway/server/hooks.ts index 8630ef008..0ba718adc 100644 --- a/src/gateway/server/hooks.ts +++ b/src/gateway/server/hooks.ts @@ -1,6 +1,6 @@ import { randomUUID } from "node:crypto"; import type { CliDeps } from "../../cli/deps.js"; -import { loadConfig } from "../../config/config.js"; +import { loadConfig, type OpenClawConfig } from "../../config/config.js"; import { resolveMainSessionKeyFromConfig } from "../../config/sessions.js"; import { runCronIsolatedAgentTurn } from "../../cron/isolated-agent.js"; import type { CronJob } from "../../cron/types.js"; @@ -12,18 +12,26 @@ import { type HookAgentDispatchPayload, type HooksConfigResolved, } from "../hooks.js"; -import { createHooksRequestHandler } from "../server-http.js"; +import { createHooksRequestHandler, type HookClientIpConfig } from "../server-http.js"; type SubsystemLogger = ReturnType; +export function resolveHookClientIpConfig(cfg: OpenClawConfig): HookClientIpConfig { + return { + trustedProxies: cfg.gateway?.trustedProxies, + allowRealIpFallback: cfg.gateway?.allowRealIpFallback === true, + }; +} + export function createGatewayHooksRequestHandler(params: { deps: CliDeps; getHooksConfig: () => HooksConfigResolved | null; + getClientIpConfig: () => HookClientIpConfig; bindHost: string; port: number; logHooks: SubsystemLogger; }) { - const { deps, getHooksConfig, bindHost, port, logHooks } = params; + const { deps, getHooksConfig, getClientIpConfig, bindHost, port, logHooks } = params; const dispatchWakeHook = (value: { text: string; mode: "now" | "next-heartbeat" }) => { const sessionKey = resolveMainSessionKeyFromConfig(); @@ -108,13 +116,7 @@ export function createGatewayHooksRequestHandler(params: { bindHost, port, logHooks, - getClientIpConfig: () => { - const cfg = loadConfig(); - return { - trustedProxies: cfg.gateway?.trustedProxies, - allowRealIpFallback: cfg.gateway?.allowRealIpFallback === true, - }; - }, + getClientIpConfig, dispatchAgentHook, dispatchWakeHook, });