/** * Synthetic fixtures for eml-parser.test.ts. Nothing here is real customer * content — all addresses, subjects, and bodies are invented for testing * only (per this milestone's explicit synthetic-fixture-only constraint). */ import type { Attachment } from '@/lib/types/autotask'; function makeAttachment(overrides: Partial & { id: number }): Attachment { return { attachmentType: 'FILE_ATTACHMENT', fullPath: '', title: '', publish: 1, contentType: 'message/rfc822', ...overrides, }; } /** Tier 1: exact `rfc.eml` present among message/rfc822 attachments (Microsoft "Report Message" flow). */ export const RFC_EML_TIER_ATTACHMENTS: Attachment[] = [ makeAttachment({ id: 1, title: 'rfc.eml', fullPath: 'rfc.eml' }), makeAttachment({ id: 2, title: 'OriginatingEmail.eml', fullPath: 'OriginatingEmail.eml' }), ]; /** Same tier, but with mixed case to verify case-insensitive matching. */ export const RFC_EML_TIER_ATTACHMENTS_UPPERCASE: Attachment[] = [ makeAttachment({ id: 1, title: 'RFC.EML', fullPath: 'RFC.EML' }), makeAttachment({ id: 2, title: 'OriginatingEmail.EML', fullPath: 'OriginatingEmail.EML' }), ]; /** Tier 2: KnowBe4 PhishER flow — versioned filename, no literal rfc.eml. */ export const KNOWBE4_TIER_ATTACHMENTS: Attachment[] = [ makeAttachment({ id: 10, title: 'phish_alert_sp2_2.0.0.0.eml', fullPath: 'phish_alert_sp2_2.0.0.0.eml', }), makeAttachment({ id: 11, title: 'OriginatingEmail.eml', fullPath: 'OriginatingEmail.eml' }), ]; /** Tier 3: only OriginatingEmail.eml present (older tickets, majority-case fallback). */ export const ORIGINATING_ONLY_ATTACHMENTS: Attachment[] = [ makeAttachment({ id: 20, title: 'OriginatingEmail.eml', fullPath: 'OriginatingEmail.eml' }), ]; /** Ambiguous: two non-OriginatingEmail message/rfc822 candidates, no rfc.eml — falls back to OriginatingEmail.eml. */ export const AMBIGUOUS_WITH_FALLBACK_ATTACHMENTS: Attachment[] = [ makeAttachment({ id: 30, title: 'weird_name_1.eml', fullPath: 'weird_name_1.eml' }), makeAttachment({ id: 31, title: 'weird_name_2.eml', fullPath: 'weird_name_2.eml' }), makeAttachment({ id: 32, title: 'OriginatingEmail.eml', fullPath: 'OriginatingEmail.eml' }), ]; /** Ambiguous with no fallback available — selectOriginalMessage should return null. */ export const AMBIGUOUS_NO_FALLBACK_ATTACHMENTS: Attachment[] = [ makeAttachment({ id: 40, title: 'weird_name_1.eml', fullPath: 'weird_name_1.eml' }), makeAttachment({ id: 41, title: 'weird_name_2.eml', fullPath: 'weird_name_2.eml' }), ]; /** No .eml attachments at all — selectOriginalMessage should return null. */ export const NO_EML_ATTACHMENTS: Attachment[] = [ makeAttachment({ id: 50, title: 'screenshot.png', fullPath: 'screenshot.png', contentType: 'image/png', }), ]; /** Empty attachment list. */ export const EMPTY_ATTACHMENTS: Attachment[] = []; // --------------------------------------------------------------------------- // Synthetic raw .eml buffers for parseEml (EVID-03/EVID-04). All addresses, // bodies, and content below are invented for testing only — no real // customer email content per this milestone's Out of Scope constraint. // --------------------------------------------------------------------------- /** * Rich multipart fixture: text + html bodies (each carrying the same URL), * one non-inline base64 attachment, and an Authentication-Results header * with spf=pass, dkim=fail, dmarc=none. */ export const RICH_MULTIPART_EML = Buffer.from( `From: "Attacker Corp" To: victim@wulfconsulting.test Cc: cc-user@wulfconsulting.test Reply-To: reply@evil-example.test Return-Path: Subject: Urgent: verify your account Date: Mon, 15 Jul 2026 12:00:00 +0000 Message-ID: Authentication-Results: mx.wulfconsulting.test; spf=pass smtp.mailfrom=evil-example.test; dkim=fail header.d=evil-example.test; dmarc=none header.from=evil-example.test Received: from mx1.example.test by mx2.example.test; Mon, 15 Jul 2026 11:59:00 +0000 Received: from mx0.example.test by mx1.example.test; Mon, 15 Jul 2026 11:58:00 +0000 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="BOUNDARY1" --BOUNDARY1 Content-Type: multipart/alternative; boundary="BOUNDARY2" --BOUNDARY2 Content-Type: text/plain; charset="UTF-8" Please visit http://evil-example.test/verify to verify your account. --BOUNDARY2 Content-Type: text/html; charset="UTF-8"

