feat(security): add blocked domains and strict TLD validation
- Adds `BLOCKED_DOMAINS` list to reject disposable/invalid email domains. - Enforces TLD length >= 2 chars in `isValidEmail`. - Updates tests to cover new validation rules. Co-authored-by: ragusa-it <196988693+ragusa-it@users.noreply.github.com>
This commit is contained in:
@@ -29,14 +29,14 @@ describe('Security Utils', () => {
|
||||
|
||||
describe('isValidEmail', () => {
|
||||
it('accepts valid email addresses', () => {
|
||||
expect(isValidEmail('test@example.com')).toBe(true);
|
||||
expect(isValidEmail('test@valid-domain.com')).toBe(true);
|
||||
expect(isValidEmail('john.doe@sub.domain.co.uk')).toBe(true);
|
||||
expect(isValidEmail('user+tag@example.com')).toBe(true);
|
||||
expect(isValidEmail('user+tag@valid-domain.com')).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects invalid email formats', () => {
|
||||
expect(isValidEmail('plainaddress')).toBe(false);
|
||||
expect(isValidEmail('@example.com')).toBe(false);
|
||||
expect(isValidEmail('@valid-domain.com')).toBe(false);
|
||||
expect(isValidEmail('user@')).toBe(false);
|
||||
expect(isValidEmail('user@.com')).toBe(false);
|
||||
expect(isValidEmail('user@com')).toBe(false); // Missing dot in domain part (simple regex might allow, but strict one requires dot)
|
||||
@@ -54,13 +54,31 @@ describe('Security Utils', () => {
|
||||
});
|
||||
|
||||
it('accepts emails with apostrophes', () => {
|
||||
expect(isValidEmail("user'name@example.com")).toBe(true);
|
||||
expect(isValidEmail("o'connor@example.com")).toBe(true);
|
||||
expect(isValidEmail("user'name@valid-domain.com")).toBe(true);
|
||||
expect(isValidEmail("o'connor@valid-domain.com")).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects emails with whitespace', () => {
|
||||
expect(isValidEmail('user @example.com')).toBe(false);
|
||||
expect(isValidEmail('user@ example.com')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects short TLDs (less than 2 chars)', () => {
|
||||
expect(isValidEmail('user@domain.c')).toBe(false);
|
||||
expect(isValidEmail('user@domain.1')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects blocked/disposable domains', () => {
|
||||
expect(isValidEmail('user@example.com')).toBe(false);
|
||||
expect(isValidEmail('test@test.com')).toBe(false);
|
||||
expect(isValidEmail('spam@mailinator.com')).toBe(false);
|
||||
expect(isValidEmail('bot@yopmail.com')).toBe(false);
|
||||
expect(isValidEmail('temp@temp-mail.org')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects blocked domains regardless of case', () => {
|
||||
expect(isValidEmail('user@EXAMPLE.COM')).toBe(false);
|
||||
expect(isValidEmail('user@MaIlInAtOr.CoM')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,9 +17,22 @@ export function sanitizeInput(input: string): string {
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
// Common disposable email providers and invalid domains
|
||||
const BLOCKED_DOMAINS = new Set([
|
||||
"example.com",
|
||||
"test.com",
|
||||
"mailinator.com",
|
||||
"yopmail.com",
|
||||
"temp-mail.org",
|
||||
"guerrillamail.com",
|
||||
"10minutemail.com",
|
||||
"trashmail.com",
|
||||
]);
|
||||
|
||||
/**
|
||||
* Validates an email address format securely.
|
||||
* Rejects inputs containing dangerous characters like <, >, or whitespace.
|
||||
* Also validates domain validity (blocked domains, TLD length).
|
||||
*
|
||||
* @param email - The email string to validate.
|
||||
* @returns True if the email is valid and safe, false otherwise.
|
||||
@@ -30,7 +43,13 @@ export function isValidEmail(email: string): boolean {
|
||||
// @ : Literal @
|
||||
// [^\s@<>]+ : Domain part - no whitespace, @, <, or >
|
||||
// \. : Literal .
|
||||
// [^\s@<>]+ : TLD part - no whitespace, @, <, or >
|
||||
const emailRegex = /^[^\s@<>,"`]+@[^\s@<>,"`]+\.[^\s@<>,"`]+$/;
|
||||
return emailRegex.test(email);
|
||||
// [^\s@<>]+ : TLD part - no whitespace, @, <, or > (min 2 chars)
|
||||
const emailRegex = /^[^\s@<>,"`]+@[^\s@<>,"`]+\.[^\s@<>,"`]{2,}$/;
|
||||
if (!emailRegex.test(email)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check against blocked domains
|
||||
const domain = email.split("@")[1].toLowerCase();
|
||||
return !BLOCKED_DOMAINS.has(domain);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user