mirror of
https://github.com/smittix/intercept.git
synced 2026-07-07 09:08:12 -07:00
Add ISMS Listening Station with GSM cell detection
- Add spectrum monitoring via rtl_power with configurable presets - Add OpenCelliD tower integration with Leaflet map display - Add grgsm_scanner integration for passive GSM cell detection (alpha) - Add rules engine for anomaly detection and findings - Add baseline recording and comparison system - Add setup.sh support for gr-gsm installation on Debian/Ubuntu Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+124
-3
@@ -385,6 +385,7 @@
|
||||
</button>
|
||||
<div class="mode-nav-dropdown-menu">
|
||||
<button class="mode-nav-btn" onclick="switchMode('tscm')"><span class="nav-icon">🔍</span><span class="nav-label">TSCM</span></button>
|
||||
<button class="mode-nav-btn" onclick="switchMode('isms')"><span class="nav-icon">📊</span><span class="nav-label">ISMS Station</span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mode-nav-actions">
|
||||
@@ -403,6 +404,7 @@
|
||||
<button class="mobile-nav-btn" data-mode="wifi" onclick="switchMode('wifi')">📶 WiFi</button>
|
||||
<button class="mobile-nav-btn" data-mode="bluetooth" onclick="switchMode('bluetooth')">🔵 BT</button>
|
||||
<button class="mobile-nav-btn" data-mode="tscm" onclick="switchMode('tscm')">🔍 TSCM</button>
|
||||
<button class="mobile-nav-btn" data-mode="isms" onclick="switchMode('isms')">📊 ISMS</button>
|
||||
<button class="mobile-nav-btn" data-mode="satellite" onclick="switchMode('satellite')">🛰️ Sat</button>
|
||||
<button class="mobile-nav-btn" data-mode="listening" onclick="switchMode('listening')">📻 Scanner</button>
|
||||
</nav>
|
||||
@@ -501,6 +503,8 @@
|
||||
|
||||
{% include 'partials/modes/tscm.html' %}
|
||||
|
||||
{% include 'partials/modes/isms.html' %}
|
||||
|
||||
<button class="preset-btn" onclick="killAll()" style="width: 100%; margin-top: 10px; border-color: #ff3366; color: #ff3366;">
|
||||
Kill All Processes
|
||||
</button>
|
||||
@@ -1112,6 +1116,113 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ISMS Listening Station Dashboard -->
|
||||
<div id="ismsVisuals" class="isms-dashboard" style="display: none; padding: 16px;">
|
||||
<!-- Legal/Info Banner -->
|
||||
<div class="isms-info-banner" style="margin-bottom: 12px; padding: 8px 12px; background: rgba(0, 212, 255, 0.1); border: 1px solid rgba(0, 212, 255, 0.3); border-radius: 4px; font-size: 10px; color: var(--text-muted);">
|
||||
<strong>ISMS Listening Station:</strong> RF spectrum monitoring for situational awareness.
|
||||
Requires rtl_power. Tower data from OpenCelliD (API token required).
|
||||
</div>
|
||||
|
||||
<!-- Main Grid Layout -->
|
||||
<div class="isms-grid" style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;">
|
||||
|
||||
<!-- Band Activity Meters -->
|
||||
<div class="isms-panel" style="grid-column: span 4; background: var(--bg-card); border-radius: 8px; padding: 12px; border: 1px solid var(--border-color);">
|
||||
<div class="isms-panel-header" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
|
||||
<span style="font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px;">Band Activity</span>
|
||||
<span id="ismsScanStatus" style="font-size: 10px; color: var(--accent-cyan);">IDLE</span>
|
||||
</div>
|
||||
<div id="ismsBandMeters" style="display: flex; gap: 12px; flex-wrap: wrap; justify-content: center;">
|
||||
<div style="color: var(--text-muted); font-size: 11px; text-align: center; padding: 20px;">
|
||||
Start a scan to see band activity
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top Peaks -->
|
||||
<div class="isms-panel" style="grid-column: span 2; background: var(--bg-card); border-radius: 8px; padding: 12px; border: 1px solid var(--border-color);">
|
||||
<div class="isms-panel-header" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
||||
<span style="font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px;">Top Peaks</span>
|
||||
<span id="ismsPeakCount" style="font-size: 10px; color: var(--accent-cyan);">0</span>
|
||||
</div>
|
||||
<div id="ismsPeaksList" style="max-height: 200px; overflow-y: auto;">
|
||||
<table style="width: 100%; font-size: 10px; border-collapse: collapse;">
|
||||
<thead>
|
||||
<tr style="color: var(--text-muted); text-transform: uppercase;">
|
||||
<th style="text-align: left; padding: 4px 8px;">Freq</th>
|
||||
<th style="text-align: right; padding: 4px 8px;">Power</th>
|
||||
<th style="text-align: left; padding: 4px 8px;">Band</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="ismsPeaksBody">
|
||||
<tr><td colspan="3" style="text-align: center; padding: 20px; color: var(--text-muted);">No peaks detected</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nearby Towers Map -->
|
||||
<div class="isms-panel" style="grid-column: span 2; background: var(--bg-card); border-radius: 8px; padding: 12px; border: 1px solid var(--border-color);">
|
||||
<div class="isms-panel-header" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
||||
<span style="font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px;">Nearby Towers</span>
|
||||
<button class="preset-btn" onclick="ismsRefreshTowers()" style="padding: 2px 8px; font-size: 9px;">Refresh</button>
|
||||
</div>
|
||||
<div id="ismsTowerMap" style="height: 180px; background: rgba(0,0,0,0.3); border-radius: 4px; margin-bottom: 8px;">
|
||||
<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-muted); font-size: 11px;">
|
||||
Set location and query towers
|
||||
</div>
|
||||
</div>
|
||||
<div id="ismsTowerList" style="max-height: 80px; overflow-y: auto; font-size: 10px;">
|
||||
<!-- Tower list items will appear here -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Findings Timeline -->
|
||||
<div class="isms-panel" style="grid-column: span 4; background: var(--bg-card); border-radius: 8px; padding: 12px; border: 1px solid var(--border-color);">
|
||||
<div class="isms-panel-header" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
||||
<span style="font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px;">Findings</span>
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<span id="ismsFindingsHigh" class="isms-badge isms-badge-high" style="display: none;">0 HIGH</span>
|
||||
<span id="ismsFindingsWarn" class="isms-badge isms-badge-warn" style="display: none;">0 WARN</span>
|
||||
<span id="ismsFindingsInfo" class="isms-badge isms-badge-info">0 INFO</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ismsFindingsTimeline" style="max-height: 150px; overflow-y: auto;">
|
||||
<div style="color: var(--text-muted); font-size: 11px; text-align: center; padding: 20px;">
|
||||
No findings yet. Start a scan and enable baseline comparison.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Baseline Comparison (collapsible) -->
|
||||
<div class="isms-panel collapsible" style="grid-column: span 4; background: var(--bg-card); border-radius: 8px; border: 1px solid var(--border-color);">
|
||||
<div class="isms-panel-header clickable" onclick="ismsToggleBaselinePanel()" style="padding: 12px; cursor: pointer; display: flex; justify-content: space-between; align-items: center;">
|
||||
<span style="font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px;">
|
||||
<span id="ismsBaselinePanelIcon">▶</span> Baseline Comparison
|
||||
</span>
|
||||
<span id="ismsBaselineStatus" style="font-size: 10px; color: var(--text-muted);">No baseline selected</span>
|
||||
</div>
|
||||
<div id="ismsBaselineCompare" style="display: none; padding: 0 12px 12px 12px;">
|
||||
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;">
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 9px; color: var(--text-muted); text-transform: uppercase;">Noise Floor Delta</div>
|
||||
<div id="ismsNoiseFloorDelta" style="font-size: 18px; font-weight: bold; color: var(--accent-cyan);">-- dB</div>
|
||||
</div>
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 9px; color: var(--text-muted); text-transform: uppercase;">Activity Delta</div>
|
||||
<div id="ismsActivityDelta" style="font-size: 18px; font-weight: bold; color: var(--accent-cyan);">--%</div>
|
||||
</div>
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 9px; color: var(--text-muted); text-transform: uppercase;">New Peaks</div>
|
||||
<div id="ismsNewPeaks" style="font-size: 18px; font-weight: bold; color: var(--accent-cyan);">--</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Device Intelligence Dashboard (above waterfall for prominence) -->
|
||||
<div class="recon-panel collapsed" id="reconPanel">
|
||||
<div class="recon-header" onclick="toggleReconCollapse()" style="cursor: pointer;">
|
||||
@@ -1185,6 +1296,7 @@
|
||||
<script src="{{ url_for('static', filename='js/core/audio.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/components/radio-knob.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/modes/listening-post.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/modes/isms.js') }}"></script>
|
||||
|
||||
<script>
|
||||
// Selected mode from welcome screen
|
||||
@@ -1532,7 +1644,7 @@
|
||||
'pager': 'sdr', 'sensor': 'sdr',
|
||||
'aprs': 'sdr', 'satellite': 'sdr', 'listening': 'sdr',
|
||||
'wifi': 'wireless', 'bluetooth': 'wireless',
|
||||
'tscm': 'security'
|
||||
'tscm': 'security', 'isms': 'security'
|
||||
};
|
||||
|
||||
// Remove has-active from all dropdowns
|
||||
@@ -1590,6 +1702,7 @@
|
||||
document.getElementById('listeningPostMode').classList.toggle('active', mode === 'listening');
|
||||
document.getElementById('aprsMode').classList.toggle('active', mode === 'aprs');
|
||||
document.getElementById('tscmMode').classList.toggle('active', mode === 'tscm');
|
||||
document.getElementById('ismsMode').classList.toggle('active', mode === 'isms');
|
||||
document.getElementById('pagerStats').style.display = mode === 'pager' ? 'flex' : 'none';
|
||||
document.getElementById('sensorStats').style.display = mode === 'sensor' ? 'flex' : 'none';
|
||||
document.getElementById('satelliteStats').style.display = mode === 'satellite' ? 'flex' : 'none';
|
||||
@@ -1615,7 +1728,8 @@
|
||||
'bluetooth': 'BLUETOOTH',
|
||||
'listening': 'LISTENING POST',
|
||||
'aprs': 'APRS',
|
||||
'tscm': 'TSCM'
|
||||
'tscm': 'TSCM',
|
||||
'isms': 'ISMS STATION'
|
||||
};
|
||||
document.getElementById('activeModeIndicator').innerHTML = '<span class="pulse-dot"></span>' + modeNames[mode];
|
||||
document.getElementById('wifiLayoutContainer').style.display = mode === 'wifi' ? 'flex' : 'none';
|
||||
@@ -1624,6 +1738,12 @@
|
||||
document.getElementById('listeningPostVisuals').style.display = mode === 'listening' ? 'grid' : 'none';
|
||||
document.getElementById('aprsVisuals').style.display = mode === 'aprs' ? 'flex' : 'none';
|
||||
document.getElementById('tscmVisuals').style.display = mode === 'tscm' ? 'flex' : 'none';
|
||||
document.getElementById('ismsVisuals').style.display = mode === 'isms' ? 'block' : 'none';
|
||||
|
||||
// Initialize ISMS mode when switching to it
|
||||
if (mode === 'isms' && typeof initIsmsMode === 'function') {
|
||||
initIsmsMode();
|
||||
}
|
||||
|
||||
// Update output panel title based on mode
|
||||
const titles = {
|
||||
@@ -1634,7 +1754,8 @@
|
||||
'bluetooth': 'Bluetooth Scanner',
|
||||
'listening': 'Listening Post',
|
||||
'aprs': 'APRS Tracker',
|
||||
'tscm': 'TSCM Counter-Surveillance'
|
||||
'tscm': 'TSCM Counter-Surveillance',
|
||||
'isms': 'ISMS Listening Station'
|
||||
};
|
||||
document.getElementById('outputTitle').textContent = titles[mode] || 'Signal Monitor';
|
||||
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
<!-- ISMS LISTENING STATION MODE -->
|
||||
<div id="ismsMode" class="mode-content">
|
||||
<div class="section">
|
||||
<h3>Status</h3>
|
||||
|
||||
<!-- Quick Status -->
|
||||
<div style="background: rgba(0,0,0,0.3); border-radius: 6px; padding: 12px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
||||
<span style="font-size: 10px; color: var(--text-muted); text-transform: uppercase;">Status</span>
|
||||
<span id="ismsQuickStatus" style="font-size: 11px; color: var(--accent-cyan);">IDLE</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
||||
<span style="font-size: 10px; color: var(--text-muted); text-transform: uppercase;">Band</span>
|
||||
<span id="ismsQuickBand" style="font-size: 11px; color: var(--text-primary);">--</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
||||
<span style="font-size: 10px; color: var(--text-muted); text-transform: uppercase;">Findings</span>
|
||||
<span id="ismsQuickFindings" style="font-size: 14px; font-weight: bold; color: var(--accent-green);">0</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<span style="font-size: 10px; color: var(--text-muted); text-transform: uppercase;">Location</span>
|
||||
<span id="ismsQuickLocation" style="font-size: 10px; color: var(--text-muted);">--</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Scan Preset</h3>
|
||||
<select id="ismsScanPreset" class="full-width-select">
|
||||
<option value="vhf_airband">VHF Airband (118-137 MHz)</option>
|
||||
<option value="uhf_airband">UHF Airband (225-400 MHz)</option>
|
||||
<option value="uhf_pmr">UHF PMR446</option>
|
||||
<option value="ism_433" selected>ISM 433 MHz</option>
|
||||
<option value="ism_868">ISM 868 MHz</option>
|
||||
<option value="ism_915">ISM 915 MHz (US)</option>
|
||||
<option value="cellular_700">Cellular 700 MHz</option>
|
||||
<option value="cellular_850">Cellular 850 MHz</option>
|
||||
<option value="cellular_900">Cellular 900 MHz</option>
|
||||
<option value="full_sweep">Full Spectrum</option>
|
||||
<option value="custom">Custom Range</option>
|
||||
</select>
|
||||
|
||||
<!-- Custom range (shown when custom selected) -->
|
||||
<div id="ismsCustomRange" style="display: none; margin-top: 8px;">
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<input type="number" id="ismsStartFreq" placeholder="Start MHz" style="flex: 1; padding: 6px; background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-primary); border-radius: 4px; font-size: 11px;">
|
||||
<input type="number" id="ismsEndFreq" placeholder="End MHz" style="flex: 1; padding: 6px; background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-primary); border-radius: 4px; font-size: 11px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>SDR Settings</h3>
|
||||
<div class="form-group">
|
||||
<label>Device</label>
|
||||
<select id="ismsSdrDevice" class="full-width-select">
|
||||
<option value="0">Device 0</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Gain</label>
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<input type="range" id="ismsGain" min="0" max="50" value="40" style="flex: 1;">
|
||||
<span id="ismsGainValue" style="min-width: 32px; text-align: right; font-size: 11px;">40</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Activity Threshold</label>
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<input type="range" id="ismsActivityThreshold" min="0" max="100" value="50" style="flex: 1;">
|
||||
<span id="ismsThresholdValue" style="min-width: 32px; text-align: right; font-size: 11px;">50%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Location</h3>
|
||||
<div class="form-group">
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<button class="preset-btn" onclick="ismsUseGPS()" style="flex: 1;">Use GPS</button>
|
||||
<button class="preset-btn" onclick="ismsSetManualLocation()" style="flex: 1;">Manual</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ismsCoords" style="font-size: 10px; color: var(--text-muted); margin-top: 4px; font-family: 'JetBrains Mono', monospace;">
|
||||
Lat: --, Lon: --
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Baseline</h3>
|
||||
<select id="ismsBaselineSelect" class="full-width-select">
|
||||
<option value="">No Baseline (Compare Disabled)</option>
|
||||
</select>
|
||||
<div style="display: flex; gap: 8px; margin-top: 8px;">
|
||||
<button class="preset-btn" id="ismsRecordBaselineBtn" onclick="ismsToggleBaselineRecording()" style="flex: 1;">
|
||||
Record New
|
||||
</button>
|
||||
<button class="preset-btn" onclick="ismsRefreshBaselines()" style="padding: 6px 10px;">
|
||||
<span style="font-size: 12px;">↻</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="ismsBaselineRecordingStatus" style="display: none; margin-top: 8px; padding: 8px; background: rgba(255, 100, 100, 0.1); border-radius: 4px; font-size: 10px; color: var(--accent-red);">
|
||||
Recording baseline...
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Cell Towers</h3>
|
||||
<div class="form-group">
|
||||
<button class="preset-btn" onclick="ismsRefreshTowers()" style="width: 100%;">
|
||||
Query Nearby Towers
|
||||
</button>
|
||||
</div>
|
||||
<div id="ismsTowerCount" style="font-size: 10px; color: var(--text-muted); margin-top: 4px;">
|
||||
No tower data
|
||||
</div>
|
||||
<div style="margin-top: 8px;">
|
||||
<a href="https://www.ofcom.org.uk/phones-and-broadband/coverage-and-quality/mobile-coverage-checker" target="_blank" rel="noopener" style="font-size: 10px; color: var(--accent-cyan);">
|
||||
Ofcom Coverage Checker
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://www.ofcom.org.uk/phones-telecoms-and-internet/information-for-industry/radiocomms-and-spectrum/radio-spectrum/spectrum-for-mobile-services/electromagnetic-fields-emf" target="_blank" rel="noopener" style="font-size: 10px; color: var(--accent-cyan);">
|
||||
Ofcom EMF Info
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>GSM Scanner</h3>
|
||||
<div style="background: rgba(255, 170, 0, 0.1); border: 1px solid rgba(255, 170, 0, 0.3); border-radius: 4px; padding: 6px 8px; margin-bottom: 8px; font-size: 9px; color: var(--accent-orange);">
|
||||
Alpha - Under Development
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>GSM Band</label>
|
||||
<select id="ismsGsmBand" class="full-width-select">
|
||||
<option value="GSM900" selected>GSM 900 MHz (Europe)</option>
|
||||
<option value="EGSM900">E-GSM 900 MHz</option>
|
||||
<option value="GSM1800">GSM 1800 MHz (DCS)</option>
|
||||
<option value="GSM850">GSM 850 MHz (US)</option>
|
||||
<option value="GSM1900">GSM 1900 MHz (PCS)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style="display: flex; gap: 8px; margin-top: 8px;">
|
||||
<button class="preset-btn" id="ismsGsmScanBtn" onclick="ismsToggleGsmScan()" style="flex: 1;">
|
||||
Scan GSM Cells
|
||||
</button>
|
||||
<button class="preset-btn" onclick="ismsSetGsmBaseline()" style="padding: 6px 10px;" title="Save as baseline">
|
||||
<span style="font-size: 12px;">💾</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="ismsGsmStatus" style="margin-top: 8px; padding: 8px; background: rgba(0,0,0,0.3); border-radius: 4px; font-size: 10px;">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 4px;">
|
||||
<span style="color: var(--text-muted);">Status:</span>
|
||||
<span id="ismsGsmStatusText" style="color: var(--accent-cyan);">Ready</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<span style="color: var(--text-muted);">Cells Found:</span>
|
||||
<span id="ismsGsmCellCount" style="color: var(--accent-green); font-weight: bold;">0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ismsGsmCells" style="margin-top: 8px; max-height: 150px; overflow-y: auto; font-size: 10px; font-family: 'JetBrains Mono', monospace;">
|
||||
<!-- GSM cells will be populated here -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="run-btn" id="ismsStartBtn" onclick="ismsToggleScan()">
|
||||
Start Scan
|
||||
</button>
|
||||
</div>
|
||||
Reference in New Issue
Block a user