Compare commits

..

12 Commits

Author SHA1 Message Date
Smittix 9a9b1e9856 v2.26.9: add rtl_biast fallback for ADS-B bias-t on Blog V4 (#195)
When dump1090 lacks native --enable-biast support, the system now falls
back to rtl_biast (RTL-SDR Blog drivers) to enable bias-t power before
starting dump1090. The Blog V4's built-in LNA requires bias-t to
receive ADS-B signals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 18:05:15 +00:00
Smittix 8aeb52380e v2.26.8: fix acarsdec build failure on macOS (#187)
HOST_NAME_MAX is Linux-specific and undefined on macOS, causing 3
compile errors in acarsdec.c. Now patched with #define HOST_NAME_MAX 255
before building. Also fixed deprecated -Ofast flag on all macOS archs
(was only patched for arm64).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 16:03:46 +00:00
Smittix 05141b9a1b v2.26.7: fix health check SDR detection on macOS (#188)
timeout (GNU coreutils) is not available on macOS, causing rtl_test to
silently fail and report no SDR device found. Now tries timeout, then
gtimeout (Homebrew coreutils), then falls back to background process
with manual kill.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 16:01:55 +00:00
Smittix dc0850d339 v2.26.6: fix oversized branded 'i' logo on dashboard pages (#189)
.logo span { display: inline } in dashboard CSS had specificity (0,1,1),
overriding .brand-i { display: inline-block } at (0,1,0). Inline elements
ignore width/height, so the SVG rendered at intrinsic size (~80px tall).
Added .logo .brand-i selector at (0,2,0) to retain inline-block display.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 15:57:25 +00:00
Smittix 2bbf896e7c v2.26.5: fix database errors crashing entire UI (#190)
get_setting() now catches sqlite3.OperationalError and returns the
default value. Previously, an inaccessible database (e.g. root-owned
instance/ from sudo) caused inject_offline_settings to crash every
page render with 500 Internal Server Error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 15:49:29 +00:00
Smittix faf57741a1 v2.26.4: fix Environment Configurator crash when .env variable missing (#191)
read_env_var() grep pipeline failed under set -euo pipefail when .env
existed but didn't contain the requested key. grep returned 1 (no match),
pipefail propagated it, and set -e killed the script.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 15:44:48 +00:00
Smittix fd7d01fc7d v2.26.3: fix SatDump AVX2 crash on older CPUs (#185)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 15:41:28 +00:00
Smittix 8ef9dca6ee fix(build): compile SatDump with baseline x86-64 to avoid AVX2 crashes (#185)
On x86_64, explicitly pass -march=x86-64 so the compiler emits only
baseline instructions. SatDump's SIMD plugins still compile with their
own per-target flags and do runtime CPU detection, so AVX2 acceleration
remains available on capable hardware. ARM builds are unaffected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 20:58:59 +00:00
Smittix 4610804de6 v2.26.2: fix Docker startup crash — data/ package excluded by .dockerignore
The data/ directory became a Python package (oui.py, patterns.py, satellites.py)
in v2.26.0, but .dockerignore still blanket-excluded it as runtime data.
This caused ModuleNotFoundError: No module named 'data.oui' on container startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 16:35:22 +00:00
Smittix 6d8836ddfc feat(docs): add branded 'i' logo to GitHub Pages site
Apply the branded SVG "i" glyph to nav logo, hero heading, and footer
on the GitHub Pages landing page, matching the main app's branding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:51:42 +00:00
Smittix 17944554e6 v2.26.1: fix default admin credentials (admin:admin)
Patch release for #186 — default ADMIN_PASSWORD now matches README,
and credential changes in config.py sync to DB on restart.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:31:01 +00:00
Smittix 47a7376632 fix(auth): default admin password now matches README (admin:admin)
The default ADMIN_PASSWORD was an empty string, triggering random
password generation on first run — contradicting the README which
states admin:admin. Additionally, editing config.py after first run
had no effect since init_db() only seeded users on an empty table.

- Change default ADMIN_PASSWORD from '' to 'admin'
- Sync admin credentials from config on every startup so that
  changes to config.py or env vars take effect without wiping the DB

Fixes #186

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:30:04 +00:00
11 changed files with 293 additions and 48 deletions
+5 -1
View File
@@ -40,7 +40,11 @@ tasks/
# Runtime data (mounted as volume) # Runtime data (mounted as volume)
instance/ instance/
data/
# data/ is a Python package — only exclude non-code files
data/*.json
data/*.csv
data/*.db
# Build scripts # Build scripts
build-multiarch.sh build-multiarch.sh
+64
View File
@@ -2,6 +2,70 @@
All notable changes to iNTERCEPT will be documented in this file. All notable changes to iNTERCEPT will be documented in this file.
## [2.26.9] - 2026-03-14
### Fixed
- **ADS-B bias-t support for RTL-SDR Blog V4** — When dump1090 lacks native `--enable-biast` support, the system now falls back to `rtl_biast` (from RTL-SDR Blog drivers) to enable bias-t power before starting dump1090. The Blog V4's built-in LNA requires bias-t to receive ADS-B signals. (#195)
---
## [2.26.8] - 2026-03-14
### Fixed
- **acarsdec build failure on macOS** — `HOST_NAME_MAX` is Linux-specific (`<limits.h>`) and undefined on macOS, causing 3 compile errors in `acarsdec.c`. Now patched with `#define HOST_NAME_MAX 255` before building. Also fixed deprecated `-Ofast` flag warning on all macOS architectures (was only patched for arm64). (#187)
---
## [2.26.7] - 2026-03-14
### Fixed
- **Health check SDR detection on macOS** — `timeout` (GNU coreutils) is not available on macOS, causing `rtl_test` to silently fail and report "No RTL-SDR device found" even when one is connected. Now tries `timeout`, then `gtimeout` (Homebrew coreutils), then falls back to a background process with manual kill. (#188)
---
## [2.26.6] - 2026-03-14
### Fixed
- **Oversized branded 'i' logo on dashboards** — `.logo span { display: inline }` in dashboard CSS had higher specificity (0,1,1) than `.brand-i { display: inline-block }` (0,1,0), forcing the branded "i" SVG to render as inline which ignores width/height. Added `.logo .brand-i` selector (0,2,0) to retain `inline-block` display. (#189)
---
## [2.26.5] - 2026-03-14
### Fixed
- **Database errors crash entire UI** — `get_setting()` now catches `sqlite3.OperationalError` and returns the default value instead of propagating the exception. Previously, if the database was inaccessible (e.g. root-owned `instance/` directory from running with `sudo`), the `inject_offline_settings` context processor would crash every page render with a 500 Internal Server Error. (#190)
---
## [2.26.4] - 2026-03-14
### Fixed
- **Environment Configurator crash** — `read_env_var()` crashed with "Setup failed at line 2333" when `.env` existed but didn't contain the variable being looked up. `grep` returned exit code 1 (no match), which `pipefail` propagated and `set -e` turned into a fatal error. Fixed by appending `|| true` to the pipeline. (#191)
---
## [2.26.3] - 2026-03-13
### Fixed
- **SatDump AVX2 crash** — SatDump now compiles with `-march=x86-64` on x86_64 platforms (Docker and `setup.sh`), preventing "Illegal instruction" crashes on CPUs without AVX2. SIMD plugins still use runtime detection for acceleration on capable hardware. (#185)
---
## [2.26.2] - 2026-03-13
### Fixed
- **Docker startup crash** — `.dockerignore` excluded the entire `data/` directory, which is now a Python package (`data.oui`, `data.patterns`, `data.satellites`). Caused `ModuleNotFoundError: No module named 'data.oui'` on container startup. Fixed by only excluding non-code files from `data/`.
---
## [2.26.1] - 2026-03-13
### Fixed
- **Default admin credentials** — Default `ADMIN_PASSWORD` changed from empty string to `admin`, matching the README documentation (`admin:admin`)
- **Config credential sync** — Admin password changes in `config.py` or via `INTERCEPT_ADMIN_PASSWORD` env var now sync to the database on restart, without needing to delete the DB
---
## [2.26.0] - 2026-03-13 ## [2.26.0] - 2026-03-13
### Fixed ### Fixed
+4 -1
View File
@@ -130,7 +130,10 @@ RUN cd /tmp \
&& git clone --depth 1 --branch 1.2.2 https://github.com/SatDump/SatDump.git \ && git clone --depth 1 --branch 1.2.2 https://github.com/SatDump/SatDump.git \
&& cd SatDump \ && cd SatDump \
&& mkdir build && cd build \ && mkdir build && cd build \
&& cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=OFF -DCMAKE_INSTALL_LIBDIR=lib .. \ && ARCH_FLAGS=""; if [ "$(uname -m)" = "x86_64" ]; then ARCH_FLAGS="-march=x86-64"; fi \
&& cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=OFF -DCMAKE_INSTALL_LIBDIR=lib \
-DCMAKE_C_FLAGS="$ARCH_FLAGS" \
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" .. \
&& make -j$(nproc) \ && make -j$(nproc) \
&& make install \ && make install \
&& ldconfig \ && ldconfig \
+66 -2
View File
@@ -7,10 +7,74 @@ import os
import sys import sys
# Application version # Application version
VERSION = "2.26.0" VERSION = "2.26.9"
# Changelog - latest release notes (shown on welcome screen) # Changelog - latest release notes (shown on welcome screen)
CHANGELOG = [ CHANGELOG = [
{
"version": "2.26.9",
"date": "March 2026",
"highlights": [
"ADS-B bias-t fallback via rtl_biast for Blog V4 when dump1090 lacks native support",
]
},
{
"version": "2.26.8",
"date": "March 2026",
"highlights": [
"Fix acarsdec build failure on macOS (HOST_NAME_MAX undefined)",
]
},
{
"version": "2.26.7",
"date": "March 2026",
"highlights": [
"Fix health check SDR detection on macOS (timeout command not available)",
]
},
{
"version": "2.26.6",
"date": "March 2026",
"highlights": [
"Fix oversized branded 'i' logo on Aircraft & Vessel dashboards",
]
},
{
"version": "2.26.5",
"date": "March 2026",
"highlights": [
"Fix database errors crashing the entire UI — pages now degrade gracefully",
]
},
{
"version": "2.26.4",
"date": "March 2026",
"highlights": [
"Fix Environment Configurator crash when .env exists but variable is missing",
]
},
{
"version": "2.26.3",
"date": "March 2026",
"highlights": [
"Fix SatDump AVX2 crash on older CPUs — build now targets baseline x86-64",
]
},
{
"version": "2.26.2",
"date": "March 2026",
"highlights": [
"Fix Docker startup crash — data/ Python package was excluded by .dockerignore",
]
},
{
"version": "2.26.1",
"date": "March 2026",
"highlights": [
"Fix default admin credentials — now matches README (admin:admin)",
"Admin password changes in config.py / env vars now sync to DB on restart",
]
},
{ {
"version": "2.26.0", "version": "2.26.0",
"date": "March 2026", "date": "March 2026",
@@ -418,7 +482,7 @@ ALERT_WEBHOOK_TIMEOUT = _get_env_int('ALERT_WEBHOOK_TIMEOUT', 5)
# Admin credentials # Admin credentials
ADMIN_USERNAME = _get_env('ADMIN_USERNAME', 'admin') ADMIN_USERNAME = _get_env('ADMIN_USERNAME', 'admin')
ADMIN_PASSWORD = _get_env('ADMIN_PASSWORD', '') ADMIN_PASSWORD = _get_env('ADMIN_PASSWORD', 'admin')
def configure_logging() -> None: def configure_logging() -> None:
+3 -3
View File
@@ -14,7 +14,7 @@
<canvas id="bg-canvas"></canvas> <canvas id="bg-canvas"></canvas>
<nav class="navbar"> <nav class="navbar">
<div class="nav-container"> <div class="nav-container">
<a href="#" class="nav-logo">iNTERCEPT</a> <a href="#" class="nav-logo"><span class="brand-i"><svg viewBox="36 14 28 68" width="1em" height="1em" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="20" r="6" fill="#00ff88"/><rect x="44" y="33" width="12" height="45" rx="2" fill="#00d4ff"/><rect x="38" y="33" width="24" height="4" rx="1" fill="#00d4ff"/><rect x="38" y="74" width="24" height="4" rx="1" fill="#00d4ff"/></svg></span>NTERCEPT</a>
<div class="nav-links"> <div class="nav-links">
<a href="#features">Features</a> <a href="#features">Features</a>
<a href="#screenshots">Screenshots</a> <a href="#screenshots">Screenshots</a>
@@ -28,7 +28,7 @@
<header class="hero"> <header class="hero">
<div class="hero-content"> <div class="hero-content">
<div class="hero-badge">Open Source SIGINT Platform</div> <div class="hero-badge">Open Source SIGINT Platform</div>
<h1>iNTERCEPT</h1> <h1><span class="brand-i"><svg viewBox="36 14 28 68" width="1em" height="1em" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="20" r="6" fill="#00ff88"/><rect x="44" y="33" width="12" height="45" rx="2" fill="#00d4ff"/><rect x="38" y="33" width="24" height="4" rx="1" fill="#00d4ff"/><rect x="38" y="74" width="24" height="4" rx="1" fill="#00d4ff"/></svg></span>NTERCEPT</h1>
<p class="hero-subtitle">A unified web interface for software-defined radio tools. Monitor pagers, track aircraft, scan WiFi networks, and more — all from your browser.</p> <p class="hero-subtitle">A unified web interface for software-defined radio tools. Monitor pagers, track aircraft, scan WiFi networks, and more — all from your browser.</p>
<div class="hero-buttons"> <div class="hero-buttons">
<a href="#installation" class="btn btn-primary">Get Started</a> <a href="#installation" class="btn btn-primary">Get Started</a>
@@ -435,7 +435,7 @@ docker compose --profile basic up -d --build</code></pre>
<div class="container"> <div class="container">
<div class="footer-content"> <div class="footer-content">
<div class="footer-brand"> <div class="footer-brand">
<span class="footer-logo">iNTERCEPT</span> <span class="footer-logo"><span class="brand-i"><svg viewBox="36 14 28 68" width="1em" height="1em" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="20" r="6" fill="#00ff88"/><rect x="44" y="33" width="12" height="45" rx="2" fill="#00d4ff"/><rect x="38" y="33" width="24" height="4" rx="1" fill="#00d4ff"/><rect x="38" y="74" width="24" height="4" rx="1" fill="#00d4ff"/></svg></span>NTERCEPT</span>
<p>Signal Intelligence Platform</p> <p>Signal Intelligence Platform</p>
</div> </div>
<div class="footer-links"> <div class="footer-links">
+15
View File
@@ -86,6 +86,21 @@ body {
letter-spacing: 2px; letter-spacing: 2px;
} }
/* Branded "i" — inline SVG glyph matching the app logo */
.brand-i {
display: inline-block;
width: 0.55em;
height: 0.9em;
vertical-align: baseline;
position: relative;
top: 0.05em;
}
.brand-i svg {
display: block;
width: 100%;
height: 100%;
}
.nav-links { .nav-links {
display: flex; display: flex;
align-items: center; align-items: center;
+1 -1
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "intercept" name = "intercept"
version = "2.26.0" version = "2.26.9"
description = "Signal Intelligence Platform - Pager/433MHz/ADS-B/Satellite/WiFi/Bluetooth" description = "Signal Intelligence Platform - Pager/433MHz/ADS-B/Satellite/WiFi/Bluetooth"
readme = "README.md" readme = "README.md"
requires-python = ">=3.9" requires-python = ">=3.9"
+39 -5
View File
@@ -174,7 +174,7 @@ read_env_var() {
local fallback="${2:-}" local fallback="${2:-}"
if [[ -f "$SCRIPT_DIR/.env" ]]; then if [[ -f "$SCRIPT_DIR/.env" ]]; then
local val local val
val=$(grep -E "^${key}=" "$SCRIPT_DIR/.env" 2>/dev/null | tail -1 | cut -d'=' -f2-) val=$(grep -E "^${key}=" "$SCRIPT_DIR/.env" 2>/dev/null | tail -1 | cut -d'=' -f2- || true)
if [[ -n "$val" ]]; then if [[ -n "$val" ]]; then
# Strip surrounding quotes # Strip surrounding quotes
val="${val#\"}" val="${val#\"}"
@@ -751,9 +751,26 @@ install_acarsdec_from_source_macos() {
cd "$tmp_dir/acarsdec" cd "$tmp_dir/acarsdec"
# Replace deprecated -Ofast (all macOS, not just arm64)
if grep -q '\-Ofast' CMakeLists.txt 2>/dev/null; then
sed -i '' 's/-Ofast/-O3 -ffast-math/g' CMakeLists.txt
info "Patched deprecated -Ofast flag"
fi
# macOS doesn't have -march=native on arm64
if [[ "$(uname -m)" == "arm64" ]]; then if [[ "$(uname -m)" == "arm64" ]]; then
sed -i '' 's/-Ofast -march=native/-O3 -ffast-math/g' CMakeLists.txt sed -i '' 's/ -march=native//g' CMakeLists.txt
info "Patched compiler flags for Apple Silicon (arm64)" info "Removed -march=native for Apple Silicon"
fi
# HOST_NAME_MAX is Linux-specific; macOS uses _POSIX_HOST_NAME_MAX
if grep -q 'HOST_NAME_MAX' acarsdec.c 2>/dev/null; then
sed -i '' '1i\
#ifndef HOST_NAME_MAX\
#define HOST_NAME_MAX 255\
#endif
' acarsdec.c
info "Patched HOST_NAME_MAX for macOS compatibility"
fi fi
if grep -q 'pthread_tryjoin_np' rtl.c 2>/dev/null; then if grep -q 'pthread_tryjoin_np' rtl.c 2>/dev/null; then
@@ -957,8 +974,14 @@ install_satdump_from_source_debian() {
) & ) &
progress_pid=$! progress_pid=$!
local arch_flags=""
if [[ "$(uname -m)" == "x86_64" ]]; then
arch_flags="-march=x86-64"
fi
if cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=OFF -DCMAKE_INSTALL_LIBDIR=lib \ if cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=OFF -DCMAKE_INSTALL_LIBDIR=lib \
-DCMAKE_CXX_FLAGS="-Wno-template-body" .. >"$build_log" 2>&1 \ -DCMAKE_C_FLAGS="$arch_flags" \
-DCMAKE_CXX_FLAGS="$arch_flags -Wno-template-body" .. >"$build_log" 2>&1 \
&& make -j "$(nproc)" >>"$build_log" 2>&1; then && make -j "$(nproc)" >>"$build_log" 2>&1; then
kill $progress_pid 2>/dev/null; wait $progress_pid 2>/dev/null kill $progress_pid 2>/dev/null; wait $progress_pid 2>/dev/null
$SUDO make install >/dev/null 2>&1 $SUDO make install >/dev/null 2>&1
@@ -1918,7 +1941,18 @@ do_health_check() {
info "SDR device detection..." info "SDR device detection..."
if cmd_exists rtl_test; then if cmd_exists rtl_test; then
local rtl_output local rtl_output
rtl_output=$(timeout 3 rtl_test -d 0 2>&1 || true) if cmd_exists timeout; then
rtl_output=$(timeout 3 rtl_test -d 0 2>&1 || true)
elif cmd_exists gtimeout; then
rtl_output=$(gtimeout 3 rtl_test -d 0 2>&1 || true)
else
# No timeout command (common on macOS) — run with background kill
rtl_test -d 0 > /tmp/.rtl_test_out 2>&1 & local rtl_pid=$!
sleep 2
kill "$rtl_pid" 2>/dev/null; wait "$rtl_pid" 2>/dev/null
rtl_output=$(cat /tmp/.rtl_test_out 2>/dev/null || true)
rm -f /tmp/.rtl_test_out
fi
if echo "$rtl_output" | grep -q "Found\|Using device"; then if echo "$rtl_output" | grep -q "Found\|Using device"; then
ok "RTL-SDR device detected" ok "RTL-SDR device detected"
((pass++)) || true ((pass++)) || true
+5 -2
View File
@@ -88,8 +88,11 @@
} }
/* Branded "i" — inline SVG that matches the logo icon. /* Branded "i" — inline SVG that matches the logo icon.
Sized to 0.9em so it sits naturally alongside text at any font-size. */ Sized to 0.9em so it sits naturally alongside text at any font-size.
.brand-i { Uses .logo .brand-i (0,2,0) to beat .logo span (0,1,1) in dashboard CSS
which otherwise forces display:inline and breaks width/height. */
.brand-i,
.logo .brand-i {
display: inline-block; display: inline-block;
width: 0.55em; width: 0.55em;
height: 0.9em; height: 0.9em;
+55 -29
View File
@@ -12,7 +12,7 @@ from contextlib import contextmanager
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
from werkzeug.security import generate_password_hash from werkzeug.security import check_password_hash, generate_password_hash
logger = logging.getLogger('intercept.database') logger = logging.getLogger('intercept.database')
@@ -252,14 +252,15 @@ def init_db() -> None:
) )
''') ''')
from config import ADMIN_PASSWORD, ADMIN_USERNAME
cursor = conn.execute('SELECT COUNT(*) FROM users') cursor = conn.execute('SELECT COUNT(*) FROM users')
if cursor.fetchone()[0] == 0: if cursor.fetchone()[0] == 0:
import secrets as _secrets # First run — seed the admin user from config / env vars.
from config import ADMIN_PASSWORD, ADMIN_USERNAME
admin_password = ADMIN_PASSWORD admin_password = ADMIN_PASSWORD
if not admin_password: if not admin_password:
import secrets as _secrets
admin_password = _secrets.token_urlsafe(16) admin_password = _secrets.token_urlsafe(16)
logger.warning(f"Generated admin password: {admin_password}") logger.warning(f"Generated admin password: {admin_password}")
logger.warning("Set INTERCEPT_ADMIN_PASSWORD env var to use a fixed password.") logger.warning("Set INTERCEPT_ADMIN_PASSWORD env var to use a fixed password.")
@@ -277,6 +278,27 @@ def init_db() -> None:
INSERT INTO users (username, password_hash, role) INSERT INTO users (username, password_hash, role)
VALUES (?, ?, ?) VALUES (?, ?, ?)
''', (ADMIN_USERNAME, hashed_pw, 'admin')) ''', (ADMIN_USERNAME, hashed_pw, 'admin'))
elif ADMIN_PASSWORD:
# Sync admin credentials from config on every startup so that
# changes to config.py / env vars take effect without wiping the DB.
row = conn.execute(
'SELECT password_hash FROM users WHERE username = ? AND role = ?',
(ADMIN_USERNAME, 'admin'),
).fetchone()
if row:
if not check_password_hash(row['password_hash'], ADMIN_PASSWORD):
conn.execute(
'UPDATE users SET password_hash = ? WHERE username = ? AND role = ?',
(generate_password_hash(ADMIN_PASSWORD), ADMIN_USERNAME, 'admin'),
)
logger.info(f"Admin password updated from config for user '{ADMIN_USERNAME}'.")
else:
# Admin user doesn't exist (maybe renamed) — create it.
conn.execute(
'INSERT OR IGNORE INTO users (username, password_hash, role) VALUES (?, ?, ?)',
(ADMIN_USERNAME, generate_password_hash(ADMIN_PASSWORD), 'admin'),
)
logger.info(f"Created admin user '{ADMIN_USERNAME}' from config.")
# ===================================================================== # =====================================================================
# TSCM (Technical Surveillance Countermeasures) Tables # TSCM (Technical Surveillance Countermeasures) Tables
# ===================================================================== # =====================================================================
@@ -639,32 +661,36 @@ def get_setting(key: str, default: Any = None) -> Any:
Returns: Returns:
Setting value (auto-converted from JSON for complex types) Setting value (auto-converted from JSON for complex types)
""" """
with get_db() as conn: try:
cursor = conn.execute( with get_db() as conn:
'SELECT value, value_type FROM settings WHERE key = ?', cursor = conn.execute(
(key,) 'SELECT value, value_type FROM settings WHERE key = ?',
) (key,)
row = cursor.fetchone() )
row = cursor.fetchone()
if row is None: if row is None:
return default
value, value_type = row['value'], row['value_type']
# Convert based on type
if value_type == 'json':
try:
return json.loads(value)
except json.JSONDecodeError:
return default return default
elif value_type == 'int':
return int(value) value, value_type = row['value'], row['value_type']
elif value_type == 'float':
return float(value) # Convert based on type
elif value_type == 'bool': if value_type == 'json':
return value.lower() in ('true', '1', 'yes') try:
else: return json.loads(value)
return value except json.JSONDecodeError:
return default
elif value_type == 'int':
return int(value)
elif value_type == 'float':
return float(value)
elif value_type == 'bool':
return value.lower() in ('true', '1', 'yes')
else:
return value
except sqlite3.OperationalError:
logger.warning("Database unavailable reading setting '%s', using default", key)
return default
def set_setting(key: str, value: Any) -> None: def set_setting(key: str, value: Any) -> None:
+36 -4
View File
@@ -46,6 +46,35 @@ def _rtl_tool_supports_bias_t(tool_path: str) -> bool:
return False return False
def enable_bias_t_via_rtl_biast(device_index: int = 0) -> bool:
"""Enable bias-t power using rtl_biast (RTL-SDR Blog drivers).
Runs rtl_biast to set the bias-t register on the device, then exits.
The setting persists across device opens until the device is reset.
Returns True if bias-t was enabled successfully.
"""
rtl_biast_path = get_tool_path('rtl_biast') or 'rtl_biast'
try:
result = subprocess.run(
[rtl_biast_path, '-b', '1', '-d', str(device_index)],
capture_output=True,
text=True,
timeout=5
)
if result.returncode == 0:
logger.info(f"Bias-t enabled via rtl_biast on device {device_index}")
return True
logger.warning(f"rtl_biast failed (exit {result.returncode}): {result.stderr.strip()}")
return False
except FileNotFoundError:
logger.warning("rtl_biast not found — install RTL-SDR Blog drivers for bias-t support")
return False
except Exception as e:
logger.warning(f"Failed to enable bias-t via rtl_biast: {e}")
return False
def _get_dump1090_bias_t_flag(dump1090_path: str) -> str | None: def _get_dump1090_bias_t_flag(dump1090_path: str) -> str | None:
"""Detect the correct bias-t flag for the installed dump1090 variant. """Detect the correct bias-t flag for the installed dump1090 variant.
@@ -197,10 +226,13 @@ class RTLSDRCommandBuilder(CommandBuilder):
if bias_t_flag: if bias_t_flag:
cmd.append(bias_t_flag) cmd.append(bias_t_flag)
else: else:
logger.warning( # Fallback: use rtl_biast to set bias-t before starting dump1090
f"Bias-t requested but {dump1090_path} does not support it. " if not enable_bias_t_via_rtl_biast(device.index):
"Consider using dump1090-fa or readsb for bias-t support." logger.warning(
) f"Bias-t requested but {dump1090_path} does not support it "
"and rtl_biast is not available. Install RTL-SDR Blog drivers "
"or use dump1090-fa/readsb for bias-t support."
)
return cmd return cmd