diff --git a/lib/auth/__tests__/validation.test.ts b/lib/auth/__tests__/validation.test.ts index 91fb10a..38dd18a 100644 --- a/lib/auth/__tests__/validation.test.ts +++ b/lib/auth/__tests__/validation.test.ts @@ -179,4 +179,58 @@ describe("resetPasswordSchema", () => { }) expect(result.success).toBe(false) }) +}) + +describe("signupSchema — domain block", () => { + it("rejects @deckyvault.xyz email when NODE_ENV is not development", () => { + const result = signupSchema.safeParse({ + name: "Test User", + email: "user@deckyvault.xyz", + password: "abcdefghij", + }) + expect(result.success).toBe(false) + if (!result.success) { + const emailIssues = result.error.issues.filter( + (i) => i.path[0] === "email" + ) + expect(emailIssues.length).toBeGreaterThan(0) + expect(emailIssues[0].message).toContain("deckyvault.xyz") + } + }) + + it("rejects @DECKYVAULT.XYZ email (uppercase) when not in dev", () => { + const result = signupSchema.safeParse({ + name: "Test User", + email: "admin@DECKYVAULT.XYZ", + password: "abcdefghij", + }) + expect(result.success).toBe(false) + }) + + it("rejects @deckyvault.xyz with plus addressing when not in dev", () => { + const result = signupSchema.safeParse({ + name: "Test User", + email: "user+spam@deckyvault.xyz", + password: "abcdefghij", + }) + expect(result.success).toBe(false) + }) + + it("accepts @gmail.com email (non-deckyvault domain)", () => { + const result = signupSchema.safeParse({ + name: "Test User", + email: "user@gmail.com", + password: "abcdefghij", + }) + expect(result.success).toBe(true) + }) + + it("accepts valid email from any non-deckyvault domain", () => { + const result = signupSchema.safeParse({ + name: "Test User", + email: "hello@outlook.com", + password: "abcdefghij", + }) + expect(result.success).toBe(true) + }) }) \ No newline at end of file diff --git a/lib/auth/validation.ts b/lib/auth/validation.ts index f173e37..3267328 100644 --- a/lib/auth/validation.ts +++ b/lib/auth/validation.ts @@ -1,4 +1,5 @@ import { z } from "zod" +import { isDeckyVaultEmail, DOMAIN_BLOCK_ERROR } from "./domain-block" export const loginEmailSchema = z.object({ email: z.string().email("Please enter a valid email address"), @@ -9,16 +10,26 @@ export const loginSchema = z.object({ password: z.string().min(1, "Password is required"), }) -export const signupSchema = z.object({ - name: z - .string() - .min(1, "Name is required") - .max(100, "Name must be 100 characters or less"), - email: z.string().email("Please enter a valid email address"), - password: z - .string() - .min(10, "Password must be at least 10 characters"), -}) +export const signupSchema = z + .object({ + name: z + .string() + .min(1, "Name is required") + .max(100, "Name must be 100 characters or less"), + email: z.string().email("Please enter a valid email address"), + password: z + .string() + .min(10, "Password must be at least 10 characters"), + }) + .refine( + (data) => + process.env.NODE_ENV === "development" || + !isDeckyVaultEmail(data.email), + { + message: DOMAIN_BLOCK_ERROR, + path: ["email"], + }, + ) export const otpSchema = z.object({ otp: z.string().length(6, "OTP must be exactly 6 digits"),