import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as plugins from './plugins.js'; import { createTestServer } from '../../helpers/server.loader.js'; import { createSmtpClient } from '../../helpers/smtp.client.js'; tap.test('CEDGE-05: should handle encoding issues gracefully', async (tools) => { const testId = 'CEDGE-05-encoding-issues'; console.log(`\n${testId}: Testing encoding issue handling...`); let scenarioCount = 0; // Scenario 1: Mixed character encodings in email content await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing mixed character encodings`); const testServer = await createTestServer({ onConnection: async (socket) => { console.log(' [Server] Client connected'); socket.write('220 mail.example.com ESMTP\r\n'); let inData = false; let messageData = ''; socket.on('data', (data) => { const text = data.toString(); if (inData) { messageData += text; if (text.includes('\r\n.\r\n')) { inData = false; console.log(` [Server] Received message data (${messageData.length} bytes)`); // Check for various encodings const hasUtf8 = /[\u0080-\uFFFF]/.test(messageData); const hasBase64 = /Content-Transfer-Encoding:\s*base64/i.test(messageData); const hasQuotedPrintable = /Content-Transfer-Encoding:\s*quoted-printable/i.test(messageData); console.log(` [Server] Encodings detected: UTF-8=${hasUtf8}, Base64=${hasBase64}, QP=${hasQuotedPrintable}`); socket.write('250 OK\r\n'); messageData = ''; } return; } const command = text.trim(); console.log(` [Server] Received: ${command}`); if (command.startsWith('EHLO')) { socket.write('250-mail.example.com\r\n'); socket.write('250-8BITMIME\r\n'); socket.write('250-SMTPUTF8\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); inData = true; } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false }); // Email with mixed encodings const email = new plugins.smartmail.Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Test with émojis 🎉 and spéçiål characters', text: 'Plain text with Unicode: café, naïve, 你好, مرحبا', html: '
HTML with entities: café, naïve, and emoji 🌟
', attachments: [{ filename: 'tëst-filé.txt', content: 'Attachment content with special chars: ñ, ü, ß' }] }); const result = await smtpClient.sendMail(email); console.log(` Result: ${result.messageId ? 'Success' : 'Failed'}`); expect(result).toBeDefined(); expect(result.messageId).toBeDefined(); await testServer.server.close(); })(); // Scenario 2: Invalid UTF-8 sequences await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing invalid UTF-8 sequences`); const testServer = await createTestServer({ onConnection: async (socket) => { console.log(' [Server] Client connected'); socket.write('220 mail.example.com ESMTP\r\n'); let inData = false; socket.on('data', (data) => { if (inData) { if (data.toString().includes('\r\n.\r\n')) { inData = false; socket.write('250 OK\r\n'); } return; } const command = data.toString().trim(); console.log(` [Server] Received: ${command}`); if (command.startsWith('EHLO')) { socket.write('250-mail.example.com\r\n'); socket.write('250-8BITMIME\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { // Check for invalid UTF-8 in email address const hasInvalidUtf8 = Buffer.from(command).some((byte, i, arr) => { if (byte >= 0x80) { // Check if it's valid UTF-8 if ((byte & 0xE0) === 0xC0) { return i + 1 >= arr.length || (arr[i + 1] & 0xC0) !== 0x80; } // Add more UTF-8 validation as needed } return false; }); if (hasInvalidUtf8) { socket.write('501 5.5.4 Invalid UTF-8 in address\r\n'); } else { socket.write('250 OK\r\n'); } } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); inData = true; } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false }); // Create email with potentially problematic content const email = new plugins.smartmail.Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Test with various encodings', text: 'Testing text with special chars', headers: { 'X-Custom-Header': 'Test value with special chars' } }); const result = await smtpClient.sendMail(email); console.log(` Result: ${result.messageId ? 'Success' : 'Failed'}`); expect(result).toBeDefined(); await testServer.server.close(); })(); // Scenario 3: Base64 encoding edge cases await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing Base64 encoding edge cases`); const testServer = await createTestServer({ onConnection: async (socket) => { console.log(' [Server] Client connected'); socket.write('220 mail.example.com ESMTP\r\n'); let inData = false; let messageData = ''; socket.on('data', (data) => { if (inData) { messageData += data.toString(); if (messageData.includes('\r\n.\r\n')) { inData = false; // Check for base64 content const base64Match = messageData.match(/Content-Transfer-Encoding:\s*base64\r?\n\r?\n([^\r\n]+)/i); if (base64Match) { const base64Content = base64Match[1]; console.log(` [Server] Found base64 content: ${base64Content.substring(0, 50)}...`); // Verify it's valid base64 const isValidBase64 = /^[A-Za-z0-9+/]*={0,2}$/.test(base64Content.replace(/\s/g, '')); console.log(` [Server] Base64 valid: ${isValidBase64}`); } socket.write('250 OK\r\n'); messageData = ''; } return; } const command = data.toString().trim(); console.log(` [Server] Received: ${command}`); if (command.startsWith('EHLO')) { socket.write('250-mail.example.com\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); inData = true; } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false }); // Create various sizes of binary content const sizes = [0, 1, 2, 3, 57, 58, 59, 76, 77]; // Edge cases for base64 line wrapping for (const size of sizes) { const binaryContent = Buffer.alloc(size); for (let i = 0; i < size; i++) { binaryContent[i] = i % 256; } const email = new plugins.smartmail.Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: `Base64 test with ${size} bytes`, text: 'Testing base64 encoding', attachments: [{ filename: `test-${size}.bin`, content: binaryContent }] }); console.log(` Testing with ${size} byte attachment...`); const result = await smtpClient.sendMail(email); expect(result).toBeDefined(); expect(result.messageId).toBeDefined(); } await testServer.server.close(); })(); // Scenario 4: Quoted-printable encoding edge cases await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing quoted-printable encoding`); const testServer = await createTestServer({ onConnection: async (socket) => { console.log(' [Server] Client connected'); socket.write('220 mail.example.com ESMTP\r\n'); let inData = false; let messageData = ''; socket.on('data', (data) => { if (inData) { messageData += data.toString(); if (messageData.includes('\r\n.\r\n')) { inData = false; // Check for quoted-printable content if (/Content-Transfer-Encoding:\s*quoted-printable/i.test(messageData)) { console.log(' [Server] Found quoted-printable content'); // Check for proper QP encoding const qpLines = messageData.split('\r\n'); const longLines = qpLines.filter(line => line.length > 76); if (longLines.length > 0) { console.log(` [Server] Warning: ${longLines.length} lines exceed 76 characters`); } } socket.write('250 OK\r\n'); messageData = ''; } return; } const command = data.toString().trim(); console.log(` [Server] Received: ${command}`); if (command.startsWith('EHLO')) { socket.write('250-mail.example.com\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); inData = true; } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false }); // Test with content that requires quoted-printable encoding const email = new plugins.smartmail.Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Quoted-printable test', text: [ 'Line with special chars: café, naïve', 'Very long line that exceeds the 76 character limit and should be properly wrapped when encoded with quoted-printable encoding', 'Line with = sign and trailing spaces ', 'Line ending with =', 'Tést with various spëcial characters: ñ, ü, ß, ø, å' ].join('\n') }); const result = await smtpClient.sendMail(email); console.log(` Result: ${result.messageId ? 'Success' : 'Failed'}`); expect(result).toBeDefined(); expect(result.messageId).toBeDefined(); await testServer.server.close(); })(); // Scenario 5: Header encoding (RFC 2047) await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing header encoding (RFC 2047)`); const testServer = await createTestServer({ onConnection: async (socket) => { console.log(' [Server] Client connected'); socket.write('220 mail.example.com ESMTP\r\n'); let inData = false; let headers: string[] = []; socket.on('data', (data) => { const text = data.toString(); if (inData) { if (!text.startsWith('\r\n') && text.includes(':')) { headers.push(text.split('\r\n')[0]); } if (text.includes('\r\n.\r\n')) { inData = false; // Check encoded headers const encodedHeaders = headers.filter(h => h.includes('=?')); console.log(` [Server] Found ${encodedHeaders.length} encoded headers`); encodedHeaders.forEach(h => { const match = h.match(/=\?([^?]+)\?([BQ])\?([^?]+)\?=/); if (match) { console.log(` [Server] Encoded header: charset=${match[1]}, encoding=${match[2]}`); } }); socket.write('250 OK\r\n'); headers = []; } return; } const command = text.trim(); console.log(` [Server] Received: ${command}`); if (command.startsWith('EHLO')) { socket.write('250-mail.example.com\r\n'); socket.write('250-SMTPUTF8\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); inData = true; } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false }); // Test various header encodings const testCases = [ { subject: 'Simple ASCII subject', from: { name: 'John Doe', address: 'john@example.com' } }, { subject: 'Subject with émojis 🎉 and spéçiål çhåracters', from: { name: 'Jöhn Døe', address: 'john@example.com' } }, { subject: 'Japanese: こんにちは, Chinese: 你好, Arabic: مرحبا', from: { name: '山田太郎', address: 'yamada@example.com' } }, { subject: 'Very long subject that contains special characters and should be encoded and folded properly: café, naïve, résumé, piñata', from: { name: 'Sender with a véry løng nåme that éxceeds normal limits', address: 'sender@example.com' } } ]; for (const testCase of testCases) { console.log(` Testing: "${testCase.subject.substring(0, 50)}..."`); const email = new plugins.smartmail.Email({ from: testCase.from, to: ['recipient@example.com'], subject: testCase.subject, text: 'Testing header encoding', headers: { 'X-Custom': `Custom header with special chars: ${testCase.subject.substring(0, 20)}` } }); const result = await smtpClient.sendMail(email); expect(result).toBeDefined(); expect(result.messageId).toBeDefined(); } await testServer.server.close(); })(); // Scenario 6: Content-Type charset mismatches await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing Content-Type charset handling`); const testServer = await createTestServer({ onConnection: async (socket) => { console.log(' [Server] Client connected'); socket.write('220 mail.example.com ESMTP\r\n'); let inData = false; socket.on('data', (data) => { if (inData) { if (data.toString().includes('\r\n.\r\n')) { inData = false; socket.write('250 OK\r\n'); } return; } const command = data.toString().trim(); console.log(` [Server] Received: ${command}`); if (command.startsWith('EHLO')) { socket.write('250-mail.example.com\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); inData = true; } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false }); // Test with different charset declarations const email = new plugins.smartmail.Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Charset test', text: 'Text with special chars: é, ñ, ü', html: 'HTML with different chars: café, naïve
', headers: { 'Content-Type': 'text/plain; charset=iso-8859-1' // Mismatch with actual UTF-8 content } }); const result = await smtpClient.sendMail(email); console.log(` Result: ${result.messageId ? 'Success' : 'Failed'}`); expect(result).toBeDefined(); await testServer.server.close(); })(); console.log(`\n${testId}: All ${scenarioCount} encoding scenarios tested ✓`); });