mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-17 13:55:50 +00:00
* feat: 支持自托管的 remote-control-server (#214) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
209 lines
6.2 KiB
TypeScript
209 lines
6.2 KiB
TypeScript
import { describe, test, expect, beforeEach, afterAll, mock } from "bun:test";
|
|
|
|
// Mock config before imports
|
|
const mockConfig = {
|
|
port: 3000,
|
|
host: "0.0.0.0",
|
|
apiKeys: ["test-api-key"],
|
|
baseUrl: "http://localhost:3000",
|
|
pollTimeout: 8,
|
|
heartbeatInterval: 20,
|
|
jwtExpiresIn: 3600,
|
|
disconnectTimeout: 300,
|
|
};
|
|
|
|
mock.module("../config", () => ({
|
|
config: mockConfig,
|
|
getBaseUrl: () => "http://localhost:3000",
|
|
}));
|
|
|
|
import { Hono } from "hono";
|
|
import { storeReset, storeCreateUser } from "../store";
|
|
import { apiKeyAuth, sessionIngressAuth, uuidAuth, getUuidFromRequest } from "../auth/middleware";
|
|
import { issueToken } from "../auth/token";
|
|
import { generateWorkerJwt } from "../auth/jwt";
|
|
|
|
// Helper: create a test app with middleware and a simple handler
|
|
function createTestApp() {
|
|
const app = new Hono();
|
|
|
|
// Test route for apiKeyAuth
|
|
app.get("/api-key-test", apiKeyAuth, (c) => {
|
|
return c.json({ username: c.get("username") || null });
|
|
});
|
|
|
|
// Test route for sessionIngressAuth
|
|
app.get("/ingress/:id", sessionIngressAuth, (c) => {
|
|
return c.json({ ok: true, jwtPayload: c.get("jwtPayload") || null });
|
|
});
|
|
|
|
// Test route for uuidAuth
|
|
app.get("/uuid-test", uuidAuth, (c) => {
|
|
return c.json({ uuid: c.get("uuid") });
|
|
});
|
|
|
|
// Test route for getUuidFromRequest
|
|
app.get("/uuid-extract", (c) => {
|
|
return c.json({ uuid: getUuidFromRequest(c) });
|
|
});
|
|
|
|
return app;
|
|
}
|
|
|
|
describe("Auth Middleware", () => {
|
|
let app: Hono;
|
|
|
|
beforeEach(() => {
|
|
storeReset();
|
|
app = createTestApp();
|
|
});
|
|
|
|
describe("apiKeyAuth", () => {
|
|
test("accepts valid API key with username header", async () => {
|
|
const res = await app.request("/api-key-test", {
|
|
headers: {
|
|
Authorization: "Bearer test-api-key",
|
|
"X-Username": "alice",
|
|
},
|
|
});
|
|
expect(res.status).toBe(200);
|
|
const body = await res.json();
|
|
expect(body.username).toBe("alice");
|
|
});
|
|
|
|
test("accepts valid API key with username query param", async () => {
|
|
const res = await app.request("/api-key-test?username=bob", {
|
|
headers: { Authorization: "Bearer test-api-key" },
|
|
});
|
|
expect(res.status).toBe(200);
|
|
const body = await res.json();
|
|
expect(body.username).toBe("bob");
|
|
});
|
|
|
|
test("accepts valid session token", async () => {
|
|
storeCreateUser("charlie");
|
|
const { token } = issueToken("charlie");
|
|
const res = await app.request("/api-key-test", {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
expect(res.status).toBe(200);
|
|
const body = await res.json();
|
|
expect(body.username).toBe("charlie");
|
|
});
|
|
|
|
test("rejects invalid token", async () => {
|
|
const res = await app.request("/api-key-test", {
|
|
headers: { Authorization: "Bearer wrong-key" },
|
|
});
|
|
expect(res.status).toBe(401);
|
|
});
|
|
|
|
test("rejects missing token", async () => {
|
|
const res = await app.request("/api-key-test");
|
|
expect(res.status).toBe(401);
|
|
});
|
|
|
|
test("accepts token from query param", async () => {
|
|
storeCreateUser("dave");
|
|
const { token } = issueToken("dave");
|
|
const res = await app.request(`/api-key-test?token=${token}`);
|
|
expect(res.status).toBe(200);
|
|
const body = await res.json();
|
|
expect(body.username).toBe("dave");
|
|
});
|
|
});
|
|
|
|
describe("sessionIngressAuth", () => {
|
|
const originalKeys = process.env.RCS_API_KEYS;
|
|
beforeEach(() => {
|
|
process.env.RCS_API_KEYS = "test-api-key";
|
|
});
|
|
afterAll(() => {
|
|
process.env.RCS_API_KEYS = originalKeys;
|
|
});
|
|
|
|
test("accepts valid API key", async () => {
|
|
const res = await app.request("/ingress/ses_123", {
|
|
headers: { Authorization: "Bearer test-api-key" },
|
|
});
|
|
expect(res.status).toBe(200);
|
|
});
|
|
|
|
test("accepts valid JWT with matching session_id", async () => {
|
|
const jwt = generateWorkerJwt("ses_123", 3600);
|
|
const res = await app.request("/ingress/ses_123", {
|
|
headers: { Authorization: `Bearer ${jwt}` },
|
|
});
|
|
expect(res.status).toBe(200);
|
|
const body = await res.json();
|
|
expect(body.jwtPayload).not.toBeNull();
|
|
expect(body.jwtPayload.session_id).toBe("ses_123");
|
|
});
|
|
|
|
test("rejects JWT with mismatched session_id", async () => {
|
|
const jwt = generateWorkerJwt("ses_456", 3600);
|
|
const res = await app.request("/ingress/ses_123", {
|
|
headers: { Authorization: `Bearer ${jwt}` },
|
|
});
|
|
expect(res.status).toBe(403);
|
|
});
|
|
|
|
test("rejects missing token", async () => {
|
|
const res = await app.request("/ingress/ses_123");
|
|
expect(res.status).toBe(401);
|
|
});
|
|
|
|
test("rejects invalid token", async () => {
|
|
const res = await app.request("/ingress/ses_123", {
|
|
headers: { Authorization: "Bearer invalid" },
|
|
});
|
|
expect(res.status).toBe(401);
|
|
});
|
|
});
|
|
|
|
describe("uuidAuth", () => {
|
|
test("accepts UUID from query param", async () => {
|
|
const res = await app.request("/uuid-test?uuid=test-uuid-1");
|
|
expect(res.status).toBe(200);
|
|
const body = await res.json();
|
|
expect(body.uuid).toBe("test-uuid-1");
|
|
});
|
|
|
|
test("accepts UUID from header", async () => {
|
|
const res = await app.request("/uuid-test", {
|
|
headers: { "X-UUID": "test-uuid-2" },
|
|
});
|
|
expect(res.status).toBe(200);
|
|
const body = await res.json();
|
|
expect(body.uuid).toBe("test-uuid-2");
|
|
});
|
|
|
|
test("rejects missing UUID", async () => {
|
|
const res = await app.request("/uuid-test");
|
|
expect(res.status).toBe(401);
|
|
});
|
|
});
|
|
|
|
describe("getUuidFromRequest", () => {
|
|
test("extracts from query param", async () => {
|
|
const res = await app.request("/uuid-extract?uuid=from-query");
|
|
const body = await res.json();
|
|
expect(body.uuid).toBe("from-query");
|
|
});
|
|
|
|
test("extracts from header", async () => {
|
|
const res = await app.request("/uuid-extract", {
|
|
headers: { "X-UUID": "from-header" },
|
|
});
|
|
const body = await res.json();
|
|
expect(body.uuid).toBe("from-header");
|
|
});
|
|
|
|
test("returns undefined when no UUID", async () => {
|
|
const res = await app.request("/uuid-extract");
|
|
const body = await res.json();
|
|
expect(body.uuid).toBeUndefined();
|
|
});
|
|
});
|
|
});
|