import { describe, expect, it } from "vitest"; import { sanitizeRconOutput, validateRconCommand, validateRconConnection } from "./rcon-validation"; describe("RCON validation", () => { it("normalizes any valid DNS hostname and port without deployment configuration", () => { expect(validateRconConnection({ name: " Season 4 ", host: "SEASON4.SOMC.SVC.CLUSTER.LOCAL", port: "25575", password: "correct horse battery staple", }, { passwordRequired: true })).toEqual({ name: "Season 4", host: "season4.somc.svc.cluster.local", port: 25575, password: "correct horse battery staple", }); expect(validateRconConnection({ name: "Creative", host: "creative.example.net", port: "43210", password: "secret", }, { passwordRequired: true })).toEqual({ name: "Creative", host: "creative.example.net", port: 43210, password: "secret", }); }); it("rejects IP literals and malformed DNS hostnames", () => { for (const host of ["10.0.0.1", "2001:db8::1", "season4.", "-season4.example", "season4..example"]) { expect(validateRconConnection({ name: "Server", host, port: "25575", password: "secret" }, { passwordRequired: true, })).toBeNull(); } }); it("allows a blank replacement password only while editing", () => { expect(validateRconConnection({ name: "Server", host: "season4.somc.svc.cluster.local", port: "25575", password: "" }, { passwordRequired: false, })?.password).toBeNull(); expect(validateRconConnection({ name: "Server", host: "season4.somc.svc.cluster.local", port: "25575", password: "" }, { passwordRequired: true, })).toBeNull(); }); it("bounds commands by UTF-8 bytes and rejects control characters", () => { expect(validateRconCommand(" list ")).toBe("list"); expect(validateRconCommand("say first\nsay second")).toBeNull(); expect(validateRconCommand("say \u001b[31mred")).toBeNull(); expect(validateRconCommand(`say ${"😀".repeat(300)}`)).toBeNull(); }); it("strips output controls and bounds output by UTF-8 bytes", () => { expect(sanitizeRconOutput("ok\u001b[31mred\u0000done")).toBe("ok[31mreddone"); expect(Buffer.byteLength(sanitizeRconOutput("😀".repeat(20_000)), "utf8")).toBeLessThanOrEqual(65_536); }); });