- Beacon detail endpoints (LiveView + REST API) now hide unapproved beacons from anonymous and unauthorized viewers; only the submitter and admins can see pending records before approval. Adds Beacons.get_visible_beacon/2 with scope-aware checks. - API contact pagination now honors per_page end-to-end. Radio.list_contacts/1 accepts :per_page and clamps to 200. - API rate limiter: ETS table is now owned by a long-lived Sweeper GenServer (won't die with a request task); Sweeper periodically prunes expired-window rows to bound memory; init_table/0 race is rescued. - /scores/cells and /weather/cells: add per-IP rate limiting and a shared GridBounds clamp/413 guard so global / oversized viewports no longer drive unbounded binary responses. - NEXRAD PNG unfilter (sub/up/average/paeth): replace acc++[byte] + Enum.at(acc, idx-bpp) with O(n) binary recursion. Decode time for the 12200x5400 n0q frame goes from quadratic to linear. - LiveTableFooter.parse_page and ScoresFile.fetch_bound: switch String.to_integer/String.to_float to Integer.parse/Float.parse, fall back to defaults instead of raising. - PathLive and MapLive band-event handlers: replace String.to_integer(params["band"]) with parse_int / parse_band_param so a non-numeric band parameter no longer crashes the LiveView.
1.3 KiB
Bugs Found 2026-05-11
The first batch (7 items: pending-beacon access control, per_page contract, rate-limiter ETS lifecycle, unbounded grid endpoints, NEXRAD PNG quadratic unfilter, LiveTableFooter parser, ScoresFile parser) was fixed and removed from this file as each was resolved. The items below are additional bugs surfaced by a follow-up audit.
A. String.to_integer on user-controlled band param crashes LiveViews
Status: Fixed. Severity: High Category: Availability / unhandled crash on user input Files:
lib/microwaveprop_web/live/path_live.ex(formerly lines 227, 284)lib/microwaveprop_web/live/map_live.ex(formerly line 198)
PathLive.handle_event("calculate", …) and the auto-calculate path both
called String.to_integer(params["band"]) directly on the band form
parameter. MapLive.handle_event("select_band", %{"value" => band}, …)
did the same. A non-numeric band value — supplied via a hand-crafted
URL (/path?band=abc) or a misbehaving JS hook — raised ArgumentError
inside the LiveView process and crashed the channel.
Fix: Use the existing LiveHelpers.parse_int/2 (PathLive) and the
existing parse_band_param/1 plus a small normalize_band_event/1 helper
(MapLive). Unknown bands now fall back to a safe default or a no-op
instead of crashing the process.