Files
community-rule/tests/unit/authMagicLinkVerifyRoute.test.ts
adilalloandCursor f780eac1fa Encode sign-in mail as base64 so webmail cannot mangle the verify token.
Quoted-printable still rewrote token= as token=3D in the raw MIME, which some clients never decode. Distinguish a missing token from a real expiry, and keep links valid for 60 minutes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-01 17:07:00 -06:00

92 lines
2.9 KiB
TypeScript

import { NextRequest } from "next/server";
import { beforeEach, describe, expect, it, vi } from "vitest";
const isDatabaseConfiguredMock = vi.fn();
const getSessionPepperMock = vi.fn();
const hashSessionTokenMock = vi.fn();
const findUniqueMock = vi.fn();
const deleteMock = vi.fn();
const upsertMock = vi.fn();
const createSessionForUserMock = vi.fn();
const setSessionCookieMock = vi.fn();
vi.mock("../../lib/server/env", () => ({
isDatabaseConfigured: () => isDatabaseConfiguredMock(),
getSessionPepper: () => getSessionPepperMock(),
}));
vi.mock("../../lib/server/hash", () => ({
hashSessionToken: (...args: unknown[]) => hashSessionTokenMock(...args),
}));
vi.mock("../../lib/server/session", () => ({
createSessionForUser: (...args: unknown[]) =>
createSessionForUserMock(...args),
setSessionCookie: (...args: unknown[]) => setSessionCookieMock(...args),
}));
vi.mock("../../lib/server/db", () => ({
prisma: {
magicLinkToken: {
findUnique: (...args: unknown[]) => findUniqueMock(...args),
delete: (...args: unknown[]) => deleteMock(...args),
},
user: {
upsert: (...args: unknown[]) => upsertMock(...args),
},
},
}));
import { GET } from "../../app/api/auth/magic-link/verify/route";
beforeEach(() => {
isDatabaseConfiguredMock.mockReset();
getSessionPepperMock.mockReset();
hashSessionTokenMock.mockReset();
findUniqueMock.mockReset();
deleteMock.mockReset();
upsertMock.mockReset();
createSessionForUserMock.mockReset();
setSessionCookieMock.mockReset();
isDatabaseConfiguredMock.mockReturnValue(true);
getSessionPepperMock.mockReturnValue("pepper");
hashSessionTokenMock.mockReturnValue("token-hash");
});
function getWithToken(token: string) {
return new NextRequest(
`https://x.test/api/auth/magic-link/verify?token=${encodeURIComponent(token)}`,
);
}
describe("GET /api/auth/magic-link/verify", () => {
it("redirects with invalid_link when the token is missing", async () => {
const res = await GET(
new NextRequest("https://x.test/api/auth/magic-link/verify"),
);
expect(res.status).toBe(307);
expect(res.headers.get("location")).toContain("error=invalid_link");
});
it("redirects with invalid_link when no row matches", async () => {
findUniqueMock.mockResolvedValue(null);
const res = await GET(getWithToken("a-token-value-long-enough"));
expect(res.status).toBe(307);
expect(res.headers.get("location")).toContain("error=invalid_link");
});
it("redirects with expired_link when the row is past expiresAt", async () => {
findUniqueMock.mockResolvedValue({
id: "row-1",
email: "a@b.c",
expiresAt: new Date(Date.now() - 1000),
nextPath: null,
draftPayload: null,
});
const res = await GET(getWithToken("a-token-value-long-enough"));
expect(res.status).toBe(307);
expect(res.headers.get("location")).toContain("error=expired_link");
});
});