fix: harden gateway auth defaults

This commit is contained in:
Peter Steinberger
2026-01-26 18:18:55 +00:00
parent ab73aceb27
commit 3314b3996e
8 changed files with 65 additions and 151 deletions

View File

@@ -122,6 +122,18 @@ describe("gateway server auth/connect", () => {
await new Promise<void>((resolve) => ws.once("close", () => resolve()));
});
test("requires nonce when host is non-local", async () => {
const ws = new WebSocket(`ws://127.0.0.1:${port}`, {
headers: { host: "example.com" },
});
await new Promise<void>((resolve) => ws.once("open", resolve));
const res = await connectReq(ws);
expect(res.ok).toBe(false);
expect(res.error?.message).toBe("device nonce required");
await new Promise<void>((resolve) => ws.once("close", () => resolve()));
});
test(
"invalid connect params surface in response and close reason",
{ timeout: 60_000 },
@@ -290,6 +302,7 @@ describe("gateway server auth/connect", () => {
test("allows control ui with device identity when insecure auth is enabled", async () => {
testState.gatewayControlUi = { allowInsecureAuth: true };
testState.gatewayAuth = { mode: "token", token: "secret" };
const { writeConfigFile } = await import("../config/config.js");
await writeConfigFile({
gateway: {
@@ -354,6 +367,7 @@ describe("gateway server auth/connect", () => {
test("allows control ui with stale device identity when device auth is disabled", async () => {
testState.gatewayControlUi = { dangerouslyDisableDeviceAuth: true };
testState.gatewayAuth = { mode: "token", token: "secret" };
const prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN;
process.env.CLAWDBOT_GATEWAY_TOKEN = "secret";
const port = await getFreePort();
@@ -399,28 +413,6 @@ describe("gateway server auth/connect", () => {
}
});
test("rejects proxied connections without auth when proxy headers are untrusted", async () => {
testState.gatewayAuth = { mode: "none" };
const prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
const port = await getFreePort();
const server = await startGatewayServer(port);
const ws = new WebSocket(`ws://127.0.0.1:${port}`, {
headers: { "x-forwarded-for": "203.0.113.10" },
});
await new Promise<void>((resolve) => ws.once("open", resolve));
const res = await connectReq(ws, { skipDefaultAuth: true });
expect(res.ok).toBe(false);
expect(res.error?.message ?? "").toContain("gateway auth required");
ws.close();
await server.close();
if (prevToken === undefined) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken;
}
});
test("accepts device token auth for paired device", async () => {
const { loadOrCreateDeviceIdentity } = await import("../infra/device-identity.js");
const { approveDevicePairing, getPairedDevice, listDevicePairing } =