-
š Selected Device
-
-
Click a network or client to view details
+
+
+
+
+
+
+
š Selected Device
+
+
Click a network or client to view details
+
-
Network Radar
@@ -1313,6 +1315,19 @@
Waiting for client probe requests...
+
+
+
+
+
+
+ Start scanning to discover WiFi networks
+
+
+
@@ -2345,7 +2360,7 @@
'listening': 'LISTENING POST'
};
document.getElementById('activeModeIndicator').innerHTML = '
' + modeNames[mode];
- document.getElementById('wifiVisuals').style.display = mode === 'wifi' ? 'grid' : 'none';
+ document.getElementById('wifiLayoutContainer').style.display = mode === 'wifi' ? 'flex' : 'none';
document.getElementById('btVisuals').style.display = mode === 'bluetooth' ? 'grid' : 'none';
// Respect the "Show Radar Display" checkbox for aircraft mode
const showRadar = document.getElementById('adsbEnableMap').checked;
@@ -2391,7 +2406,7 @@
// Hide waterfall and output console for modes with their own visualizations
document.querySelector('.waterfall-container').style.display = (mode === 'satellite' || mode === 'listening' || mode === 'aircraft' || mode === 'wifi') ? 'none' : 'block';
- document.getElementById('output').style.display = (mode === 'satellite' || mode === 'aircraft') ? 'none' : 'block';
+ document.getElementById('output').style.display = (mode === 'satellite' || mode === 'aircraft' || mode === 'wifi') ? 'none' : 'block';
document.querySelector('.status-bar').style.display = (mode === 'satellite') ? 'none' : 'flex';
// Load interfaces and initialize visualizations when switching modes
@@ -5032,11 +5047,17 @@
}
}
- // Add WiFi network card to output
+ // Add WiFi network card to device list
function addWifiNetworkCard(net, isNew) {
- const output = document.getElementById('output');
- const placeholder = output.querySelector('.placeholder');
- if (placeholder) placeholder.remove();
+ // Use the WiFi device list panel instead of the generic output
+ const deviceList = document.getElementById('wifiDeviceListContent');
+ if (!deviceList) return;
+
+ // Remove placeholder if present
+ const placeholder = deviceList.querySelector('div[style*="text-align: center"]');
+ if (placeholder && placeholder.textContent.includes('Start scanning')) {
+ placeholder.remove();
+ }
// Check if card already exists
let card = document.getElementById('wifi_' + net.bssid.replace(/:/g, ''));
@@ -5044,13 +5065,17 @@
if (!card) {
card = document.createElement('div');
card.id = 'wifi_' + net.bssid.replace(/:/g, '');
- card.className = 'sensor-card';
+ card.className = 'sensor-card wifi-network-card';
card.style.borderLeftColor = net.privacy.includes('WPA') ? 'var(--accent-orange)' :
net.privacy.includes('WEP') ? 'var(--accent-red)' :
'var(--accent-green)';
card.style.cursor = 'pointer';
card.onclick = () => selectWifiDevice(net.bssid, 'network');
- output.insertBefore(card, output.firstChild);
+ deviceList.insertBefore(card, deviceList.firstChild);
+
+ // Update device count
+ const countEl = document.getElementById('wifiDeviceListCount');
+ if (countEl) countEl.textContent = Object.keys(wifiNetworks).length;
}
// Handle signal strength - airodump returns -1 when not measured
@@ -5105,47 +5130,75 @@
}
// Start handshake capture
- function captureHandshake(bssid, channel) {
+ async function captureHandshake(bssid, channel) {
if (!confirm('Start handshake capture for ' + bssid + '? This will stop the current scan.')) {
return;
}
- fetch('/wifi/handshake/capture', {
- method: 'POST',
- headers: {'Content-Type': 'application/json'},
- body: JSON.stringify({bssid: bssid, channel: channel})
- }).then(r => r.json())
- .then(data => {
- if (data.status === 'started') {
- showInfo('šÆ Capturing handshakes for ' + bssid);
- setWifiRunning(true);
+ const iface = monitorInterface || document.getElementById('wifiInterfaceSelect').value;
+ if (!iface) {
+ showError('No monitor interface available. Enable monitor mode first.');
+ return;
+ }
- // Update handshake indicator to show active capture
- const hsSpan = document.getElementById('handshakeCount');
- hsSpan.style.animation = 'pulse 1s infinite';
- hsSpan.title = 'Capturing: ' + bssid;
+ // Stop any existing scan first
+ if (isWifiRunning) {
+ showInfo('Stopping current scan...');
+ try {
+ await fetch('/wifi/scan/stop', {method: 'POST'});
+ if (wifiEventSource) {
+ wifiEventSource.close();
+ wifiEventSource = null;
+ }
+ setWifiRunning(false);
+ // Brief delay to ensure process stops
+ await new Promise(resolve => setTimeout(resolve, 500));
+ } catch (e) {
+ console.error('Error stopping scan:', e);
+ }
+ }
- // Show capture status panel
- const panel = document.getElementById('captureStatusPanel');
- panel.style.display = 'block';
- document.getElementById('captureTargetBssid').textContent = bssid;
- document.getElementById('captureTargetChannel').textContent = channel;
- document.getElementById('captureFilePath').textContent = data.capture_file;
- document.getElementById('captureStatus').textContent = 'Waiting for handshake...';
- document.getElementById('captureStatus').style.color = 'var(--accent-orange)';
+ try {
+ const response = await fetch('/wifi/handshake/capture', {
+ method: 'POST',
+ headers: {'Content-Type': 'application/json'},
+ body: JSON.stringify({bssid: bssid, channel: channel, interface: iface})
+ });
+ const data = await response.json();
- // Store active capture info and start polling
- activeCapture = {
- bssid: bssid,
- channel: channel,
- file: data.capture_file,
- startTime: Date.now(),
- pollInterval: setInterval(checkCaptureStatus, 5000) // Check every 5 seconds
- };
- } else {
- alert('Error: ' + data.message);
- }
- });
+ if (data.status === 'started') {
+ showInfo('šÆ Capturing handshakes for ' + bssid);
+ setWifiRunning(true);
+
+ // Update handshake indicator to show active capture
+ const hsSpan = document.getElementById('handshakeCount');
+ hsSpan.style.animation = 'pulse 1s infinite';
+ hsSpan.title = 'Capturing: ' + bssid;
+
+ // Show capture status panel
+ const panel = document.getElementById('captureStatusPanel');
+ panel.style.display = 'block';
+ document.getElementById('captureTargetBssid').textContent = bssid;
+ document.getElementById('captureTargetChannel').textContent = channel;
+ document.getElementById('captureFilePath').textContent = data.capture_file;
+ document.getElementById('captureStatus').textContent = 'Waiting for handshake...';
+ document.getElementById('captureStatus').style.color = 'var(--accent-orange)';
+
+ // Store active capture info and start polling
+ activeCapture = {
+ bssid: bssid,
+ channel: channel,
+ file: data.capture_file,
+ startTime: Date.now(),
+ pollInterval: setInterval(checkCaptureStatus, 5000) // Check every 5 seconds
+ };
+ } else {
+ showError('Handshake capture failed: ' + (data.message || 'Unknown error'));
+ }
+ } catch (err) {
+ showError('Handshake capture error: ' + err.message);
+ console.error('Handshake capture error:', err);
+ }
}
// Check handshake capture status
@@ -5222,20 +5275,41 @@
// PMKID Capture
let activePmkid = null;
- function capturePmkid(bssid, channel) {
- if (!confirm('Start PMKID capture for ' + bssid + '?\\n\\nThis uses hcxdumptool to capture PMKID without needing clients.\\n\\nā Only use on networks you own or have authorization to test!')) {
+ async function capturePmkid(bssid, channel) {
+ if (!confirm('Start PMKID capture for ' + bssid + '?\n\nThis uses hcxdumptool to capture PMKID without needing clients.\n\nā Only use on networks you own or have authorization to test!')) {
return;
}
- const iface = document.getElementById('wifiInterfaceSelect').value;
+ const iface = monitorInterface || document.getElementById('wifiInterfaceSelect').value;
+ if (!iface) {
+ showError('No monitor interface available. Enable monitor mode first.');
+ return;
+ }
+
+ // Stop any existing scan first
+ if (isWifiRunning) {
+ showInfo('Stopping current scan...');
+ try {
+ await fetch('/wifi/scan/stop', {method: 'POST'});
+ if (wifiEventSource) {
+ wifiEventSource.close();
+ wifiEventSource = null;
+ }
+ setWifiRunning(false);
+ await new Promise(resolve => setTimeout(resolve, 500));
+ } catch (e) {
+ console.error('Error stopping scan:', e);
+ }
+ }
+
+ try {
+ const response = await fetch('/wifi/pmkid/capture', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ interface: iface, bssid: bssid, channel: channel })
+ });
+ const data = await response.json();
- fetch('/wifi/pmkid/capture', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ interface: iface, bssid: bssid, channel: channel })
- })
- .then(r => r.json())
- .then(data => {
if (data.status === 'started') {
activePmkid = { bssid: bssid, file: data.file, startTime: Date.now() };
document.getElementById('pmkidPanel').style.display = 'block';
@@ -5247,9 +5321,12 @@
// Poll for PMKID
activePmkid.pollInterval = setInterval(checkPmkidStatus, 3000);
} else {
- alert('Failed to start PMKID capture: ' + data.message);
+ showError('PMKID capture failed: ' + (data.message || 'Unknown error'));
}
- });
+ } catch (err) {
+ showError('PMKID capture error: ' + err.message);
+ console.error('PMKID capture error:', err);
+ }
}
function checkPmkidStatus() {