OpenClawBot / src /gateway /auth.test.ts
darkfire514's picture
Upload 189 files
0c95196 verified
import { describe, expect, it } from "vitest";
import crypto from "node:crypto";
import { authorizeGatewayConnect } from "./auth.js";
describe("gateway auth", () => {
it("does not throw when req is missing socket", async () => {
const res = await authorizeGatewayConnect({
auth: { mode: "token", token: "secret", allowTailscale: false },
connectAuth: { token: "secret" },
// Regression: avoid crashing on req.socket.remoteAddress when callers pass a non-IncomingMessage.
req: {} as never,
});
expect(res.ok).toBe(true);
});
it("reports missing and mismatched token reasons", async () => {
const missing = await authorizeGatewayConnect({
auth: { mode: "token", token: "secret", allowTailscale: false },
connectAuth: null,
});
expect(missing.ok).toBe(false);
expect(missing.reason).toBe("token_missing");
const mismatch = await authorizeGatewayConnect({
auth: { mode: "token", token: "secret", allowTailscale: false },
connectAuth: { token: "wrong" },
});
expect(mismatch.ok).toBe(false);
expect(mismatch.reason).toBe("token_mismatch");
});
it("reports missing token config reason", async () => {
const res = await authorizeGatewayConnect({
auth: { mode: "token", allowTailscale: false },
connectAuth: { token: "anything" },
});
expect(res.ok).toBe(false);
expect(res.reason).toBe("token_missing_config");
});
it("reports missing and mismatched password reasons", async () => {
const missing = await authorizeGatewayConnect({
auth: { mode: "password", password: "secret", allowTailscale: false },
connectAuth: null,
});
expect(missing.ok).toBe(false);
expect(missing.reason).toBe("password_missing");
const mismatch = await authorizeGatewayConnect({
auth: { mode: "password", password: "secret", allowTailscale: false },
connectAuth: { password: "wrong" },
});
expect(mismatch.ok).toBe(false);
expect(mismatch.reason).toBe("password_mismatch");
});
it("reports missing password config reason", async () => {
const res = await authorizeGatewayConnect({
auth: { mode: "password", allowTailscale: false },
connectAuth: { password: "secret" },
});
expect(res.ok).toBe(false);
expect(res.reason).toBe("password_missing_config");
});
it("treats local tailscale serve hostnames as direct", async () => {
const res = await authorizeGatewayConnect({
auth: { mode: "token", token: "secret", allowTailscale: true },
connectAuth: { token: "secret" },
req: {
socket: { remoteAddress: "127.0.0.1" },
headers: { host: "gateway.tailnet-1234.ts.net:443" },
} as never,
});
expect(res.ok).toBe(true);
expect(res.method).toBe("token");
});
it("allows tailscale identity to satisfy token mode auth", async () => {
const res = await authorizeGatewayConnect({
auth: { mode: "token", token: "secret", allowTailscale: true },
connectAuth: null,
tailscaleWhois: async () => ({ login: "peter", name: "Peter" }),
req: {
socket: { remoteAddress: "127.0.0.1" },
headers: {
host: "gateway.local",
"x-forwarded-for": "100.64.0.1",
"x-forwarded-proto": "https",
"x-forwarded-host": "ai-hub.bone-egret.ts.net",
"tailscale-user-login": "peter",
"tailscale-user-name": "Peter",
},
} as never,
});
expect(res.ok).toBe(true);
expect(res.method).toBe("tailscale");
expect(res.user).toBe("peter");
});
it("allows Control UI oauth session cookie to satisfy token mode auth", async () => {
const prevEnv = {
OPENCLAW_CONTROL_UI_GOOGLE_CLIENT_ID: process.env.OPENCLAW_CONTROL_UI_GOOGLE_CLIENT_ID,
OPENCLAW_CONTROL_UI_GOOGLE_CLIENT_SECRET: process.env.OPENCLAW_CONTROL_UI_GOOGLE_CLIENT_SECRET,
OPENCLAW_CONTROL_UI_SESSION_SECRET: process.env.OPENCLAW_CONTROL_UI_SESSION_SECRET,
OPENCLAW_CONTROL_UI_ALLOWED_GOOGLE_EMAILS: process.env.OPENCLAW_CONTROL_UI_ALLOWED_GOOGLE_EMAILS,
};
try {
process.env.OPENCLAW_CONTROL_UI_GOOGLE_CLIENT_ID = "cid";
process.env.OPENCLAW_CONTROL_UI_GOOGLE_CLIENT_SECRET = "csecret";
process.env.OPENCLAW_CONTROL_UI_SESSION_SECRET = "session-secret";
process.env.OPENCLAW_CONTROL_UI_ALLOWED_GOOGLE_EMAILS = "admin@example.com";
const payload = {
v: 1,
exp: Math.floor(Date.now() / 1000) + 60,
provider: "google",
sub: "sub-1",
email: "admin@example.com",
};
const body = Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
const sig = crypto.createHmac("sha256", "session-secret").update(body).digest("base64url");
const cookieToken = `${body}.${sig}`;
const res = await authorizeGatewayConnect({
auth: { mode: "token", token: "gateway-token", allowTailscale: false },
connectAuth: null,
client: { id: "openclaw-control-ui", version: "test", platform: "web", mode: "webchat" },
req: {
socket: { remoteAddress: "203.0.113.1" },
headers: { host: "example.com", cookie: `openclaw_ui_session=${encodeURIComponent(cookieToken)}` },
} as never,
});
expect(res.ok).toBe(true);
expect(res.method).toBe("control-ui-oauth");
expect(res.user).toBe("admin@example.com");
} finally {
process.env.OPENCLAW_CONTROL_UI_GOOGLE_CLIENT_ID = prevEnv.OPENCLAW_CONTROL_UI_GOOGLE_CLIENT_ID;
process.env.OPENCLAW_CONTROL_UI_GOOGLE_CLIENT_SECRET = prevEnv.OPENCLAW_CONTROL_UI_GOOGLE_CLIENT_SECRET;
process.env.OPENCLAW_CONTROL_UI_SESSION_SECRET = prevEnv.OPENCLAW_CONTROL_UI_SESSION_SECRET;
process.env.OPENCLAW_CONTROL_UI_ALLOWED_GOOGLE_EMAILS = prevEnv.OPENCLAW_CONTROL_UI_ALLOWED_GOOGLE_EMAILS;
}
});
});