From 40e02a418c853b0afd7c6b4326e40f781bbb0c0d Mon Sep 17 00:00:00 2001 From: qingminlong Date: Thu, 2 Jul 2026 09:06:21 +0800 Subject: [PATCH] fix(wizard): reject loose gateway port input (#98689) * fix(wizard): reject loose gateway port input * fix(wizard): reuse shared gateway port parser --- src/wizard/setup.gateway-config.test.ts | 17 ++++++++++++++++- src/wizard/setup.gateway-config.ts | 22 +++++++++++----------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/wizard/setup.gateway-config.test.ts b/src/wizard/setup.gateway-config.test.ts index c8e2a3d4973..de6a5efc185 100644 --- a/src/wizard/setup.gateway-config.test.ts +++ b/src/wizard/setup.gateway-config.test.ts @@ -39,7 +39,14 @@ describe("configureGatewayForSetup", () => { return buildWizardPrompter({ select, - text: vi.fn(async () => textQueue.shift() as string), + text: vi.fn(async (paramsLocal) => { + const value = textQueue.shift() as string; + const error = typeof value === "string" ? paramsLocal.validate?.(value) : undefined; + if (error) { + throw new Error(error); + } + return value; + }), }); } @@ -100,6 +107,14 @@ describe("configureGatewayForSetup", () => { expect(result.nextConfig.gateway?.nodes?.denyCommands).toContain("screen.record"); }); + it.each(["1e3", "0x1000"])("rejects loose gateway port input: %s", async (port) => { + mocks.randomToken.mockReturnValue("generated-token"); + + await expect(runGatewayConfig({ textQueue: [port] })).rejects.toThrow( + "Use a port number from 1 to 65535", + ); + }); + it("prefers OPENCLAW_GATEWAY_TOKEN during quickstart token setup", async () => { const prevToken = process.env.OPENCLAW_GATEWAY_TOKEN; process.env.OPENCLAW_GATEWAY_TOKEN = "token-from-env"; diff --git a/src/wizard/setup.gateway-config.ts b/src/wizard/setup.gateway-config.ts index 51aa78c37c0..1b25fc88ea3 100644 --- a/src/wizard/setup.gateway-config.ts +++ b/src/wizard/setup.gateway-config.ts @@ -1,6 +1,7 @@ // Setup gateway config helpers build gateway config from onboarding answers. import { validateIPv4AddressInput } from "@openclaw/net-policy/ipv4"; import { formatPortRangeHint } from "../cli/error-format.js"; +import { parsePort } from "../cli/shared/parse-port.js"; import { normalizeGatewayTokenInput, randomToken, @@ -62,8 +63,7 @@ function normalizeWizardTextInput(value: unknown): string { } function validateGatewayPortInput(value: unknown): string | undefined { - const port = Number(normalizeWizardTextInput(value)); - if (!Number.isInteger(port) || port < 1 || port > 65_535) { + if (parsePort(value) === null) { return formatPortRangeHint(); } return undefined; @@ -78,16 +78,16 @@ export async function configureGatewayForSetup( const port = flow === "quickstart" ? quickstartGateway.port - : Number.parseInt( - normalizeWizardTextInput( - await prompter.text({ - message: t("wizard.gateway.port"), - initialValue: String(localPort), - validate: validateGatewayPortInput, - }), - ), - 10, + : parsePort( + await prompter.text({ + message: t("wizard.gateway.port"), + initialValue: String(localPort), + validate: validateGatewayPortInput, + }), ); + if (port === null) { + throw new Error(formatPortRangeHint()); + } let bind: GatewayWizardSettings["bind"] = flow === "quickstart"