mirror of
https://github.com/smittix/intercept.git
synced 2026-04-23 22:30:00 -07:00
Fix security issues, breaking changes, and code cleanup for weather satellite PR
Co-authored-by: mitchross <6330506+mitchross@users.noreply.github.com>
This commit is contained in:
12
app.py
12
app.py
@@ -692,8 +692,7 @@ def kill_all() -> Response:
|
||||
'airodump-ng', 'aireplay-ng', 'airmon-ng',
|
||||
'dump1090', 'acarsdec', 'direwolf', 'AIS-catcher',
|
||||
'hcitool', 'bluetoothctl', 'satdump', 'dsd',
|
||||
'rtl_tcp', 'rtl_power', 'rtlamr', 'ffmpeg',
|
||||
'grgsm_scanner', 'grgsm_livemon', 'tshark'
|
||||
'rtl_tcp', 'rtl_power', 'rtlamr', 'ffmpeg'
|
||||
]
|
||||
|
||||
for proc in processes_to_kill:
|
||||
@@ -870,6 +869,15 @@ def main() -> None:
|
||||
from routes import register_blueprints
|
||||
register_blueprints(app)
|
||||
|
||||
# Initialize TLE auto-refresh (must be after blueprint registration)
|
||||
try:
|
||||
from routes.satellite import init_tle_auto_refresh
|
||||
import os
|
||||
if not os.environ.get('TESTING'):
|
||||
init_tle_auto_refresh()
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to initialize TLE auto-refresh: {e}")
|
||||
|
||||
# Update TLE data in background thread (non-blocking)
|
||||
def update_tle_background():
|
||||
try:
|
||||
|
||||
@@ -152,7 +152,7 @@ def _get_env_bool(key: str, default: bool) -> bool:
|
||||
|
||||
|
||||
# Logging configuration
|
||||
_log_level_str = _get_env('LOG_LEVEL', 'INFO').upper()
|
||||
_log_level_str = _get_env('LOG_LEVEL', 'WARNING').upper()
|
||||
LOG_LEVEL = getattr(logging, _log_level_str, logging.WARNING)
|
||||
LOG_FORMAT = _get_env('LOG_FORMAT', '%(asctime)s - %(levelname)s - %(message)s')
|
||||
|
||||
|
||||
@@ -12,13 +12,10 @@
|
||||
|
||||
services:
|
||||
intercept:
|
||||
# When INTERCEPT_IMAGE is set, use that pre-built image; when empty/unset,
|
||||
# the empty string causes Docker Compose to fall through to the build: directive.
|
||||
image: ${INTERCEPT_IMAGE:-}
|
||||
# When INTERCEPT_IMAGE is set, use that pre-built image; otherwise build locally
|
||||
image: ${INTERCEPT_IMAGE:-intercept:latest}
|
||||
build: .
|
||||
container_name: intercept
|
||||
profiles:
|
||||
- basic
|
||||
ports:
|
||||
- "5050:5050"
|
||||
# Privileged mode required for USB SDR device access
|
||||
@@ -64,7 +61,7 @@ services:
|
||||
# Enable with: docker compose --profile history up -d
|
||||
intercept-history:
|
||||
# Same image/build fallback pattern as above
|
||||
image: ${INTERCEPT_IMAGE:-}
|
||||
image: ${INTERCEPT_IMAGE:-intercept:latest}
|
||||
build: .
|
||||
container_name: intercept-history
|
||||
profiles:
|
||||
|
||||
@@ -30,22 +30,22 @@ ALLOWED_TLE_HOSTS = ['celestrak.org', 'celestrak.com', 'www.celestrak.org', 'www
|
||||
# Local TLE cache (can be updated via API)
|
||||
_tle_cache = dict(TLE_SATELLITES)
|
||||
|
||||
# Auto-refresh TLEs from CelesTrak on startup (non-blocking)
|
||||
import os
|
||||
import threading
|
||||
|
||||
def _auto_refresh_tle():
|
||||
try:
|
||||
updated = refresh_tle_data()
|
||||
if updated:
|
||||
logger.info(f"Auto-refreshed TLE data for: {', '.join(updated)}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Auto TLE refresh failed: {e}")
|
||||
|
||||
# Delay import — refresh_tle_data is defined later in this module
|
||||
# Guard to avoid firing during tests
|
||||
if not os.environ.get('TESTING'):
|
||||
def init_tle_auto_refresh():
|
||||
"""Initialize TLE auto-refresh. Called by app.py after initialization."""
|
||||
import threading
|
||||
|
||||
def _auto_refresh_tle():
|
||||
try:
|
||||
updated = refresh_tle_data()
|
||||
if updated:
|
||||
logger.info(f"Auto-refreshed TLE data for: {', '.join(updated)}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Auto TLE refresh failed: {e}")
|
||||
|
||||
# Start auto-refresh in background
|
||||
threading.Timer(2.0, _auto_refresh_tle).start()
|
||||
logger.info("TLE auto-refresh scheduled")
|
||||
|
||||
|
||||
def _fetch_iss_realtime(observer_lat: Optional[float] = None, observer_lon: Optional[float] = None) -> Optional[dict]:
|
||||
@@ -498,7 +498,8 @@ def update_tle():
|
||||
'updated': updated
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({'status': 'error', 'message': str(e)})
|
||||
logger.error(f"Error updating TLE data: {e}")
|
||||
return jsonify({'status': 'error', 'message': 'TLE update failed'})
|
||||
|
||||
|
||||
@satellite_bp.route('/celestrak/<category>')
|
||||
@@ -552,4 +553,5 @@ def fetch_celestrak(category):
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'status': 'error', 'message': str(e)})
|
||||
logger.error(f"Error fetching CelesTrak data: {e}")
|
||||
return jsonify({'status': 'error', 'message': 'Failed to fetch satellite data'})
|
||||
|
||||
@@ -253,7 +253,7 @@ def test_decode():
|
||||
}), 400
|
||||
|
||||
if not input_path.is_file():
|
||||
logger.warning(f"Test-decode file not found: {input_file}")
|
||||
logger.warning("Test-decode file not found")
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': 'File not found'
|
||||
@@ -313,7 +313,7 @@ def stop_capture():
|
||||
JSON confirmation.
|
||||
"""
|
||||
decoder = get_weather_sat_decoder()
|
||||
device_index = decoder._device_index
|
||||
device_index = decoder.device_index
|
||||
|
||||
decoder.stop()
|
||||
|
||||
|
||||
@@ -446,8 +446,17 @@ const WeatherSat = (function() {
|
||||
* Load pass predictions (with trajectory + ground track)
|
||||
*/
|
||||
async function loadPasses() {
|
||||
const storedLat = localStorage.getItem('observerLat');
|
||||
const storedLon = localStorage.getItem('observerLon');
|
||||
let storedLat, storedLon;
|
||||
|
||||
// Use ObserverLocation if available, otherwise fall back to localStorage
|
||||
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||
const shared = ObserverLocation.getShared();
|
||||
storedLat = shared?.lat?.toString();
|
||||
storedLon = shared?.lon?.toString();
|
||||
} else {
|
||||
storedLat = localStorage.getItem('observerLat');
|
||||
storedLon = localStorage.getItem('observerLon');
|
||||
}
|
||||
|
||||
if (!storedLat || !storedLon) {
|
||||
renderPasses([]);
|
||||
|
||||
@@ -185,6 +185,11 @@ class WeatherSatDecoder:
|
||||
def current_frequency(self) -> float:
|
||||
return self._current_frequency
|
||||
|
||||
@property
|
||||
def device_index(self) -> int:
|
||||
"""Return current device index."""
|
||||
return self._device_index
|
||||
|
||||
def _detect_decoder(self) -> str | None:
|
||||
"""Detect which weather satellite decoder is available."""
|
||||
if shutil.which('satdump'):
|
||||
|
||||
@@ -51,14 +51,16 @@ class ScheduledPass:
|
||||
def start_dt(self) -> datetime:
|
||||
dt = datetime.fromisoformat(self.start_time)
|
||||
if dt.tzinfo is None:
|
||||
return dt.replace(tzinfo=timezone.utc)
|
||||
# Naive datetime - assume UTC
|
||||
dt = dt.replace(tzinfo=timezone.utc)
|
||||
return dt.astimezone(timezone.utc)
|
||||
|
||||
@property
|
||||
def end_dt(self) -> datetime:
|
||||
dt = datetime.fromisoformat(self.end_time)
|
||||
if dt.tzinfo is None:
|
||||
return dt.replace(tzinfo=timezone.utc)
|
||||
# Naive datetime - assume UTC
|
||||
dt = dt.replace(tzinfo=timezone.utc)
|
||||
return dt.astimezone(timezone.utc)
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
|
||||
Reference in New Issue
Block a user