This commit is contained in:
overcuriousity
2025-09-09 14:54:02 +02:00
parent 8263f5cfa9
commit 0c9cf00a3b
12 changed files with 1475 additions and 252 deletions

View File

@@ -1,15 +1,73 @@
// DNS Reconnaissance Tool - Frontend JavaScript
// DNS Reconnaissance Tool - Enhanced Frontend JavaScript with Real-time Updates
class ReconTool {
constructor() {
this.currentScanId = null;
this.pollInterval = null;
this.liveDataInterval = null;
this.currentReport = null;
this.init();
}
init() {
this.bindEvents();
this.setupRealtimeElements();
}
setupRealtimeElements() {
// Create live discovery container if it doesn't exist
if (!document.getElementById('liveDiscoveries')) {
const progressSection = document.getElementById('progressSection');
const liveDiv = document.createElement('div');
liveDiv.id = 'liveDiscoveries';
liveDiv.innerHTML = `
<div class="live-discoveries" style="display: none;">
<h3>🔍 Live Discoveries</h3>
<div class="stats-grid">
<div class="stat-item">
<span class="stat-label">Hostnames:</span>
<span id="liveHostnames" class="stat-value">0</span>
</div>
<div class="stat-item">
<span class="stat-label">IP Addresses:</span>
<span id="liveIPs" class="stat-value">0</span>
</div>
<div class="stat-item">
<span class="stat-label">DNS Records:</span>
<span id="liveDNS" class="stat-value">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Certificates:</span>
<span id="liveCerts" class="stat-value">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Shodan Results:</span>
<span id="liveShodan" class="stat-value">0</span>
</div>
<div class="stat-item">
<span class="stat-label">VirusTotal:</span>
<span id="liveVT" class="stat-value">0</span>
</div>
</div>
<div class="discoveries-list">
<h4>📋 Recent Discoveries</h4>
<div id="recentHostnames" class="discovery-section">
<strong>Hostnames:</strong>
<div class="hostname-list"></div>
</div>
<div id="recentIPs" class="discovery-section">
<strong>IP Addresses:</strong>
<div class="ip-list"></div>
</div>
<div id="activityLog" class="discovery-section">
<strong>Activity Log:</strong>
<div class="activity-list"></div>
</div>
</div>
</div>
`;
progressSection.appendChild(liveDiv);
}
}
bindEvents() {
@@ -69,6 +127,8 @@ class ReconTool {
this.showProgressSection();
this.updateProgress(0, 'Starting scan...');
console.log('🚀 Starting scan with data:', scanData);
const response = await fetch('/api/scan', {
method: 'POST',
headers: {
@@ -88,15 +148,19 @@ class ReconTool {
}
this.currentScanId = result.scan_id;
console.log('✅ Scan started with ID:', this.currentScanId);
this.startPolling();
this.startLiveDataPolling();
} catch (error) {
console.error('❌ Failed to start scan:', error);
this.showError(`Failed to start scan: ${error.message}`);
}
}
startPolling() {
// Poll every 2 seconds for updates
// Poll every 2 seconds for status updates
this.pollInterval = setInterval(() => {
this.checkScanStatus();
}, 2000);
@@ -104,6 +168,22 @@ class ReconTool {
// Also check immediately
this.checkScanStatus();
}
startLiveDataPolling() {
// Poll every 3 seconds for live data updates
this.liveDataInterval = setInterval(() => {
this.updateLiveData();
}, 3000);
// Show the live discoveries section
const liveSection = document.querySelector('.live-discoveries');
if (liveSection) {
liveSection.style.display = 'block';
}
// Also update immediately
this.updateLiveData();
}
async checkScanStatus() {
if (!this.currentScanId) {
@@ -125,9 +205,15 @@ class ReconTool {
// Update progress
this.updateProgress(status.progress, status.message);
// Update live stats
if (status.live_stats) {
this.updateLiveStats(status.live_stats);
}
// Check if completed
if (status.status === 'completed') {
console.log('✅ Scan completed');
this.stopPolling();
await this.loadScanReport();
} else if (status.status === 'error') {
@@ -136,13 +222,101 @@ class ReconTool {
}
} catch (error) {
console.error('❌ Error checking scan status:', error);
this.stopPolling();
this.showError(`Error checking scan status: ${error.message}`);
}
}
async updateLiveData() {
if (!this.currentScanId) {
return;
}
try {
const response = await fetch(`/api/scan/${this.currentScanId}/live-data`);
if (!response.ok) {
return; // Silently fail for live data
}
const data = await response.json();
if (data.error) {
return; // Silently fail for live data
}
// Update live discoveries
this.updateLiveDiscoveries(data);
} catch (error) {
// Silently fail for live data updates
console.debug('Live data update failed:', error);
}
}
updateLiveStats(stats) {
// Update the live statistics counters
const statElements = {
'liveHostnames': stats.hostnames || 0,
'liveIPs': stats.ip_addresses || 0,
'liveDNS': stats.dns_records || 0,
'liveCerts': stats.certificates || 0,
'liveShodan': stats.shodan_results || 0,
'liveVT': stats.virustotal_results || 0
};
Object.entries(statElements).forEach(([elementId, value]) => {
const element = document.getElementById(elementId);
if (element) {
element.textContent = value;
// Add a brief highlight effect when value changes
if (element.textContent !== value.toString()) {
element.style.backgroundColor = '#ff9900';
setTimeout(() => {
element.style.backgroundColor = '';
}, 1000);
}
}
});
}
updateLiveDiscoveries(data) {
// Update hostnames list
const hostnameList = document.querySelector('#recentHostnames .hostname-list');
if (hostnameList && data.hostnames) {
// Show last 10 hostnames
const recentHostnames = data.hostnames.slice(-10);
hostnameList.innerHTML = recentHostnames.map(hostname =>
`<span class="discovery-item">${hostname}</span>`
).join('');
}
// Update IP addresses list
const ipList = document.querySelector('#recentIPs .ip-list');
if (ipList && data.ip_addresses) {
// Show last 10 IPs
const recentIPs = data.ip_addresses.slice(-10);
ipList.innerHTML = recentIPs.map(ip =>
`<span class="discovery-item">${ip}</span>`
).join('');
}
// Update activity log
const activityList = document.querySelector('#activityLog .activity-list');
if (activityList && data.latest_discoveries) {
const activities = data.latest_discoveries.slice(-5); // Last 5 activities
activityList.innerHTML = activities.map(activity => {
const time = new Date(activity.timestamp * 1000).toLocaleTimeString();
return `<div class="activity-item">[${time}] ${activity.message}</div>`;
}).join('');
}
}
async loadScanReport() {
try {
console.log('📄 Loading scan report...');
const response = await fetch(`/api/scan/${this.currentScanId}/report`);
if (!response.ok) {
@@ -156,10 +330,12 @@ class ReconTool {
}
this.currentReport = report;
console.log('✅ Report loaded successfully');
this.showResultsSection();
this.showReport('text'); // Default to text view
} catch (error) {
console.error('❌ Error loading report:', error);
this.showError(`Error loading report: ${error.message}`);
}
}
@@ -169,6 +345,10 @@ class ReconTool {
clearInterval(this.pollInterval);
this.pollInterval = null;
}
if (this.liveDataInterval) {
clearInterval(this.liveDataInterval);
this.liveDataInterval = null;
}
}
showProgressSection() {
@@ -181,6 +361,12 @@ class ReconTool {
document.getElementById('scanForm').style.display = 'none';
document.getElementById('progressSection').style.display = 'none';
document.getElementById('resultsSection').style.display = 'block';
// Hide live discoveries in results section
const liveSection = document.querySelector('.live-discoveries');
if (liveSection) {
liveSection.style.display = 'none';
}
}
resetToForm() {
@@ -192,6 +378,12 @@ class ReconTool {
document.getElementById('progressSection').style.display = 'none';
document.getElementById('resultsSection').style.display = 'none';
// Hide live discoveries
const liveSection = document.querySelector('.live-discoveries');
if (liveSection) {
liveSection.style.display = 'none';
}
// Clear form
document.getElementById('target').value = '';
document.getElementById('shodanKey').value = '';
@@ -227,9 +419,16 @@ class ReconTool {
if (type === 'json') {
// Show JSON report
try {
const jsonData = JSON.parse(this.currentReport.json_report);
// The json_report should already be a string from the server
let jsonData;
if (typeof this.currentReport.json_report === 'string') {
jsonData = JSON.parse(this.currentReport.json_report);
} else {
jsonData = this.currentReport.json_report;
}
reportContent.textContent = JSON.stringify(jsonData, null, 2);
} catch (e) {
console.error('Error parsing JSON report:', e);
reportContent.textContent = this.currentReport.json_report;
}
@@ -252,7 +451,9 @@ class ReconTool {
let content, filename, mimeType;
if (type === 'json') {
content = this.currentReport.json_report;
content = typeof this.currentReport.json_report === 'string'
? this.currentReport.json_report
: JSON.stringify(this.currentReport.json_report, null, 2);
filename = `recon-report-${this.currentScanId}.json`;
mimeType = 'application/json';
} else {
@@ -276,5 +477,6 @@ class ReconTool {
// Initialize the application when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
console.log('🌐 DNS Reconnaissance Tool initialized');
new ReconTool();
});

View File

@@ -211,6 +211,40 @@ header p {
word-wrap: break-word;
}
.hostname-list, .ip-list {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.discovery-item {
background: #2a2a2a;
color: #00ff41;
padding: 2px 6px;
border-radius: 2px;
font-family: 'Courier New', monospace;
font-size: 0.8rem;
border: 1px solid #444;
}
.activity-list {
max-height: 150px;
overflow-y: auto;
}
.activity-item {
color: #a0a0a0;
font-family: 'Courier New', monospace;
font-size: 0.8rem;
padding: 2px 0;
border-bottom: 1px solid #333;
}
.activity-item:last-child {
border-bottom: none;
}
/* Responsive design adjustments */
@media (max-width: 768px) {
.container {
@@ -240,6 +274,23 @@ header p {
flex: 1;
min-width: 120px;
}
.stats-grid {
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
.stat-item {
padding: 6px 8px;
}
.stat-label, .stat-value {
font-size: 0.8rem;
}
.hostname-list, .ip-list {
flex-direction: column;
align-items: flex-start;
}
}
/* Tactical loading spinner */
@@ -253,6 +304,79 @@ header p {
animation: spin 1s linear infinite;
}
.live-discoveries {
background: rgba(0, 20, 0, 0.6);
border: 1px solid #00ff41;
border-radius: 4px;
padding: 20px;
margin-top: 20px;
}
.live-discoveries h3 {
color: #00ff41;
margin-bottom: 15px;
text-transform: uppercase;
letter-spacing: 1px;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.stat-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
background: rgba(0, 0, 0, 0.5);
border: 1px solid #333;
border-radius: 2px;
}
.stat-label {
color: #a0a0a0;
font-size: 0.9rem;
}
.stat-value {
color: #00ff41;
font-weight: bold;
font-family: 'Courier New', monospace;
transition: background-color 0.3s ease;
}
.discoveries-list {
margin-top: 20px;
}
.discoveries-list h4 {
color: #ff9900;
margin-bottom: 15px;
border-bottom: 1px solid #444;
padding-bottom: 5px;
}
.discovery-section {
margin-bottom: 15px;
padding: 10px;
background: rgba(0, 0, 0, 0.3);
border: 1px solid #333;
border-radius: 2px;
}
.discovery-section strong {
color: #c7c7c7;
display: block;
margin-bottom: 8px;
font-size: 0.9rem;
}
@keyframes spin {
to { transform: rotate(360deg); }
}