mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
bug fixes and feature updates
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"version": "2026-01-04_e27bf619",
|
||||
"downloaded": "2026-01-07T14:55:20.680977Z"
|
||||
"version": "2026-01-11_fae1348c",
|
||||
"downloaded": "2026-01-12T15:55:42.769654Z"
|
||||
}
|
||||
@@ -25,6 +25,7 @@ from utils.validation import (
|
||||
from utils.sse import format_sse
|
||||
from utils.process import safe_terminate, register_process
|
||||
from utils.sdr import SDRFactory, SDRType, SDRValidationError
|
||||
from utils.dependencies import get_tool_path
|
||||
|
||||
pager_bp = Blueprint('pager', __name__)
|
||||
|
||||
@@ -245,7 +246,10 @@ def start_decoding() -> Response:
|
||||
bias_t=bias_t
|
||||
)
|
||||
|
||||
multimon_cmd = ['multimon-ng', '-t', 'raw'] + decoders + ['-f', 'alpha', '-']
|
||||
multimon_path = get_tool_path('multimon-ng')
|
||||
if not multimon_path:
|
||||
return jsonify({'status': 'error', 'message': 'multimon-ng not found'}), 400
|
||||
multimon_cmd = [multimon_path, '-t', 'raw'] + decoders + ['-f', 'alpha', '-']
|
||||
|
||||
full_cmd = ' '.join(rtl_cmd) + ' | ' + ' '.join(multimon_cmd)
|
||||
logger.info(f"Running: {full_cmd}")
|
||||
|
||||
2
setup.sh
2
setup.sh
@@ -285,7 +285,7 @@ install_multimon_ng_from_source_macos() {
|
||||
trap 'rm -rf "$tmp_dir"' EXIT
|
||||
|
||||
info "Cloning multimon-ng..."
|
||||
git clone --depth 1 https://github.com/EliasOeworkem/multimon-ng.git "$tmp_dir/multimon-ng" >/dev/null 2>&1 \
|
||||
git clone --depth 1 https://github.com/EliasOewornal/multimon-ng.git "$tmp_dir/multimon-ng" >/dev/null 2>&1 \
|
||||
|| { fail "Failed to clone multimon-ng"; exit 1; }
|
||||
|
||||
cd "$tmp_dir/multimon-ng"
|
||||
|
||||
@@ -1229,8 +1229,8 @@ header h1 .tagline {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 11px;
|
||||
background: var(--bg-primary);
|
||||
min-height: 100px;
|
||||
max-height: 250px;
|
||||
min-height: 400px;
|
||||
max-height: 600px;
|
||||
}
|
||||
|
||||
.output-content::-webkit-scrollbar {
|
||||
@@ -1496,20 +1496,18 @@ header h1 .tagline {
|
||||
background: var(--accent-cyan);
|
||||
}
|
||||
|
||||
.waterfall-container {
|
||||
padding: 0 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#waterfallCanvas {
|
||||
/* Waterfall canvases (inside collapsible panels) */
|
||||
#waterfallCanvas,
|
||||
#sensorWaterfallCanvas {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
height: 30px;
|
||||
background: var(--bg-primary);
|
||||
border: 1px solid var(--border-color);
|
||||
transition: box-shadow 0.3s ease;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#waterfallCanvas.active {
|
||||
#waterfallCanvas.active,
|
||||
#sensorWaterfallCanvas.active {
|
||||
border-color: var(--accent-cyan);
|
||||
}
|
||||
|
||||
@@ -1637,20 +1635,54 @@ header h1 .tagline {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.waterfall-container {
|
||||
position: relative;
|
||||
background: #000;
|
||||
/* Removed - now using sensor-waterfall-panel structure for waterfalls */
|
||||
|
||||
/* Waterfall Panel (used for both pager and 433MHz modes) */
|
||||
.sensor-waterfall-panel {
|
||||
margin: 0 15px 10px 15px;
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#waterfallCanvas {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
display: block;
|
||||
.sensor-waterfall-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
background: var(--bg-tertiary);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.sensor-waterfall-header:hover {
|
||||
background: var(--bg-hover);
|
||||
}
|
||||
|
||||
.sensor-waterfall-content {
|
||||
background: #000;
|
||||
transition: max-height 0.3s ease, padding 0.3s ease;
|
||||
max-height: 50px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sensor-waterfall-panel.collapsed .sensor-waterfall-content {
|
||||
max-height: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sensor-waterfall-panel.collapsed .sensor-waterfall-header {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Removed duplicate - consolidated above */
|
||||
|
||||
.waterfall-scale {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -1530,9 +1530,9 @@
|
||||
</div>
|
||||
|
||||
<!-- Device Intelligence Dashboard (above waterfall for prominence) -->
|
||||
<div class="recon-panel" id="reconPanel">
|
||||
<div class="recon-panel collapsed" id="reconPanel">
|
||||
<div class="recon-header" onclick="toggleReconCollapse()" style="cursor: pointer;">
|
||||
<h4><span id="reconCollapseIcon">▼</span> Device Intelligence</h4>
|
||||
<h4><span id="reconCollapseIcon">▶</span> Device Intelligence</h4>
|
||||
<div class="recon-stats">
|
||||
<div>TRACKED: <span id="trackedCount">0</span></div>
|
||||
<div>NEW: <span id="newDeviceCount">0</span></div>
|
||||
@@ -1546,16 +1546,32 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="waterfall-container">
|
||||
<canvas id="waterfallCanvas" width="800" height="60"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="output-content" id="output">
|
||||
<div class="placeholder" style="color: #888; text-align: center; padding: 50px;">
|
||||
Configure settings and click "Start Decoding" to begin.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pager Waterfall (pager mode only, at bottom, collapsible) -->
|
||||
<div class="sensor-waterfall-panel collapsed" id="pagerWaterfallPanel" style="display: none;">
|
||||
<div class="sensor-waterfall-header" onclick="togglePagerWaterfall()" style="cursor: pointer;">
|
||||
<span id="pagerWaterfallIcon">▶</span> Signal Waterfall
|
||||
</div>
|
||||
<div class="sensor-waterfall-content" id="pagerWaterfallContent">
|
||||
<canvas id="waterfallCanvas" width="800" height="30"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sensor Waterfall (433MHz mode only, at bottom, collapsible) -->
|
||||
<div class="sensor-waterfall-panel collapsed" id="sensorWaterfallPanel" style="display: none;">
|
||||
<div class="sensor-waterfall-header" onclick="toggleSensorWaterfall()" style="cursor: pointer;">
|
||||
<span id="sensorWaterfallIcon">▶</span> Signal Waterfall
|
||||
</div>
|
||||
<div class="sensor-waterfall-content" id="sensorWaterfallContent">
|
||||
<canvas id="sensorWaterfallCanvas" width="800" height="30"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status-bar">
|
||||
<div class="status-indicator">
|
||||
<div class="status-dot" id="statusDot"></div>
|
||||
@@ -2231,7 +2247,10 @@
|
||||
document.getElementById('toolStatusAircraft').style.display = (mode === 'aircraft') ? 'grid' : 'none';
|
||||
|
||||
// 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' || mode === 'bluetooth') ? 'none' : 'block';
|
||||
// Pager waterfall: show only for pager mode
|
||||
document.getElementById('pagerWaterfallPanel').style.display = (mode === 'pager') ? 'block' : 'none';
|
||||
// Sensor waterfall: show only for sensor (433MHz) mode
|
||||
document.getElementById('sensorWaterfallPanel').style.display = (mode === 'sensor') ? 'block' : 'none';
|
||||
document.getElementById('output').style.display = (mode === 'satellite' || mode === 'aircraft' || mode === 'wifi' || mode === 'bluetooth' || mode === 'listening') ? 'none' : 'block';
|
||||
document.querySelector('.status-bar').style.display = (mode === 'satellite') ? 'none' : 'flex';
|
||||
|
||||
@@ -2518,8 +2537,9 @@
|
||||
signalActivity = Math.min(1, signalActivity + 0.4);
|
||||
lastMessageTime = Date.now();
|
||||
|
||||
// Flash waterfall canvas
|
||||
const canvas = document.getElementById('waterfallCanvas');
|
||||
// Flash waterfall canvas (use appropriate canvas based on mode)
|
||||
const canvasId = (currentMode === 'sensor') ? 'sensorWaterfallCanvas' : 'waterfallCanvas';
|
||||
const canvas = document.getElementById(canvasId);
|
||||
if (canvas) {
|
||||
canvas.classList.add('active');
|
||||
setTimeout(() => canvas.classList.remove('active'), 500);
|
||||
@@ -2539,7 +2559,9 @@
|
||||
}
|
||||
|
||||
function renderWaterfall() {
|
||||
const canvas = document.getElementById('waterfallCanvas');
|
||||
// Render to the appropriate canvas based on current mode
|
||||
const canvasId = (currentMode === 'sensor') ? 'sensorWaterfallCanvas' : 'waterfallCanvas';
|
||||
const canvas = document.getElementById(canvasId);
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d', { willReadFrequently: true });
|
||||
const width = canvas.width;
|
||||
@@ -3537,6 +3559,20 @@
|
||||
icon.textContent = panel.classList.contains('collapsed') ? '▶' : '▼';
|
||||
}
|
||||
|
||||
function toggleSensorWaterfall() {
|
||||
const panel = document.getElementById('sensorWaterfallPanel');
|
||||
const icon = document.getElementById('sensorWaterfallIcon');
|
||||
panel.classList.toggle('collapsed');
|
||||
icon.textContent = panel.classList.contains('collapsed') ? '▶' : '▼';
|
||||
}
|
||||
|
||||
function togglePagerWaterfall() {
|
||||
const panel = document.getElementById('pagerWaterfallPanel');
|
||||
const icon = document.getElementById('pagerWaterfallIcon');
|
||||
panel.classList.toggle('collapsed');
|
||||
icon.textContent = panel.classList.contains('collapsed') ? '▶' : '▼';
|
||||
}
|
||||
|
||||
// ============== WIFI RECONNAISSANCE ==============
|
||||
|
||||
let wifiEventSource = null;
|
||||
|
||||
@@ -7,8 +7,8 @@ from typing import Any
|
||||
|
||||
logger = logging.getLogger('intercept.dependencies')
|
||||
|
||||
# Additional paths to search for tools (e.g., /usr/sbin on Debian)
|
||||
EXTRA_TOOL_PATHS = ['/usr/sbin', '/sbin']
|
||||
# Additional paths to search for tools (e.g., /usr/sbin on Debian, /opt/local/bin for MacPorts)
|
||||
EXTRA_TOOL_PATHS = ['/usr/sbin', '/sbin', '/opt/local/bin', '/opt/local/sbin']
|
||||
|
||||
|
||||
def check_tool(name: str) -> bool:
|
||||
@@ -51,7 +51,7 @@ TOOL_DEPENDENCIES = {
|
||||
'description': 'Digital transmission decoder',
|
||||
'install': {
|
||||
'apt': 'sudo apt install multimon-ng',
|
||||
'brew': 'brew install multimon-ng',
|
||||
'brew': 'sudo port install multimon-ng (MacPorts) or build from source',
|
||||
'manual': 'https://github.com/EliasOewornal/multimon-ng'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -10,6 +10,7 @@ from __future__ import annotations
|
||||
from typing import Optional
|
||||
|
||||
from .base import CommandBuilder, SDRCapabilities, SDRDevice, SDRType
|
||||
from utils.dependencies import get_tool_path
|
||||
|
||||
|
||||
class RTLSDRCommandBuilder(CommandBuilder):
|
||||
@@ -53,8 +54,9 @@ class RTLSDRCommandBuilder(CommandBuilder):
|
||||
|
||||
Used for pager decoding. Supports local devices and rtl_tcp connections.
|
||||
"""
|
||||
rtl_fm_path = get_tool_path('rtl_fm') or 'rtl_fm'
|
||||
cmd = [
|
||||
'rtl_fm',
|
||||
rtl_fm_path,
|
||||
'-d', self._get_device_arg(device),
|
||||
'-f', f'{frequency_mhz}M',
|
||||
'-M', modulation,
|
||||
@@ -99,8 +101,9 @@ class RTLSDRCommandBuilder(CommandBuilder):
|
||||
"connect to its SBS output (port 30003)."
|
||||
)
|
||||
|
||||
dump1090_path = get_tool_path('dump1090') or 'dump1090'
|
||||
cmd = [
|
||||
'dump1090',
|
||||
dump1090_path,
|
||||
'--net',
|
||||
'--device-index', str(device.index),
|
||||
'--quiet'
|
||||
@@ -127,8 +130,9 @@ class RTLSDRCommandBuilder(CommandBuilder):
|
||||
|
||||
Outputs JSON for easy parsing. Supports local devices and rtl_tcp connections.
|
||||
"""
|
||||
rtl_433_path = get_tool_path('rtl_433') or 'rtl_433'
|
||||
cmd = [
|
||||
'rtl_433',
|
||||
rtl_433_path,
|
||||
'-d', self._get_device_arg(device),
|
||||
'-f', f'{frequency_mhz}M',
|
||||
'-F', 'json'
|
||||
|
||||
Reference in New Issue
Block a user