mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-10-23 09:32:26 +00:00
fix: anomaly detection matched a bare "MM:" prefix, but text is sender-prefixed
decodeGrpTxt (cmd/ingestor/decoder.go) builds decoded_json.text as "<sender>: <message>", so a wardriving message's real text is "<sender>: MM:<base64>", not a bare "MM:<base64>" at the start of the string. detectWardrivingAnomalies's HasPrefix(text, "MM:") check never matched anything live, silently returning standardPayloadCount=0 and no anomalies — caught after deploying idea 6 to stg and seeing 0/0 against traffic that should have had ~160 standard-format messages. Fixed to match the exact "<sender>: MM:" prefix. The Go test fixtures shared the same wrong assumption and are fixed too. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3453caee53
commit
d9d3883a53
2 files changed
+20
-7
No files matched your search
+15
-6
@@ -3537,10 +3537,12 @@ func (db *DB) buildWardrivingSessions(channel, since string) ([]WardrivingSessio
|
||||
const wardrivingStandardPayloadBytes = 7
|
||||
|
||||
// detectWardrivingAnomalies scans every #wardriving message's "MM:<base64>"
|
||||
// payload (messages without that prefix — e.g. manual human chat on the
|
||||
// channel — are ignored entirely, not counted either way) and buckets them
|
||||
// into the standard-length count vs per-sender anomalies for any
|
||||
// non-standard length or undecodable payload.
|
||||
// payload — stored as "<sender>: MM:<base64>" in decoded_json.text, per
|
||||
// decodeGrpTxt's "<sender>: <message>" convention — and buckets them into
|
||||
// the standard-length count vs per-sender anomalies for any non-standard
|
||||
// length or undecodable payload. Messages that don't match that exact
|
||||
// "<sender>: MM:" prefix (e.g. manual human chat on the channel) are
|
||||
// ignored entirely, not counted either way.
|
||||
func (db *DB) detectWardrivingAnomalies(channel, since string) (int, []WardrivingAnomaly, error) {
|
||||
rows, err := db.conn.Query(`
|
||||
SELECT json_extract(decoded_json, '$.sender'), json_extract(decoded_json, '$.text'), first_seen
|
||||
@@ -3567,10 +3569,17 @@ func (db *DB) detectWardrivingAnomalies(channel, since string) (int, []Wardrivin
|
||||
if err := rows.Scan(&sender, &text, &ts); err != nil {
|
||||
continue
|
||||
}
|
||||
if !text.Valid || !strings.HasPrefix(text.String, "MM:") {
|
||||
if !sender.Valid || !text.Valid {
|
||||
continue
|
||||
}
|
||||
payload := strings.TrimPrefix(text.String, "MM:")
|
||||
// decodeGrpTxt (cmd/ingestor/decoder.go) builds Text as
|
||||
// "<sender>: <message>", so the wardriving payload prefix is
|
||||
// "<sender>: MM:" — not a bare "MM:" at the start of text.
|
||||
prefix := sender.String + ": MM:"
|
||||
if !strings.HasPrefix(text.String, prefix) {
|
||||
continue
|
||||
}
|
||||
payload := strings.TrimPrefix(text.String, prefix)
|
||||
decoded, decErr := base64.RawURLEncoding.DecodeString(payload)
|
||||
if decErr == nil && len(decoded) == wardrivingStandardPayloadBytes {
|
||||
standardCount++
|
||||
|
||||
@@ -296,8 +296,12 @@ func TestHandleWardrivingStats_Anomalies(t *testing.T) {
|
||||
t.Fatalf("clear transmissions: %v", err)
|
||||
}
|
||||
|
||||
insertTx := func(hash, sender, text string, tsOffset time.Duration) {
|
||||
// insertTx mirrors decodeGrpTxt's "<sender>: <message>" convention —
|
||||
// text is NOT a bare "MM:<base64>", it's sender-prefixed, and
|
||||
// detectWardrivingAnomalies matches on that exact "<sender>: MM:" prefix.
|
||||
insertTx := func(hash, sender, mmPayload string, tsOffset time.Duration) {
|
||||
ts := time.Now().UTC().Add(tsOffset).Format(time.RFC3339)
|
||||
text := sender + ": " + mmPayload
|
||||
if _, err := srv.db.conn.Exec(
|
||||
`INSERT INTO transmissions (raw_hex,hash,first_seen,route_type,payload_type,channel_hash,decoded_json) VALUES (?,?,?,1,5,'#wardriving',?)`,
|
||||
"aa", hash, ts, `{"sender":"`+sender+`","text":"`+text+`"}`,
|
||||
|
||||
Reference in new issue
Block a user