security: CORS hardening, path traversal fix, WebSocket auth + cleanup

- Restrict CORS to localhost origins (was allow_origins=[*])
- Require valid JWT on WebSocket /ws (anonymous no longer gets admin view)
- Fix path traversal in delete_cell(): resolve() + parent check
- Validate cell_id format in /charts/download-noaa/{cell_id}
- Exclude charts/ and Cartas/ from git (keep US1GC09M world overview)
- Add NOAA ENC Portal external link in charts catalog tab
- Untrack __pycache__/, .db, .claude/ session files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 12:45:43 -04:00
parent 3e04c4113f
commit cfd94f905a
47 changed files with 1847 additions and 427 deletions
+19 -3
View File
@@ -113,11 +113,22 @@ def decode_type8_aton(payload: str) -> dict | None:
analog3 = _bits(payload, 81, 12) * 0.05
analog4 = _bits(payload, 93, 12) * 0.05
# Digital bits: racon, lamp, buoy code alarm, controller alarm, etc.
racon = bool(_bits(payload, 105, 2))
light_ok = bool(_bits(payload, 107, 2))
health = _bits(payload, 109, 2) # 0=ok,1=warn,2=alarm,3=no signal
racon = bool(_bits(payload, 105, 2))
light_ok = bool(_bits(payload, 107, 2))
health = _bits(payload, 109, 2) # 0=ok,1=warn,2=alarm,3=no signal
battery_low = bool(_bits(payload, 111, 1))
# IEC 62320-2 extended digital inputs (bits 112119)
# bit 112 = buoy code / hull integrity → water ingress sensor (IN3)
# bit 113 = controller alarm → listing/tilt sensor (IN4)
# bit 114 = fog signal status
# bit 115 = EPIRB armed
# bit 116 = water level alarm → bilge high (critical)
# bits 117-119 = spare / manufacturer-defined
din3 = bool(_bits(payload, 112, 1)) # hull/water ingress
din4 = bool(_bits(payload, 113, 1)) # listing/tilt
water_level = bool(_bits(payload, 116, 1)) # bilge high level
return {
"mmsi": str(mmsi),
"msg_type": 8,
@@ -132,6 +143,11 @@ def decode_type8_aton(payload: str) -> dict | None:
"light_ok": light_ok,
"health": health,
"battery_low": battery_low,
# Digital inputs — meaning depends on din3_function / din4_function
# configured per-aid in the Aid model
"din3": din3, # IN3 state (True = triggered)
"din4": din4, # IN4 state (True = triggered)
"water_level_high": water_level, # bilge high level (IEC standard bit)
"timestamp": datetime.utcnow().isoformat(),
}
except Exception: