mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
Release v2.13.1 - Help modal and navigation improvements
- Add help modal system with keyboard shortcuts reference - Add Main Dashboard button in navigation bar - Make settings modal accessible from all dashboards - Dashboard CSS improvements and consistency fixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,8 @@
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/global-nav.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/help-modal.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/adsb_dashboard.css') }}">
|
||||
<script>
|
||||
window.INTERCEPT_SHARED_OBSERVER_LOCATION = {{ shared_observer_location | tojson }};
|
||||
@@ -49,8 +51,6 @@
|
||||
<input type="checkbox" id="showAllAgents" onchange="toggleShowAllAgents()"> All
|
||||
</label>
|
||||
</div>
|
||||
<a href="#" onclick="history.back(); return false;" class="back-link">Back</a>
|
||||
<a href="/?mode=aircraft" class="back-link">Main Dashboard</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -2372,7 +2372,7 @@ sudo make install</code>
|
||||
now.toISOString().substring(11, 19) + ' UTC';
|
||||
}
|
||||
|
||||
function initMap() {
|
||||
async function initMap() {
|
||||
radarMap = L.map('radarMap', {
|
||||
center: [observerLocation.lat, observerLocation.lon],
|
||||
zoom: 7,
|
||||
@@ -2382,7 +2382,9 @@ sudo make install</code>
|
||||
|
||||
// Use settings manager for tile layer (allows runtime changes)
|
||||
window.radarMap = radarMap;
|
||||
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
|
||||
if (typeof Settings !== 'undefined') {
|
||||
// Wait for settings to load from server before applying tiles
|
||||
await Settings.init();
|
||||
Settings.createTileLayer().addTo(radarMap);
|
||||
Settings.registerMap(radarMap);
|
||||
} else {
|
||||
@@ -4521,6 +4523,14 @@ sudo make install</code>
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Settings Modal -->
|
||||
{% include 'partials/settings-modal.html' %}
|
||||
|
||||
<!-- Help Modal -->
|
||||
{% include 'partials/help-modal.html' %}
|
||||
|
||||
<script src="{{ url_for('static', filename='js/core/settings-manager.js') }}"></script>
|
||||
|
||||
<!-- Agent Manager -->
|
||||
<script src="{{ url_for('static', filename='js/core/agents.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/core/global-nav.js') }}"></script>
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
{% endif %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/global-nav.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/help-modal.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/adsb_history.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
@@ -769,6 +771,14 @@
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Settings Modal -->
|
||||
{% include 'partials/settings-modal.html' %}
|
||||
|
||||
<!-- Help Modal -->
|
||||
{% include 'partials/help-modal.html' %}
|
||||
|
||||
<script src="{{ url_for('static', filename='js/core/settings-manager.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/core/global-nav.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -6,9 +6,13 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>iNTERCEPT // Remote Agents</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/agents.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/base.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/global-nav.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/agents.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/help-modal.css') }}">
|
||||
<style>
|
||||
.agents-container {
|
||||
max-width: 1200px;
|
||||
@@ -224,26 +228,6 @@
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* Navigation links */
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: var(--accent-cyan);
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Toast notifications */
|
||||
.toast {
|
||||
position: fixed;
|
||||
@@ -304,22 +288,6 @@
|
||||
{% include 'partials/nav.html' with context %}
|
||||
|
||||
<div class="agents-container">
|
||||
<div class="nav-links">
|
||||
<a href="#" onclick="history.back(); return false;" class="back-link">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M19 12H5M12 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
Back
|
||||
</a>
|
||||
<a href="/" class="back-link">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
||||
<polyline points="9 22 9 12 15 12 15 22"/>
|
||||
</svg>
|
||||
Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="agents-header">
|
||||
<h1>Remote Agents</h1>
|
||||
</div>
|
||||
@@ -587,6 +555,14 @@
|
||||
// Load agents on page load
|
||||
document.addEventListener('DOMContentLoaded', loadAgents);
|
||||
</script>
|
||||
|
||||
<!-- Settings Modal -->
|
||||
{% include 'partials/settings-modal.html' %}
|
||||
|
||||
<!-- Help Modal -->
|
||||
{% include 'partials/help-modal.html' %}
|
||||
|
||||
<script src="{{ url_for('static', filename='js/core/settings-manager.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/core/global-nav.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/ais_dashboard.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/global-nav.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/help-modal.css') }}">
|
||||
<script>
|
||||
window.INTERCEPT_SHARED_OBSERVER_LOCATION = {{ shared_observer_location | tojson }};
|
||||
</script>
|
||||
@@ -49,8 +51,6 @@
|
||||
<input type="checkbox" id="showAllAgents" onchange="toggleShowAllAgents()"> All
|
||||
</label>
|
||||
</div>
|
||||
<a href="#" onclick="history.back(); return false;" class="back-link">Back</a>
|
||||
<a href="/" class="back-link">Main Dashboard</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -390,7 +390,7 @@
|
||||
};
|
||||
|
||||
// Initialize map
|
||||
function initMap() {
|
||||
async function initMap() {
|
||||
if (observerLocation) {
|
||||
document.getElementById('obsLat').value = observerLocation.lat;
|
||||
document.getElementById('obsLon').value = observerLocation.lon;
|
||||
@@ -404,7 +404,9 @@
|
||||
|
||||
// Use settings manager for tile layer (allows runtime changes)
|
||||
window.vesselMap = vesselMap;
|
||||
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
|
||||
if (typeof Settings !== 'undefined') {
|
||||
// Wait for settings to load from server before applying tiles
|
||||
await Settings.init();
|
||||
Settings.createTileLayer().addTo(vesselMap);
|
||||
Settings.registerMap(vesselMap);
|
||||
} else {
|
||||
@@ -1553,6 +1555,14 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Settings Modal -->
|
||||
{% include 'partials/settings-modal.html' %}
|
||||
|
||||
<!-- Help Modal -->
|
||||
{% include 'partials/help-modal.html' %}
|
||||
|
||||
<script src="{{ url_for('static', filename='js/core/settings-manager.js') }}"></script>
|
||||
|
||||
<!-- Agent Manager -->
|
||||
<script src="{{ url_for('static', filename='js/core/agents.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/core/global-nav.js') }}"></script>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
|
||||
{% endif %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/global-nav.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/acars.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/aprs.css') }}">
|
||||
@@ -2070,6 +2071,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
function applySettingsFromQuery() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
if (params.get('settings') === '1') {
|
||||
// Remove settings param from URL to avoid reopening on refresh
|
||||
params.delete('settings');
|
||||
const newUrl = params.toString()
|
||||
? window.location.pathname + '?' + params.toString()
|
||||
: window.location.pathname;
|
||||
window.history.replaceState({}, '', newUrl);
|
||||
// Open settings modal after a brief delay to ensure page is ready
|
||||
setTimeout(() => {
|
||||
if (typeof showSettings === 'function') {
|
||||
showSettings();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
function acceptDisclaimer() {
|
||||
localStorage.setItem('disclaimerAccepted', 'true');
|
||||
document.getElementById('disclaimerModal').classList.add('disclaimer-hidden');
|
||||
@@ -2410,6 +2429,9 @@
|
||||
|
||||
// Apply mode from URL query (e.g., /?mode=wifi)
|
||||
applyModeFromQuery();
|
||||
|
||||
// Check for settings=1 query param (from dashboard settings button)
|
||||
applySettingsFromQuery();
|
||||
});
|
||||
|
||||
// Toggle section collapse
|
||||
@@ -7923,7 +7945,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
function initAprsMap() {
|
||||
async function initAprsMap() {
|
||||
if (aprsMap) return;
|
||||
|
||||
const mapContainer = document.getElementById('aprsMap');
|
||||
@@ -7938,7 +7960,9 @@
|
||||
window.aprsMap = aprsMap;
|
||||
|
||||
// Use settings manager for tile layer (allows runtime changes)
|
||||
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
|
||||
if (typeof Settings !== 'undefined') {
|
||||
// Wait for settings to load from server before applying tiles
|
||||
await Settings.init();
|
||||
Settings.createTileLayer().addTo(aprsMap);
|
||||
Settings.registerMap(aprsMap);
|
||||
} else {
|
||||
@@ -8846,7 +8870,7 @@
|
||||
let observerMarker = null;
|
||||
let satPositionInterval = null;
|
||||
|
||||
function initGroundTrackMap() {
|
||||
async function initGroundTrackMap() {
|
||||
const mapContainer = document.getElementById('groundTrackMap');
|
||||
if (!mapContainer || groundTrackMap) return;
|
||||
|
||||
@@ -8859,7 +8883,9 @@
|
||||
window.groundTrackMap = groundTrackMap;
|
||||
|
||||
// Use settings manager for tile layer (allows runtime changes)
|
||||
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
|
||||
if (typeof Settings !== 'undefined') {
|
||||
// Wait for settings to load from server before applying tiles
|
||||
await Settings.init();
|
||||
Settings.createTileLayer().addTo(groundTrackMap);
|
||||
Settings.registerMap(groundTrackMap);
|
||||
} else {
|
||||
|
||||
@@ -12,22 +12,25 @@
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/agents.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/global-nav.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/help-modal.css') }}">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
:root {
|
||||
--font-sans: 'Space Mono', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
--font-mono: 'Space Mono', 'Fira Code', 'Consolas', monospace;
|
||||
--bg-primary: #0a0a0f;
|
||||
--bg-secondary: #12121a;
|
||||
--bg-tertiary: #1a1a2e;
|
||||
--text-primary: #e0e0e0;
|
||||
--text-secondary: #888;
|
||||
--border-color: #2a2a3e;
|
||||
--accent-cyan: #00d4ff;
|
||||
--accent-green: #00ff88;
|
||||
--accent-red: #ff3366;
|
||||
--accent-orange: #ff9f1c;
|
||||
--bg-primary: #0a0c10;
|
||||
--bg-secondary: #0f1218;
|
||||
--bg-tertiary: #151a23;
|
||||
--text-primary: #e8eaed;
|
||||
--text-secondary: #9ca3af;
|
||||
--text-dim: #4b5563;
|
||||
--border-color: #1f2937;
|
||||
--accent-cyan: #4a9eff;
|
||||
--accent-green: #22c55e;
|
||||
--accent-red: #ef4444;
|
||||
--accent-orange: #f59e0b;
|
||||
--accent-purple: #a855f7;
|
||||
}
|
||||
|
||||
@@ -120,12 +123,13 @@
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
/* Header ~50px + Nav 44px + Status bar ~40px = ~134px, using 150px for safety */
|
||||
.main-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 300px;
|
||||
gap: 20px;
|
||||
padding: 20px;
|
||||
height: calc(100vh - 110px);
|
||||
height: calc(100vh - 150px);
|
||||
}
|
||||
|
||||
.data-panel {
|
||||
@@ -157,7 +161,7 @@
|
||||
.panel-count {
|
||||
font-size: 10px;
|
||||
padding: 2px 8px;
|
||||
background: rgba(0, 212, 255, 0.2);
|
||||
background: rgba(74, 158, 255, 0.2);
|
||||
color: var(--accent-cyan);
|
||||
border-radius: 10px;
|
||||
font-family: var(--font-mono);
|
||||
@@ -188,7 +192,7 @@
|
||||
}
|
||||
|
||||
.panel-tab.active {
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
background: rgba(74, 158, 255, 0.1);
|
||||
color: var(--accent-cyan);
|
||||
border-color: var(--accent-cyan);
|
||||
}
|
||||
@@ -226,7 +230,7 @@
|
||||
}
|
||||
|
||||
.data-table tr:hover {
|
||||
background: rgba(0, 212, 255, 0.05);
|
||||
background: rgba(74, 158, 255, 0.05);
|
||||
}
|
||||
|
||||
.mono {
|
||||
@@ -245,7 +249,7 @@
|
||||
gap: 4px;
|
||||
padding: 2px 6px;
|
||||
font-size: 9px;
|
||||
background: rgba(0, 212, 255, 0.15);
|
||||
background: rgba(74, 158, 255, 0.15);
|
||||
color: var(--accent-cyan);
|
||||
border-radius: 8px;
|
||||
font-family: var(--font-mono);
|
||||
@@ -260,7 +264,7 @@
|
||||
|
||||
/* Different colors for different agents */
|
||||
.source-badge:nth-child(2) {
|
||||
background: rgba(0, 255, 136, 0.15);
|
||||
background: rgba(34, 197, 94, 0.15);
|
||||
color: var(--accent-green);
|
||||
}
|
||||
.source-badge:nth-child(2) .dot {
|
||||
@@ -276,7 +280,7 @@
|
||||
}
|
||||
|
||||
.source-badge:nth-child(4) {
|
||||
background: rgba(255, 159, 28, 0.15);
|
||||
background: rgba(245, 158, 11, 0.15);
|
||||
color: var(--accent-orange);
|
||||
}
|
||||
.source-badge:nth-child(4) .dot {
|
||||
@@ -435,23 +439,23 @@
|
||||
gap: 6px;
|
||||
margin-top: 4px;
|
||||
padding: 3px 8px;
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
background: rgba(74, 158, 255, 0.1);
|
||||
border-radius: 4px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.location-estimate.high {
|
||||
background: rgba(0, 255, 136, 0.15);
|
||||
background: rgba(34, 197, 94, 0.15);
|
||||
border-left: 2px solid var(--accent-green);
|
||||
}
|
||||
|
||||
.location-estimate.medium {
|
||||
background: rgba(255, 159, 28, 0.15);
|
||||
background: rgba(245, 158, 11, 0.15);
|
||||
border-left: 2px solid var(--accent-orange);
|
||||
}
|
||||
|
||||
.location-estimate.low {
|
||||
background: rgba(255, 51, 102, 0.15);
|
||||
background: rgba(239, 68, 68, 0.15);
|
||||
border-left: 2px solid var(--accent-red);
|
||||
}
|
||||
|
||||
@@ -493,11 +497,11 @@
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.type-badge.type-wifi { background: rgba(0, 212, 255, 0.2); color: var(--accent-cyan); }
|
||||
.type-badge.type-wifi { background: rgba(74, 158, 255, 0.2); color: var(--accent-cyan); }
|
||||
.type-badge.type-bluetooth { background: rgba(168, 85, 247, 0.2); color: var(--accent-purple); }
|
||||
.type-badge.type-adsb { background: rgba(0, 255, 136, 0.2); color: var(--accent-green); }
|
||||
.type-badge.type-ais { background: rgba(255, 159, 28, 0.2); color: var(--accent-orange); }
|
||||
.type-badge.type-sensor { background: rgba(255, 51, 102, 0.2); color: var(--accent-red); }
|
||||
.type-badge.type-adsb { background: rgba(34, 197, 94, 0.2); color: var(--accent-green); }
|
||||
.type-badge.type-ais { background: rgba(245, 158, 11, 0.2); color: var(--accent-orange); }
|
||||
.type-badge.type-sensor { background: rgba(239, 68, 68, 0.2); color: var(--accent-red); }
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.main-grid {
|
||||
@@ -1106,6 +1110,14 @@
|
||||
connectStream();
|
||||
addLogEntry('system', 'Network Monitor initialized');
|
||||
</script>
|
||||
|
||||
<!-- Settings Modal -->
|
||||
{% include 'partials/settings-modal.html' %}
|
||||
|
||||
<!-- Help Modal -->
|
||||
{% include 'partials/help-modal.html' %}
|
||||
|
||||
<script src="{{ url_for('static', filename='js/core/settings-manager.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/core/global-nav.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
318
templates/partials/help-modal.html
Normal file
318
templates/partials/help-modal.html
Normal file
@@ -0,0 +1,318 @@
|
||||
{#
|
||||
Help Modal Partial
|
||||
Provides consistent help modal across all pages
|
||||
#}
|
||||
|
||||
<!-- Help Modal -->
|
||||
<div id="helpModal" class="help-modal" onclick="if(event.target === this) hideHelp()">
|
||||
<div class="help-content">
|
||||
<button class="help-close" onclick="hideHelp()">×</button>
|
||||
<h2>iNTERCEPT Help</h2>
|
||||
|
||||
<div class="help-tabs">
|
||||
<button class="help-tab active" data-tab="icons" onclick="switchHelpTab('icons')">Icons</button>
|
||||
<button class="help-tab" data-tab="modes" onclick="switchHelpTab('modes')">Modes</button>
|
||||
<button class="help-tab" data-tab="wifi" onclick="switchHelpTab('wifi')">WiFi</button>
|
||||
<button class="help-tab" data-tab="tips" onclick="switchHelpTab('tips')">Tips</button>
|
||||
</div>
|
||||
|
||||
<!-- Icons Section -->
|
||||
<div id="help-icons" class="help-section active">
|
||||
<h3>Stats Bar Icons</h3>
|
||||
<div class="icon-grid">
|
||||
<div class="icon-item"><span class="icon">📟</span><span class="desc">POCSAG messages decoded</span></div>
|
||||
<div class="icon-item"><span class="icon">📠</span><span class="desc">FLEX messages decoded</span></div>
|
||||
<div class="icon-item"><span class="icon">📨</span><span class="desc">Total messages received</span></div>
|
||||
<div class="icon-item"><span class="icon">🌡️</span><span class="desc">Unique sensors detected</span></div>
|
||||
<div class="icon-item"><span class="icon">📊</span><span class="desc">Device types found</span></div>
|
||||
<div class="icon-item"><span class="icon">🛰️</span><span class="desc">Satellites monitored</span></div>
|
||||
<div class="icon-item"><span class="icon">📡</span><span class="desc">WiFi Access Points</span></div>
|
||||
<div class="icon-item"><span class="icon">👤</span><span class="desc">Connected WiFi clients</span></div>
|
||||
<div class="icon-item"><span class="icon">🤝</span><span class="desc">Captured handshakes</span></div>
|
||||
<div class="icon-item"><span class="icon">🚁</span><span class="desc">Detected drones (click for details)</span></div>
|
||||
<div class="icon-item"><span class="icon">⚠️</span><span class="desc">Rogue APs (click for details)</span></div>
|
||||
<div class="icon-item"><span class="icon">🔵</span><span class="desc">Bluetooth devices</span></div>
|
||||
<div class="icon-item"><span class="icon">📍</span><span class="desc">BLE beacons / APRS stations</span></div>
|
||||
</div>
|
||||
|
||||
<h3>Mode Tab Icons</h3>
|
||||
<div class="icon-grid">
|
||||
<div class="icon-item"><span class="icon">📟</span><span class="desc">Pager - POCSAG/FLEX decoder</span></div>
|
||||
<div class="icon-item"><span class="icon">📡</span><span class="desc">433MHz - Sensor decoder</span></div>
|
||||
<div class="icon-item"><span class="icon">⚡</span><span class="desc">Meters - Utility meter decoder</span></div>
|
||||
<div class="icon-item"><span class="icon">✈️</span><span class="desc">Aircraft - ADS-B tracking & history</span></div>
|
||||
<div class="icon-item"><span class="icon">🚢</span><span class="desc">Vessels - AIS & VHF DSC distress</span></div>
|
||||
<div class="icon-item"><span class="icon">📻</span><span class="desc">Spy Stations - Number stations database</span></div>
|
||||
<div class="icon-item"><span class="icon">📍</span><span class="desc">APRS - Amateur radio tracking</span></div>
|
||||
<div class="icon-item"><span class="icon">🛰️</span><span class="desc">Satellite - Pass prediction</span></div>
|
||||
<div class="icon-item"><span class="icon">📶</span><span class="desc">WiFi - Network scanner</span></div>
|
||||
<div class="icon-item"><span class="icon">🔵</span><span class="desc">Bluetooth - BT/BLE scanner</span></div>
|
||||
<div class="icon-item"><span class="icon">📻</span><span class="desc">Listening Post - SDR scanner</span></div>
|
||||
<div class="icon-item"><span class="icon">🔍</span><span class="desc">TSCM - Counter-surveillance</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modes Section -->
|
||||
<div id="help-modes" class="help-section">
|
||||
<h3>Pager Mode</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Decodes POCSAG and FLEX pager signals using RTL-SDR</li>
|
||||
<li>Set frequency to local pager frequencies (common: 152-158 MHz)</li>
|
||||
<li>Messages are displayed in real-time as they're decoded</li>
|
||||
<li>Use presets for common pager frequencies</li>
|
||||
</ul>
|
||||
|
||||
<h3>433MHz Sensor Mode</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Decodes wireless sensors on 433.92 MHz ISM band</li>
|
||||
<li>Detects temperature, humidity, weather stations, tire pressure monitors</li>
|
||||
<li>Supports many common protocols (Acurite, LaCrosse, Oregon Scientific, etc.)</li>
|
||||
<li>Device intelligence builds profiles of recurring devices</li>
|
||||
</ul>
|
||||
|
||||
<h3>Utility Meter Mode</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Decodes utility meter transmissions (water, gas, electric) using rtlamr</li>
|
||||
<li>Supports ERT protocol on 912 MHz (North America) or 868 MHz (Europe)</li>
|
||||
<li>Displays meter IDs and consumption data in real-time</li>
|
||||
<li>Supports SCM, SCM+, IDM, NetIDM, and R900 message types</li>
|
||||
</ul>
|
||||
|
||||
<h3>Aircraft (Dashboard)</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Opens the dedicated ADS-B Dashboard for aircraft tracking</li>
|
||||
<li>Features radar scope, map view, airband audio, and ACARS decoding</li>
|
||||
<li>Optional history mode persists data to Postgres for long-term analysis</li>
|
||||
<li>Access history dashboard at <code>/adsb/history</code></li>
|
||||
</ul>
|
||||
|
||||
<h3>Vessels (Dashboard)</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Opens the AIS Dashboard for maritime vessel tracking</li>
|
||||
<li>Displays vessel name, MMSI, callsign, destination, and navigation data</li>
|
||||
<li><strong>VHF DSC Channel 70:</strong> Monitors maritime distress frequency (156.525 MHz)</li>
|
||||
<li>Decodes DSC messages: Distress, Urgency, Safety, and Routine calls</li>
|
||||
<li>MMSI country identification via Maritime Identification Digits (MID)</li>
|
||||
<li>Visual alerts for DISTRESS and URGENCY messages with map markers</li>
|
||||
</ul>
|
||||
|
||||
<h3>Spy Stations</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Database of number stations and diplomatic HF networks</li>
|
||||
<li>Browse stations from priyom.org with frequencies and schedules</li>
|
||||
<li>Filter by type (number/diplomatic), country, and mode</li>
|
||||
<li>Famous stations: UVB-76 "The Buzzer", Cuban HM01, Israeli E17z</li>
|
||||
<li>Click "Tune" to listen via Listening Post mode</li>
|
||||
</ul>
|
||||
|
||||
<h3>APRS Mode</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Decodes APRS (Automatic Packet Reporting System) on VHF</li>
|
||||
<li>Tracks amateur radio operators transmitting position data</li>
|
||||
<li>Regional frequencies: 144.390 MHz (N. America), 144.800 MHz (Europe)</li>
|
||||
<li>Uses Direwolf or multimon-ng for packet decoding</li>
|
||||
<li>Interactive map shows station positions in real-time</li>
|
||||
</ul>
|
||||
|
||||
<h3>Satellite Mode</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Track satellites using TLE (Two-Line Element) data</li>
|
||||
<li>Add satellites manually or fetch from Celestrak by category</li>
|
||||
<li>Categories: Amateur, Weather, ISS, Starlink, GPS, and more</li>
|
||||
<li>View next pass predictions with elevation and duration</li>
|
||||
</ul>
|
||||
|
||||
<h3>WiFi Mode</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Requires a WiFi adapter capable of monitor mode</li>
|
||||
<li>Click "Enable Monitor" to put adapter in monitor mode</li>
|
||||
<li>Scans all channels or lock to a specific channel</li>
|
||||
<li>Detects drones by SSID patterns and manufacturer OUI</li>
|
||||
<li>Rogue AP detection flags same SSID on multiple BSSIDs</li>
|
||||
<li>Click network rows to target for deauth or handshake capture</li>
|
||||
</ul>
|
||||
|
||||
<h3>Bluetooth Mode</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Scans for classic Bluetooth and BLE devices</li>
|
||||
<li>Shows device names, addresses, and signal strength</li>
|
||||
<li>Manufacturer lookup from MAC address OUI</li>
|
||||
<li>Radar visualization shows device proximity</li>
|
||||
</ul>
|
||||
|
||||
<h3>Listening Post Mode</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Wideband SDR scanner with spectrum visualization</li>
|
||||
<li>Tune to any frequency supported by your SDR hardware</li>
|
||||
<li>AM/FM/USB/LSB demodulation modes</li>
|
||||
<li>Bookmark frequencies for quick recall</li>
|
||||
<li>Quick tune presets for emergency and marine channels</li>
|
||||
</ul>
|
||||
|
||||
<h3>TSCM Mode</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Technical Surveillance Countermeasures sweep</li>
|
||||
<li>Scans for unknown RF transmitters, WiFi devices, Bluetooth</li>
|
||||
<li>Baseline comparison to detect new/anomalous devices</li>
|
||||
<li>Threat classification: Critical, High, Medium, Low</li>
|
||||
<li>Useful for security audits and bug sweeps</li>
|
||||
<li><em style="color: var(--text-muted);">Note: This feature is in early development</em></li>
|
||||
</ul>
|
||||
|
||||
<h3>Meshtastic Mode</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Integrates with Meshtastic LoRa mesh network devices</li>
|
||||
<li>Connect Heltec, T-Beam, RAK, or other compatible devices via USB</li>
|
||||
<li>Real-time message streaming with RSSI and SNR metrics</li>
|
||||
<li>Configure channels with encryption keys</li>
|
||||
<li>View connected nodes and message history</li>
|
||||
<li>Requires: Meshtastic device + <code>pip install meshtastic</code></li>
|
||||
</ul>
|
||||
|
||||
<h3>Network Monitor</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Aggregates data from multiple remote INTERCEPT agents</li>
|
||||
<li>View all WiFi, Bluetooth, ADS-B, AIS data in one unified view</li>
|
||||
<li>Real-time streaming via Server-Sent Events (SSE)</li>
|
||||
<li>Location estimation using multi-agent trilateration</li>
|
||||
<li>Manage agents at <code>/controller/manage</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- WiFi Section -->
|
||||
<div id="help-wifi" class="help-section">
|
||||
<h3>Monitor Mode</h3>
|
||||
<ul class="tip-list">
|
||||
<li><strong>Enable Monitor:</strong> Puts WiFi adapter in monitor mode for passive scanning</li>
|
||||
<li><strong>Kill Processes:</strong> Optional - stops NetworkManager/wpa_supplicant (may drop other connections)</li>
|
||||
<li>Some adapters rename when entering monitor mode (e.g., wlan0 → wlan0mon)</li>
|
||||
</ul>
|
||||
|
||||
<h3>Handshake Capture</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Click "Capture" on a network to start targeted handshake capture</li>
|
||||
<li>Status panel shows capture progress and file location</li>
|
||||
<li>Use deauth to force clients to reconnect (only on authorized networks!)</li>
|
||||
<li>Handshake files saved to /tmp/intercept_handshake_*.cap</li>
|
||||
</ul>
|
||||
|
||||
<h3>Drone Detection</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Drones detected by SSID patterns (DJI, Parrot, Autel, etc.)</li>
|
||||
<li>Also detected by manufacturer OUI in MAC address</li>
|
||||
<li>Distance estimated from signal strength (approximate)</li>
|
||||
<li>Click drone count in stats bar to see all detected drones</li>
|
||||
</ul>
|
||||
|
||||
<h3>Rogue AP Detection</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Flags networks where same SSID appears on multiple BSSIDs</li>
|
||||
<li>Could indicate evil twin attack or legitimate multi-AP setup</li>
|
||||
<li>Click rogue count to see which SSIDs are flagged</li>
|
||||
</ul>
|
||||
|
||||
<h3>Proximity Alerts</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Add MAC addresses to watch list for alerts when detected</li>
|
||||
<li>Watch list persists in browser localStorage</li>
|
||||
<li>Useful for tracking specific devices</li>
|
||||
</ul>
|
||||
|
||||
<h3>Client Probe Analysis</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Shows what networks client devices are looking for</li>
|
||||
<li>Orange highlights indicate sensitive/private network names</li>
|
||||
<li>Reveals user location history (home, work, hotels, airports)</li>
|
||||
<li>Useful for security awareness and pen test reports</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Tips Section -->
|
||||
<div id="help-tips" class="help-section">
|
||||
<h3>General Tips</h3>
|
||||
<ul class="tip-list">
|
||||
<li><strong>Collapsible sections:</strong> Click any section header (∇) to collapse/expand</li>
|
||||
<li><strong>Sound alerts:</strong> Toggle sound on/off in settings for each mode</li>
|
||||
<li><strong>Export data:</strong> Use export buttons to save captured data as JSON</li>
|
||||
<li><strong>Device Intelligence:</strong> Tracks device patterns over time</li>
|
||||
<li><strong>Theme toggle:</strong> Click the theme button in header to switch dark/light mode</li>
|
||||
<li><strong>Settings:</strong> Click the gear icon in the header to access settings</li>
|
||||
<li><strong>Offline mode:</strong> Enable in Settings to use local assets without internet</li>
|
||||
</ul>
|
||||
|
||||
<h3>Keyboard Shortcuts</h3>
|
||||
<ul class="tip-list">
|
||||
<li><strong>F1</strong> - Open this help page</li>
|
||||
<li><strong>?</strong> - Open help (when not typing in a field)</li>
|
||||
<li><strong>Escape</strong> - Close help and modal dialogs</li>
|
||||
</ul>
|
||||
|
||||
<h3>Requirements</h3>
|
||||
<ul class="tip-list">
|
||||
<li><strong>Pager:</strong> RTL-SDR, rtl_fm, multimon-ng</li>
|
||||
<li><strong>433MHz Sensors:</strong> RTL-SDR, rtl_433</li>
|
||||
<li><strong>Utility Meters:</strong> RTL-SDR, rtl_tcp, rtlamr</li>
|
||||
<li><strong>Aircraft (ADS-B):</strong> RTL-SDR, dump1090 or rtl_adsb</li>
|
||||
<li><strong>Aircraft (ACARS):</strong> Second RTL-SDR, acarsdec</li>
|
||||
<li><strong>Vessels (AIS):</strong> RTL-SDR, AIS-catcher</li>
|
||||
<li><strong>APRS:</strong> RTL-SDR, direwolf or multimon-ng</li>
|
||||
<li><strong>Satellite:</strong> Internet for Celestrak (optional), skyfield</li>
|
||||
<li><strong>WiFi:</strong> Monitor-mode adapter, aircrack-ng suite</li>
|
||||
<li><strong>Bluetooth:</strong> Bluetooth adapter, bluez (hcitool/bluetoothctl)</li>
|
||||
<li><strong>Listening Post:</strong> RTL-SDR or SoapySDR-compatible hardware</li>
|
||||
<li><strong>TSCM:</strong> WiFi adapter, Bluetooth adapter, RTL-SDR (all optional)</li>
|
||||
<li>Run as root/sudo for full hardware access</li>
|
||||
</ul>
|
||||
|
||||
<h3>Legal Notice</h3>
|
||||
<ul class="tip-list">
|
||||
<li>Only use on networks and devices you own or have authorization to test</li>
|
||||
<li>Passive monitoring may be legal; active attacks require authorization</li>
|
||||
<li>Check local laws regarding radio frequency monitoring</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Help modal functions - defined here so all pages have them
|
||||
(function() {
|
||||
// Only define if not already defined (index.html defines its own)
|
||||
if (typeof window.showHelp === 'undefined') {
|
||||
window.showHelp = function() {
|
||||
document.getElementById('helpModal').classList.add('active');
|
||||
document.body.style.overflow = 'hidden';
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof window.hideHelp === 'undefined') {
|
||||
window.hideHelp = function() {
|
||||
document.getElementById('helpModal').classList.remove('active');
|
||||
document.body.style.overflow = '';
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof window.switchHelpTab === 'undefined') {
|
||||
window.switchHelpTab = function(tab) {
|
||||
document.querySelectorAll('.help-tab').forEach(t => t.classList.remove('active'));
|
||||
document.querySelectorAll('.help-section').forEach(s => s.classList.remove('active'));
|
||||
document.querySelector('.help-tab[data-tab="' + tab + '"]').classList.add('active');
|
||||
document.getElementById('help-' + tab).classList.add('active');
|
||||
};
|
||||
}
|
||||
|
||||
// Keyboard shortcuts for help (only add once)
|
||||
if (!window._helpKeyboardSetup) {
|
||||
window._helpKeyboardSetup = true;
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape') hideHelp();
|
||||
// Open help with F1 or ? key (when not typing in an input)
|
||||
var helpModal = document.getElementById('helpModal');
|
||||
if (helpModal && (e.key === 'F1' || (e.key === '?' && !e.target.matches('input, textarea, select'))) && !helpModal.classList.contains('active')) {
|
||||
e.preventDefault();
|
||||
showHelp();
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
@@ -134,6 +134,11 @@
|
||||
<span class="utc-time" id="headerUtcTime">--:--:--</span>
|
||||
</div>
|
||||
<div class="nav-divider"></div>
|
||||
<a href="/" class="nav-dashboard-btn" title="Return to Main Dashboard" style="text-decoration: none;">
|
||||
<span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg></span>
|
||||
<span class="nav-label">Main Dashboard</span>
|
||||
</a>
|
||||
<div class="nav-divider"></div>
|
||||
<div class="nav-tools">
|
||||
<button class="nav-tool-btn" onclick="toggleAnimations()" title="Toggle Animations">
|
||||
<span class="icon-effects-on icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
@@ -235,17 +240,33 @@
|
||||
|
||||
if (typeof showSettings === 'undefined') {
|
||||
window.showSettings = function() {
|
||||
// Navigate to main page settings
|
||||
window.location.href = '/?settings=1';
|
||||
// Try to open settings modal if it exists on this page
|
||||
const modal = document.getElementById('settingsModal');
|
||||
if (modal) {
|
||||
modal.classList.add('active');
|
||||
if (typeof Settings !== 'undefined' && Settings.init) {
|
||||
Settings.init().then(() => {
|
||||
if (Settings.checkAssets) Settings.checkAssets();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Fall back to navigating to main page settings
|
||||
window.location.href = '/?settings=1';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof showHelp === 'undefined') {
|
||||
window.showHelp = function() {
|
||||
window.open('https://smittix.github.io/intercept', '_blank');
|
||||
if (typeof hideSettings === 'undefined') {
|
||||
window.hideSettings = function() {
|
||||
const modal = document.getElementById('settingsModal');
|
||||
if (modal) {
|
||||
modal.classList.remove('active');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// showHelp is defined by the help-modal.html partial
|
||||
|
||||
if (typeof logout === 'undefined') {
|
||||
window.logout = function(e) {
|
||||
if (e) e.preventDefault();
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/global-nav.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/help-modal.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/satellite_dashboard.css') }}">
|
||||
<script>
|
||||
window.INTERCEPT_SHARED_OBSERVER_LOCATION = {{ shared_observer_location | tojson }};
|
||||
@@ -69,7 +71,6 @@
|
||||
<span id="trackingStatus">TRACKING</span>
|
||||
</div>
|
||||
<div class="datetime" id="utcTime">--:--:-- UTC</div>
|
||||
<a href="/?mode=satellite" class="back-link">Main Dashboard</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -437,7 +438,7 @@
|
||||
now.toISOString().substring(11, 19) + ' UTC';
|
||||
}
|
||||
|
||||
function initGroundMap() {
|
||||
async function initGroundMap() {
|
||||
groundMap = L.map('groundMap', {
|
||||
center: [20, 0],
|
||||
zoom: 2,
|
||||
@@ -448,7 +449,9 @@
|
||||
|
||||
// Use settings manager for tile layer (allows runtime changes)
|
||||
window.groundMap = groundMap;
|
||||
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
|
||||
if (typeof Settings !== 'undefined') {
|
||||
// Wait for settings to load from server before applying tiles
|
||||
await Settings.init();
|
||||
Settings.createTileLayer().addTo(groundMap);
|
||||
Settings.registerMap(groundMap);
|
||||
} else {
|
||||
@@ -1085,6 +1088,14 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Settings Modal -->
|
||||
{% include 'partials/settings-modal.html' %}
|
||||
|
||||
<!-- Help Modal -->
|
||||
{% include 'partials/help-modal.html' %}
|
||||
|
||||
<script src="{{ url_for('static', filename='js/core/settings-manager.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/core/global-nav.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user