All files / Scripts/row Antispam.ts

100% Statements 51/51
100% Branches 13/13
100% Functions 12/12
100% Lines 47/47

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 984x 4x   4x   4x 42x 42x 42x               34x 308x 5x       29x       71x 582x 53x 53x 53x       18x         13x 13x 1x         12x       12x       12x   12x 12x 12x 12x 47x 47x 47x 18x           12x 12x     8x   14x 2x 2x     12x     34x   8x 6x 87x   6x 4x 4x 16x   4x      
import { mhaStrings } from "../mhaStrings";
import { Strings } from "../Strings";
import { Header } from "./Header";
import { Row } from "./Row";
 
export class AntiSpamReport {
    private sourceInternal = "";
    private unparsedInternal = "";
    private antiSpamRows: Row[] = [
        new Row("BCL", mhaStrings.mhaBcl, "X-Microsoft-Antispam"),
        new Row("PCL", mhaStrings.mhaPcl, "X-Microsoft-Antispam"),
        new Row("source", mhaStrings.mhaSource, "X-Microsoft-Antispam"),
        new Row("unparsed", mhaStrings.mhaUnparsed, "X-Microsoft-Antispam")
    ];
 
    public existsInternal(rows: Row[]): boolean {
        for (const row of rows) {
            if (row.value) {
                return true;
            }
        }
 
        return false;
    }
 
    private setRowValue(rows: Row[], key: string, value: string): boolean {
        for (const row of rows) {
            if (row.header.toUpperCase() === key.toUpperCase()) {
                row.value = value;
                row.onGetUrl = (headerName: string, value: string) => { return Strings.mapHeaderToURL(headerName, value); };
                return true;
            }
        }
 
        return false;
    }
 
    // https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/anti-spam-message-headers
    public parse(report: string): void {
        this.sourceInternal = report;
        if (!report) {
            return;
        }
 
        // Sometimes we see extraneous (null) in the report. They look like this: UIP:(null);(null);(null)SFV:SKI
        // First pass: Remove the (null).
        report = report.replace(/\(null\)/g, "");
 
        // Occasionally, we find the final ; is missing.
        // Second pass: Add one. If it is extraneous, the next pass will remove it.
        report = report + ";";
 
        // Removing the (null) can leave consecutive ; which confound later parsing.
        // Third pass: Collapse them.
        report = report.replace(/;+/g, ";");
 
        const lines = report.match(/(.*?):(.*?);/g);
        this.unparsedInternal = "";
        if (lines) {
            for (let iLine = 0; iLine < lines.length; iLine++) {
                const line = lines[iLine]?.match(/(.*?):(.*?);/m);
                if (line && line[1]) {
                    if (line[2] === undefined || !this.setRowValue(this.rows, line[1], line[2])) {
                        this.unparsedInternal += line[1] + ":" + line[2] + ";";
                    }
                }
            }
        }
 
        this.setRowValue(this.rows, "source", this.sourceInternal);
        this.setRowValue(this.rows, "unparsed", this.unparsedInternal);
    }
 
    public addInternal(report: string): void { this.parse(report); }
    public add(header: Header): boolean {
        if (header.header.toUpperCase() === "X-Microsoft-Antispam".toUpperCase()) {
            this.parse(header.value);
            return true;
        }
 
        return false;
    }
 
    public exists(): boolean { return this.existsInternal(this.rows); }
 
    public get source(): string { return this.sourceInternal; }
    public get unparsed(): string { return this.unparsedInternal; }
    public get rows(): Row[] { return this.antiSpamRows; }
    public toString(): string {
        if (!this.exists()) return "";
        const ret = ["AntiSpamReport"];
        this.rows.forEach(function (row) {
            if (row.value) { ret.push(row.toString()); }
        });
        return ret.join("\n");
    }
}