From d8294a83830f4dfd1f6b72e61b54e50e0c8f6771 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Mon, 2 Mar 2026 16:46:18 -0800 Subject: [PATCH] Add more warnings around radio config, stats loading, and packet decrypt (and remove accidentally committed script whoops) --- AGENTS.md | 5 +-- CHANGELOG.md | 17 ---------- app/packet_processor.py | 7 ++++ .../settings/SettingsRadioSection.tsx | 32 +++++++++++++++---- .../settings/SettingsStatisticsSection.tsx | 9 +++++- scripts/deploy.sh | 19 ----------- 6 files changed, 43 insertions(+), 46 deletions(-) delete mode 100644 scripts/deploy.sh diff --git a/AGENTS.md b/AGENTS.md index 33aec20..70631a2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -171,8 +171,9 @@ This message-layer echo/path handling is independent of raw-packet storage dedup │ └── vite.config.ts ├── scripts/ │ ├── all_quality.sh # Run all lint, format, typecheck, tests, build (parallelized) -│ ├── publish.sh # Version bump, changelog, docker build & push -│ └── deploy.sh # Deploy to production server +│ ├── collect_licenses.sh # Gather third-party license attributions +│ ├── e2e.sh # End-to-end test runner +│ └── publish.sh # Version bump, changelog, docker build & push ├── tests/ # Backend tests (pytest) ├── data/ # SQLite database (runtime) └── pyproject.toml # Python dependencies diff --git a/CHANGELOG.md b/CHANGELOG.md index d685877..deb0a76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -153,23 +153,6 @@ Misc: Always flood advertisements Misc: Better packet dupe handling Misc: Dead code cleanup, test improvements -## [1.8.0] - 2026-02-07 - -Feature: Single hop ping -Feature: PWA viewport fixes(thanks @rgregg) -Feature (?): No frontend distribution; build it yourself ;P -Bugfix: Fix channel message send race condition (concurrent sends could corrupt shared radio slot) -Bugfix: Fix TOCTOU race in radio reconnect (duplicate connections under contention) -Bugfix: Better guarding around reconnection -Bugfix: Duplicate websocket connection fixes -Bugfix: Settings tab error cleanliness on tab swap -Bugfix: Fix path traversal vuln -UI: Swap visualizer legend ordering (yay prettier) -Misc: Perf and locking improvements -Misc: Always flood advertisements -Misc: Better packet dupe handling -Misc: Dead code cleanup, test improvements - ## [1.7.1] - 2026-02-03 Feature: Clickable hyperlinks diff --git a/app/packet_processor.py b/app/packet_processor.py index 010d49d..eb092ec 100644 --- a/app/packet_processor.py +++ b/app/packet_processor.py @@ -518,6 +518,13 @@ async def process_raw_packet( payload_type = packet_info.payload_type if packet_info else None payload_type_name = payload_type.name if payload_type else "Unknown" + if packet_info is None and len(raw_bytes) > 2: + logger.warning( + "Failed to parse %d-byte packet (id=%d); stored undecrypted", + len(raw_bytes), + packet_id, + ) + # Log packet arrival at debug level path_hex = packet_info.path.hex() if packet_info and packet_info.path else "" logger.debug( diff --git a/frontend/src/components/settings/SettingsRadioSection.tsx b/frontend/src/components/settings/SettingsRadioSection.tsx index aaf0032..b04fc38 100644 --- a/frontend/src/components/settings/SettingsRadioSection.tsx +++ b/frontend/src/components/settings/SettingsRadioSection.tsx @@ -103,18 +103,36 @@ export function SettingsRadioSection({ const handleSave = async () => { setError(null); + + const parsedLat = parseFloat(lat); + const parsedLon = parseFloat(lon); + const parsedTxPower = parseInt(txPower, 10); + const parsedFreq = parseFloat(freq); + const parsedBw = parseFloat(bw); + const parsedSf = parseInt(sf, 10); + const parsedCr = parseInt(cr, 10); + + if ( + [parsedLat, parsedLon, parsedTxPower, parsedFreq, parsedBw, parsedSf, parsedCr].some( + (v) => isNaN(v) + ) + ) { + setError('All numeric fields must have valid values'); + return; + } + setBusy(true); try { const update: RadioConfigUpdate = { - lat: parseFloat(lat), - lon: parseFloat(lon), - tx_power: parseInt(txPower, 10), + lat: parsedLat, + lon: parsedLon, + tx_power: parsedTxPower, radio: { - freq: parseFloat(freq), - bw: parseFloat(bw), - sf: parseInt(sf, 10), - cr: parseInt(cr, 10), + freq: parsedFreq, + bw: parsedBw, + sf: parsedSf, + cr: parsedCr, }, }; await onSave(update); diff --git a/frontend/src/components/settings/SettingsStatisticsSection.tsx b/frontend/src/components/settings/SettingsStatisticsSection.tsx index 0664084..b609447 100644 --- a/frontend/src/components/settings/SettingsStatisticsSection.tsx +++ b/frontend/src/components/settings/SettingsStatisticsSection.tsx @@ -6,10 +6,12 @@ import type { StatisticsResponse } from '../../types'; export function SettingsStatisticsSection({ className }: { className?: string }) { const [stats, setStats] = useState(null); const [statsLoading, setStatsLoading] = useState(false); + const [statsError, setStatsError] = useState(false); useEffect(() => { let cancelled = false; setStatsLoading(true); + setStatsError(false); api.getStatistics().then( (data) => { if (!cancelled) { @@ -18,7 +20,10 @@ export function SettingsStatisticsSection({ className }: { className?: string }) } }, () => { - if (!cancelled) setStatsLoading(false); + if (!cancelled) { + setStatsError(true); + setStatsLoading(false); + } } ); return () => { @@ -145,6 +150,8 @@ export function SettingsStatisticsSection({ className }: { className?: string }) )} + ) : statsError ? ( +
Failed to load statistics.
) : null} ); diff --git a/scripts/deploy.sh b/scripts/deploy.sh deleted file mode 100644 index bf68115..0000000 --- a/scripts/deploy.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -set -e - -# Colors for output -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -echo -e "${YELLOW}Deploying to production server...${NC}" -ssh jack@192.168.1.199 "\ - cd /opt/remoteterm/ && \ - sudo -u remoteterm git checkout main && \ - sudo -u remoteterm git pull && \ - cd frontend && \ - sudo -u remoteterm bash -c 'source ~/.nvm/nvm.sh && npm install && npm run build' && \ - sudo systemctl restart remoteterm && \ - sudo journalctl -u remoteterm -f" - -echo -e "${GREEN}=== Deploy complete! ===${NC}"