mirror of
https://github.com/jason5ng32/MyIP.git
synced 2026-11-04 08:55:47 +00:00
Remove callback adapters while preserving record formatting and errors. Co-Authored-By: GPT-6 <noreply@openai.com>
163 lines
7.1 KiB
JavaScript
163 lines
7.1 KiB
JavaScript
// Offline coverage for turning each transport's raw DNS answer into the one
|
|
// display string a result row shows — Node's Resolver objects and the DoH JSON
|
|
// envelope alike. No test performs a real lookup.
|
|
|
|
import assert from 'node:assert/strict';
|
|
import { Resolver } from 'node:dns/promises';
|
|
import { afterEach, describe, it } from 'node:test';
|
|
|
|
import { dohRecords, formatCaaRecords, formatSoaRecord, resolveDns, resolveDoh, withRootDot } from '../api/dns-resolver.js';
|
|
|
|
const originalResolveCname = Resolver.prototype.resolveCname;
|
|
const originalFetch = globalThis.fetch;
|
|
|
|
afterEach(() => {
|
|
Resolver.prototype.resolveCname = originalResolveCname;
|
|
globalThis.fetch = originalFetch;
|
|
});
|
|
|
|
describe('UDP DNS Promise API', () => {
|
|
const cases = [
|
|
['A', 'resolve4', ['192.0.2.1'], ['192.0.2.1']],
|
|
['AAAA', 'resolve6', ['2001:db8::1'], ['2001:db8::1']],
|
|
['TXT', 'resolveTxt', [['first', 'second'], ['third']], ['first', 'second', 'third']],
|
|
['CNAME', 'resolveCname', ['alias.example.test'], ['alias.example.test.']],
|
|
['NS', 'resolveNs', ['ns.example.test'], ['ns.example.test.']],
|
|
['MX', 'resolveMx', [{ priority: 10, exchange: 'mail.example.test' }], '10 mail.example.test.'],
|
|
['SOA', 'resolveSoa', {
|
|
nsname: 'ns.example.test', hostmaster: 'hostmaster.example.test',
|
|
serial: 1, refresh: 2, retry: 3, expire: 4, minttl: 5,
|
|
}, 'ns.example.test. hostmaster.example.test. 1 2 3 4 5'],
|
|
['CAA', 'resolveCaa', [{ critical: 0, type: 'CAA', issue: 'ca.example.test' }], '0 issue "ca.example.test"'],
|
|
];
|
|
|
|
for (const [type, method, records, expected] of cases) {
|
|
it(`preserves ${type} results and queries the configured server`, async (t) => {
|
|
for (const [, candidate] of cases) {
|
|
t.mock.method(Resolver.prototype, candidate, async () => {
|
|
assert.fail(`Unexpected DNS method: ${candidate}`);
|
|
});
|
|
}
|
|
const query = t.mock.method(Resolver.prototype, method, async () => records);
|
|
assert.deepEqual(await resolveDns('example.test', type, 'Example DNS', '192.0.2.1'), expected);
|
|
assert.equal(query.mock.callCount(), 1);
|
|
assert.deepEqual(query.mock.calls[0].arguments, ['example.test']);
|
|
assert.deepEqual(query.mock.calls[0].this.getServers(), ['192.0.2.1']);
|
|
});
|
|
}
|
|
|
|
it('returns N/A for an empty result', async (t) => {
|
|
t.mock.method(Resolver.prototype, 'resolve4', async () => []);
|
|
assert.equal(await resolveDns('example.test', 'A', 'Example DNS', '192.0.2.1'), 'N/A');
|
|
});
|
|
});
|
|
|
|
describe('DNS resolver record formatting', () => {
|
|
it('formats an SOA object in DNS presentation order, with the root dots the DoH path returns', () => {
|
|
assert.equal(formatSoaRecord({
|
|
nsname: 'ns1.example.com',
|
|
hostmaster: 'hostmaster.example.com',
|
|
serial: 2026082301,
|
|
refresh: 3600,
|
|
retry: 600,
|
|
expire: 1209600,
|
|
minttl: 300,
|
|
}), 'ns1.example.com. hostmaster.example.com. 2026082301 3600 600 1209600 300');
|
|
});
|
|
|
|
it('formats standard and provider-specific CAA tags from each record shape', () => {
|
|
assert.equal(formatCaaRecords([
|
|
{ critical: 0, type: 'CAA', issue: 'letsencrypt.org' },
|
|
{ critical: 128, type: 'CAA', issuewild: ';' },
|
|
{ critical: 0, type: 'CAA', iodef: 'mailto:security@example.com' },
|
|
{ critical: 1, type: 'CAA', customprovider: 'ca.example' },
|
|
]), [
|
|
'0 issue "letsencrypt.org"',
|
|
'128 issuewild ";"',
|
|
'0 iodef "mailto:security@example.com"',
|
|
'1 customprovider "ca.example"',
|
|
].join(', '));
|
|
});
|
|
|
|
it('drops a CAA record carrying no tag rather than rendering an undefined one', () => {
|
|
assert.equal(formatCaaRecords([
|
|
{ critical: 0, type: 'CAA' },
|
|
{ critical: 0, type: 'CAA', issue: 'ca.example' },
|
|
]), '0 issue "ca.example"');
|
|
});
|
|
});
|
|
|
|
describe('DoH answer selection', () => {
|
|
it('prefers the answer section', () => {
|
|
const data = {
|
|
Answer: [{ type: 1, data: '192.0.2.1' }],
|
|
Authority: [{ type: 6, data: 'ns1.example.com. hostmaster.example.com. 1 2 3 4 5' }],
|
|
};
|
|
assert.deepEqual(dohRecords(data, 'A'), data.Answer);
|
|
});
|
|
|
|
it('skips a CNAME answer and takes the authority SOA for a SOA query on an aliased name', () => {
|
|
const soa = { type: 6, data: 'ns1.example.com. hostmaster.example.com. 1 2 3 4 5' };
|
|
assert.deepEqual(dohRecords({
|
|
Answer: [{ type: 5, data: 'target.example.net.' }],
|
|
Authority: [soa],
|
|
}, 'SOA'), [soa]);
|
|
});
|
|
|
|
it('keeps a SOA answer at the zone apex', () => {
|
|
const soa = { type: 6, data: 'ns1.example.com. hostmaster.example.com. 1 2 3 4 5' };
|
|
assert.deepEqual(dohRecords({ Answer: [soa] }, 'SOA'), [soa]);
|
|
});
|
|
|
|
it('falls back to the authority SOA for a name below the zone apex', () => {
|
|
const soa = { type: 6, data: 'ns1.example.com. hostmaster.example.com. 1 2 3 4 5' };
|
|
assert.deepEqual(dohRecords({ Authority: [{ type: 2, data: 'ns1.example.com.' }, soa] }, 'SOA'), [soa]);
|
|
});
|
|
|
|
it('leaves the authority section alone for every other record type', () => {
|
|
const data = { Authority: [{ type: 6, data: 'ns1.example.com. hostmaster.example.com. 1 2 3 4 5' }] };
|
|
assert.deepEqual(dohRecords(data, 'A'), []);
|
|
assert.deepEqual(dohRecords(data, 'MX'), []);
|
|
});
|
|
|
|
it('reports nothing when neither section carries an answer', () => {
|
|
assert.deepEqual(dohRecords({}, 'SOA'), []);
|
|
assert.deepEqual(dohRecords({ Answer: [] }, 'A'), []);
|
|
});
|
|
});
|
|
|
|
describe('root-dot normalization', () => {
|
|
it('adds the dot only when it is missing', () => {
|
|
assert.equal(withRootDot('dns.google'), 'dns.google.');
|
|
assert.equal(withRootDot('dns.google.'), 'dns.google.');
|
|
});
|
|
|
|
it('normalizes the UDP side, which Node returns bare', async () => {
|
|
Resolver.prototype.resolveCname = async () => ['github.com'];
|
|
assert.deepEqual(
|
|
await resolveDns('www.github.com', 'CNAME', 'Example DNS', '192.0.2.1'),
|
|
['github.com.'],
|
|
);
|
|
});
|
|
|
|
it('normalizes the DoH side, whichever way the endpoint writes it', async () => {
|
|
globalThis.fetch = async () => new Response(JSON.stringify({
|
|
Answer: [{ type: 5, data: 'github.com' }, { type: 5, data: 'other.example.' }],
|
|
}), { status: 200 });
|
|
assert.deepEqual(
|
|
await resolveDoh('www.github.com', 'CNAME', 'Example DoH', 'https://doh.example.test/resolve?'),
|
|
['github.com.', 'other.example.'],
|
|
);
|
|
});
|
|
|
|
it('leaves address- and text-valued answers untouched', async () => {
|
|
globalThis.fetch = async () => new Response(JSON.stringify({
|
|
Answer: [{ type: 1, data: '192.0.2.1' }],
|
|
}), { status: 200 });
|
|
assert.deepEqual(
|
|
await resolveDoh('example.com', 'A', 'Example DoH', 'https://doh.example.test/resolve?'),
|
|
['192.0.2.1'],
|
|
);
|
|
});
|
|
});
|