feat: add isDeckyVaultEmail domain validation helper (Task 1)

This commit is contained in:
2026-05-28 00:06:16 +08:00
parent 05ddb8b4cc
commit 60f25b08f6
2 changed files with 69 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
import { describe, it, expect } from "vitest"
import { isDeckyVaultEmail, DOMAIN_BLOCK_ERROR } from "../domain-block"
describe("isDeckyVaultEmail", () => {
it("returns true for a @deckyvault.xyz email (lowercase)", () => {
expect(isDeckyVaultEmail("user@deckyvault.xyz")).toBe(true)
})
it("returns true for a @deckyvault.xyz email (mixed case)", () => {
expect(isDeckyVaultEmail("User@DeckyVault.xyz")).toBe(true)
})
it("returns true for a @deckyvault.xyz email with plus addressing", () => {
expect(isDeckyVaultEmail("user+tag@deckyvault.xyz")).toBe(true)
})
it("returns true for a @deckyvault.xyz email with surrounding whitespace", () => {
expect(isDeckyVaultEmail(" admin@deckyvault.xyz ")).toBe(true)
})
it("returns false for a @gmail.com email", () => {
expect(isDeckyVaultEmail("user@gmail.com")).toBe(false)
})
it("returns false for a @example.com email", () => {
expect(isDeckyVaultEmail("user@example.com")).toBe(false)
})
it("returns false for a subdomain like @mail.deckyvault.xyz", () => {
expect(isDeckyVaultEmail("user@mail.deckyvault.xyz")).toBe(false)
})
it("returns false for an empty string", () => {
expect(isDeckyVaultEmail("")).toBe(false)
})
it("returns false for a string without @", () => {
expect(isDeckyVaultEmail("deckyvault.xyz")).toBe(false)
})
it("returns true for a .DECKYVAULT.XYZ email (uppercase domain)", () => {
expect(isDeckyVaultEmail("admin@DECKYVAULT.XYZ")).toBe(true)
})
})
describe("DOMAIN_BLOCK_ERROR", () => {
it("is a non-empty string", () => {
expect(DOMAIN_BLOCK_ERROR).toBeTruthy()
expect(typeof DOMAIN_BLOCK_ERROR).toBe("string")
})
})
+18
View File
@@ -0,0 +1,18 @@
export const DOMAIN_BLOCK_ERROR =
"Signing up with a @deckyvault.xyz email is not allowed."
/**
* Returns true if the email address has a deckyvault.xyz domain.
* Handles case-insensitive comparison, whitespace trimming, and
* plus-notation aliases (user+tag@domain → domain).
*
* Only matches the exact domain "deckyvault.xyz" — NOT subdomains
* like "mail.deckyvault.xyz".
*/
export function isDeckyVaultEmail(email: string): boolean {
const trimmed = email.trim().toLowerCase()
const atIndex = trimmed.lastIndexOf("@")
if (atIndex === -1) return false
const domain = trimmed.slice(atIndex + 1)
return domain === "deckyvault.xyz"
}