email-dns-tools/assets/scripts/tools/DmarcTool.js
2026-01-14 13:55:59 +01:00

117 lines
3.3 KiB
JavaScript

import { ConstantField } from "../fields/ConstantField.js";
import { EnumField } from "../fields/EnumField.js";
import { IntField } from "../fields/IntField.js";
import { Field } from "../fields/Field.js";
import { DmarcUriListField } from "../fields/DmarcUriListField.js";
import { DnsTool } from "./DnsTool.js";
import { ValidationError } from "../ValidationError.js";
export class DmarcTool extends DnsTool {
static fields = [
new ConstantField("v", "DMARC1")
.required()
.atIndex(0),
new EnumField("p", ["none", "quarantine", "reject"])
.label("Mail Receiver policy")
.desc("How to handle failed validations. The email may be quarantined (usually means sent to spam) or rejected")
.options(["None", "Quarantine", "Reject"])
.required()
.atIndex(1)
.after("v"),
new EnumField("adkim", ["r", "s"])
.label("DKIM")
.desc("How strictly to handle DKIM validation")
.options(["Relaxed", "Strict"])
.default("r"),
new EnumField("aspf", ["r", "s"])
.label("SPF")
.desc("How strictly to handle SPF validation")
.options(["Relaxed", "Strict"])
.default("r"),
new EnumField("sp", ["none", "quarantine", "reject"])
.label("Mail Receiver policy (for subdomains)")
.desc("Same as Mail Receiver policy, but applies only to subdomains. If not set, Mail Receiver policy applies to both top-level domain and subdomains")
.category("advanced")
.options(["None", "Quarantine", "Reject"]),
new IntField("pct", 0, 100)
.label("Percentage")
.desc("Percentage of emails to apply DMARC validation on. Useful for split-testing and continuous rollout")
.category("advanced")
.default(100),
new DmarcUriListField("ruf")
.label("Send failure reports to")
.desc("When DMARC validation fails, reports are sent to this email")
.category("failure-reporting"),
new EnumField("fo", ["0", "1", "d", "s"])
.label("Failure reporting options")
.desc("Define how reports will be generated")
.category("failure-reporting")
.options([
"Generate DMARC failure report if any fail",
"Generate DMARC failure report if all fail",
"Generate DKIM failure report",
"Generate SPF failure report",
])
.default("0"),
new DmarcUriListField("rua")
.label("Send aggregate feedback to")
.desc("Aggregate reports will be sent to this email, if defined")
.category("failure-reporting"),
new IntField("ri", 0, 2 ** 32)
.label("Aggregate report interval")
.desc("Interval (in seconds) between aggregate reports")
.category("failure-reporting")
.default(86400),
new Field("rf").default("afrf"), // Other values not supported
];
static categories = {
"advanced": "Advanced",
"failure-reporting": "Failure reporting",
};
constructor(text) {
super(text);
}
tokenize() {
return this.text
.replace(/;\s+$/, "")
.split(/;\s*/);
}
getKeyValues() {
const result = [];
for (const token of this.tokenize()) {
const [key, value] = token.split(/\s*=\s*/);
if (!value) {
throw new ValidationError(`Field "${key}" is missing a value`);
}
result.push({ key, value });
}
return result;
}
fieldsToString() {
let tokens = this.constructor.fields
.filter(field => !field.defaultValue || field.getInputValue() !== field.defaultValue)
.filter(field => field.getInputValue())
.map(field => field.key + "=" + field.getInputValue());
return tokens.join("; ");
}
}