diff --git a/cmd/server/db.go b/cmd/server/db.go index d6f6741c..875eea2f 100644 --- a/cmd/server/db.go +++ b/cmd/server/db.go @@ -3537,10 +3537,12 @@ func (db *DB) buildWardrivingSessions(channel, since string) ([]WardrivingSessio const wardrivingStandardPayloadBytes = 7 // detectWardrivingAnomalies scans every #wardriving message's "MM:" -// 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 ": MM:" in decoded_json.text, per +// decodeGrpTxt's ": " 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 +// ": 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 + // ": ", so the wardriving payload prefix is + // ": 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++ diff --git a/cmd/server/wardriving_stats_test.go b/cmd/server/wardriving_stats_test.go index 810d6a87..8908eadb 100644 --- a/cmd/server/wardriving_stats_test.go +++ b/cmd/server/wardriving_stats_test.go @@ -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 ": " convention — + // text is NOT a bare "MM:", it's sender-prefixed, and + // detectWardrivingAnomalies matches on that exact ": 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+`"}`,