x402-domain-check / tree / src/mailauth.js ยท raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
// Parsers for mail-authentication DNS records: SPF (RFC 7208), DMARC (RFC 7489), MTA-STS (RFC 8461),
// TLS-RPT (RFC 8460), BIMI; plus MX provider and parking-nameserver detection. Pure functions.

export function parseSpf(txts) {
  const recs = txts.filter((t) => /^v=spf1(\s|$)/i.test(t.trim()));
  if (!recs.length) return { present: false };
  const record = recs[0].trim();
  const terms = record.split(/\s+/).slice(1);
  const mech = terms.map((t) => { const m = /^([+\-~?]?)([a-z0-9]+)(?:[:=/](.*))?$/i.exec(t); return m ? { q: m[1] || '+', name: m[2].toLowerCase(), value: m[3] || null } : { q: '+', name: 'invalid', value: t }; });
  const all = mech.find((m) => m.name === 'all');
  const lookups = mech.filter((m) => ['include', 'a', 'mx', 'ptr', 'exists', 'redirect'].includes(m.name)).length;
  const policy = all ? { '-': 'fail', '~': 'softfail', '?': 'neutral', '+': 'pass' }[all.q] : (mech.some((m) => m.name === 'redirect') ? 'redirect' : 'none');
  return {
    present: true, record, multiple: recs.length > 1,
    all: all ? `${all.q === '+' ? '+' : all.q}all` : null, policy,
    includes: mech.filter((m) => m.name === 'include').map((m) => m.value),
    redirect: mech.find((m) => m.name === 'redirect')?.value || null,
    dns_lookups_top_level: lookups,
    invalid_terms: mech.filter((m) => m.name === 'invalid').map((m) => m.value),
  };
}

export function parseTags(record) {
  const tags = {};
  for (const part of record.split(';')) { const i = part.indexOf('='); if (i > 0) tags[part.slice(0, i).trim().toLowerCase()] = part.slice(i + 1).trim(); }
  return tags;
}

export function parseDmarc(txts, { inherited = false, from = null } = {}) {
  const recs = txts.filter((t) => /^v\s*=\s*DMARC1\s*(;|$)/i.test(t.trim()));
  if (!recs.length) return { present: false };
  const record = recs[0].trim(); const t = parseTags(record);
  const p = (t.p || '').toLowerCase();
  return {
    present: true, record, multiple: recs.length > 1, inherited_from: inherited ? from : null,
    policy: ['none', 'quarantine', 'reject'].includes(p) ? p : (p ? `invalid:${p}` : 'missing'),
    subdomain_policy: (t.sp || '').toLowerCase() || null,
    pct: t.pct !== undefined ? Number(t.pct) : 100,
    rua: !!t.rua, ruf: !!t.ruf,
    adkim: (t.adkim || 'r').toLowerCase(), aspf: (t.aspf || 'r').toLowerCase(),
  };
}

export function parseMtaSts(txts) {
  const r = txts.find((t) => /^v=STSv1/i.test(t.trim()));
  return r ? { present: true, id: parseTags(r).id || null } : { present: false };
}
export function parseTlsRpt(txts) { const r = txts.find((t) => /^v=TLSRPTv1/i.test(t.trim())); return { present: !!r }; }
export function parseBimi(txts) { const r = txts.find((t) => /^v=BIMI1/i.test(t.trim())); if (!r) return { present: false }; const t = parseTags(r); return { present: true, logo: t.l || null, vmc: !!t.a }; }
export function parseDkim(txts) {
  const r = txts.find((t) => /(^|;)\s*(v=DKIM1|k=|p=)/i.test(t));
  if (!r) return null;
  const t = parseTags(r);
  return { key_type: (t.k || 'rsa').toLowerCase(), revoked: t.p === '', testing: /y/i.test(t.t || '') };
}

// Common DKIM selectors (big providers). DKIM selectors can't be enumerated, so absence here proves nothing.
// Kept to 10 so a full report stays well under the Workers free-plan limit of 50 subrequests, even with DoH fallback.
export const DKIM_SELECTORS = ['google', 'selector1', 'selector2', 'default', 'k1', 's1', 's2', 'dkim', 'protonmail', 'fm1'];

const MX_PROVIDERS = [
  [/(^|\.)google(mail)?\.com$|aspmx\.l\.google\.com$|\.googlemail\.com$|smtp\.google\.com$/, 'Google Workspace / Gmail'],
  [/\.mail\.protection\.outlook\.com$|\.olc\.protection\.outlook\.com$|hotmail\.com$|outlook\.com$/, 'Microsoft 365 / Outlook'],
  [/\.yahoodns\.net$|yahoo\.com$/, 'Yahoo'],
  [/icloud\.com$|me\.com$/, 'Apple iCloud'],
  [/protonmail\.ch$|proton\.me$/, 'Proton Mail'],
  [/zoho\.(com|eu|in|com\.au)$/, 'Zoho Mail'],
  [/messagingengine\.com$/, 'Fastmail'],
  [/yandex\.(net|ru)$/, 'Yandex'],
  [/mail\.ru$/, 'Mail.ru'],
  [/mimecast\.com$/, 'Mimecast'],
  [/pphosted\.com$|ppe-hosted\.com$/, 'Proofpoint'],
  [/barracudanetworks\.com$/, 'Barracuda'],
  [/cf-emailsecurity\.net$|mx\.cloudflare\.net$/, 'Cloudflare'],
  [/amazonaws\.com$|amazonses\.com$/, 'Amazon SES / WorkMail'],
  [/secureserver\.net$/, 'GoDaddy'],
  [/ovh\.net$/, 'OVH'],
  [/ionos\.|kundenserver\.de$|1and1\./, 'IONOS'],
  [/gmx\.(net|com)$|web\.de$/, 'GMX / WEB.DE'],
  [/hostinger\.com$/, 'Hostinger'],
  [/namecheap|privateemail\.com$|registrar-servers\.com$/, 'Namecheap'],
  [/mailgun\.org$/, 'Mailgun'],
  [/sendgrid\.net$/, 'SendGrid'],
  [/tutanota\.de$|tuta\.io$/, 'Tuta'],
  [/improvmx\.com$/, 'ImprovMX (forwarding)'],
  [/forwardemail\.net$/, 'Forward Email (forwarding)'],
  [/mx\d*\.zoho/, 'Zoho Mail'],
];
export function mxProvider(hosts) {
  for (const h of hosts) for (const [re, name] of MX_PROVIDERS) if (re.test(h)) return name;
  return hosts.length ? 'other / self-hosted' : null;
}

// Nameservers of domain-parking / for-sale services.
const PARKING_NS = /(sedoparking\.com|parkingcrew\.net|bodis\.com|above\.com|afternic\.com|dan\.com|undeveloped\.com|parklogic\.com|uniregistrymarket\.link|huge-domains\.com|hugedomains\.com|domaincontrol\.com\.parked|ns1\.parked|parked\.com|namebrightdns\.com|smartname\.com|cashparking\.com|dsredirection\.com|fabulous\.com|voodoo\.com|rookdns\.com|ztomy\.com|brandbucket\.com|squadhelp\.com|atom\.com|perfectdomain\.com|epik\.com\.parked)$/;
export const isParkingNs = (ns) => PARKING_NS.test(ns);

agentgate-source: code mirror on Cloudflare Pages. All repos