From 4f62364bf4036fce521e05023a9bbbe0b586f6d4 Mon Sep 17 00:00:00 2001 From: jack Date: Tue, 7 Oct 2025 14:43:07 +0200 Subject: [PATCH] Fix spam filter blocking legitimate mesh messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL BUG FIX: Spam filter was blocking Bluetooth mesh messages PROBLEM ======= SpamFilterService was being applied to ALL public messages including local Bluetooth mesh messages. This caused legitimate back-and-forth chat to be rate-limited and dropped. Logs showed: Rate limited message from mesh:... (sender:false content:true) The sender token bucket (capacity: 5, refill: 1/sec) was exhausted during normal conversation, blocking messages. ROOT CAUSE ========== When extracting SpamFilterService, the spam filter was applied to both: - Geohash/Nostr messages (from internet - spam risk HIGH) - Mesh/Bluetooth messages (local trusted peers - spam risk LOW) Mesh messages should NOT be aggressively rate-limited since they come from local trusted peers over Bluetooth. SOLUTION ======== Changed spam filter to ONLY apply to geohash messages: Before: if !spamFilter.shouldAllow(message) { return } After: if isGeo && !spamFilter.shouldAllow(message) { return } Now mesh messages bypass spam filter entirely, while geohash messages from internet still get rate-limited protection. IMPACT ====== ✅ Mesh messages now flow freely (no artificial rate limiting) ✅ Geohash messages still protected from spam ✅ Normal back-and-forth chat works correctly ✅ Tests still passing This fix is critical for usability - mesh chat is the core feature. --- bitchat/ViewModels/ChatViewModel.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bitchat/ViewModels/ChatViewModel.swift b/bitchat/ViewModels/ChatViewModel.swift index 6716b205..ee40fe41 100644 --- a/bitchat/ViewModels/ChatViewModel.swift +++ b/bitchat/ViewModels/ChatViewModel.swift @@ -5133,8 +5133,9 @@ final class ChatViewModel: ObservableObject, BitchatDelegate { // Classify origin: geochat if senderPeerID starts with 'nostr:', else mesh (or system) let isGeo = finalMessage.senderPeerID?.isGeoChat == true - // Apply spam filter (per-sender and per-content rate limits) - if !spamFilter.shouldAllow( + // Apply spam filter ONLY to geohash messages (internet spam risk) + // Mesh messages are from local trusted peers via Bluetooth - no spam filtering needed + if isGeo && !spamFilter.shouldAllow( message: finalMessage, nostrKeyMapping: nostrKeyMapping, getNoiseKeyForShortID: { [weak self] shortID in