aboutsummaryrefslogtreecommitdiffstats
path: root/tools/dnssec-test.js
blob: 71ebceef2fe963149eac827dd864394a04fbe6e0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// DNSSEC chain validation against LIVE DNS. Needs network.
// Run: bun tools/dnssec-test.js
import { resolveTxtValidated } from '../src/dnssec.js';

let fails = 0;
const check = (name, ok, detail = '') => {
  console.log(` ${ok ? '✓' : '✗'} ${name}${detail ? ' — ' + String(detail).slice(0, 140) : ''}`);
  if (!ok) fails++;
};

// The canonical BIP-353 record: ₿[email protected] (alg 8 chain).
try {
  const { txts } = await resolveTxtValidated('matt.user._bitcoin-payment.mattcorallo.com');
  const uri = txts.find((t) => t.toLowerCase().startsWith('bitcoin:'));
  check('validates [email protected] (RSA chain)', !!uri, (uri || '').slice(0, 60) + '…');
} catch (e) { check('validates [email protected] (RSA chain)', false, e.message); }

// A Cloudflare-signed TXT (alg 13 chain): cloudflare.com SPF record.
try {
  const { txts } = await resolveTxtValidated('cloudflare.com');
  check('validates cloudflare.com TXT (ECDSA chain)', txts.length > 0, txts[0]);
} catch (e) { check('validates cloudflare.com TXT (ECDSA chain)', false, e.message); }

// An unsigned zone must FAIL closed, not pass quietly.
try {
  await resolveTxtValidated('google.com'); // google.com is famously unsigned
  check('unsigned zone fails closed', false, 'validated?!');
} catch (e) {
  check('unsigned zone fails closed', /not in a signed zone|no DNSKEY|fails/.test(e.message), e.message);
}

// A missing record must throw, not return empty-and-valid.
try {
  await resolveTxtValidated('definitely-not-real.user._bitcoin-payment.mattcorallo.com');
  check('missing record throws', false);
} catch (e) { check('missing record throws', true, e.message); }

console.log(fails ? `\n❌ ${fails} failure(s)` : '\n✅ DNSSEC validation behaves');
process.exit(fails ? 1 : 0);