45 lines
1.8 KiB
TypeScript
45 lines
1.8 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import type { User } from "../drizzle/schema";
|
|
|
|
vi.mock("./db", () => ({ getUserById: vi.fn() }));
|
|
|
|
import * as db from "./db";
|
|
import { authenticateRequest, createSessionToken } from "./_core/auth";
|
|
import { ENV } from "./_core/env";
|
|
import { COOKIE_NAME } from "../shared/const";
|
|
|
|
function user(overrides: Partial<User> = {}): User {
|
|
const now = new Date();
|
|
return { id: 7, username: "session-user", passwordHash: "unused", name: "Session User", email: null, role: "user", isActive: 1, mustChangePassword: 0, sessionVersion: 3, createdAt: now, updatedAt: now, lastLoginAt: null, ...overrides };
|
|
}
|
|
|
|
function requestWith(token: string) {
|
|
return { headers: { cookie: `${COOKIE_NAME}=${token}` } } as Parameters<typeof authenticateRequest>[0];
|
|
}
|
|
|
|
describe("会话即时失效", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
ENV.cookieSecret = "test-session-secret-with-at-least-32-chars";
|
|
});
|
|
|
|
it("有效账号与匹配版本可恢复会话", async () => {
|
|
const current = user();
|
|
vi.mocked(db.getUserById).mockResolvedValue(current);
|
|
const token = await createSessionToken(current);
|
|
await expect(authenticateRequest(requestWith(token))).resolves.toMatchObject({ id: 7, sessionVersion: 3 });
|
|
});
|
|
|
|
it("改密或重置密码递增版本后旧会话立即失效", async () => {
|
|
const token = await createSessionToken(user());
|
|
vi.mocked(db.getUserById).mockResolvedValue(user({ sessionVersion: 4 }));
|
|
await expect(authenticateRequest(requestWith(token))).resolves.toBeNull();
|
|
});
|
|
|
|
it("账号被禁用后旧会话立即失效", async () => {
|
|
const token = await createSessionToken(user());
|
|
vi.mocked(db.getUserById).mockResolvedValue(user({ isActive: 0 }));
|
|
await expect(authenticateRequest(requestWith(token))).resolves.toBeNull();
|
|
});
|
|
});
|