Files
backend/src/mail-dns/mail-dns.ts
T

86 lines
2.8 KiB
TypeScript

export const MAIL_IPV4 = '185.214.101.41';
export const MAIL_HOSTNAME = 'mail.meshkee.com';
export const MAIL_MX_PRIORITY = 10;
export const MAIL_SPF = 'v=spf1 mx -all';
/** Old provider selector (dkim._domainkey.example.com) — removed on mail DNS update. */
export const LEGACY_DKIM_NAME = 'dkim._domainkey';
export const DMARC_NAME = '_dmarc';
export type MailDkimKey = {
selector: string;
text: string;
};
/** Bare selector, or `name._domainkey` / `name._domainkey.example.com.` */
export function normalizeDkimSelector(raw: string | undefined | null): string | null {
if (raw == null) return null;
let input = raw.trim().replace(/^"+|"+$/g, '').trim();
if (!input) return null;
const hostMatch = input.match(/^([a-z0-9][a-z0-9-]*)\._domainkey(?:\.|$)/i);
if (hostMatch) return hostMatch[1].toLowerCase();
if (/^[a-z0-9][a-z0-9-]*$/i.test(input)) return input.toLowerCase();
return null;
}
export function parseDkimPaste(
raw: string,
expectedKind: 'ed25519' | 'rsa',
selectorHint?: string,
): MailDkimKey {
const input = raw.trim();
if (!input) {
throw new Error(
`Paste the ${expectedKind} DKIM TXT value (v=DKIM1; …) or the full Stalwart zone line.`,
);
}
const quoted = [...input.matchAll(/"([^"]*)"/g)].map((match) => match[1]).join('');
const compact = input.replace(/[()\n\r\t]+/g, ' ').replace(/\s+/g, ' ').trim();
const blob = (quoted || compact).replace(/"\s+"/g, '');
const txtMatch = blob.match(/v=DKIM1[\s\S]*/i);
let text = (txtMatch ? txtMatch[0] : blob).trim();
text = text.replace(/^"+|"+$/g, '').replace(/\s+/g, ' ').replace(/[.\s]+$/g, '').trim();
if (!/^v=DKIM1/i.test(text)) {
// Stalwart sometimes copies only the public key / p=… body.
const bare = text.replace(/^p=/i, '').replace(/\s+/g, '');
if (/^[A-Za-z0-9+/=]+$/.test(bare) && bare.length >= 20) {
text =
expectedKind === 'ed25519'
? `v=DKIM1; k=ed25519; h=sha256; p=${bare}`
: `v=DKIM1; k=rsa; h=sha256; p=${bare}`;
} else {
throw new Error(
`Could not find a v=DKIM1 value in the ${expectedKind} field. Paste the TXT value or Stalwart zone line.`,
);
}
}
const kind = /k=ed25519/i.test(text)
? 'ed25519'
: /k=rsa/i.test(text)
? 'rsa'
: null;
if (kind && kind !== expectedKind) {
throw new Error(
`That paste is ${kind} DKIM. Put it in the ${kind === 'ed25519' ? 'Ed25519' : 'RSA'} field.`,
);
}
const nameMatch = compact.match(/([a-z0-9][a-z0-9-]*)\._domainkey/i);
const selector =
(nameMatch ? nameMatch[1].toLowerCase() : null) || normalizeDkimSelector(selectorHint);
if (!selector) {
throw new Error(
'Could not find a DKIM selector. Enter the selector (for example v1-ed25519-20260901), or paste a zone line that includes …._domainkey.',
);
}
return {
selector,
text,
};
}