Fix TSCM WiFi detection, SDR capabilities, layout, and correlation/cluster emission

- Use networksetup instead of deprecated airport utility for macOS WiFi detection
- Fix SDRDevice attribute access (use getattr instead of dict .get())
- Move Detected Threats panel next to RF Signals in 2-column grid
- Always run correlation/identity analysis at sweep end, even if stopped by user

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Smittix
2026-02-05 16:41:10 +00:00
parent f001e4f4df
commit 3fa1813ed5
4 changed files with 22 additions and 29 deletions
+17 -21
View File
@@ -368,25 +368,21 @@ def _check_available_devices(wifi: bool, bt: bool, rf: bool) -> dict:
# Check WiFi # Check WiFi
if wifi: if wifi:
if platform.system() == 'Darwin': if platform.system() == 'Darwin':
# macOS: Check for airport utility # macOS: Use networksetup to detect WiFi interfaces (same as /tscm/devices endpoint)
airport_path = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport' try:
if os.path.exists(airport_path): result = subprocess.run(
try: ['networksetup', '-listallhardwareports'],
result = subprocess.run( capture_output=True,
[airport_path, '-I'], text=True,
capture_output=True, timeout=5
text=True, )
timeout=5 if result.returncode == 0 and ('Wi-Fi' in result.stdout or 'AirPort' in result.stdout):
) available['wifi'] = True
if result.returncode == 0: available['wifi_reason'] = 'macOS WiFi available'
available['wifi'] = True else:
available['wifi_reason'] = 'macOS WiFi available' available['wifi_reason'] = 'No WiFi hardware port found'
else: except (subprocess.TimeoutExpired, FileNotFoundError, subprocess.SubprocessError):
available['wifi_reason'] = 'WiFi interface not active' available['wifi_reason'] = 'Cannot detect WiFi interfaces'
except (subprocess.TimeoutExpired, subprocess.SubprocessError):
available['wifi_reason'] = 'Cannot access WiFi interface'
else:
available['wifi_reason'] = 'macOS airport utility not found'
else: else:
# Linux: Check for wireless tools # Linux: Check for wireless tools
if shutil.which('airodump-ng') or shutil.which('iwlist') or shutil.which('iw'): if shutil.which('airodump-ng') or shutil.which('iwlist') or shutil.which('iw'):
@@ -1981,8 +1977,8 @@ def _run_sweep(
time.sleep(2) # Update every 2 seconds time.sleep(2) # Update every 2 seconds
# Complete sweep # Complete sweep (run even if stopped by user so correlations/clusters are computed)
if _sweep_running and _current_sweep_id: if _current_sweep_id:
# Run cross-protocol correlation analysis # Run cross-protocol correlation analysis
correlations = correlation.correlate_devices() correlations = correlation.correlate_devices()
findings = correlation.get_all_findings() findings = correlation.get_all_findings()
-5
View File
@@ -69,11 +69,6 @@
min-height: 200px; min-height: 200px;
height: 200px; height: 200px;
} }
/* Full-width panels (like Detected Threats) get more height */
.tscm-panel[style*="grid-column: span 2"] {
min-height: 150px;
height: 150px;
}
.tscm-panel-header { .tscm-panel-header {
padding: 10px 12px; padding: 10px 12px;
background: rgba(0,0,0,0.3); background: rgba(0,0,0,0.3);
+1 -1
View File
@@ -1557,7 +1557,7 @@
</div> </div>
<!-- Threats Panel --> <!-- Threats Panel -->
<div class="tscm-panel" id="tscmThreatPanel" style="grid-column: span 2;"> <div class="tscm-panel" id="tscmThreatPanel">
<div class="tscm-panel-header"> <div class="tscm-panel-header">
Detected Threats Detected Threats
<span class="badge" id="tscmThreatCount">0</span> <span class="badge" id="tscmThreatCount">0</span>
+4 -2
View File
@@ -372,8 +372,10 @@ def _detect_rf_capabilities(caps: SweepCapabilities, sdr_device: Any) -> None:
if devices: if devices:
device = devices[0] # Use first device device = devices[0] # Use first device
rf_cap.available = True rf_cap.available = True
rf_cap.device_type = device.get('type', 'unknown') rf_cap.device_type = getattr(device, 'sdr_type', 'unknown')
rf_cap.driver = device.get('driver', '') if hasattr(rf_cap.device_type, 'value'):
rf_cap.device_type = rf_cap.device_type.value
rf_cap.driver = getattr(device, 'driver', '')
# Set frequency ranges based on device type # Set frequency ranges based on device type
if 'rtl' in rf_cap.device_type.lower(): if 'rtl' in rf_cap.device_type.lower():