diff --git a/scripts/e2e/telegram-user-crabbox-proof.ts b/scripts/e2e/telegram-user-crabbox-proof.ts index c9980402144a..a3d009660deb 100644 --- a/scripts/e2e/telegram-user-crabbox-proof.ts +++ b/scripts/e2e/telegram-user-crabbox-proof.ts @@ -227,11 +227,25 @@ function trimToValue(value: string | undefined) { return trimmed && trimmed.length > 0 ? trimmed : undefined; } +const positiveIntegerPattern = /^[1-9]\d*$/u; + function parsePositiveInteger(value: string, label: string) { - const parsed = Number(value); - if (!Number.isInteger(parsed) || parsed < 1) { + const trimmed = value.trim(); + if (!positiveIntegerPattern.test(trimmed)) { throw new Error(`${label} must be a positive integer.`); } + const parsed = Number(trimmed); + if (!Number.isSafeInteger(parsed)) { + throw new Error(`${label} must be a positive integer.`); + } + return parsed; +} + +function parseTcpPort(value: string, label: string) { + const parsed = parsePositiveInteger(value, label); + if (parsed > 65_535) { + throw new Error(`${label} must be a TCP port from 1 to 65535.`); + } return parsed; } @@ -314,7 +328,7 @@ function parseArgs(argvInput: string[]): Options { } opts.expect.push(readValue()); } else if (arg === "--gateway-port") { - opts.gatewayPort = parsePositiveInteger(readValue(), "--gateway-port"); + opts.gatewayPort = parseTcpPort(readValue(), "--gateway-port"); } else if (arg === "--id") { opts.leaseId = readValue(); } else if (arg === "--idle-timeout") { @@ -322,7 +336,7 @@ function parseArgs(argvInput: string[]): Options { } else if (arg === "--keep-box") { opts.keepBox = true; } else if (arg === "--mock-port") { - opts.mockPort = parsePositiveInteger(readValue(), "--mock-port"); + opts.mockPort = parseTcpPort(readValue(), "--mock-port"); } else if (arg === "--mock-response-file") { opts.mockResponseText = fs.readFileSync(resolveRepoPath(process.cwd(), readValue()), "utf8"); } else if (arg === "--message-id") { diff --git a/test/scripts/telegram-user-crabbox-proof.test.ts b/test/scripts/telegram-user-crabbox-proof.test.ts index 2c690bf3ac7d..ec4a35d715d8 100644 --- a/test/scripts/telegram-user-crabbox-proof.test.ts +++ b/test/scripts/telegram-user-crabbox-proof.test.ts @@ -1,4 +1,5 @@ // Telegram User Crabbox Proof tests cover telegram user crabbox proof script behavior. +import { spawnSync } from "node:child_process"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; @@ -39,6 +40,22 @@ function writeExecutable(pathname: string, content: string): void { fs.writeFileSync(pathname, content, { mode: 0o755 }); } +function runProofCli(args: string[]) { + return spawnSync( + process.execPath, + ["--import", "tsx", "scripts/e2e/telegram-user-crabbox-proof.ts", ...args], + { + cwd: process.cwd(), + encoding: "utf8", + env: { + ...process.env, + GIT_CONFIG_NOSYSTEM: "1", + GIT_TERMINAL_PROMPT: "0", + }, + }, + ); +} + async function waitFor(predicate: () => boolean, timeoutMs = 5_000): Promise { const started = Date.now(); while (Date.now() - started < timeoutMs) { @@ -101,6 +118,20 @@ describe("telegram user Crabbox proof log polling", () => { ).toBe(4096); }); + it("rejects loose and out-of-range proof ports before remote setup", () => { + const looseGatewayPort = runProofCli(["--gateway-port", "1e3", "--dry-run"]); + expect(looseGatewayPort.status).toBe(1); + expect(looseGatewayPort.stderr).toContain("--gateway-port must be a positive integer."); + + const highGatewayPort = runProofCli(["--gateway-port", "65536", "--dry-run"]); + expect(highGatewayPort.status).toBe(1); + expect(highGatewayPort.stderr).toContain("--gateway-port must be a TCP port from 1 to 65535."); + + const highMockPort = runProofCli(["--mock-port", "65536", "--dry-run"]); + expect(highMockPort.status).toBe(1); + expect(highMockPort.stderr).toContain("--mock-port must be a TCP port from 1 to 65535."); + }); + it("reads only the requested log tail", () => { const logPath = path.join(makeTempDir(), "gateway.log"); fs.writeFileSync(logPath, `${"old\n".repeat(2000)}ready\n`, "utf8");