91 lines
2.2 KiB
TypeScript
91 lines
2.2 KiB
TypeScript
|
|
const DISPOSABLE_EMAIL_DOMAINS = [
|
||
|
|
'tempmail.com',
|
||
|
|
'throwawaymail.com',
|
||
|
|
'tempmail100.com'
|
||
|
|
];
|
||
|
|
|
||
|
|
export type EmailValidationError =
|
||
|
|
| 'invalid_email_format'
|
||
|
|
| 'email_part_too_long'
|
||
|
|
| 'disposable_email_not_allowed'
|
||
|
|
| 'invalid_characters';
|
||
|
|
|
||
|
|
const EMAIL_REGEX = /^(?=[a-zA-Z0-9@._%+-]{6,254}$)[a-zA-Z0-9._%+-]{1,64}@(?:[a-zA-Z0-9-]{1,63}\.){1,8}[a-zA-Z]{2,63}$/;
|
||
|
|
|
||
|
|
export function validateEmail(email: string): {
|
||
|
|
isValid: boolean;
|
||
|
|
error?: string;
|
||
|
|
} {
|
||
|
|
// validate email format
|
||
|
|
if (!EMAIL_REGEX.test(email)) {
|
||
|
|
return {
|
||
|
|
isValid: false,
|
||
|
|
error: 'invalid_email_format'
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// check domain length
|
||
|
|
const [localPart, domain] = email.split('@');
|
||
|
|
if (domain.length > 255 || localPart.length > 64) {
|
||
|
|
return {
|
||
|
|
isValid: false,
|
||
|
|
error: 'email_part_too_long'
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// check if it's a disposable email
|
||
|
|
if (DISPOSABLE_EMAIL_DOMAINS.includes(domain.toLowerCase())) {
|
||
|
|
return {
|
||
|
|
isValid: false,
|
||
|
|
error: 'disposable_email_not_allowed'
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// check for special characters
|
||
|
|
if (/[<>()[\]\\.,;:\s@"]+/.test(localPart)) {
|
||
|
|
return {
|
||
|
|
isValid: false,
|
||
|
|
error: 'invalid_characters'
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
return { isValid: true };
|
||
|
|
}
|
||
|
|
|
||
|
|
// email validation (including alias detection)
|
||
|
|
export function normalizeEmail(email: string): string {
|
||
|
|
if (!email) return '';
|
||
|
|
|
||
|
|
// convert to lowercase
|
||
|
|
let normalizedEmail = email.toLowerCase();
|
||
|
|
|
||
|
|
// separate email local part and domain part
|
||
|
|
const [localPart, domain] = normalizedEmail.split('@');
|
||
|
|
|
||
|
|
// handle different email service provider alias rules
|
||
|
|
switch (domain) {
|
||
|
|
case 'gmail.com':
|
||
|
|
// remove dot and + suffix
|
||
|
|
const gmailBase = localPart
|
||
|
|
.replace(/\./g, '')
|
||
|
|
.split('+')[0];
|
||
|
|
return `${gmailBase}@${domain}`;
|
||
|
|
|
||
|
|
case 'outlook.com':
|
||
|
|
case 'hotmail.com':
|
||
|
|
case 'live.com':
|
||
|
|
// remove + suffix
|
||
|
|
const microsoftBase = localPart.split('+')[0];
|
||
|
|
return `${microsoftBase}@${domain}`;
|
||
|
|
|
||
|
|
case 'yahoo.com':
|
||
|
|
// remove - suffix
|
||
|
|
const yahooBase = localPart.split('-')[0];
|
||
|
|
return `${yahooBase}@${domain}`;
|
||
|
|
|
||
|
|
default:
|
||
|
|
// for other emails, only remove + suffix
|
||
|
|
const baseLocalPart = localPart.split('+')[0];
|
||
|
|
return `${baseLocalPart}@${domain}`;
|
||
|
|
}
|
||
|
|
}
|