# forensic ## Purpose Implements `parseDmarcForensic`, the entry point for parsing DMARC forensic (RUF) reports. Forensic reports notify domain owners of individual authentication failures; they share the `` / `` / `` structure with aggregate reports but omit the `` block and may include a raw MIME-formatted `auth_failure_report` element. This module provides the same auto-detect-decompress → parse → map → validate pipeline as the aggregate parser but targets the forensic schema. ## Features - Auto-detects gzip input via magic-byte probe - Accepts raw XML strings or `Uint8Array` binary blobs - Maps snake_case XML fields to camelCase typed fields - Surfaces `authFailureReport` string when present in the source XML - Validates against `DmarcForensicReportSchema` (Zod) - Emits OTel counter and histogram for both success and error paths - Wraps all failures in typed `DmarcError` with stable codes ## Usage: Basic Example ```ts import { parseDmarcForensic } from "@suaveplan/dmarc/parsers/forensic"; const report = parseDmarcForensic(` 1.0 Example Corp dmarc@example.com ruf-001 16094592001609545600 example.com rr

none

100
`); console.log(report.feedback.reportMetadata.orgName); // "Example Corp" ``` ## Usage: Advanced Example ```ts import { parseDmarcForensic } from "@suaveplan/dmarc/parsers/forensic"; import { DmarcError, DMARC_CODES } from "@suaveplan/dmarc/errors"; import { gzipSync, strToU8 } from "fflate"; const compressed = gzipSync(strToU8(xmlString)); const report = parseDmarcForensic(compressed); // Access optional auth failure report body if (report.authFailureReport) { console.log("Failure report MIME body:", report.authFailureReport); } // Discriminated error handling try { parseDmarcForensic("xml"); } catch (err) { if (err instanceof DmarcError && err.code === DMARC_CODES.INVALID_REPORT) { // Schema validation failed — missing required elements } } ``` ## API Reference ### `parseDmarcForensic(input, options?): DmarcForensicReport` **Parameters:** - `input: string | Uint8Array` — raw XML string or binary data - `options.decompress?: boolean` — force gzip decompression **Returns:** `DmarcForensicReport` — validated forensic report **Throws:** - `DmarcError(DMARC.PARSE_ERROR)` — XML parse failure - `DmarcError(DMARC.INVALID_REPORT)` — schema validation failure or missing required elements - `DmarcError(DMARC.UNSUPPORTED_ENCODING)` — gzip decompression failure ### `ParseDmarcForensicOptions` `{ decompress?: boolean }` ## Implementation Notes The forensic parser is structurally identical to the aggregate parser except for the output schema. Both share the same `str`/`num` coercion helpers and the same two-phase (map → validate) approach. In practice, RFC 7489 forensic reports are far less common than aggregate reports and are often transmitted as raw MIME messages rather than standalone XML files; the `authFailureReport` field is therefore optional and surfaced as a plain string for callers to process further if needed.