mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-10-11 23:17:25 +00:00
Observer `id` and `iata` come from the MQTT topic; `origin` (name), `model`, `firmware`, `client_version` and `radio` come from the status JSON. Any publisher controls them and nothing bounded their length, so one message could store a 64 KB observer id or name. Each new id is also a new `observers` row, and that table is joined by most packet queries. **Fix:** a small `clampObserverField` helper strips control characters and truncates: ids to 128 runes, text fields to 128, IATA to 16. Applied on the status path, the packet path and in `extractObserverMeta`. Values are truncated rather than rejected, so a legitimate observer with a long name still appears. **Tests:** `observer_fields_test.go` — short values untouched, long values cut at 128 runes (not bytes, so multi-byte names are not split), control characters removed, `extractObserverMeta` caps all string fields. Full ingestor suite passes. Running in production on our instance since 2026-10-07. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Mythos 5.1 <noreply@anthropic.com>
25 lines
862 B
Go
25 lines
862 B
Go
package main
|
||
|
||
import "unicode/utf8"
|
||
|
||
// Observer-supplied strings come straight from the MQTT topic (id, IATA) or
|
||
// the status JSON (origin/name, model, firmware, client version, radio). Any
|
||
// publisher controls them and nothing upstream bounds their length, so cap
|
||
// them before they reach the observers table. Values are truncated, not
|
||
// dropped, so a legitimate observer with a long name still shows up.
|
||
const (
|
||
maxObserverIDLen = 128 // ids are 64-hex pubkeys in practice
|
||
maxObserverTextLen = 128 // name, model, firmware, client version, radio
|
||
maxObserverIATALen = 16 // region codes are 3–8 chars
|
||
)
|
||
|
||
// clampObserverField strips control characters and truncates to max runes.
|
||
func clampObserverField(s string, max int) string {
|
||
s = sanitizeName(s)
|
||
if utf8.RuneCountInString(s) <= max {
|
||
return s
|
||
}
|
||
r := []rune(s)
|
||
return string(r[:max])
|
||
}
|