Commit Graph

3 Commits

Author SHA1 Message Date
jing
0162ec0cdf pre-deploy: escape external feed strings in InfoBox HTML (ship-check)
Defense-in-depth for the public deploy: USGS/EONET place/title/category are now
HTML-escaped before interpolation into Cesium InfoBox descriptions, and the
USGS/EONET links are passed through lib.safeUrl (http(s)-only) so a hostile feed
can't inject markup or a javascript:/data: href. Entity names/labels stay raw
(Cesium renders those as text). Verified: escapeHtml neutralizes
<img onerror>, safeUrl drops javascript:/data:, 219 quakes + 500 fires still
render normally.

ship-check pass: no auth surface (dev-only history/snap not deployed); no
secrets in tree (AIS key empty, data/ gitignored); proxy upstreams are a fixed
dict (no SSRF); no money paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 20:55:42 +10:00
jing
403884e480 wave2: adversarial-review fixes (9 confirmed findings)
Ran a 7-reviewer × per-finding-verifier workflow over the Wave 2 code; 9 of 13
raw findings survived adversarial verification. Fixes:

- quakes.js: refresh now UPDATES revised quakes, not just dedupes — a signature
  (mag|place|depth|time) per id detects USGS revisions and rebuilds that entity,
  so a quake revised M4.4→M5.2 no longer stays visually understated (SPEC2 §2
  "update, don't duplicate").
- aircraft.js: (a) poll() drops its result if the clock scrubbed off-live mid-
  fetch, so late live data never paints over the replay view; (b) re-enabling the
  aircraft layer while scrubbed now restores the replayed frame instead of
  leaving it hidden; (c) transient (non-404) history errors schedule a bounded
  retry so a paused clock doesn't wedge on an error frame.
- satellites.js: ground track centers on the VIEWER clock (not wall-clock now)
  so it stays under a scrubbed satellite; and it hides when the Satellites layer
  is toggled off (no stray dashed line).
- main.js: malformed camera hash with blank tokens (#c=,,,,) is now rejected
  instead of applying a bogus (0,0,0) camera — falls back to the default view.
- serve.py: history t-parse catches OverflowError (t=inf/1e999 → 400, not a
  crashed handler); stale-on-error now also covers upstream 5xx, not just 429.

Verified: t=inf/-inf/1e999/nan → 400; malformed hash → default Gulf camera;
ground track 427 km from the scrubbed dot (was ~2 orbits off) and hidden on
layer-off; aircraft re-enable during replay restores 6062 billboards; zero
console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 17:16:24 +10:00
jing
dadc068271 wave2 phase 1: earthquakes layer (real USGS, time-anchored)
New js/layers/quakes.js — fetches the USGS all_day GeoJSON directly (ACAO:*,
no proxy), refreshes every 5 min regardless of scrub state. Quakes are
time-anchored via availability: in-window quakes appear as the slider crosses
their origin time, older-than-window quakes stay visible the whole window
(intervals clamped to [start, stop]). Magnitude ramps amber→red, size scales
with magnitude, quakes <1h old pulse (age-aware callback), labels only for
M>=4.5. Deduped by feature id across refreshes, capped at 400 (smallest mag
dropped first). HUD row "Earthquakes (USGS)" with count/max-mag status.

Also: serve.py now sends Cache-Control: no-store on all responses (was
proxy-only) so iterative js/css edits always take effect on reload — the
module graph was caching stale copies during dev.

Verified in browser: 223 quakes, 11 labeled, time-anchoring confirmed
(187 visible at -6h → 223 at now), zero console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 16:01:59 +10:00