import { beforeEach, describe, expect, it, vi } from "vitest"; import { env } from "@/env"; import { checkLogin } from "@/lib/auth/password"; import { prisma } from "@/lib/prisma"; import { clientIp, rateLimit } from "@/lib/rate-limit"; import { captchaConfig, verifyCaptcha } from "@/lib/services/captcha"; import { siteSettings } from "@/lib/services/site-settings"; import { precheckLogin } from "./auth-precheck"; vi.mock("@/env", () => ({ env: { CONVERT_PASSWORDS: false } })); vi.mock("@/lib/auth/password", () => ({ checkLogin: vi.fn() })); vi.mock("@/lib/prisma", () => ({ prisma: { user: { findUnique: vi.fn() } } })); vi.mock("@/lib/rate-limit", () => ({ clientIp: vi.fn(), rateLimit: vi.fn() })); vi.mock("@/lib/services/captcha", () => ({ captchaConfig: vi.fn(), verifyCaptcha: vi.fn(), })); vi.mock("@/lib/services/site-settings", () => ({ siteSettings: { getBool: vi.fn() }, })); beforeEach(() => { vi.clearAllMocks(); vi.mocked(clientIp).mockResolvedValue("1.2.3.4"); vi.mocked(rateLimit).mockResolvedValue({ ok: true }); vi.mocked(checkLogin).mockResolvedValue({ valid: true } as never); vi.mocked(captchaConfig).mockResolvedValue({ provider: "none" } as never); }); describe("precheckLogin", () => { it("returns ok for valid login without 2FA", async () => { vi.mocked(prisma.user.findUnique).mockResolvedValue({ password: "hash", twoFactorConfirmedAt: null, mail: null, mailVerified: "0", } as never); expect(await precheckLogin("user", "pass")).toBe("ok"); }); it("returns twofactor when 2FA is set up", async () => { vi.mocked(prisma.user.findUnique).mockResolvedValue({ password: "hash", twoFactorConfirmedAt: new Date(), mail: null, mailVerified: "0", } as never); expect(await precheckLogin("user", "pass")).toBe("twofactor"); }); it("returns invalid for empty inputs", async () => { expect(await precheckLogin("", "")).toBe("invalid"); }); it("returns captcha when captcha required", async () => { vi.mocked(captchaConfig).mockResolvedValue({ provider: "hcaptcha", } as never); vi.mocked(verifyCaptcha).mockResolvedValue(false); vi.mocked(prisma.user.findUnique).mockResolvedValue({ password: "hash", twoFactorConfirmedAt: null, mail: null, mailVerified: "0", } as never); expect(await precheckLogin("user", "pass", "bad-token")).toBe("captcha"); }); it("returns invalid when user not found (dummy hash check)", async () => { vi.mocked(prisma.user.findUnique).mockResolvedValue(null); const result = await precheckLogin("nonexistent", "pass"); expect(result).toBe("invalid"); expect(checkLogin).toHaveBeenCalled(); }); it("returns unverified when email verification required", async () => { vi.mocked(prisma.user.findUnique).mockResolvedValue({ password: "hash", twoFactorConfirmedAt: null, mail: "user@example.com", mailVerified: "0", } as never); vi.mocked(siteSettings.getBool).mockResolvedValue(true); expect(await precheckLogin("user", "pass")).toBe("unverified"); }); });