import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as plugins from '../plugins.js'; import * as net from 'net'; import { startTestServer, stopTestServer, TEST_PORT, sendEmailWithRawSocket } from '../../helpers/server.loader.js'; import type { SmtpServer } from '../../../ts/mail/delivery/smtpserver/index.js'; let testServer: SmtpServer; tap.test('setup - start test server', async () => { testServer = await startTestServer(); await plugins.smartdelay.delayFor(1000); }); tap.test('Content Scanning - Suspicious content patterns', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; socket.write('MAIL FROM:\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt' && dataBuffer.includes('250')) { step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } else if (step === 'data' && dataBuffer.includes('354')) { // Email with suspicious content const email = [ `From: sender@example.com`, `To: recipient@example.com`, `Subject: Content Scanning Test`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, '', 'This email contains suspicious content that should trigger content scanning:', 'VIRUS_TEST_STRING', 'SUSPICIOUS_ATTACHMENT_PATTERN', 'MALWARE_SIGNATURE_TEST', 'Click here for FREE MONEY!!!', 'Visit http://phishing-site.com/steal-data', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') || dataBuffer.includes('550 ')) { const accepted = dataBuffer.includes('250'); const rejected = dataBuffer.includes('550'); console.log(`Suspicious content: accepted=${accepted}, rejected=${rejected}`); if (rejected) { console.log('Content scanning active - suspicious content detected'); } else { console.log('Content scanning operational - email processed'); } expect(accepted || rejected).toEqual(true); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('Content Scanning - Malware patterns', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; socket.write('MAIL FROM:\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt' && dataBuffer.includes('250')) { step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } else if (step === 'data' && dataBuffer.includes('354')) { // Email with malware-like patterns const email = [ `From: sender@example.com`, `To: recipient@example.com`, `Subject: Important Security Update`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, 'Content-Type: multipart/mixed; boundary="malware-boundary"', '', '--malware-boundary', 'Content-Type: text/plain', '', 'Please run the attached file to update your security software.', '', '--malware-boundary', 'Content-Type: application/x-msdownload; name="update.exe"', 'Content-Transfer-Encoding: base64', 'Content-Disposition: attachment; filename="update.exe"', '', 'TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'AAAA4AAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1v', '', '--malware-boundary--', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') || dataBuffer.includes('550 ')) { const accepted = dataBuffer.includes('250'); const rejected = dataBuffer.includes('550'); console.log(`Malware pattern email: ${accepted ? 'accepted' : 'rejected'}`); expect(accepted || rejected).toEqual(true); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('Content Scanning - Spam keywords', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; socket.write('MAIL FROM:\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt' && dataBuffer.includes('250')) { step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } else if (step === 'data' && dataBuffer.includes('354')) { // Email with spam keywords const email = [ `From: sender@example.com`, `To: recipient@example.com`, `Subject: URGENT!!! Act NOW!!! Limited Time OFFER!!!`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, '', 'CONGRATULATIONS!!! You have WON!!!', 'FREE FREE FREE!!!', 'VIAGRA CIALIS CHEAP MEDS!!!', 'MAKE $$$ FAST!!!', 'WORK FROM HOME!!!', 'NO CREDIT CHECK!!!', 'GUARANTEED WINNER!!!', 'CLICK HERE NOW!!!', 'This is NOT SPAM!!!', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') || dataBuffer.includes('550 ')) { const accepted = dataBuffer.includes('250'); const rejected = dataBuffer.includes('550'); console.log(`Spam keyword email: ${accepted ? 'accepted' : 'rejected (spam detected)'}`); expect(accepted || rejected).toEqual(true); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('Content Scanning - Clean legitimate email', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; socket.write('MAIL FROM:\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt' && dataBuffer.includes('250')) { step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } else if (step === 'data' && dataBuffer.includes('354')) { // Clean legitimate email const email = [ `From: sender@example.com`, `To: recipient@example.com`, `Subject: Meeting Tomorrow`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, '', 'Hi,', '', 'Just wanted to confirm our meeting for tomorrow at 2 PM.', 'Please let me know if you need to reschedule.', '', 'Best regards,', 'John', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') && dataBuffer.includes('Message accepted')) { console.log('Clean email accepted - content scanning allows legitimate emails'); expect(true).toEqual(true); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('Content Scanning - Large attachment', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; socket.write('MAIL FROM:\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt' && dataBuffer.includes('250')) { step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } else if (step === 'data' && dataBuffer.includes('354')) { // Email with large attachment pattern const largeData = 'A'.repeat(10000); // 10KB of data const email = [ `From: sender@example.com`, `To: recipient@example.com`, `Subject: Large Attachment Test`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, 'Content-Type: multipart/mixed; boundary="boundary123"', '', '--boundary123', 'Content-Type: text/plain', '', 'Please find the attached file.', '', '--boundary123', 'Content-Type: application/octet-stream; name="largefile.dat"', 'Content-Transfer-Encoding: base64', 'Content-Disposition: attachment; filename="largefile.dat"', '', Buffer.from(largeData).toString('base64'), '', '--boundary123--', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') || dataBuffer.includes('550 ') || dataBuffer.includes('552 ')) { const accepted = dataBuffer.includes('250'); const rejected = dataBuffer.includes('550') || dataBuffer.includes('552'); console.log(`Large attachment: ${accepted ? 'accepted' : 'rejected (size or content issue)'}`); expect(accepted || rejected).toEqual(true); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('cleanup - stop test server', async () => { await stopTestServer(testServer); }); tap.start();