mirror of
https://github.com/n0mjs710/HBlink4.git
synced 2026-11-08 04:19:26 +00:00
A repeater's registration was displaced by an unauthenticated RPTL: any packet carrying a known radio ID, from any source address, tore down the live registration before anything was proven. Radio IDs are public, so this was enough to knock any repeater off the network with an 8-byte packet, repeatable at will. A login claiming an ID that is already registered from a different sockaddr is now held in _pending_logins and challenged. The incumbent is removed only after the claimant proves the passphrase; on any failure the claimant is discarded and the registration is untouched. Recovery for a genuine NAT remap is unchanged in speed — login, auth, config, one round trip later. Liveness is now gated on the address matching too. _check_repeater_timeouts decides purely on last_ping, which was refreshed by any packet bearing a known ID before validation, so a stale or spoofed source could keep a dead entry from ever aging out. Report reconnects instead of diagnosing them. When a radio ID logs in again, log how long the previous session lasted as D:HH:MM:SS. Hours means a NAT lease expired or the device was power cycled; seconds, repeating, means it cannot stay online — and two addresses alternating is a duplicate radio ID. The operator reads that in a glance; no thresholds are guessed at in code. reconnect_report_threshold (default 3600, 0 disables) filters out routine long sessions. Only reported once a session actually existed, since connect_time is meaningless before the connected state. Fix dashboard uptime resetting for repeaters that never dropped. The dashboard stamped its own event-arrival time as connected_at, but repeater_connected is also emitted on missed pings, on recovery, and on state replay when the dashboard reconnects. The server's connect_time now rides in the payload, with a fallback for older servers. Logging: ping and pong lines now both carry radio ID and sockaddr, as do all inbound dispatch lines, so either field can be grepped for a whole exchange. Fixes an f-string whose conditional sat inside the string literal, raising AttributeError and surfacing as a generic datagram error for exactly the wrong-address pings this change is about. Adds tests/test_id_takeover.py: 31 tests over the auth gate, the login races, threshold filtering and connect_time. Verified by mutation — each reverted behavior fails a specific test. Also documents three unreachable/misleading branches in the dispatch chain found along the way, in code and in docs/TODO.md. Behavior unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>