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
JavaScript
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