NSL / src /static /script.js
Fred808's picture
Upload 17 files
e1b4496 verified
class PortScanner {
constructor() {
this.isScanning = false;
this.progressInterval = null;
this.initializeEventListeners();
}
initializeEventListeners() {
// Form elements
this.targetIpInput = document.getElementById('target-ip');
this.startPortInput = document.getElementById('start-port');
this.endPortInput = document.getElementById('end-port');
this.timeoutInput = document.getElementById('timeout');
this.threadsInput = document.getElementById('threads');
// Buttons
this.scanBtn = document.getElementById('scan-btn');
this.pingBtn = document.getElementById('ping-btn');
this.exportBtn = document.getElementById('export-btn');
this.clearBtn = document.getElementById('clear-btn');
// Sections
this.progressSection = document.getElementById('progress-section');
this.resultsSection = document.getElementById('results-section');
// Event listeners
this.scanBtn.addEventListener('click', () => this.startScan());
this.pingBtn.addEventListener('click', () => this.pingHost());
this.exportBtn.addEventListener('click', () => this.exportResults());
this.clearBtn.addEventListener('click', () => this.clearResults());
// Preset buttons
document.querySelectorAll('.preset-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
const start = e.target.dataset.start;
const end = e.target.dataset.end;
this.startPortInput.value = start;
this.endPortInput.value = end;
});
});
// Form validation
this.targetIpInput.addEventListener('input', () => this.validateForm());
this.startPortInput.addEventListener('input', () => this.validateForm());
this.endPortInput.addEventListener('input', () => this.validateForm());
}
validateForm() {
const ip = this.targetIpInput.value.trim();
const startPort = parseInt(this.startPortInput.value);
const endPort = parseInt(this.endPortInput.value);
let isValid = true;
// IP validation
if (!ip || !this.isValidIP(ip)) {
isValid = false;
}
// Port validation
if (startPort < 1 || endPort > 65535 || startPort > endPort) {
isValid = false;
}
this.scanBtn.disabled = !isValid || this.isScanning;
return isValid;
}
isValidIP(ip) {
const ipRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
return ipRegex.test(ip);
}
async pingHost() {
const ip = this.targetIpInput.value.trim();
if (!ip || !this.isValidIP(ip)) {
this.showNotification('Please enter a valid IP address', 'error');
return;
}
this.pingBtn.disabled = true;
this.pingBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Pinging...';
try {
const response = await fetch('/api/ping', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ ip: ip })
});
const data = await response.json();
if (response.ok) {
const status = data.status === 'reachable' ? 'Host is reachable' : 'Host appears unreachable';
const type = data.status === 'reachable' ? 'success' : 'error';
this.showNotification(status, type);
} else {
this.showNotification(data.error || 'Ping failed', 'error');
}
} catch (error) {
this.showNotification('Network error during ping', 'error');
} finally {
this.pingBtn.disabled = false;
this.pingBtn.innerHTML = '<i class="fas fa-satellite-dish"></i> Ping';
}
}
async startScan() {
if (!this.validateForm()) {
this.showNotification('Please check your input values', 'error');
return;
}
const scanData = {
ip: this.targetIpInput.value.trim(),
start_port: parseInt(this.startPortInput.value),
end_port: parseInt(this.endPortInput.value),
timeout: parseFloat(this.timeoutInput.value),
threads: parseInt(this.threadsInput.value)
};
// Check port range limit
const portRange = scanData.end_port - scanData.start_port + 1;
if (portRange > 10000) {
this.showNotification('Port range too large (max 10000 ports)', 'error');
return;
}
this.isScanning = true;
this.scanBtn.disabled = true;
this.scanBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Scanning...';
// Show progress section
this.progressSection.style.display = 'block';
this.resultsSection.style.display = 'none';
// Start progress monitoring
this.startProgressMonitoring();
try {
const response = await fetch('/api/scan', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(scanData)
});
const data = await response.json();
if (response.ok) {
this.displayResults(data);
this.showNotification(`Scan completed! Found ${data.total_open} open ports`, 'success');
} else {
this.showNotification(data.error || 'Scan failed', 'error');
}
} catch (error) {
this.showNotification('Network error during scan', 'error');
} finally {
this.stopProgressMonitoring();
this.isScanning = false;
this.scanBtn.disabled = false;
this.scanBtn.innerHTML = '<i class="fas fa-search"></i> Start Scan';
this.progressSection.style.display = 'none';
}
}
startProgressMonitoring() {
this.progressInterval = setInterval(async () => {
try {
const response = await fetch('/api/progress');
const data = await response.json();
const progressFill = document.getElementById('progress-fill');
const progressText = document.getElementById('progress-text');
progressFill.style.width = `${data.percentage}%`;
progressText.textContent = `Scanning... ${data.progress}/${data.total} ports (${data.percentage}%)`;
} catch (error) {
console.error('Error fetching progress:', error);
}
}, 500);
}
stopProgressMonitoring() {
if (this.progressInterval) {
clearInterval(this.progressInterval);
this.progressInterval = null;
}
}
displayResults(data) {
const resultsSection = document.getElementById('results-section');
const resultsSummary = document.getElementById('results-summary');
const resultsTableBody = document.getElementById('results-tbody');
// Update summary
resultsSummary.innerHTML = `
<strong>Target:</strong> ${data.target_ip} |
<strong>Range:</strong> ${data.scan_range} |
<strong>Open Ports:</strong> ${data.total_open}/${data.total_scanned} |
<strong>Duration:</strong> ${data.scan_duration}s
`;
// Clear previous results
resultsTableBody.innerHTML = '';
// Add results to table
if (data.open_ports && data.open_ports.length > 0) {
data.open_ports.forEach(port => {
const row = document.createElement('tr');
row.innerHTML = `
<td><strong>${port.port}</strong></td>
<td><span class="status-${port.status}">${port.status.toUpperCase()}</span></td>
<td>${port.service || 'unknown'}</td>
<td>TCP</td>
`;
resultsTableBody.appendChild(row);
});
} else {
const row = document.createElement('tr');
row.innerHTML = '<td colspan="4" style="text-align: center; color: #666;">No open ports found</td>';
resultsTableBody.appendChild(row);
}
// Show results section
resultsSection.style.display = 'block';
// Store results for export
this.lastScanResults = data;
}
exportResults() {
if (!this.lastScanResults) {
this.showNotification('No results to export', 'error');
return;
}
const data = this.lastScanResults;
let csvContent = 'Port,Status,Service,Protocol\n';
if (data.open_ports && data.open_ports.length > 0) {
data.open_ports.forEach(port => {
csvContent += `${port.port},${port.status},${port.service || 'unknown'},TCP\n`;
});
}
// Create and download file
const blob = new Blob([csvContent], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `port_scan_${data.target_ip}_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.csv`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
this.showNotification('Results exported successfully', 'success');
}
clearResults() {
this.resultsSection.style.display = 'none';
this.lastScanResults = null;
this.showNotification('Results cleared', 'info');
}
showNotification(message, type = 'info') {
const notification = document.getElementById('notification');
notification.textContent = message;
notification.className = `notification ${type}`;
notification.classList.add('show');
setTimeout(() => {
notification.classList.remove('show');
}, 4000);
}
}
// Initialize the application when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
new PortScanner();
});
// Add some utility functions for better UX
document.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && e.target.tagName === 'INPUT') {
const scanner = new PortScanner();
if (scanner.validateForm()) {
scanner.startScan();
}
}
});
// Auto-focus on IP input when page loads
window.addEventListener('load', () => {
document.getElementById('target-ip').focus();
});