86 lines
2.8 KiB
TypeScript
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,
|
|
};
|
|
}
|