Merge pull request #7443 from hayaksi1/fix/4519-hide-verification-fallback

Do not render in-chat key verification requests in the timeline
This commit is contained in:
Benoit Marty
2026-08-21 16:52:58 +02:00
committed by GitHub
3 changed files with 67 additions and 2 deletions
@@ -21,6 +21,9 @@ import io.element.android.libraries.androidutils.diff.MutableListDiffCache
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.Flow
@@ -110,7 +113,11 @@ class TimelineItemsFactory(
): TimelineItem? {
val timelineItem =
when (val currentTimelineItem = timelineItems[index]) {
is MatrixTimelineItem.Event -> eventItemFactory.create(currentTimelineItem, index, timelineItems, roomMembers, renderReadReceipts)
is MatrixTimelineItem.Event -> if (currentTimelineItem.event.isKeyVerificationRequest()) {
null
} else {
eventItemFactory.create(currentTimelineItem, index, timelineItems, roomMembers, renderReadReceipts)
}
is MatrixTimelineItem.Virtual -> virtualItemFactory.create(currentTimelineItem)
MatrixTimelineItem.Other -> null
}
@@ -118,3 +125,8 @@ class TimelineItemsFactory(
return timelineItem
}
}
private fun EventTimelineItem.isKeyVerificationRequest(): Boolean {
val messageType = (content as? MessageContent)?.type
return messageType is OtherMessageType && messageType.isKeyVerificationRequest
}
@@ -12,8 +12,10 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactory
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.timeline.aMessageContent
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
@@ -82,6 +84,50 @@ class TimelineItemsFactoryTest {
).inOrder()
}
@Test
fun `a key verification request is not rendered`() = runTest {
val factory = aTimelineItemsFactory(
config = TimelineItemsFactoryConfig(
computeReadReceipts = false,
computeReactions = false,
)
)
val items = listOf(
MatrixTimelineItem.Event(
uniqueId = UniqueId("event-0"),
event = anEventTimelineItem(
sender = A_USER_ID,
content = aMessageContent(
body = "Alice is requesting to verify your key, but your client does not support in-chat key verification.",
messageType = OtherMessageType(
msgType = "m.key.verification.request",
body = "Alice is requesting to verify your key, but your client does not support in-chat key verification.",
),
),
),
),
MatrixTimelineItem.Event(
uniqueId = UniqueId("event-1"),
event = anEventTimelineItem(
sender = A_USER_ID,
content = aMessageContent(body = "A regular message"),
),
),
)
factory.timelineItems.test {
factory.replaceWith(
timelineItems = items,
roomMembers = emptyList(),
renderReadReceipts = false,
)
val bodies = awaitItem()
.filterIsInstance<TimelineItem.Event>()
.map { (it.content as TimelineItemTextContent).body }
assertThat(bodies).containsExactly("A regular message")
cancelAndIgnoreRemainingEvents()
}
}
private suspend fun TestScope.groupPositionsOf(timestamps: List<Long>): List<TimelineItemGroupPosition> {
val factory = aTimelineItemsFactory(
config = TimelineItemsFactoryConfig(
@@ -128,4 +128,11 @@ sealed interface GalleryItemType {
data class OtherMessageType(
val msgType: String,
val body: String,
) : MessageType
) : MessageType {
/**
* A `m.key.verification.request` carries a body meant for clients that cannot handle in-chat
* verification, so it must not be rendered as a message.
*/
val isKeyVerificationRequest: Boolean
get() = msgType == "m.key.verification.request"
}