import * as plugins from '@git.zone/tstest/tapbundle'; import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as net from 'net'; import { startTestServer, stopTestServer } from '../../helpers/server.loader.js'; const TEST_PORT = 2525; let testServer; tap.test('prepare server', async () => { testServer = await startTestServer({ port: TEST_PORT }); await new Promise(resolve => setTimeout(resolve, 100)); }); tap.test('ERR-06: Malformed MIME handling - Invalid boundary', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); socket.on('connect', async () => { try { // Read greeting await new Promise((resolve) => { socket.once('data', () => resolve()); }); // Send EHLO socket.write('EHLO testhost\r\n'); await new Promise((resolve) => { let data = ''; const handleData = (chunk: Buffer) => { data += chunk.toString(); if (data.includes('250 ') && data.includes('\r\n')) { socket.removeListener('data', handleData); resolve(); } }; socket.on('data', handleData); }); // Send MAIL FROM socket.write('MAIL FROM:\r\n'); await new Promise((resolve) => { socket.once('data', (chunk) => { const response = chunk.toString(); expect(response).toInclude('250'); resolve(); }); }); // Send RCPT TO socket.write('RCPT TO:\r\n'); await new Promise((resolve) => { socket.once('data', (chunk) => { const response = chunk.toString(); expect(response).toInclude('250'); resolve(); }); }); // Send DATA socket.write('DATA\r\n'); const dataResponse = await new Promise((resolve) => { socket.once('data', (chunk) => { resolve(chunk.toString()); }); }); expect(dataResponse).toInclude('354'); // Send malformed MIME with invalid boundary const malformedMime = [ 'From: sender@example.com', 'To: recipient@example.com', 'Subject: Malformed MIME Test', 'MIME-Version: 1.0', 'Content-Type: multipart/mixed; boundary=invalid-boundary', '', '--invalid-boundary', 'Content-Type: text/plain', 'Content-Transfer-Encoding: invalid-encoding', '', 'This is malformed MIME content.', '--invalid-boundary', 'Content-Type: application/octet-stream', 'Content-Disposition: attachment; filename="malformed.txt', // Missing closing quote '', 'Malformed attachment content without proper boundary.', '--invalid-boundary--missing-final-boundary', // Malformed closing boundary '.', '' ].join('\r\n'); socket.write(malformedMime); const response = await new Promise((resolve) => { socket.once('data', (chunk) => { resolve(chunk.toString()); }); }); // Server should either: // 1. Accept the message (250) - tolerant handling // 2. Reject with error (550/552) - strict MIME validation // 3. Return temporary failure (4xx) - processing error const validResponse = response.includes('250') || response.includes('550') || response.includes('552') || response.includes('451') || response.includes('mime') || response.includes('malformed'); console.log('Malformed MIME response:', response.substring(0, 100)); expect(validResponse).toEqual(true); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } catch (error) { socket.end(); done.reject(error); } }); socket.on('error', (error) => { done.reject(error); }); }); tap.test('ERR-06: Malformed MIME handling - Missing headers', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); socket.on('connect', async () => { try { // Read greeting await new Promise((resolve) => { socket.once('data', () => resolve()); }); // Send EHLO socket.write('EHLO testhost\r\n'); await new Promise((resolve) => { let data = ''; const handleData = (chunk: Buffer) => { data += chunk.toString(); if (data.includes('250 ') && data.includes('\r\n')) { socket.removeListener('data', handleData); resolve(); } }; socket.on('data', handleData); }); // Send MAIL FROM socket.write('MAIL FROM:\r\n'); await new Promise((resolve) => { socket.once('data', (chunk) => { const response = chunk.toString(); expect(response).toInclude('250'); resolve(); }); }); // Send RCPT TO socket.write('RCPT TO:\r\n'); await new Promise((resolve) => { socket.once('data', (chunk) => { const response = chunk.toString(); expect(response).toInclude('250'); resolve(); }); }); // Send DATA socket.write('DATA\r\n'); const dataResponse = await new Promise((resolve) => { socket.once('data', (chunk) => { resolve(chunk.toString()); }); }); expect(dataResponse).toInclude('354'); // Send MIME with missing required headers const malformedMime = [ 'Subject: Missing MIME headers', 'Content-Type: multipart/mixed', // Missing boundary parameter '', '--boundary', // Missing Content-Type for part '', 'This part has no Content-Type header.', '--boundary', 'Content-Type: text/plain', // Missing blank line between headers and body 'This part has no separator line.', '--boundary--', '.', '' ].join('\r\n'); socket.write(malformedMime); const response = await new Promise((resolve) => { socket.once('data', (chunk) => { resolve(chunk.toString()); }); }); // Server should handle this gracefully const validResponse = response.includes('250') || response.includes('550') || response.includes('552') || response.includes('451'); console.log('Missing headers response:', response.substring(0, 100)); expect(validResponse).toEqual(true); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } catch (error) { socket.end(); done.reject(error); } }); socket.on('error', (error) => { done.reject(error); }); }); tap.test('ERR-06: Malformed MIME handling - Nested multipart errors', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); socket.on('connect', async () => { try { // Read greeting await new Promise((resolve) => { socket.once('data', () => resolve()); }); // Send EHLO socket.write('EHLO testhost\r\n'); await new Promise((resolve) => { let data = ''; const handleData = (chunk: Buffer) => { data += chunk.toString(); if (data.includes('250 ') && data.includes('\r\n')) { socket.removeListener('data', handleData); resolve(); } }; socket.on('data', handleData); }); // Send MAIL FROM socket.write('MAIL FROM:\r\n'); await new Promise((resolve) => { socket.once('data', (chunk) => { const response = chunk.toString(); expect(response).toInclude('250'); resolve(); }); }); // Send RCPT TO socket.write('RCPT TO:\r\n'); await new Promise((resolve) => { socket.once('data', (chunk) => { const response = chunk.toString(); expect(response).toInclude('250'); resolve(); }); }); // Send DATA socket.write('DATA\r\n'); const dataResponse = await new Promise((resolve) => { socket.once('data', (chunk) => { resolve(chunk.toString()); }); }); expect(dataResponse).toInclude('354'); // Send deeply nested multipart with errors const malformedMime = [ 'From: sender@example.com', 'To: recipient@example.com', 'Subject: Nested multipart errors', 'MIME-Version: 1.0', 'Content-Type: multipart/mixed; boundary="outer"', '', '--outer', 'Content-Type: multipart/alternative; boundary="inner"', '', '--inner', 'Content-Type: multipart/related; boundary="nested"', // Too deeply nested '', '--nested', 'Content-Type: text/plain', 'Content-Transfer-Encoding: base64', '', 'NOT-VALID-BASE64-CONTENT!!!', // Invalid base64 '--nested', // Missing closing -- '--inner--', // Improper nesting '--outer', // Missing part content '--outer--', '.', '' ].join('\r\n'); socket.write(malformedMime); const response = await new Promise((resolve) => { socket.once('data', (chunk) => { resolve(chunk.toString()); }); }); // Server should handle complex MIME errors gracefully const validResponse = response.includes('250') || response.includes('550') || response.includes('552') || response.includes('451'); console.log('Nested multipart response:', response.substring(0, 100)); expect(validResponse).toEqual(true); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } catch (error) { socket.end(); done.reject(error); } }); socket.on('error', (error) => { done.reject(error); }); }); tap.test('cleanup server', async () => { await stopTestServer(testServer); }); export default tap.start();