UNPKG

domainlooker

Version:

A fast CLI and MCP server for inspecting domains: WHOIS/RDAP, DNS, SSL, ports, subdomains, with CSV/JSON export.

124 lines 4.83 kB
import { WhoisService } from '../services/whois.js'; import { DNSService } from '../services/dns.js'; import { SSLService } from '../services/ssl.js'; import { NetworkService } from '../services/network.js'; import { SubdomainService } from '../services/subdomain.js'; import { PropagationService } from '../services/propagation.js'; export function hasWhoisData(whois) { // A parser can leave a key set to `undefined` (a matched label with no value), // so require at least one field with an actual value — not merely a key. return !!whois && Object.values(whois).some(v => v != null && (!Array.isArray(v) || v.length > 0)); } export function hasDnsData(dns) { return !!dns && Object.values(dns).some(v => v != null && (!Array.isArray(v) || v.length > 0)); } /** Lightweight, factual checks surfaced at the end of a report and in exports. */ export function collectAdvisories(info) { const advisories = []; if (!info.ssl) { advisories.push('No SSL certificate detected.'); } else if (info.ssl.daysUntilExpiry !== undefined && info.ssl.daysUntilExpiry < 30) { advisories.push(`SSL certificate expires in ${info.ssl.daysUntilExpiry} days.`); } if (info.whois?.registrationDate) { const days = (Date.now() - new Date(info.whois.registrationDate).getTime()) / 86400000; if (days >= 0 && days < 30) { advisories.push(`Domain was registered ${Math.round(days)} days ago.`); } } return advisories; } /** * Gathers domain intelligence with no side effects (no console output, no * spinners). Every method resolves to its data or `null` and never rejects, so * callers can run them concurrently and compose the results freely. This is the * shared engine behind both the CLI and the MCP server. */ export class DomainCollector { constructor() { this.whoisService = new WhoisService(); this.dnsService = new DNSService(); this.sslService = new SSLService(); this.networkService = new NetworkService(); this.subdomainService = new SubdomainService(); this.propagationService = new PropagationService(); } /** Run every enabled lookup in parallel; total time is bounded by the slowest one. */ async collect(domain, options = {}) { const info = { domain }; const tasks = [ this.whois(domain, options).then(r => { info.whois = r ?? undefined; }), this.dns(domain, options).then(r => { info.dns = r ?? undefined; }), this.ssl(domain, options).then(r => { info.ssl = r ?? undefined; }), ]; if (!options.quick) { tasks.push(this.ports(domain, options).then(r => { info.network = r ?? undefined; })); } if (options.subdomains) { tasks.push(this.subdomains(domain, options).then(r => { info.subdomains = r ?? undefined; })); } await Promise.all(tasks); return info; } async whois(domain, options = {}) { try { const result = await this.whoisService.lookup(domain, { timeout: options.whoisTimeoutMs, rdapTimeout: options.rdapTimeoutMs, }); // A lookup can succeed while yielding nothing usable; report that as "no data". return hasWhoisData(result) ? result : null; } catch (error) { options.onError?.('whois', error); return null; } } async dns(domain, options = {}) { try { return await this.dnsService.lookup(domain); } catch (error) { options.onError?.('dns', error); return null; } } async ssl(domain, options = {}) { try { return await this.sslService.getCertificate(domain, 443, options.sslTimeoutMs); } catch (error) { options.onError?.('ssl', error); return null; } } async ports(domain, options = {}) { try { return await this.networkService.getNetworkInfo(domain, { timeoutMs: options.portTimeoutMs }); } catch (error) { options.onError?.('ports', error); return null; } } async subdomains(domain, options = {}) { try { return await this.subdomainService.discoverSubdomains(domain); } catch (error) { options.onError?.('subdomains', error); return null; } } async propagation(domain, recordType = 'A', options = {}) { try { return await this.propagationService.check(domain, recordType); } catch (error) { options.onError?.('propagation', error); return null; } } } //# sourceMappingURL=collector.js.map