← back to Domain Sniper
check.js
81 lines
#!/usr/bin/env node
// Leak-minimal single-domain availability check.
// Method: Cloudflare 1.1.1.1 DoH (DNS-over-HTTPS), query type=NS.
// Avoids: WHOIS, RDAP at registry, GoDaddy availability API, registrar search boxes —
// all known leak vectors after 3 confirmed snipes (callr.app, callr.co, butlr.app).
const https = require('https');
const { isOwned } = require('./owned-check');
const target = (process.argv[2] || '').trim().toLowerCase();
if (!target || !target.includes('.')) {
console.error('usage: node check.js <domain>');
process.exit(2);
}
function doh(name, type = 'NS') {
return new Promise((resolve, reject) => {
const url = `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(name)}&type=${type}`;
https
.get(url, { headers: { Accept: 'application/dns-json' } }, (res) => {
let data = '';
res.on('data', (c) => (data += c));
res.on('end', () => {
try {
resolve(JSON.parse(data));
} catch (e) {
reject(new Error(`bad DoH response: ${data.slice(0, 200)}`));
}
});
})
.on('error', reject);
});
}
(async () => {
// Two parallel queries — NS (does the TLD know about it) + SOA (does it have a zone of its own).
// Both via Cloudflare. We do NOT call WHOIS/RDAP under any circumstance.
const [ns, soa] = await Promise.all([doh(target, 'NS'), doh(target, 'SOA')]);
// DNS Status codes:
// 0 = NOERROR — TLD knows the name (registered, possibly parked)
// 2 = SERVFAIL — temporary, retry
// 3 = NXDOMAIN — TLD doesn't know the name (unregistered)
const nxNs = ns.Status === 3;
const nxSoa = soa.Status === 3;
const hasNs = !!(ns.Answer && ns.Answer.length);
const hasSoa = !!(soa.Answer && soa.Answer.length);
// Available if BOTH NS + SOA come back NXDOMAIN. Either NOERROR signals the TLD recognizes it.
const available = nxNs && nxSoa;
const owned = isOwned(target);
const result = {
domain: target,
available,
owned,
confidence: available ? 'high' : hasNs || hasSoa ? 'high' : 'medium',
signals: {
ns_status: ns.Status,
soa_status: soa.Status,
has_ns: hasNs,
has_soa: hasSoa,
ns_records: hasNs ? ns.Answer.map((a) => a.data) : [],
},
method: 'cloudflare-doh-ns-soa',
leak_minimal: true,
timestamp: new Date().toISOString(),
advice: owned
? 'OWNED — this domain is in data/owned.json (you already have it). DoH still ran.'
: available
? 'AVAILABLE — register within minutes via API. Do not type into registrar search boxes.'
: 'TAKEN — TLD recognizes the name. Move on to the next candidate.',
};
console.log(JSON.stringify(result, null, 2));
process.exit(available ? 0 : 1);
})().catch((err) => {
console.error(JSON.stringify({ error: err.message, domain: target }, null, 2));
process.exit(3);
});