Improve SPF validation

This commit is contained in:
Reimar 2026-01-19 09:51:04 +01:00
parent dbde3a5834
commit 7183b21d24
Signed by: Reimar
GPG Key ID: 93549FA07F0AE268
4 changed files with 16 additions and 5 deletions

View File

@ -108,11 +108,19 @@ export class SpfRecord {
const term = this.constructor.fields.find(f => f.key === name); const term = this.constructor.fields.find(f => f.key === name);
if (!term) { if (!term) {
throw new ValidationError(`Unknown term: ${name}`); throw new ValidationError(name ? `Unknown term: ${name}` : "Syntax error");
} }
const [directive, value] = token.split(term.separator); const [directive, value] = token.split(term.separator);
const [, qualifier, key] = directive.match(/^([-+?~]?)(\w*)/); const [, qualifier, key] = directive.match(/^([-+?~]?)(.*)/);
if (key !== name) {
throw new ValidationError(`Invalid separator for term: ${name}`);
}
if (token.includes(term.separator) && !value) {
throw new ValidationError(`No value specified for term: ${name}`);
}
result.push({ qualifier, key, value }); result.push({ qualifier, key, value });
} }
@ -135,7 +143,7 @@ export class SpfRecord {
const term = this.constructor.fields.find(d => d.key === input.key); const term = this.constructor.fields.find(d => d.key === input.key);
if (!term) { if (!term) {
throw new ValidationError(`Unknown term: ${input.key}`); throw new ValidationError(input.key ? `Unknown term: ${input.key}` : "Syntax error");
} }
if (term.position < lastPos) { if (term.position < lastPos) {
@ -144,8 +152,8 @@ export class SpfRecord {
throw new ValidationError(`Term "${lastDirective.key}" must come after "${term.key}"`); throw new ValidationError(`Term "${lastDirective.key}" must come after "${term.key}"`);
} }
if (term instanceof Modifier && input.qualifier) { if (!term.qualifierAllowed && input.qualifier) {
throw new ValidationError(`Modifier "${term.key}" must not have a qualifier`) throw new ValidationError(`Term "${term.key}" must not have a qualifier`)
} }
if (!input.value && term.valueRequirement === ValueRequirement.REQUIRED) { if (!input.value && term.valueRequirement === ValueRequirement.REQUIRED) {

View File

@ -4,6 +4,7 @@ import { ValueRequirement } from "./ValueRequirement.js";
export class Mechanism extends Term { export class Mechanism extends Term {
separator = ":"; separator = ":";
placeholder = null; placeholder = null;
qualifierAllowed = true;
constructor(key) { constructor(key) {
super(key); super(key);

View File

@ -4,6 +4,7 @@ import { validateSpfDomain } from "./utils.js";
export class Modifier extends Term { export class Modifier extends Term {
separator = "="; separator = "=";
qualifierAllowed = false;
constructor(key) { constructor(key) {
super(key); super(key);

View File

@ -3,6 +3,7 @@ import { ValidationError } from "../ValidationError.js";
export class VersionTerm extends Term { export class VersionTerm extends Term {
separator = "="; separator = "=";
qualifierAllowed = false;
constructor(key, version) { constructor(key, version) {
super(key); super(key);