mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-30 02:10:12 -06:00
Co-authored-by: Paribesh01 <nepalparibesh01@gmail.com> Co-authored-by: Paribesh Nepal <100255987+Paribesh01@users.noreply.github.com>
172 lines
5.4 KiB
TypeScript
172 lines
5.4 KiB
TypeScript
import { env } from "@/lib/env";
|
|
import { beforeEach, describe, expect, test, vi } from "vitest";
|
|
import { prisma } from "@formbricks/database";
|
|
import {
|
|
createEmailChangeToken,
|
|
createEmailToken,
|
|
createInviteToken,
|
|
createToken,
|
|
createTokenForLinkSurvey,
|
|
getEmailFromEmailToken,
|
|
verifyEmailChangeToken,
|
|
verifyInviteToken,
|
|
verifyToken,
|
|
verifyTokenForLinkSurvey,
|
|
} from "./jwt";
|
|
|
|
// Mock environment variables
|
|
vi.mock("@/lib/env", () => ({
|
|
env: {
|
|
ENCRYPTION_KEY: "0".repeat(32), // 32-byte key for AES-256-GCM
|
|
NEXTAUTH_SECRET: "test-nextauth-secret",
|
|
} as typeof env,
|
|
}));
|
|
|
|
// Mock prisma
|
|
vi.mock("@formbricks/database", () => ({
|
|
prisma: {
|
|
user: {
|
|
findUnique: vi.fn(),
|
|
},
|
|
},
|
|
}));
|
|
|
|
describe("JWT Functions", () => {
|
|
const mockUser = {
|
|
id: "test-user-id",
|
|
email: "test@example.com",
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
(prisma.user.findUnique as any).mockResolvedValue(mockUser);
|
|
});
|
|
|
|
describe("createToken", () => {
|
|
test("should create a valid token", () => {
|
|
const token = createToken(mockUser.id, mockUser.email);
|
|
expect(token).toBeDefined();
|
|
expect(typeof token).toBe("string");
|
|
});
|
|
});
|
|
|
|
describe("createTokenForLinkSurvey", () => {
|
|
test("should create a valid survey link token", () => {
|
|
const surveyId = "test-survey-id";
|
|
const token = createTokenForLinkSurvey(surveyId, mockUser.email);
|
|
expect(token).toBeDefined();
|
|
expect(typeof token).toBe("string");
|
|
});
|
|
});
|
|
|
|
describe("createEmailToken", () => {
|
|
test("should create a valid email token", () => {
|
|
const token = createEmailToken(mockUser.email);
|
|
expect(token).toBeDefined();
|
|
expect(typeof token).toBe("string");
|
|
});
|
|
|
|
test("should throw error if NEXTAUTH_SECRET is not set", () => {
|
|
const originalSecret = env.NEXTAUTH_SECRET;
|
|
try {
|
|
(env as any).NEXTAUTH_SECRET = undefined;
|
|
expect(() => createEmailToken(mockUser.email)).toThrow("NEXTAUTH_SECRET is not set");
|
|
} finally {
|
|
(env as any).NEXTAUTH_SECRET = originalSecret;
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("getEmailFromEmailToken", () => {
|
|
test("should extract email from valid token", () => {
|
|
const token = createEmailToken(mockUser.email);
|
|
const extractedEmail = getEmailFromEmailToken(token);
|
|
expect(extractedEmail).toBe(mockUser.email);
|
|
});
|
|
});
|
|
|
|
describe("createInviteToken", () => {
|
|
test("should create a valid invite token", () => {
|
|
const inviteId = "test-invite-id";
|
|
const token = createInviteToken(inviteId, mockUser.email);
|
|
expect(token).toBeDefined();
|
|
expect(typeof token).toBe("string");
|
|
});
|
|
});
|
|
|
|
describe("verifyTokenForLinkSurvey", () => {
|
|
test("should verify valid survey link token", () => {
|
|
const surveyId = "test-survey-id";
|
|
const token = createTokenForLinkSurvey(surveyId, mockUser.email);
|
|
const verifiedEmail = verifyTokenForLinkSurvey(token, surveyId);
|
|
expect(verifiedEmail).toBe(mockUser.email);
|
|
});
|
|
|
|
test("should return null for invalid token", () => {
|
|
const result = verifyTokenForLinkSurvey("invalid-token", "test-survey-id");
|
|
expect(result).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("verifyToken", () => {
|
|
test("should verify valid token", async () => {
|
|
const token = createToken(mockUser.id, mockUser.email);
|
|
const verified = await verifyToken(token);
|
|
expect(verified).toEqual({
|
|
id: mockUser.id,
|
|
email: mockUser.email,
|
|
});
|
|
});
|
|
|
|
test("should throw error if user not found", async () => {
|
|
(prisma.user.findUnique as any).mockResolvedValue(null);
|
|
const token = createToken(mockUser.id, mockUser.email);
|
|
await expect(verifyToken(token)).rejects.toThrow("User not found");
|
|
});
|
|
});
|
|
|
|
describe("verifyInviteToken", () => {
|
|
test("should verify valid invite token", () => {
|
|
const inviteId = "test-invite-id";
|
|
const token = createInviteToken(inviteId, mockUser.email);
|
|
const verified = verifyInviteToken(token);
|
|
expect(verified).toEqual({
|
|
inviteId,
|
|
email: mockUser.email,
|
|
});
|
|
});
|
|
|
|
test("should throw error for invalid token", () => {
|
|
expect(() => verifyInviteToken("invalid-token")).toThrow("Invalid or expired invite token");
|
|
});
|
|
});
|
|
|
|
describe("verifyEmailChangeToken", () => {
|
|
test("should verify and decrypt valid email change token", async () => {
|
|
const userId = "test-user-id";
|
|
const email = "test@example.com";
|
|
const token = createEmailChangeToken(userId, email);
|
|
const result = await verifyEmailChangeToken(token);
|
|
expect(result).toEqual({ id: userId, email });
|
|
});
|
|
|
|
test("should throw error if token is invalid or missing fields", async () => {
|
|
// Create a token with missing fields
|
|
const jwt = await import("jsonwebtoken");
|
|
const token = jwt.sign({ foo: "bar" }, env.NEXTAUTH_SECRET as string);
|
|
await expect(verifyEmailChangeToken(token)).rejects.toThrow(
|
|
"Token is invalid or missing required fields"
|
|
);
|
|
});
|
|
|
|
test("should return original id/email if decryption fails", async () => {
|
|
// Create a token with non-encrypted id/email
|
|
const jwt = await import("jsonwebtoken");
|
|
const payload = { id: "plain-id", email: "plain@example.com" };
|
|
const token = jwt.sign(payload, env.NEXTAUTH_SECRET as string);
|
|
const result = await verifyEmailChangeToken(token);
|
|
expect(result).toEqual(payload);
|
|
});
|
|
});
|
|
});
|