| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- import assert from 'node:assert/strict';
- import dns from 'node:dns';
- import { test } from 'node:test';
- test('includes live current values for verification and dkim records', async () => {
- const originalResolver = dns.promises.Resolver;
- const lookup = new Map([
- ['example.com', ['v=spf1 ip4:192.0.2.10 a:mail.example.com ~all']],
- ['_mailhub.example.com', ['mailhub-verification=verify-token']],
- ['mh202607._domainkey.example.com', ['v=DKIM1; k=rsa; p=dkim-public']],
- ['_dmarc.example.com', ['v=DMARC1; p=none; rua=mailto:dmarc@example.com; adkim=s; aspf=s; pct=100']]
- ]);
- dns.promises.Resolver = class FakeResolver {
- setServers() {}
- async resolveTxt(name) {
- const value = lookup.get(name);
- if (!value) {
- const error = new Error('not found');
- error.code = 'ENODATA';
- throw error;
- }
- return value.map((record) => [record]);
- }
- async resolve4(name) {
- return name === 'mail.example.com' ? ['192.0.2.10'] : [];
- }
- async reverse(ip) {
- return ip === '192.0.2.10' ? ['mail.example.com'] : [];
- }
- };
- try {
- const { buildDnsGuide } = await import(`../src/dns-guide.js?test=${Date.now()}`);
- const guide = await buildDnsGuide({
- domain: 'example.com',
- selector: 'mh202607',
- verificationToken: 'verify-token',
- dkimPublic: 'dkim-public',
- senderHost: 'mail.example.com',
- sendingIp: '192.0.2.10',
- spfExtra: '',
- dmarcPolicy: 'none',
- dmarcRua: 'mailto:dmarc@example.com'
- });
- const verification = guide.records.find((record) => record.key === 'verification');
- const dkim = guide.records.find((record) => record.key === 'dkim');
- const spf = guide.records.find((record) => record.key === 'spf');
- assert.equal(guide.records.some((record) => record.key === 'ptr'), false);
- assert.deepEqual(verification.current, ['mailhub-verification=verify-token']);
- assert.deepEqual(dkim.current, ['v=DKIM1; k=rsa; p=dkim-public']);
- assert.deepEqual(guide.requiredSpf, ['a:mail.example.com']);
- assert.equal(spf.value, 'v=spf1 a:mail.example.com ~all');
- assert.equal(spf.value.includes('ip4:'), false);
- } finally {
- dns.promises.Resolver = originalResolver;
- }
- });
- test('removes the managed direct IP while preserving configured SPF extensions', async () => {
- const originalResolver = dns.promises.Resolver;
- dns.promises.Resolver = class FakeResolver {
- setServers() {}
- async resolveTxt(name) {
- if (name === 'example.com') {
- return [['v=spf1 ip4:192.0.2.10 a:mail.example.com include:spf.mailjet.com ~all']];
- }
- const error = new Error('not found');
- error.code = 'ENODATA';
- throw error;
- }
- async resolve4() {
- return ['192.0.2.20'];
- }
- };
- try {
- const { buildDnsGuide } = await import(`../src/dns-guide.js?test=${Date.now()}-spf-policy`);
- const guide = await buildDnsGuide({
- domain: 'example.com',
- selector: 'mailhub',
- verificationToken: 'verify-token',
- dkimPublic: 'dkim-public',
- senderHost: 'mail.example.com',
- sendingIp: '192.0.2.10',
- spfExtra: 'ip4:192.0.2.10 include:spf.mailjet.com',
- dmarcPolicy: 'none',
- dmarcRua: ''
- });
- const spf = guide.records.find((record) => record.key === 'spf');
- assert.equal(spf.value, 'v=spf1 a:mail.example.com include:spf.mailjet.com ~all');
- assert.match(spf.warnings.join('\n'), /直接 IP 授权/);
- } finally {
- dns.promises.Resolver = originalResolver;
- }
- });
- test('removes stale direct IP mechanisms after the managed sending IP changes', async () => {
- const originalResolver = dns.promises.Resolver;
- dns.promises.Resolver = class FakeResolver {
- setServers() {}
- async resolveTxt(name) {
- if (name === 'example.com') {
- return [['v=spf1 ip4:192.0.2.10 ip4:198.51.100.25 a:mail.example.com ~all']];
- }
- const error = new Error('not found');
- error.code = 'ENODATA';
- throw error;
- }
- async resolve4() {
- return ['192.0.2.10'];
- }
- };
- try {
- const { buildDnsGuide } = await import(`../src/dns-guide.js?test=${Date.now()}-spf-preserve`);
- const guide = await buildDnsGuide({
- domain: 'example.com',
- selector: 'mailhub',
- verificationToken: 'verify-token',
- dkimPublic: 'dkim-public',
- senderHost: 'mail.example.com',
- sendingIp: '192.0.2.20',
- spfExtra: '',
- dmarcPolicy: 'none',
- dmarcRua: ''
- });
- const spf = guide.records.find((record) => record.key === 'spf');
- assert.equal(spf.value, 'v=spf1 a:mail.example.com ~all');
- assert.match(spf.warnings.join('\n'), /直接 IP 授权/);
- } finally {
- dns.promises.Resolver = originalResolver;
- }
- });
- test('preserves direct IP mechanisms explicitly configured as SPF extensions', async () => {
- const originalResolver = dns.promises.Resolver;
- dns.promises.Resolver = class FakeResolver {
- setServers() {}
- async resolveTxt(name) {
- if (name === 'example.com') {
- return [['v=spf1 ip4:192.0.2.10 ip4:198.51.100.25 include:spf.mailjet.com ~all']];
- }
- const error = new Error('not found');
- error.code = 'ENODATA';
- throw error;
- }
- async resolve4() {
- return ['192.0.2.20'];
- }
- };
- try {
- const { buildDnsGuide } = await import(`../src/dns-guide.js?test=${Date.now()}-spf-explicit-ip`);
- const guide = await buildDnsGuide({
- domain: 'example.com',
- selector: 'mailhub',
- verificationToken: 'verify-token',
- dkimPublic: 'dkim-public',
- senderHost: 'mail.example.com',
- sendingIp: '192.0.2.20',
- spfExtra: 'ip4:198.51.100.25 include:spf.mailjet.com',
- dmarcPolicy: 'none',
- dmarcRua: ''
- });
- const spf = guide.records.find((record) => record.key === 'spf');
- assert.equal(
- spf.value,
- 'v=spf1 ip4:198.51.100.25 include:spf.mailjet.com a:mail.example.com ~all'
- );
- } finally {
- dns.promises.Resolver = originalResolver;
- }
- });
- test('builds PTR as a system delivery check', async () => {
- const originalResolver = dns.promises.Resolver;
- dns.promises.Resolver = class FakeResolver {
- setServers() {}
- async reverse(ip) {
- return ip === '192.0.2.10' ? ['mail.example.com'] : [];
- }
- };
- try {
- const { buildSystemDnsChecks } = await import(`../src/dns-guide.js?test=${Date.now()}-system`);
- const checks = await buildSystemDnsChecks({
- mailHostname: 'mail.example.com',
- sendingIp: '192.0.2.10'
- });
- assert.equal(checks.ptr.key, 'ptr');
- assert.equal(checks.ptr.host, '192.0.2.10');
- assert.equal(checks.ptr.value, 'mail.example.com');
- assert.equal(checks.ptr.status, 'ok');
- assert.deepEqual(checks.ptr.current, ['mail.example.com']);
- } finally {
- dns.promises.Resolver = originalResolver;
- }
- });
|