From f25bd69b17bfa141ad3645c0f875b482e8152611 Mon Sep 17 00:00:00 2001 From: denish-fearless Date: Wed, 15 Jan 2025 13:05:25 -0500 Subject: [PATCH] after some research found out that some subdomains do have mx records, this will fall back to root domain if subdomain fails --- backend/src/middleware/emailValidator.test.ts | 28 +++++++----------- backend/src/middleware/emailValidator.ts | 29 ++++++++++++------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/backend/src/middleware/emailValidator.test.ts b/backend/src/middleware/emailValidator.test.ts index a00a9ca88..03c09db69 100644 --- a/backend/src/middleware/emailValidator.test.ts +++ b/backend/src/middleware/emailValidator.test.ts @@ -5,7 +5,7 @@ jest.mock('dns'); const mockedDns = dns as jest.Mocked; -describe('isValidEmail Function', () => { +describe('isValidEmail Function (Full and Root Domain Validation)', () => { afterEach(() => { jest.resetAllMocks(); @@ -16,7 +16,7 @@ describe('isValidEmail Function', () => { expect(result).toBe(false); }); - test('should return true for a valid email with MX records (full domain)', async () => { + test('should return true for a valid email with MX records on the full domain', async () => { mockedDns.resolveMx.mockImplementation((domain, callback) => { if (domain === 'gmail.com') { callback(null, [{ exchange: 'mail.google.com', priority: 10 }]); @@ -29,14 +29,12 @@ describe('isValidEmail Function', () => { expect(result).toBe(true); }); - test('should return true for a valid email with MX records (root domain fallback)', async () => { + test('should return true for a valid email where MX records exist on the root domain', async () => { mockedDns.resolveMx.mockImplementation((domain, callback) => { if (domain === 'subdomain.example.com') { callback(null, []); } else if (domain === 'example.com') { callback(null, [{ exchange: 'mail.example.com', priority: 20 }]); - } else { - callback(null, []); } }); @@ -44,7 +42,7 @@ describe('isValidEmail Function', () => { expect(result).toBe(true); }); - test('should return false for a valid email but no MX records in either domain', async () => { + test('should return false when neither the full nor root domain has MX records', async () => { mockedDns.resolveMx.mockImplementation((domain, callback) => { callback(null, []); }); @@ -53,31 +51,25 @@ describe('isValidEmail Function', () => { expect(result).toBe(false); }); - test('should return false for a domain with an error during MX lookup (full domain)', async () => { + test('should return false when an error occurs during full domain lookup and no MX records exist on root', async () => { mockedDns.resolveMx.mockImplementation((domain, callback) => { - if (domain === 'fakeexample.com') { + if (domain === 'subdomain.fakeexample.com') { callback(new Error('Domain not found'), []); } else { callback(null, []); } }); - const result = await isValidEmail('test@fakeexample.com'); + const result = await isValidEmail('test@subdomain.fakeexample.com'); expect(result).toBe(false); }); - test('should return false for a domain with an error during MX lookup (root domain fallback)', async () => { + test('should return false when an error occurs during both full and root domain lookups', async () => { mockedDns.resolveMx.mockImplementation((domain, callback) => { - if (domain === 'subdomain.fakeexample.com') { - callback(new Error('Domain not found'), []); - } else if (domain === 'fakeexample.com') { - callback(new Error('Domain not found'), []); - } else { - callback(null, []); - } + callback(new Error('Domain not found'), []); }); - const result = await isValidEmail('test@subdomain.fakeexample.com'); + const result = await isValidEmail('test@error.com'); expect(result).toBe(false); }); }); diff --git a/backend/src/middleware/emailValidator.ts b/backend/src/middleware/emailValidator.ts index 8be86d65d..18e1f16d1 100644 --- a/backend/src/middleware/emailValidator.ts +++ b/backend/src/middleware/emailValidator.ts @@ -17,21 +17,30 @@ export const isValidEmail = async (email: string): Promise => { }; const validateDomainMX = (email: string): Promise => { - let domain = email.split('@')[1]; - const domainParts = domain.split('.') - if(domainParts.length > 2) { - domain = domainParts.slice(-2).join('.') - } + const domain = email.split('@')[1]; + const domainParts = domain.split('.'); + const rootDomain = domainParts.length > 2 ? domainParts.slice(-2).join('.') : domain; // If subdomain exists + return new Promise((resolve) => { + // Trying full domain first dns.resolveMx(domain, (err, addresses) => { - if (err || addresses.length === 0) { - console.log(`Invalid domain or no MX records for: ${domain}`); - resolve(false); - } else { + if (!err && addresses.length > 0) { console.log(`Valid MX records found for ${domain}:`, addresses); - resolve(true); + return resolve(true); } + + // Fallback to root domain if the full domain fails + dns.resolveMx(rootDomain, (rootErr, rootAddresses) => { + if (!rootErr && rootAddresses.length > 0) { + console.log(`Valid MX records found for ${rootDomain}:`, rootAddresses); + resolve(true); + } else { + console.log(`Invalid domain or no MX records for: ${domain}`); + resolve(false); + } + }); }); }); }; +