import assert from 'node:assert/strict'; import { mkdtempSync } from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; import { test } from 'node:test'; import { createDomain, createInboundMailbox, createInboundMessage, createUser, getInboundMessage, initDatabase } from '../src/db.js'; import { repairStoredInboundMime } from '../src/inbound-mime-repair.js'; test('repairStoredInboundMime reparses legacy APPEND records and is idempotent', async () => { initDatabase(mkdtempSync(path.join(tmpdir(), 'mailhub-inbound-mime-repair-')), 'repair-secret'); const user = createUser({ username: 'repair-user', email: 'repair@example.com', password: 'password123' }); createDomain(user.id, { domain: 'repair.example', selector: 'mh', verificationToken: 'verify', dkimPublic: 'public', dkimPrivate: 'private', senderHost: 'mail.repair.example', sendingIp: '192.0.2.40', spfExtra: '', dmarcPolicy: 'none', dmarcRua: '' }); const mailbox = createInboundMailbox(user.id, { address: 'admin@repair.example', password: 'mailbox-pass-123' }); const rawMessage = [ 'From: Admin ', 'To: Bob ', 'Subject: =?UTF-8?Q?=E6=A0=B8=E4=BA=91?=', ' =?UTF-8?Q?=E8=AE=A1=E7=AE=97?=', 'Message-ID: ', 'MIME-Version: 1.0', 'Content-Type: multipart/alternative; boundary="legacy-boundary"', '', '--legacy-boundary', 'Content-Type: text/plain; charset=UTF-8', 'Content-Transfer-Encoding: base64', '', Buffer.from('修复后的正文', 'utf8').toString('base64'), '--legacy-boundary', 'Content-Type: text/html; charset=UTF-8', '', '

Repaired HTML body.

', '--legacy-boundary--', '' ].join('\r\n'); const legacyMessage = createInboundMessage(mailbox, { folder: 'Sent', sender: 'admin@repair.example', recipients: ['bob@example.net'], subject: '=?UTF-8?Q?=E6=A0=B8=E4=BA=91?= =?UTF-8?Q?=E8=AE=A1=E7=AE=97?=', messageId: '', rawMessage, textBody: rawMessage.split('\r\n\r\n').slice(1).join('\r\n\r\n') }); const attachmentRaw = [ 'From: Admin ', 'To: Bob ', 'Subject: Attached notes', 'Content-Type: multipart/mixed; boundary="attachment-boundary"', '', '--attachment-boundary', 'Content-Type: text/plain; charset=UTF-8', 'Content-Disposition: attachment; filename="notes.txt"', '', 'Attachment content', '--attachment-boundary--', '' ].join('\r\n'); const attachmentMessage = createInboundMessage(mailbox, { folder: 'Sent', sender: 'admin@repair.example', recipients: ['bob@example.net'], subject: 'Attached notes', rawMessage: attachmentRaw, textBody: attachmentRaw.split('\r\n\r\n').slice(1).join('\r\n\r\n') }); const legitimateMessage = createInboundMessage(mailbox, { folder: 'Sent', sender: 'admin@repair.example', recipients: ['bob@example.net'], subject: 'Legitimate body', rawMessage: [ 'From: Admin ', 'To: Bob ', 'Subject: Legitimate body', 'Content-Type: multipart/alternative; boundary="legitimate-boundary"', '', '--legitimate-boundary', 'Content-Type: text/plain; charset=UTF-8', '', '-- signature', '--legitimate-boundary--', '' ].join('\r\n'), textBody: '-- signature' }); assert.deepEqual(await repairStoredInboundMime(), { repaired: 2, failed: 0 }); const repaired = getInboundMessage(user.id, legacyMessage.id); assert.equal(repaired.subject, '核云计算'); assert.equal(repaired.textBody, '修复后的正文'); assert.match(repaired.htmlBody, /Repaired HTML body/); assert.equal(repaired.preview, '修复后的正文'); assert.match(repaired.rawMessage, /Subject: =\?UTF-8\?Q\?/); const repairedAttachment = getInboundMessage(user.id, attachmentMessage.id); assert.equal(repairedAttachment.textBody, ''); assert.equal(repairedAttachment.preview, ''); assert.equal(getInboundMessage(user.id, legitimateMessage.id).textBody, '-- signature'); assert.deepEqual(await repairStoredInboundMime(), { repaired: 0, failed: 0 }); });