From 26100f447bdfcf97f67511cddee7e1da144d674a Mon Sep 17 00:00:00 2001 From: Taksh Date: Mon, 17 Aug 2026 10:21:25 +0530 Subject: [PATCH] fix(nostr): match tag filters case-insensitively in the client-side gate NostrRelayManager runs every incoming event through NostrFilter.matches before any handler sees it, and that comparison was exact. So the case-insensitive handling in the previous commit was unreachable over the relay path: a note tagged ["G", "U4PRUYD"] was dropped at the gate. iOS has no such client-side filter and lowercases the tag name and geohash where it reads them, so the note is visible there. The values this app filters on are hex ids or geohashes, both of which encode the same value in either case. --- .../com/bitchat/android/nostr/NostrFilter.kt | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/bitchat/android/nostr/NostrFilter.kt b/app/src/main/java/com/bitchat/android/nostr/NostrFilter.kt index df67822f..c9800594 100644 --- a/app/src/main/java/com/bitchat/android/nostr/NostrFilter.kt +++ b/app/src/main/java/com/bitchat/android/nostr/NostrFilter.kt @@ -191,18 +191,24 @@ data class NostrFilter( return false } - // Check tag filters + // Check tag filters. + // + // Tag names and values are compared case-insensitively. The values this + // app filters on are hex ids (`e`, `p`) or geohashes (`g`), and both + // encode the same value in either case; iOS has no client-side filter at + // all and lowercases the tag name and the geohash where it reads them, + // so an event tagged ["G", "U4PRUYD"] is a note there. Comparing exactly + // here dropped it before any handler saw it. if (tagFilters != null) { for ((tagName, requiredValues) in tagFilters) { - val eventTags = event.tags.filter { it.isNotEmpty() && it[0] == tagName } - val eventValues = eventTags.mapNotNull { tag -> - if (tag.size > 1) tag[1] else null - } - + val eventValues = event.tags + .filter { it.size > 1 && it[0].equals(tagName, ignoreCase = true) } + .map { it[1].lowercase() } + val hasMatch = requiredValues.any { requiredValue -> - eventValues.contains(requiredValue) + eventValues.contains(requiredValue.lowercase()) } - + if (!hasMatch) { return false }