mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-12 01:07:46 +00:00
fix: don't treat a group reaction as the group's latest message
filterRelevantRelayGroupMessages picked ANY group-scoped note (isGroupScoped() = carries the group's `h` tag), so a reaction (kind 7) to my message became the group's "last message" on the Messages tab — a wrong row that the chat renderer can't display. Whitelist actual chat content (kind 9 chat / 1068 poll / 11 thread / 1111 comment) and reject reactions, deletions, labels, etc. Apply the same guard to the feed()'s channel-notes scan as defense in depth. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5MLY4hq5LXJ2D5WeLRyXj
This commit is contained in:
+18
-4
@@ -33,12 +33,16 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey
|
||||
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable
|
||||
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
|
||||
import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent
|
||||
import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelMetadataEvent
|
||||
import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent
|
||||
import com.vitorpamplona.quartz.nip29RelayGroups.GroupId
|
||||
import com.vitorpamplona.quartz.nip29RelayGroups.groupId
|
||||
import com.vitorpamplona.quartz.nip29RelayGroups.isGroupScoped
|
||||
import com.vitorpamplona.quartz.nip7DThreads.ThreadEvent
|
||||
import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent
|
||||
import com.vitorpamplona.quartz.nipC7Chats.ChatEvent
|
||||
|
||||
class ChatroomListKnownFeedFilter(
|
||||
val account: Account,
|
||||
@@ -103,10 +107,11 @@ class ChatroomListKnownFeedFilter(
|
||||
account.relayGroupList.liveRelayGroupList.value.mapNotNull { groupTag ->
|
||||
val relay = RelayUrlNormalizer.normalizeOrNull(groupTag.relayUrl) ?: return@mapNotNull null
|
||||
val channel = LocalCache.getOrCreateRelayGroupChannel(GroupId(groupTag.groupId, relay))
|
||||
// Newest loaded message, or a placeholder row so a just-joined group shows up on
|
||||
// Messages before its first kind-9 arrives (mirrors the Marmot-group path above).
|
||||
// Newest loaded chat message, or a placeholder row so a just-joined group shows
|
||||
// up on Messages before its first kind-9 arrives (mirrors the Marmot-group path
|
||||
// above). Content kinds only — never a reaction/deletion as the "last message".
|
||||
channel.notes
|
||||
.filter { _, it -> account.isAcceptable(it) && it.event != null }
|
||||
.filter { _, it -> account.isAcceptable(it) && it.event != null && it.isRelayGroupChatContent() }
|
||||
.sortedByDefaultFeedOrder()
|
||||
.firstOrNull()
|
||||
?: channel.placeholderNote()
|
||||
@@ -284,6 +289,15 @@ class ChatroomListKnownFeedFilter(
|
||||
return newRelevantEphemeralChats
|
||||
}
|
||||
|
||||
// Only actual group content represents a room in the Messages list. A reaction (kind 7),
|
||||
// deletion, label, etc. carries the group's `h` tag too, so isGroupScoped() alone would let a
|
||||
// reaction to my message become the group's "last message" — a wrong, unrenderable row.
|
||||
private fun Note.isRelayGroupChatContent(): Boolean =
|
||||
when (event) {
|
||||
is ChatEvent, is PollEvent, is ThreadEvent, is CommentEvent -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
/** Latest message per joined NIP-29 group (inline view mode), keyed by group id. */
|
||||
private fun filterRelevantRelayGroupMessages(
|
||||
newItems: Set<Note>,
|
||||
@@ -295,7 +309,7 @@ class ChatroomListKnownFeedFilter(
|
||||
.mapTo(HashSet()) { it.groupId }
|
||||
val result = mutableMapOf<String, Note>()
|
||||
newItems.forEach { newNote ->
|
||||
val gid = newNote.event?.takeIf { it.isGroupScoped() }?.groupId()
|
||||
val gid = newNote.event?.takeIf { it.isGroupScoped() && newNote.isRelayGroupChatContent() }?.groupId()
|
||||
if (gid != null && gid in joinedGroupIds && account.isAcceptable(newNote)) {
|
||||
val lastNote = result[gid]
|
||||
if (lastNote == null || (newNote.createdAt() ?: 0L) > (lastNote.createdAt() ?: 0L)) {
|
||||
|
||||
Reference in New Issue
Block a user