// DNS Reconnaissance Tool - Frontend JavaScript class ReconTool { constructor() { this.currentScanId = null; this.pollInterval = null; this.currentReport = null; this.init(); } init() { this.bindEvents(); } bindEvents() { // Start scan button document.getElementById('startScan').addEventListener('click', () => { this.startScan(); }); // New scan button document.getElementById('newScan').addEventListener('click', () => { this.resetToForm(); }); // Report view toggles document.getElementById('showJson').addEventListener('click', () => { this.showReport('json'); }); document.getElementById('showText').addEventListener('click', () => { this.showReport('text'); }); // Download buttons document.getElementById('downloadJson').addEventListener('click', () => { this.downloadReport('json'); }); document.getElementById('downloadText').addEventListener('click', () => { this.downloadReport('text'); }); // Enter key in target field document.getElementById('target').addEventListener('keypress', (e) => { if (e.key === 'Enter') { this.startScan(); } }); } async startScan() { const target = document.getElementById('target').value.trim(); if (!target) { alert('Please enter a target domain or hostname'); return; } const scanData = { target: target, max_depth: parseInt(document.getElementById('maxDepth').value), shodan_key: document.getElementById('shodanKey').value.trim() || null, virustotal_key: document.getElementById('virustotalKey').value.trim() || null }; try { // Show progress section this.showProgressSection(); this.updateProgress(0, 'Starting scan...'); const response = await fetch('/api/scan', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(scanData) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); if (result.error) { throw new Error(result.error); } this.currentScanId = result.scan_id; this.startPolling(); } catch (error) { this.showError(`Failed to start scan: ${error.message}`); } } startPolling() { // Poll every 2 seconds for updates this.pollInterval = setInterval(() => { this.checkScanStatus(); }, 2000); // Also check immediately this.checkScanStatus(); } async checkScanStatus() { if (!this.currentScanId) { return; } try { const response = await fetch(`/api/scan/${this.currentScanId}/status`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const status = await response.json(); if (status.error) { throw new Error(status.error); } // Update progress this.updateProgress(status.progress, status.message); // Check if completed if (status.status === 'completed') { this.stopPolling(); await this.loadScanReport(); } else if (status.status === 'error') { this.stopPolling(); throw new Error(status.error || 'Scan failed'); } } catch (error) { this.stopPolling(); this.showError(`Error checking scan status: ${error.message}`); } } async loadScanReport() { try { const response = await fetch(`/api/scan/${this.currentScanId}/report`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const report = await response.json(); if (report.error) { throw new Error(report.error); } this.currentReport = report; this.showResultsSection(); this.showReport('text'); // Default to text view } catch (error) { this.showError(`Error loading report: ${error.message}`); } } stopPolling() { if (this.pollInterval) { clearInterval(this.pollInterval); this.pollInterval = null; } } showProgressSection() { document.getElementById('scanForm').style.display = 'none'; document.getElementById('progressSection').style.display = 'block'; document.getElementById('resultsSection').style.display = 'none'; } showResultsSection() { document.getElementById('scanForm').style.display = 'none'; document.getElementById('progressSection').style.display = 'none'; document.getElementById('resultsSection').style.display = 'block'; } resetToForm() { this.stopPolling(); this.currentScanId = null; this.currentReport = null; document.getElementById('scanForm').style.display = 'block'; document.getElementById('progressSection').style.display = 'none'; document.getElementById('resultsSection').style.display = 'none'; // Clear form document.getElementById('target').value = ''; document.getElementById('shodanKey').value = ''; document.getElementById('virustotalKey').value = ''; document.getElementById('maxDepth').value = '2'; } updateProgress(percentage, message) { const progressFill = document.getElementById('progressFill'); const progressMessage = document.getElementById('progressMessage'); progressFill.style.width = `${percentage || 0}%`; progressMessage.textContent = message || 'Processing...'; } showError(message) { // Update progress section to show error this.updateProgress(0, `Error: ${message}`); // Also alert the user alert(`Error: ${message}`); } showReport(type) { if (!this.currentReport) { return; } const reportContent = document.getElementById('reportContent'); const showJsonBtn = document.getElementById('showJson'); const showTextBtn = document.getElementById('showText'); if (type === 'json') { // Show JSON report try { const jsonData = JSON.parse(this.currentReport.json_report); reportContent.textContent = JSON.stringify(jsonData, null, 2); } catch (e) { reportContent.textContent = this.currentReport.json_report; } showJsonBtn.classList.add('active'); showTextBtn.classList.remove('active'); } else { // Show text report reportContent.textContent = this.currentReport.text_report; showTextBtn.classList.add('active'); showJsonBtn.classList.remove('active'); } } downloadReport(type) { if (!this.currentReport) { return; } let content, filename, mimeType; if (type === 'json') { content = this.currentReport.json_report; filename = `recon-report-${this.currentScanId}.json`; mimeType = 'application/json'; } else { content = this.currentReport.text_report; filename = `recon-report-${this.currentScanId}.txt`; mimeType = 'text/plain'; } // Create download link const blob = new Blob([content], { type: mimeType }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } } // Initialize the application when DOM is loaded document.addEventListener('DOMContentLoaded', () => { new ReconTool(); });