import { tap, expect } from '@git.zone/tstest/tapbundle'; import { startTestSmtpServer } from '../../helpers/server.loader.js'; import { createSmtpClient } from '../../helpers/smtp.client.js'; import { Email } from '../../../ts/mail/core/classes.email.js'; import * as dns from 'dns'; import { promisify } from 'util'; const resolveTxt = promisify(dns.resolveTxt); let testServer: any; tap.test('setup test SMTP server', async () => { testServer = await startTestSmtpServer(); expect(testServer).toBeTruthy(); expect(testServer.port).toBeGreaterThan(0); }); tap.test('CSEC-05: DMARC record parsing', async () => { // Test DMARC record parsing const testDmarcRecords = [ { domain: 'example.com', record: 'v=DMARC1; p=reject; rua=mailto:dmarc@example.com; ruf=mailto:forensics@example.com; adkim=s; aspf=s; pct=100', description: 'Strict DMARC with reporting' }, { domain: 'relaxed.com', record: 'v=DMARC1; p=quarantine; adkim=r; aspf=r; pct=50', description: 'Relaxed alignment, 50% quarantine' }, { domain: 'monitoring.com', record: 'v=DMARC1; p=none; rua=mailto:reports@monitoring.com', description: 'Monitor only mode' }, { domain: 'subdomain.com', record: 'v=DMARC1; p=reject; sp=quarantine; adkim=s; aspf=s', description: 'Different subdomain policy' } ]; console.log('DMARC Record Analysis:\n'); for (const test of testDmarcRecords) { console.log(`Domain: _dmarc.${test.domain}`); console.log(`Record: ${test.record}`); console.log(`Description: ${test.description}`); // Parse DMARC tags const tags = test.record.match(/(\w+)=([^;]+)/g); if (tags) { console.log('Tags:'); tags.forEach(tag => { const [key, value] = tag.split('='); const tagMeaning = { 'v': 'Version', 'p': 'Policy', 'sp': 'Subdomain Policy', 'rua': 'Aggregate Reports', 'ruf': 'Forensic Reports', 'adkim': 'DKIM Alignment', 'aspf': 'SPF Alignment', 'pct': 'Percentage', 'fo': 'Forensic Options' }[key] || key; console.log(` ${tagMeaning}: ${value}`); }); } console.log(''); } }); tap.test('CSEC-05: DMARC alignment testing', async () => { const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000, debug: true }); await smtpClient.connect(); // Test DMARC alignment scenarios const alignmentTests = [ { name: 'Fully aligned', fromHeader: 'sender@example.com', mailFrom: 'sender@example.com', dkimDomain: 'example.com', expectedResult: 'pass' }, { name: 'SPF aligned only', fromHeader: 'noreply@example.com', mailFrom: 'bounce@example.com', dkimDomain: 'otherdomain.com', expectedResult: 'pass' // One aligned identifier is enough }, { name: 'DKIM aligned only', fromHeader: 'sender@example.com', mailFrom: 'bounce@different.com', dkimDomain: 'example.com', expectedResult: 'pass' // One aligned identifier is enough }, { name: 'Neither aligned', fromHeader: 'sender@example.com', mailFrom: 'bounce@different.com', dkimDomain: 'another.com', expectedResult: 'fail' }, { name: 'Subdomain relaxed alignment', fromHeader: 'sender@example.com', mailFrom: 'bounce@mail.example.com', dkimDomain: 'auth.example.com', expectedResult: 'pass' // With relaxed alignment } ]; for (const test of alignmentTests) { console.log(`\nTesting DMARC alignment: ${test.name}`); console.log(` From header: ${test.fromHeader}`); console.log(` MAIL FROM: ${test.mailFrom}`); console.log(` DKIM domain: ${test.dkimDomain}`); const email = new Email({ from: test.fromHeader, to: ['recipient@example.com'], subject: `DMARC Test: ${test.name}`, text: 'Testing DMARC alignment', envelope: { from: test.mailFrom }, dkim: { domainName: test.dkimDomain, keySelector: 'default', privateKey: 'mock-key' } }); await smtpClient.sendMail(email); // Analyze alignment const fromDomain = test.fromHeader.split('@')[1]; const mailFromDomain = test.mailFrom.split('@')[1]; const dkimDomain = test.dkimDomain; // Check SPF alignment const spfStrictAlign = fromDomain === mailFromDomain; const spfRelaxedAlign = fromDomain === mailFromDomain || mailFromDomain?.endsWith(`.${fromDomain}`) || fromDomain?.endsWith(`.${mailFromDomain}`); // Check DKIM alignment const dkimStrictAlign = fromDomain === dkimDomain; const dkimRelaxedAlign = fromDomain === dkimDomain || dkimDomain?.endsWith(`.${fromDomain}`) || fromDomain?.endsWith(`.${dkimDomain}`); console.log(` SPF alignment: Strict=${spfStrictAlign}, Relaxed=${spfRelaxedAlign}`); console.log(` DKIM alignment: Strict=${dkimStrictAlign}, Relaxed=${dkimRelaxedAlign}`); console.log(` Expected result: ${test.expectedResult}`); } await smtpClient.close(); }); tap.test('CSEC-05: DMARC policy enforcement', async () => { // Test different DMARC policies const policies = [ { policy: 'none', description: 'Monitor only - no action taken', action: 'Deliver normally, send reports' }, { policy: 'quarantine', description: 'Quarantine failing messages', action: 'Move to spam/junk folder' }, { policy: 'reject', description: 'Reject failing messages', action: 'Bounce the message' } ]; console.log('\nDMARC Policy Actions:\n'); for (const p of policies) { console.log(`Policy: p=${p.policy}`); console.log(` Description: ${p.description}`); console.log(` Action: ${p.action}`); console.log(''); } // Test percentage application const percentageTests = [ { pct: 100, description: 'Apply policy to all messages' }, { pct: 50, description: 'Apply policy to 50% of messages' }, { pct: 10, description: 'Apply policy to 10% of messages' }, { pct: 0, description: 'Monitor only (effectively)' } ]; console.log('DMARC Percentage (pct) tag:\n'); for (const test of percentageTests) { console.log(`pct=${test.pct}: ${test.description}`); } }); tap.test('CSEC-05: DMARC report generation', async () => { const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000, debug: true }); await smtpClient.connect(); // Simulate DMARC report data const reportData = { reportMetadata: { orgName: 'Example ISP', email: 'dmarc-reports@example-isp.com', reportId: '12345678', dateRange: { begin: new Date(Date.now() - 86400000).toISOString(), end: new Date().toISOString() } }, policy: { domain: 'example.com', adkim: 'r', aspf: 'r', p: 'reject', sp: 'reject', pct: 100 }, records: [ { sourceIp: '192.168.1.1', count: 5, disposition: 'none', dkim: 'pass', spf: 'pass' }, { sourceIp: '10.0.0.1', count: 2, disposition: 'reject', dkim: 'fail', spf: 'fail' } ] }; console.log('\nSample DMARC Aggregate Report Structure:'); console.log(JSON.stringify(reportData, null, 2)); // Send a DMARC report email const email = new Email({ from: 'dmarc-reports@example-isp.com', to: ['dmarc@example.com'], subject: `Report Domain: example.com Submitter: example-isp.com Report-ID: ${reportData.reportMetadata.reportId}`, text: 'DMARC Aggregate Report attached', attachments: [{ filename: `example-isp.com!example.com!${Date.now()}!${Date.now() + 86400000}.xml.gz`, content: Buffer.from('mock-compressed-xml-report'), contentType: 'application/gzip' }] }); await smtpClient.sendMail(email); console.log('\nDMARC report email sent successfully'); await smtpClient.close(); }); tap.test('CSEC-05: DMARC forensic reports', async () => { // Test DMARC forensic report options const forensicOptions = [ { fo: '0', description: 'Generate reports if all underlying mechanisms fail' }, { fo: '1', description: 'Generate reports if any mechanism fails' }, { fo: 'd', description: 'Generate reports if DKIM signature failed' }, { fo: 's', description: 'Generate reports if SPF failed' }, { fo: '1:d:s', description: 'Multiple options combined' } ]; console.log('\nDMARC Forensic Report Options (fo tag):\n'); for (const option of forensicOptions) { console.log(`fo=${option.fo}: ${option.description}`); } // Example forensic report structure const forensicReport = { feedbackType: 'auth-failure', userAgent: 'Example-MTA/1.0', version: 1, originalMailFrom: 'sender@spoofed.com', sourceIp: '192.168.1.100', authResults: { spf: { domain: 'spoofed.com', result: 'fail' }, dkim: { domain: 'example.com', result: 'fail', humanResult: 'signature verification failed' }, dmarc: { domain: 'example.com', result: 'fail', policy: 'reject' } }, originalHeaders: [ 'From: sender@example.com', 'To: victim@target.com', 'Subject: Suspicious Email', 'Date: ' + new Date().toUTCString() ] }; console.log('\nSample DMARC Forensic Report:'); console.log(JSON.stringify(forensicReport, null, 2)); }); tap.test('CSEC-05: DMARC subdomain policies', async () => { const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000, debug: true }); await smtpClient.connect(); // Test subdomain policy inheritance const subdomainTests = [ { parentDomain: 'example.com', parentPolicy: 'p=reject; sp=none', subdomain: 'mail.example.com', expectedPolicy: 'none' }, { parentDomain: 'example.com', parentPolicy: 'p=reject', // No sp tag subdomain: 'mail.example.com', expectedPolicy: 'reject' // Inherits parent policy }, { parentDomain: 'example.com', parentPolicy: 'p=quarantine; sp=reject', subdomain: 'newsletter.example.com', expectedPolicy: 'reject' } ]; console.log('\nDMARC Subdomain Policy Tests:\n'); for (const test of subdomainTests) { console.log(`Parent domain: ${test.parentDomain}`); console.log(`Parent DMARC: v=DMARC1; ${test.parentPolicy}`); console.log(`Subdomain: ${test.subdomain}`); console.log(`Expected policy: ${test.expectedPolicy}`); const email = new Email({ from: `sender@${test.subdomain}`, to: ['recipient@example.com'], subject: 'Subdomain Policy Test', text: `Testing DMARC policy for ${test.subdomain}` }); await smtpClient.sendMail(email); console.log(''); } await smtpClient.close(); }); tap.test('CSEC-05: DMARC deployment best practices', async () => { // DMARC deployment phases const deploymentPhases = [ { phase: 1, policy: 'p=none; rua=mailto:dmarc@example.com', duration: '2-4 weeks', description: 'Monitor only - collect data' }, { phase: 2, policy: 'p=quarantine; pct=10; rua=mailto:dmarc@example.com', duration: '1-2 weeks', description: 'Quarantine 10% of failing messages' }, { phase: 3, policy: 'p=quarantine; pct=50; rua=mailto:dmarc@example.com', duration: '1-2 weeks', description: 'Quarantine 50% of failing messages' }, { phase: 4, policy: 'p=quarantine; pct=100; rua=mailto:dmarc@example.com', duration: '2-4 weeks', description: 'Quarantine all failing messages' }, { phase: 5, policy: 'p=reject; rua=mailto:dmarc@example.com; ruf=mailto:forensics@example.com', duration: 'Ongoing', description: 'Reject all failing messages' } ]; console.log('\nDMARC Deployment Best Practices:\n'); for (const phase of deploymentPhases) { console.log(`Phase ${phase.phase}: ${phase.description}`); console.log(` Record: v=DMARC1; ${phase.policy}`); console.log(` Duration: ${phase.duration}`); console.log(''); } // Common mistakes console.log('Common DMARC Mistakes to Avoid:\n'); const mistakes = [ 'Jumping directly to p=reject without monitoring', 'Not setting up aggregate report collection (rua)', 'Ignoring subdomain policy (sp)', 'Not monitoring legitimate email sources before enforcement', 'Setting pct=100 too quickly', 'Not updating SPF/DKIM before DMARC' ]; mistakes.forEach((mistake, i) => { console.log(`${i + 1}. ${mistake}`); }); }); tap.test('CSEC-05: DMARC and mailing lists', async () => { const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000, debug: true }); await smtpClient.connect(); // Test mailing list scenario console.log('\nDMARC Challenges with Mailing Lists:\n'); const originalEmail = new Email({ from: 'original@sender-domain.com', to: ['mailinglist@list-server.com'], subject: '[ListName] Original Subject', text: 'Original message content', headers: { 'List-Id': '', 'List-Post': '', 'List-Unsubscribe': '' } }); console.log('Original email:'); console.log(` From: ${originalEmail.from}`); console.log(` To: ${originalEmail.to[0]}`); // Mailing list forwards the email const forwardedEmail = new Email({ from: 'original@sender-domain.com', // Kept original From to: ['subscriber@recipient-domain.com'], subject: '[ListName] Original Subject', text: 'Original message content\n\n--\nMailing list footer', envelope: { from: 'bounces@list-server.com' // Changed MAIL FROM }, headers: { 'List-Id': '', 'X-Original-From': 'original@sender-domain.com' } }); console.log('\nForwarded by mailing list:'); console.log(` From header: ${forwardedEmail.from} (unchanged)`); console.log(` MAIL FROM: bounces@list-server.com (changed)`); console.log(` Result: SPF will pass for list-server.com, but DMARC alignment fails`); await smtpClient.sendMail(forwardedEmail); console.log('\nSolutions for mailing lists:'); console.log('1. ARC (Authenticated Received Chain) - preserves authentication'); console.log('2. Conditional DMARC policies for known mailing lists'); console.log('3. From header rewriting (changes to list address)'); console.log('4. Encourage subscribers to whitelist the mailing list'); await smtpClient.close(); }); tap.test('CSEC-05: DMARC record lookup', async () => { // Test real DMARC record lookups const testDomains = ['paypal.com', 'ebay.com', 'amazon.com']; console.log('\nReal DMARC Record Lookups:\n'); for (const domain of testDomains) { const dmarcDomain = `_dmarc.${domain}`; console.log(`Domain: ${domain}`); try { const txtRecords = await resolveTxt(dmarcDomain); const dmarcRecords = txtRecords .map(record => record.join('')) .filter(record => record.startsWith('v=DMARC1')); if (dmarcRecords.length > 0) { const record = dmarcRecords[0]; console.log(` Record: ${record}`); // Parse key elements const policyMatch = record.match(/p=(\w+)/); const ruaMatch = record.match(/rua=([^;]+)/); const pctMatch = record.match(/pct=(\d+)/); if (policyMatch) console.log(` Policy: ${policyMatch[1]}`); if (ruaMatch) console.log(` Reports to: ${ruaMatch[1]}`); if (pctMatch) console.log(` Percentage: ${pctMatch[1]}%`); } else { console.log(' No DMARC record found'); } } catch (error) { console.log(` Lookup failed: ${error.message}`); } console.log(''); } }); tap.test('cleanup test SMTP server', async () => { if (testServer) { await testServer.stop(); } }); export default tap.start();