Fix geohash filtering (#376)

* fix(geohash): enforce client-side filter on subscription and validate 'g' tag in handler; move dedup after validation; avoid misrouting events across geohashes

* cleanup duplicate code block

* remove
This commit is contained in:
callebtc
2025-09-05 13:26:38 +02:00
committed by GitHub
parent 905ccf5f17
commit 91f3f270d4
2 changed files with 22 additions and 1 deletions
@@ -1167,7 +1167,7 @@ class NostrGeohashService(
private fun handleUnifiedGeohashEvent(event: NostrEvent, geohash: String) {
coroutineScope.launch(Dispatchers.Default) {
try {
Log.v(TAG, "🔍 handleUnifiedGeohashEvent called - eventGeohash: $geohash, currentGeohash: $currentGeohash, eventKind: ${event.kind}, eventId: ${event.id.take(8)}...")
Log.v(TAG, "🔍 handleUnifiedGeohashEvent called - subGeohash: $geohash, currentGeohash: $currentGeohash, kind: ${event.kind}, id: ${event.id.take(8)}...")
// Only handle ephemeral kind 20000 events
if (event.kind != 20000) {
@@ -1175,6 +1175,17 @@ class NostrGeohashService(
return@launch
}
// VALIDATE EVENT G TAG AGAINST SUBSCRIPTION GEOHASH
val eventGeohash = event.tags.firstOrNull { it.size >= 2 && it[0] == "g" }?.getOrNull(1)
if (eventGeohash == null) {
Log.w(TAG, "🚫 Dropping kind=20000 without 'g' tag id=${event.id.take(8)}")
return@launch
}
if (!eventGeohash.equals(geohash, ignoreCase = true)) {
Log.w(TAG, "🚫 Dropping mismatched geohash event: sub=$geohash eventTag=$eventGeohash id=${event.id.take(8)}")
return@launch
}
// Check Proof of Work validation BEFORE other processing
val powSettings = PoWPreferenceManager.getCurrentSettings()
if (powSettings.enabled && powSettings.difficulty > 0) {
@@ -666,6 +666,16 @@ class NostrRelayManager private constructor() {
relay?.messagesReceived = (relay?.messagesReceived ?: 0) + 1
updateRelaysList()
// CLIENT-SIDE FILTER ENFORCEMENT: Ensure this event matches the subscription's filter
activeSubscriptions[response.subscriptionId]?.let { subInfo ->
val matches = try { subInfo.filter.matches(response.event) } catch (e: Exception) { true }
if (!matches) {
Log.v(TAG, "🚫 Dropping event ${response.event.id.take(16)}... not matching filter for sub=${response.subscriptionId}")
// Do NOT call deduplicator here to allow the correct subscription to process it later
return
}
}
// DEDUPLICATION: Check if we've already processed this event
val wasProcessed = eventDeduplicator.processEvent(response.event) { event ->
// Only log non-gift-wrap events to reduce noise