| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- import crypto from "node:crypto";
- import { beforeEach, describe, expect, it, vi } from "vitest";
- // Hoisted mocks
- const mockCookies = vi.hoisted(() => vi.fn());
- const mockHeaders = vi.hoisted(() => vi.fn());
- const mockGetEnvConfig = vi.hoisted(() => vi.fn());
- const mockValidateApiKeyAndGetUser = vi.hoisted(() => vi.fn());
- const mockFindKeyList = vi.hoisted(() => vi.fn());
- const mockReadSession = vi.hoisted(() => vi.fn());
- const mockCookieStore = vi.hoisted(() => ({
- get: vi.fn(),
- set: vi.fn(),
- delete: vi.fn(),
- }));
- const mockHeadersStore = vi.hoisted(() => ({
- get: vi.fn(),
- }));
- const mockConfig = vi.hoisted(() => ({
- auth: { adminToken: "test-admin-token-secret" },
- }));
- vi.mock("next/headers", () => ({
- cookies: mockCookies,
- headers: mockHeaders,
- }));
- vi.mock("@/lib/config/env.schema", () => ({
- getEnvConfig: mockGetEnvConfig,
- }));
- vi.mock("@/repository/key", () => ({
- validateApiKeyAndGetUser: mockValidateApiKeyAndGetUser,
- findKeyList: mockFindKeyList,
- }));
- vi.mock("@/lib/auth-session-store/redis-session-store", () => ({
- RedisSessionStore: class {
- read = mockReadSession;
- create = vi.fn();
- revoke = vi.fn();
- rotate = vi.fn();
- },
- }));
- vi.mock("@/lib/logger", () => ({
- logger: { warn: vi.fn(), error: vi.fn(), info: vi.fn(), debug: vi.fn() },
- }));
- vi.mock("@/lib/config/config", () => ({
- config: mockConfig,
- }));
- function toFingerprint(keyString: string): string {
- return `sha256:${crypto.createHash("sha256").update(keyString, "utf8").digest("hex")}`;
- }
- describe("opaque session with admin token (userId=-1)", () => {
- beforeEach(() => {
- vi.resetModules();
- vi.clearAllMocks();
- mockCookies.mockResolvedValue(mockCookieStore);
- mockHeaders.mockResolvedValue(mockHeadersStore);
- mockHeadersStore.get.mockReturnValue(null);
- mockCookieStore.get.mockReturnValue(undefined);
- mockGetEnvConfig.mockReturnValue({
- SESSION_TOKEN_MODE: "opaque",
- ENABLE_SECURE_COOKIES: false,
- });
- mockReadSession.mockResolvedValue(null);
- mockFindKeyList.mockResolvedValue([]);
- mockValidateApiKeyAndGetUser.mockResolvedValue(null);
- mockConfig.auth.adminToken = "test-admin-token-secret";
- });
- it("resolves admin session from opaque token with userId=-1", async () => {
- const adminToken = "test-admin-token-secret";
- mockCookieStore.get.mockReturnValue({ value: "sid_admin_test" });
- mockReadSession.mockResolvedValue({
- sessionId: "sid_admin_test",
- keyFingerprint: toFingerprint(adminToken),
- userId: -1,
- userRole: "admin",
- createdAt: Date.now() - 1000,
- expiresAt: Date.now() + 86400_000,
- });
- const { getSession } = await import("@/lib/auth");
- const session = await getSession();
- expect(session).not.toBeNull();
- expect(session!.user.id).toBe(-1);
- expect(session!.user.role).toBe("admin");
- expect(session!.key.name).toBe("ADMIN_TOKEN");
- // Must NOT call findKeyList -- virtual admin user has no DB keys
- expect(mockFindKeyList).not.toHaveBeenCalled();
- });
- it("returns null when admin token is not configured but session has userId=-1", async () => {
- mockConfig.auth.adminToken = "";
- mockCookieStore.get.mockReturnValue({ value: "sid_admin_test" });
- mockReadSession.mockResolvedValue({
- sessionId: "sid_admin_test",
- keyFingerprint: toFingerprint("test-admin-token-secret"),
- userId: -1,
- userRole: "admin",
- createdAt: Date.now() - 1000,
- expiresAt: Date.now() + 86400_000,
- });
- const { getSession } = await import("@/lib/auth");
- const session = await getSession();
- expect(session).toBeNull();
- expect(mockFindKeyList).not.toHaveBeenCalled();
- });
- it("returns null when fingerprint does not match admin token", async () => {
- mockCookieStore.get.mockReturnValue({ value: "sid_admin_test" });
- mockReadSession.mockResolvedValue({
- sessionId: "sid_admin_test",
- keyFingerprint: toFingerprint("wrong-token"),
- userId: -1,
- userRole: "admin",
- createdAt: Date.now() - 1000,
- expiresAt: Date.now() + 86400_000,
- });
- const { getSession } = await import("@/lib/auth");
- const session = await getSession();
- expect(session).toBeNull();
- expect(mockFindKeyList).not.toHaveBeenCalled();
- });
- });
|