UNPKG

domainlooker

Version:

šŸ•µļø Mission-critical domain intelligence gathering tool with spy-themed interface. Comprehensive WHOIS, DNS, SSL, network analysis, subdomain discovery, and API-ready JSON exports.

360 lines • 14 kB
import * as fs from 'fs'; import * as path from 'path'; import { v4 as uuidv4 } from 'uuid'; export class JsonExportService { constructor(options = {}) { this.domains = []; this.startTime = Date.now(); this.requestId = uuidv4(); this.options = options; } addDomain(domainInfo) { const analysisData = this.transformDomainData(domainInfo); this.domains.push(analysisData); } transformDomainData(domainInfo) { const executionStart = Date.now(); return { domain: domainInfo.domain, status: this.determineOverallStatus(domainInfo), timestamp: new Date().toISOString(), executionTimeMs: Date.now() - executionStart, whois: this.transformWhoisData(domainInfo.whois), dns: this.transformDnsData(domainInfo.dns), ssl: this.transformSslData(domainInfo.ssl), network: this.transformNetworkData(domainInfo.network), subdomains: this.transformSubdomainData(domainInfo.subdomains), threatAssessment: this.performThreatAssessment(domainInfo), sources: this.collectDataSources(domainInfo) }; } determineOverallStatus(domainInfo) { const successfulServices = [ !!domainInfo.whois, !!domainInfo.dns, !!domainInfo.ssl, !!domainInfo.network, !!domainInfo.subdomains ].filter(Boolean).length; if (successfulServices >= 3) return 'success'; if (successfulServices >= 1) return 'partial'; return 'failed'; } transformWhoisData(whois) { if (!whois) { return { status: 'not_available', data: null, error: 'WHOIS data not available' }; } const daysUntilExpiry = whois.expirationDate ? Math.ceil((new Date(whois.expirationDate).getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : undefined; return { status: 'success', data: { registrar: whois.registrar, registrationDate: whois.registrationDate, expirationDate: whois.expirationDate, registrantCountry: whois.registrantCountry, nameServers: whois.nameServers, status: whois.status, daysUntilExpiry } }; } transformDnsData(dns) { if (!dns) { return { status: 'failed', data: null, error: 'DNS lookup failed' }; } const records = { a: dns.a, aaaa: dns.aaaa, mx: dns.mx, ns: dns.ns, txt: dns.txt, cname: dns.cname, soa: dns.soa }; const recordTypes = Object.keys(records).filter(key => records[key]); const totalRecords = recordTypes.reduce((sum, type) => { const record = records[type]; return sum + (Array.isArray(record) ? record.length : (record ? 1 : 0)); }, 0); return { status: 'success', data: { records, summary: { totalRecords, recordTypes, hasIpv4: !!(dns.a && dns.a.length > 0), hasIpv6: !!(dns.aaaa && dns.aaaa.length > 0), hasMail: !!(dns.mx && dns.mx.length > 0) } } }; } transformSslData(ssl) { if (!ssl) { return { status: 'no_certificate', data: null, error: 'No SSL certificate found' }; } return { status: 'success', data: { certificate: { subject: ssl.subject || '', issuer: ssl.issuer || '', validFrom: ssl.validFrom || '', validTo: ssl.validTo || '', serialNumber: ssl.serialNumber || '', fingerprint: ssl.fingerprint || '', signatureAlgorithm: ssl.signatureAlgorithm }, validation: { isValid: ssl.isValid !== false, daysUntilExpiry: ssl.daysUntilExpiry || 0, isExpired: ssl.daysUntilExpiry ? ssl.daysUntilExpiry <= 0 : false, isSelfSigned: ssl.issuer?.includes('self-signed') || false }, security: { keySize: ssl.keySize, protocol: ssl.protocol, vulnerabilities: [] } } }; } transformNetworkData(network) { if (!network) { return { status: 'skipped', data: null, error: 'Network scan was skipped' }; } const openPorts = network.openPorts || []; const services = (network.services || []).map((service) => ({ port: service.port, protocol: service.protocol, service: service.service, version: service.version, confidence: service.confidence || 'medium' })); return { status: 'success', data: { ports: { open: openPorts, filtered: [], total: openPorts.length }, services, summary: { totalOpenPorts: openPorts.length, commonServices: services.filter((s) => ['http', 'https', 'ssh', 'ftp', 'smtp'].includes(s.service.toLowerCase())).map((s) => s.service), unusualPorts: openPorts.filter((port) => ![21, 22, 25, 53, 80, 443, 993, 995].includes(port)) } } }; } transformSubdomainData(subdomains) { if (!subdomains) { return { status: 'skipped', data: null, error: 'Subdomain discovery was not enabled' }; } const statistics = { total: subdomains.totalFound || 0, bySource: { 'Certificate Transparency': subdomains.sources?.certificateTransparency?.length || 0, 'DNS Enumeration': subdomains.sources?.dnsEnumeration?.length || 0, 'Common Names': subdomains.sources?.commonNames?.length || 0 }, patterns: this.analyzeSubdomainPatterns(subdomains.subdomains || []), depthAnalysis: this.analyzeSubdomainDepth(subdomains.subdomains || []) }; return { status: 'success', data: { subdomains: subdomains.subdomains || [], sources: { certificateTransparency: subdomains.sources?.certificateTransparency || [], dnsEnumeration: subdomains.sources?.dnsEnumeration || [], commonNames: subdomains.sources?.commonNames || [] }, statistics } }; } analyzeSubdomainPatterns(subdomains) { const patterns = {}; subdomains.forEach(subdomain => { const parts = subdomain.split('.'); if (parts.length >= 3) { const firstLevel = parts[parts.length - 3]; patterns[firstLevel] = (patterns[firstLevel] || 0) + 1; } }); return patterns; } analyzeSubdomainDepth(subdomains) { const depths = {}; subdomains.forEach(subdomain => { const parts = subdomain.split('.'); const depth = parts.length - 2; // Subtract base domain parts depths[depth] = (depths[depth] || 0) + 1; }); return depths; } performThreatAssessment(domainInfo) { const threats = []; let riskScore = 0; // SSL Certificate Analysis if (!domainInfo.ssl) { threats.push({ type: 'missing_ssl', severity: 'high', title: 'No SSL Certificate', description: 'Domain does not have an SSL certificate configured', recommendation: 'Install and configure an SSL certificate to encrypt communications' }); riskScore += 25; } else if (domainInfo.ssl.daysUntilExpiry !== undefined && domainInfo.ssl.daysUntilExpiry < 30) { const severity = domainInfo.ssl.daysUntilExpiry < 7 ? 'critical' : 'high'; threats.push({ type: 'ssl_expiry', severity, title: 'SSL Certificate Expiring Soon', description: `SSL certificate expires in ${domainInfo.ssl.daysUntilExpiry} days`, recommendation: 'Renew SSL certificate before expiration to avoid service disruption', evidence: { daysUntilExpiry: domainInfo.ssl.daysUntilExpiry } }); riskScore += severity === 'critical' ? 30 : 20; } // Domain Age Analysis if (domainInfo.whois?.registrationDate) { const regDate = new Date(domainInfo.whois.registrationDate); const daysSinceReg = (Date.now() - regDate.getTime()) / (1000 * 60 * 60 * 24); if (daysSinceReg < 30) { threats.push({ type: 'recent_registration', severity: 'medium', title: 'Recently Registered Domain', description: `Domain was registered ${Math.round(daysSinceReg)} days ago`, recommendation: 'Verify domain legitimacy if unexpected', evidence: { daysSinceRegistration: Math.round(daysSinceReg) } }); riskScore += 15; } } // Network Exposure Analysis const openPorts = domainInfo.network?.openPorts?.length || 0; if (openPorts > 5) { threats.push({ type: 'open_ports', severity: 'medium', title: 'Multiple Open Ports', description: `${openPorts} open ports detected`, recommendation: 'Review and close unnecessary ports to reduce attack surface', evidence: { openPorts: domainInfo.network?.openPorts } }); riskScore += 10; } // Determine overall risk level let overallRisk; if (riskScore >= 70) overallRisk = 'critical'; else if (riskScore >= 40) overallRisk = 'high'; else if (riskScore >= 20) overallRisk = 'medium'; else overallRisk = 'low'; const summary = { criticalIssues: threats.filter(t => t.severity === 'critical').length, warnings: threats.filter(t => t.severity === 'high' || t.severity === 'medium').length, informational: threats.filter(t => t.severity === 'low' || t.severity === 'info').length }; return { overallRisk, riskScore, threats, recommendations: threats.map(t => t.recommendation).filter(Boolean), summary }; } collectDataSources(domainInfo) { return { whois: domainInfo.whois ? ['WHOIS Registry'] : [], dns: domainInfo.dns ? ['System DNS Resolver'] : [], ssl: domainInfo.ssl ? ['TLS Connection'] : [], network: domainInfo.network ? ['TCP Port Scan'] : [], subdomains: domainInfo.subdomains ? [ ...(domainInfo.subdomains.sources.certificateTransparency.length > 0 ? ['Certificate Transparency (crt.sh)'] : []), ...(domainInfo.subdomains.sources.commonNames.length > 0 ? ['Common Name Enumeration'] : []), ...(domainInfo.subdomains.sources.dnsEnumeration.length > 0 ? ['DNS Enumeration'] : []) ] : [], threatIntelligence: ['Internal Analysis Engine'] }; } async exportToFile(filename) { const response = this.generateResponse(); const jsonContent = JSON.stringify(response, null, 2); // Ensure the filename has .json extension const jsonFilename = filename.endsWith('.json') ? filename : `${filename}.json`; // Get absolute path const fullPath = path.resolve(jsonFilename); try { await fs.promises.writeFile(fullPath, jsonContent, 'utf8'); console.log(`\nšŸ“„ JSON Export Complete: ${fullPath}`); console.log(`šŸ” Exported ${this.domains.length} domains with structured intelligence data`); console.log(`šŸ“Š Schema version: ${response.meta.version} | Request ID: ${response.meta.requestId}`); } catch (error) { console.error(`āŒ Failed to export JSON: ${error}`); throw error; } } generateResponse() { const meta = { version: '1.0.0', timestamp: new Date().toISOString(), requestId: this.requestId, executionTimeMs: Date.now() - this.startTime, totalDomains: this.domains.length, options: { includeSubdomains: !!this.options.subdomains, includeNetworkScan: !this.options.quick, quickScan: !!this.options.quick, verbose: !!this.options.verbose } }; return { meta, data: this.domains }; } getAnalysisCount() { return this.domains.length; } // Method to get the structured data for API use getStructuredData() { return this.generateResponse(); } } //# sourceMappingURL=json-export.js.map