3.4 KiB
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 <feedback> / <report_metadata> / <policy_published> structure with aggregate reports but omit the <record> 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
Uint8Arraybinary blobs - Maps snake_case XML fields to camelCase typed fields
- Surfaces
authFailureReportstring 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
DmarcErrorwith stable codes
Usage: Basic Example
import { parseDmarcForensic } from "@suaveplan/dmarc/parsers/forensic";
const report = parseDmarcForensic(`
<feedback>
<version>1.0</version>
<report_metadata>
<org_name>Example Corp</org_name>
<email>dmarc@example.com</email>
<report_id>ruf-001</report_id>
<date_range><begin>1609459200</begin><end>1609545600</end></date_range>
</report_metadata>
<policy_published>
<domain>example.com</domain>
<adkim>r</adkim><aspf>r</aspf><p>none</p><pct>100</pct>
</policy_published>
</feedback>
`);
console.log(report.feedback.reportMetadata.orgName); // "Example Corp"
Usage: Advanced Example
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("<bad>xml</bad>");
} 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 dataoptions.decompress?: boolean— force gzip decompression
Returns: DmarcForensicReport — validated forensic report
Throws:
DmarcError(DMARC.PARSE_ERROR)— XML parse failureDmarcError(DMARC.INVALID_REPORT)— schema validation failure or missing required elementsDmarcError(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.