| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- import assert from 'node:assert/strict';
- import { afterEach, test } from 'node:test';
- import { applyDnsSetup, testDnsCredential } from '../src/dns-providers.js';
- const originalFetch = globalThis.fetch;
- afterEach(() => {
- globalThis.fetch = originalFetch;
- });
- test('cloudflare provider tests credentials and replaces duplicate SPF records', async () => {
- const calls = [];
- globalThis.fetch = async (url, options = {}) => {
- calls.push({ url: String(url), method: options.method || 'GET', body: options.body });
- if (String(url).includes('/zones?')) return json({ success: true, result: [{ id: 'zone-1', name: 'example.com' }] });
- if (String(url).includes('/zones/zone-1') && !String(url).includes('/dns_records')) {
- return json({ success: true, result: { id: 'zone-1', name: 'example.com' } });
- }
- if (String(url).includes('/dns_records?')) {
- return json({
- success: true,
- result: [
- { id: 'spf-1', type: 'TXT', name: 'example.com', content: 'v=spf1 include:old ~all' },
- { id: 'spf-2', type: 'TXT', name: 'example.com', content: 'v=spf1 include:duplicate ~all' }
- ]
- });
- }
- return json({ success: true, result: { id: 'ok' } });
- };
- const credential = cloudflareCredential();
- assert.equal((await testDnsCredential(credential)).ok, true);
- const result = await applyDnsSetup(domainFixture(), credential, {
- records: [{ key: 'spf', host: 'example.com', type: 'TXT', value: 'v=spf1 ip4:127.0.0.1 ~all' }]
- });
- assert.equal(result.ok, true);
- assert.ok(calls.some((call) => call.method === 'PUT' && call.url.includes('/dns_records/spf-1')));
- assert.ok(calls.some((call) => call.method === 'DELETE' && call.url.includes('/dns_records/spf-2')));
- });
- test('aliyun provider signs and sends create/update record actions', async () => {
- const actions = [];
- globalThis.fetch = async (url) => {
- const params = new URL(String(url)).searchParams;
- const action = params.get('Action');
- actions.push(action);
- if (action === 'DescribeDomainRecords') {
- return json({
- DomainRecords: {
- Record: [{ RecordId: '1', RR: '_dmarc', Type: 'TXT', Value: 'v=DMARC1; p=none' }]
- }
- });
- }
- return json({});
- };
- const credential = aliyunCredential();
- assert.equal((await testDnsCredential(credential)).ok, true);
- const result = await applyDnsSetup(domainFixture(), credential, {
- records: [{ key: 'dmarc', host: '_dmarc.example.com', type: 'TXT', value: 'v=DMARC1; p=reject' }]
- });
- assert.equal(result.ok, true);
- assert.ok(actions.includes('UpdateDomainRecord'));
- });
- test('dnspod provider signs and sends create record actions', async () => {
- const actions = [];
- globalThis.fetch = async (url, options = {}) => {
- assert.equal(String(url), 'https://dnspod.tencentcloudapi.com');
- actions.push(options.headers['X-TC-Action']);
- if (options.headers['X-TC-Action'] === 'DescribeRecordList') {
- return json({ Response: { RecordList: [] } });
- }
- return json({ Response: { RecordId: 123 } });
- };
- const credential = dnspodCredential();
- assert.equal((await testDnsCredential(credential)).ok, true);
- const result = await applyDnsSetup(domainFixture(), credential, {
- records: [{ key: 'dkim', host: 'mh._domainkey.example.com', type: 'TXT', value: 'v=DKIM1; k=rsa; p=abc' }]
- });
- assert.equal(result.ok, true);
- assert.ok(actions.includes('CreateRecord'));
- });
- test('one-click dns setup only applies records under the user domain zone', async () => {
- const calls = [];
- globalThis.fetch = async (url, options = {}) => {
- calls.push({ url: String(url), method: options.method || 'GET' });
- if (String(url).includes('/zones?')) return json({ success: true, result: [{ id: 'zone-1', name: 'example.com' }] });
- if (String(url).includes('/dns_records?')) return json({ success: true, result: [] });
- return json({ success: true, result: { id: 'ok' } });
- };
- const result = await applyDnsSetup(domainFixture(), cloudflareCredential(), {
- records: [
- {
- key: 'dkim',
- host: 'mh._domainkey.example.com',
- type: 'TXT',
- value: 'v=DKIM1; k=rsa; p=abc',
- status: 'missing'
- },
- {
- key: 'sender-a',
- host: 'in.ss5.xyz',
- type: 'A',
- value: '127.0.0.1',
- status: 'ok'
- }
- ]
- });
- assert.equal(result.ok, true);
- assert.equal(result.results.length, 1);
- assert.equal(result.results[0].key, 'dkim');
- assert.equal(calls.filter((call) => call.method === 'POST').length, 1);
- });
- test('cloudflare one-click dns can use the current domain zone with a multi-zone token', async () => {
- const calls = [];
- globalThis.fetch = async (url, options = {}) => {
- calls.push({ url: String(url), method: options.method || 'GET' });
- if (String(url).includes('/zones?name=other.com')) {
- return json({ success: true, result: [{ id: 'zone-other', name: 'other.com' }] });
- }
- if (String(url).includes('/dns_records?')) return json({ success: true, result: [] });
- return json({ success: true, result: { id: 'ok' } });
- };
- const result = await applyDnsSetup(
- { ...domainFixture(), domain: 'other.com', senderHost: 'mail.other.com' },
- cloudflareCredential(),
- {
- records: [
- {
- key: 'verification',
- host: '_mailhub.other.com',
- type: 'TXT',
- value: 'mailhub-verification=token',
- status: 'missing'
- }
- ]
- }
- );
- assert.equal(result.ok, true);
- assert.equal(result.results[0].ok, true);
- assert.ok(calls.some((call) => call.url.includes('/zones?name=other.com')));
- assert.ok(calls.some((call) => call.method === 'POST' && call.url.includes('/zones/zone-other/dns_records')));
- });
- test('cloudflare one-click dns discovers the parent zone for subdomain sending domains', async () => {
- const calls = [];
- globalThis.fetch = async (url, options = {}) => {
- calls.push({ url: String(url), method: options.method || 'GET' });
- if (String(url).includes('/zones?name=sender.a4sky.com')) {
- return json({ success: true, result: [] });
- }
- if (String(url).includes('/zones?name=a4sky.com')) {
- return json({ success: true, result: [{ id: 'zone-a4sky', name: 'a4sky.com' }] });
- }
- if (String(url).includes('/dns_records?')) return json({ success: true, result: [] });
- return json({ success: true, result: { id: 'ok' } });
- };
- const result = await applyDnsSetup(
- { ...domainFixture(), domain: 'sender.a4sky.com', senderHost: 'in.ss5.xyz' },
- cloudflareCredential(),
- {
- records: [
- {
- key: 'verification',
- host: '_mailhub.sender.a4sky.com',
- type: 'TXT',
- value: 'mailhub-verification=token',
- status: 'missing'
- }
- ]
- }
- );
- assert.equal(result.ok, true);
- assert.equal(result.results[0].ok, true);
- assert.ok(calls.some((call) => call.url.includes('/zones?name=sender.a4sky.com')));
- assert.ok(calls.some((call) => call.url.includes('/zones?name=a4sky.com')));
- assert.ok(calls.some((call) => call.method === 'POST' && call.url.includes('/zones/zone-a4sky/dns_records')));
- });
- function cloudflareCredential() {
- return {
- provider: 'cloudflare',
- zoneName: 'example.com',
- defaultTtl: 600,
- credentials: { apiToken: 'token' }
- };
- }
- function aliyunCredential() {
- return {
- provider: 'aliyun',
- zoneName: 'example.com',
- defaultTtl: 600,
- credentials: { accessKeyId: 'id', accessKeySecret: 'secret' }
- };
- }
- function dnspodCredential() {
- return {
- provider: 'dnspod',
- zoneName: 'example.com',
- defaultTtl: 600,
- credentials: { secretId: 'id', secretKey: 'secret' }
- };
- }
- function domainFixture() {
- return {
- domain: 'example.com',
- senderHost: 'mail.example.com',
- sendingIp: '127.0.0.1'
- };
- }
- function json(payload) {
- return {
- ok: true,
- status: 200,
- async json() {
- return payload;
- }
- };
- }
|