From a154601e8646d4bacda6235f8756570d1197cf84 Mon Sep 17 00:00:00 2001 From: Smittix Date: Sun, 1 Mar 2026 20:42:14 +0000 Subject: [PATCH] fix: address PR #145 review issues - Escape ac.icao, callsign, typeCode with escapeHtml() in aircraft card (XSS) - Add linking comments between duplicated IATA_TO_ICAO mappings - VDL2 sidebar: single-click selects aircraft, double-click opens modal - Remove stale ICAOs from acarsAircraftIcaos in cleanupOldAircraft() - Add null guard to drawPolarPlot() in weather-satellite.js - Move deferred imports (translate_message, get_flight_correlator) to module level - Check all frequency checkboxes by default on initial load - Remove extra blank lines and uncertain MC/MCO airline code entry - Add TODO comments linking duplicated renderAcarsCard implementations Co-Authored-By: Claude Opus 4.6 --- routes/acars.py | 21 ++++++-------- routes/adsb.py | 42 +++++++++++++--------------- routes/vdl2.py | 20 ++++++------- static/js/modes/weather-satellite.js | 1 + templates/adsb_dashboard.html | 16 +++++++---- templates/partials/modes/acars.html | 3 +- utils/airline_codes.py | 3 +- 7 files changed, 51 insertions(+), 55 deletions(-) diff --git a/routes/acars.py b/routes/acars.py index 9ab5cd5..88b91c7 100644 --- a/routes/acars.py +++ b/routes/acars.py @@ -15,21 +15,23 @@ import time from datetime import datetime from typing import Any, Generator -from flask import Blueprint, jsonify, request, Response +from flask import Blueprint, Response, jsonify, request import app as app_module -from utils.logging import sensor_logger as logger -from utils.validation import validate_device_index, validate_gain, validate_ppm -from utils.sdr import SDRFactory, SDRType -from utils.sse import sse_stream_fanout -from utils.event_pipeline import process_event +from utils.acars_translator import translate_message from utils.constants import ( + PROCESS_START_WAIT, PROCESS_TERMINATE_TIMEOUT, SSE_KEEPALIVE_INTERVAL, SSE_QUEUE_TIMEOUT, - PROCESS_START_WAIT, ) +from utils.event_pipeline import process_event +from utils.flight_correlator import get_flight_correlator +from utils.logging import sensor_logger as logger from utils.process import register_process, unregister_process +from utils.sdr import SDRFactory, SDRType +from utils.sse import sse_stream_fanout +from utils.validation import validate_device_index, validate_gain, validate_ppm acars_bp = Blueprint('acars', __name__, url_prefix='/acars') @@ -126,7 +128,6 @@ def stream_acars_output(process: subprocess.Popen, is_text_mode: bool = False) - # Enrich with translated label and parsed fields try: - from utils.acars_translator import translate_message translation = translate_message(data) data['label_description'] = translation['label_description'] data['message_type'] = translation['message_type'] @@ -142,7 +143,6 @@ def stream_acars_output(process: subprocess.Popen, is_text_mode: bool = False) - # Feed flight correlator try: - from utils.flight_correlator import get_flight_correlator get_flight_correlator().add_acars_message(data) except Exception: pass @@ -452,11 +452,9 @@ def stream_acars() -> Response: return response - @acars_bp.route('/messages') def get_acars_messages() -> Response: """Get recent ACARS messages from correlator (for history reload).""" - from utils.flight_correlator import get_flight_correlator limit = request.args.get('limit', 50, type=int) limit = max(1, min(limit, 200)) msgs = get_flight_correlator().get_recent_messages('acars', limit) @@ -467,7 +465,6 @@ def get_acars_messages() -> Response: def clear_acars_messages() -> Response: """Clear stored ACARS messages and reset counter.""" global acars_message_count, acars_last_message_time - from utils.flight_correlator import get_flight_correlator get_flight_correlator().clear_acars() acars_message_count = 0 acars_last_message_time = None diff --git a/routes/adsb.py b/routes/adsb.py index 9cb75a0..26575c9 100644 --- a/routes/adsb.py +++ b/routes/adsb.py @@ -13,8 +13,7 @@ import time from datetime import datetime, timezone from typing import Any, Generator -from flask import Blueprint, jsonify, request, Response, render_template -from flask import make_response +from flask import Blueprint, Response, jsonify, make_response, render_template, request # psycopg2 is optional - only needed for PostgreSQL history persistence try: @@ -28,39 +27,38 @@ except ImportError: import app as app_module from config import ( + ADSB_AUTO_START, ADSB_DB_HOST, ADSB_DB_NAME, ADSB_DB_PASSWORD, ADSB_DB_PORT, ADSB_DB_USER, - ADSB_AUTO_START, ADSB_HISTORY_ENABLED, SHARED_OBSERVER_LOCATION_ENABLED, ) -from utils.logging import adsb_logger as logger -from utils.process import write_dump1090_pid, clear_dump1090_pid, cleanup_stale_dump1090 -from utils.validation import ( - validate_device_index, validate_gain, - validate_rtl_tcp_host, validate_rtl_tcp_port -) -from utils.sse import format_sse -from utils.event_pipeline import process_event -from utils.sdr import SDRFactory, SDRType +from utils import aircraft_db +from utils.acars_translator import translate_message +from utils.adsb_history import _ensure_adsb_schema, adsb_history_writer, adsb_snapshot_writer from utils.constants import ( ADSB_SBS_PORT, ADSB_TERMINATE_TIMEOUT, - PROCESS_TERMINATE_TIMEOUT, - SBS_SOCKET_TIMEOUT, - SBS_RECONNECT_DELAY, - SOCKET_BUFFER_SIZE, - SSE_KEEPALIVE_INTERVAL, - SSE_QUEUE_TIMEOUT, - SOCKET_CONNECT_TIMEOUT, ADSB_UPDATE_INTERVAL, DUMP1090_START_WAIT, + PROCESS_TERMINATE_TIMEOUT, + SBS_RECONNECT_DELAY, + SBS_SOCKET_TIMEOUT, + SOCKET_BUFFER_SIZE, + SOCKET_CONNECT_TIMEOUT, + SSE_KEEPALIVE_INTERVAL, + SSE_QUEUE_TIMEOUT, ) -from utils import aircraft_db -from utils.adsb_history import adsb_history_writer, adsb_snapshot_writer, _ensure_adsb_schema +from utils.event_pipeline import process_event +from utils.flight_correlator import get_flight_correlator +from utils.logging import adsb_logger as logger +from utils.process import cleanup_stale_dump1090, clear_dump1090_pid, write_dump1090_pid +from utils.sdr import SDRFactory, SDRType +from utils.sse import format_sse +from utils.validation import validate_device_index, validate_gain, validate_rtl_tcp_host, validate_rtl_tcp_port adsb_bp = Blueprint('adsb', __name__, url_prefix='/adsb') @@ -1247,14 +1245,12 @@ def get_aircraft_messages(icao: str): callsign = aircraft.get('callsign') if aircraft else None registration = aircraft.get('registration') if aircraft else None - from utils.flight_correlator import get_flight_correlator messages = get_flight_correlator().get_messages_for_aircraft( icao=icao.upper(), callsign=callsign, registration=registration ) # Backfill translation on messages missing label_description try: - from utils.acars_translator import translate_message for msg in messages.get('acars', []): if not msg.get('label_description'): translation = translate_message(msg) diff --git a/routes/vdl2.py b/routes/vdl2.py index abe9ca6..2d0eae2 100644 --- a/routes/vdl2.py +++ b/routes/vdl2.py @@ -15,21 +15,23 @@ import time from datetime import datetime from typing import Any, Generator -from flask import Blueprint, jsonify, request, Response +from flask import Blueprint, Response, jsonify, request import app as app_module -from utils.logging import sensor_logger as logger -from utils.validation import validate_device_index, validate_gain, validate_ppm -from utils.sdr import SDRFactory, SDRType -from utils.sse import sse_stream_fanout -from utils.event_pipeline import process_event +from utils.acars_translator import translate_message from utils.constants import ( + PROCESS_START_WAIT, PROCESS_TERMINATE_TIMEOUT, SSE_KEEPALIVE_INTERVAL, SSE_QUEUE_TIMEOUT, - PROCESS_START_WAIT, ) +from utils.event_pipeline import process_event +from utils.flight_correlator import get_flight_correlator +from utils.logging import sensor_logger as logger from utils.process import register_process, unregister_process +from utils.sdr import SDRFactory, SDRType +from utils.sse import sse_stream_fanout +from utils.validation import validate_device_index, validate_gain, validate_ppm vdl2_bp = Blueprint('vdl2', __name__, url_prefix='/vdl2') @@ -85,7 +87,6 @@ def stream_vdl2_output(process: subprocess.Popen, is_text_mode: bool = False) -> vdl2_inner = data.get('vdl2', data) acars_payload = (vdl2_inner.get('avlc') or {}).get('acars') if acars_payload and acars_payload.get('label'): - from utils.acars_translator import translate_message translation = translate_message({ 'label': acars_payload.get('label'), 'text': acars_payload.get('msg_text', ''), @@ -104,7 +105,6 @@ def stream_vdl2_output(process: subprocess.Popen, is_text_mode: bool = False) -> # Feed flight correlator try: - from utils.flight_correlator import get_flight_correlator get_flight_correlator().add_vdl2_message(data) except Exception: pass @@ -396,7 +396,6 @@ def stream_vdl2() -> Response: @vdl2_bp.route('/messages') def get_vdl2_messages() -> Response: """Get recent VDL2 messages from correlator (for history reload).""" - from utils.flight_correlator import get_flight_correlator limit = request.args.get('limit', 50, type=int) limit = max(1, min(limit, 200)) msgs = get_flight_correlator().get_recent_messages('vdl2', limit) @@ -407,7 +406,6 @@ def get_vdl2_messages() -> Response: def clear_vdl2_messages() -> Response: """Clear stored VDL2 messages and reset counter.""" global vdl2_message_count, vdl2_last_message_time - from utils.flight_correlator import get_flight_correlator get_flight_correlator().clear_vdl2() vdl2_message_count = 0 vdl2_last_message_time = None diff --git a/static/js/modes/weather-satellite.js b/static/js/modes/weather-satellite.js index 6aa98ce..e028d6d 100644 --- a/static/js/modes/weather-satellite.js +++ b/static/js/modes/weather-satellite.js @@ -727,6 +727,7 @@ const WeatherSat = (function() { * Draw polar plot for a pass trajectory */ function drawPolarPlot(pass) { + if (!pass) return; const canvas = document.getElementById('wxsatPolarCanvas'); if (!canvas) return; diff --git a/templates/adsb_dashboard.html b/templates/adsb_dashboard.html index e5b98ba..4a4d3c8 100644 --- a/templates/adsb_dashboard.html +++ b/templates/adsb_dashboard.html @@ -2864,8 +2864,8 @@ sudo make install return `
- ${callsign}${badge}${acarsIndicator}${agentBadge} - ${typeCode ? typeCode + ' • ' : ''}${ac.icao} + ${escapeHtml(callsign)}${badge}${acarsIndicator}${agentBadge} + ${typeCode ? escapeHtml(typeCode) + ' • ' : ''}${escapeHtml(ac.icao)}
@@ -3242,6 +3242,7 @@ sudo make install return '' + lbl + ''; } + // TODO: Similar to renderAcarsMainCard in partials/modes/acars.html — consider unifying function renderAcarsCard(msg) { const type = msg.message_type || 'other'; const badge = getAcarsTypeBadge(type); @@ -3346,6 +3347,7 @@ sudo make install cleanupTrail(icao); delete aircraft[icao]; delete alertedAircraft[icao]; + if (typeof acarsAircraftIcaos !== 'undefined') acarsAircraftIcaos.delete(icao); needsUpdate = true; if (selectedIcao === icao) { @@ -3811,8 +3813,8 @@ sudo make install }); container.innerHTML = freqs.map((freq, i) => { - // On initial load, only check the first (primary) frequency; otherwise preserve state - const checked = previouslyChecked.size === 0 ? (i === 0 ? 'checked' : '') : (previouslyChecked.has(freq) ? 'checked' : ''); + // On initial load, check all frequencies; otherwise preserve state + const checked = previouslyChecked.size === 0 || previouslyChecked.has(freq) ? 'checked' : ''; return `