Please visit this link to verify your account.

--BOUNDARY2-- --BOUNDARY1 Content-Type: application/pdf; name="invoice.pdf" Content-Disposition: attachment; filename="invoice.pdf" Content-Transfer-Encoding: base64 SGVsbG8gV29ybGQh --BOUNDARY1-- ` ); /** Same as RICH_MULTIPART_EML but also carries Authentication-Results-Original. */ export const RICH_MULTIPART_WITH_AUTH_ORIGINAL_EML = Buffer.from( `From: "Attacker Corp" To: victim@wulfconsulting.test Subject: Urgent: verify your account (remediated) Date: Mon, 15 Jul 2026 12:00:00 +0000 Message-ID: Authentication-Results: mx.wulfconsulting.test; spf=fail smtp.mailfrom=evil-example.test; dkim=fail header.d=evil-example.test; dmarc=fail header.from=evil-example.test Authentication-Results-Original: mx.wulfconsulting.test; spf=pass smtp.mailfrom=evil-example.test; dkim=pass header.d=evil-example.test; dmarc=pass header.from=evil-example.test MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Body text for the remediated-header fixture. ` ); /** * Inline/CID attachment fixture: html references cid:sig123, wrapped in * multipart/related so mailparser marks the image attachment `related: true` * (Pitfall 5 — inline parts must be kept, not dropped). */ export const INLINE_ATTACHMENT_EML = Buffer.from( `From: sender@evil-example.test To: victim@wulfconsulting.test Subject: Newsletter with inline logo Date: Mon, 15 Jul 2026 12:00:00 +0000 Message-ID: MIME-Version: 1.0 Content-Type: multipart/related; boundary="RELBOUND" --RELBOUND Content-Type: multipart/alternative; boundary="ALTBOUND" --ALTBOUND Content-Type: text/plain; charset="UTF-8" Plain text body with an inline logo. --ALTBOUND Content-Type: text/html; charset="UTF-8"

Hello

--ALTBOUND-- --RELBOUND Content-Type: image/png; name="sig.png" Content-Disposition: inline Content-ID: Content-Transfer-Encoding: base64 iVBORw0KGgo= --RELBOUND-- ` ); /** Long-body fixture — long enough to force buildBodyPreview truncation. */ const LONG_PARAGRAPH = 'This is a long paragraph of synthetic phishing-style body text repeated ' + 'several times to exceed the body preview truncation threshold. '.repeat(20); export const LONG_BODY_EML = Buffer.from( `From: sender@evil-example.test To: victim@wulfconsulting.test Subject: Long body fixture Date: Mon, 15 Jul 2026 12:00:00 +0000 Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" ${LONG_PARAGRAPH} ` ); /** Fuzzy (scheme-less) www. URL fixture, to exercise linkify-it's fuzzyLink mode. */ export const FUZZY_URL_EML = Buffer.from( `From: sender@evil-example.test To: victim@wulfconsulting.test Subject: Fuzzy URL fixture Date: Mon, 15 Jul 2026 12:00:00 +0000 Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Visit www.evil-example.com/login to reset your password. ` ); /** Oversized buffer — exceeds MAX_EML_BYTES, must be rejected before simpleParser runs. */ export function makeOversizedEmlBuffer(maxBytes: number): Buffer { const header = `From: sender@evil-example.test To: victim@wulfconsulting.test Subject: Oversized fixture Date: Mon, 15 Jul 2026 12:00:00 +0000 Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" `; const padding = 'A'.repeat(maxBytes + 1024 - header.length); return Buffer.from(header + padding); }