Merge pull request #2515 from vitorpamplona/claude/fix-marmot-reactions-gtBUg

Fix MIP-03 inner event verification in group messages
This commit is contained in:
Vitor Pamplona
2026-04-22 21:06:04 -04:00
committed by GitHub
2 changed files with 15 additions and 2 deletions
@@ -3075,7 +3075,12 @@ class Account(
val innerEvent =
com.vitorpamplona.quartz.nip01Core.core.Event
.fromJson(json)
val isNew = cache.justConsume(innerEvent, null, false)
// wasVerified=true: these events were already verified
// via MLS credential identity when first decrypted (see
// GroupEventHandler). Persisted inner events are
// unsigned per MIP-03, so justVerify would fail and
// reactions/deletions would silently drop here.
val isNew = cache.justConsume(innerEvent, null, true)
val innerNote = cache.getOrCreateNote(innerEvent.id)
if (isNew) {
innerNote.event = innerEvent
@@ -592,7 +592,15 @@ class GroupEventHandler(
"GroupEventHandler.add: ApplicationMessage decrypted innerKind=${innerEvent.kind} " +
"innerId=${innerEvent.id.take(8)}… author=${innerEvent.pubKey.take(8)}"
}
if (cache.justConsume(innerEvent, null, false)) {
// wasVerified=true: MIP-03 inner events are unsigned (sig is empty
// or placeholder), so justVerify() would fail. Authenticity is
// already guaranteed by the MLS layer — MarmotInboundProcessor
// enforces innerEvent.pubKey == MLS sender credential identity
// before returning ApplicationMessage. Without this, side-channel
// inner events from other Marmot clients (kind:7 reactions,
// kind:5 deletions) are silently dropped by LocalCache, so a
// WhiteNoise reaction never attaches to its target chat bubble.
if (cache.justConsume(innerEvent, null, true)) {
val innerNote = cache.getOrCreateNote(innerEvent.id)
innerNote.event = innerEvent