Skip to content

Commit

Permalink
matrix-sdk: Ensure correct room for events loaded by chunks
Browse files Browse the repository at this point in the history
Chunks should not load events from other rooms if they happen to be
requested for one eventId that already exists in a different room.

Motivation from a client that renders rich replies (although the
broken scenario can appear in other cases as well):

If somebody links an invalid eventId in a room, which however is valid
in a different room, this can mess up our timelines badly.
This can be reproduced by replying to an event in a room, then forward
the reply to a different room with a client that also forwards the
replied-to information (such as FluffyChat). Then click on the rich
reply to open the eventId. Previously, Android could find the event from
the other room and thus replace the correct timeline with the wrong one.

Compare e.g. https://matrix.to/#/!bfebJVBOZMnORmkVdO:matrix.org/$wUyRiMQEjaWOpJ-XpdBJzuXkh95N7bce2pVT4IMXW50?via=schildi.chat&via=matrix.org&via=envs.net
linking to an event that exists here
https://matrix.to/#/!SDwMepdfgrmExhyxYZ:schildi.chat/$MO2G4MZZ1zg0Ymc9gTfekIyw7QFkNn4OvYQKK1PAGlE

Change-Id: I4dcee94353d954fb6ed57c3970686a620b831c6f
  • Loading branch information
SpiritCroc committed Feb 23, 2023
1 parent 85734c0 commit 8192bb5
Show file tree
Hide file tree
Showing 6 changed files with 11 additions and 9 deletions.
1 change: 1 addition & 0 deletions changelog.d/8168.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix timeline loading a wrong room on permalink if a matching event id is found in a different room
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ internal fun updateThreadNotifications(roomId: String, realm: Realm, currentUser
val readReceipt = findMyReadReceipt(realm, roomId, currentUserId, threadId = rootThreadEventId) ?: return

val readReceiptChunk = ChunkEntity
.findIncludingEvent(realm, readReceipt) ?: return
.findIncludingEvent(realm, roomId, readReceipt) ?: return

val readReceiptChunkThreadEvents = readReceiptChunk
.timelineEvents
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,16 @@ internal fun ChunkEntity.Companion.findEventInThreadChunk(realm: Realm, roomId:
.findFirst()
}

internal fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, eventIds: List<String>): RealmResults<ChunkEntity> {
internal fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, roomId: String, eventIds: List<String>): RealmResults<ChunkEntity> {
return realm.where<ChunkEntity>()
.equalTo(ChunkEntityFields.ROOM.ROOM_ID, roomId)
.`in`(ChunkEntityFields.TIMELINE_EVENTS.EVENT_ID, eventIds.toTypedArray())
.isNull(ChunkEntityFields.ROOT_THREAD_EVENT_ID)
.findAll()
}

internal fun ChunkEntity.Companion.findIncludingEvent(realm: Realm, eventId: String): ChunkEntity? {
return findAllIncludingEvents(realm, listOf(eventId)).firstOrNull()
internal fun ChunkEntity.Companion.findIncludingEvent(realm: Realm, roomId: String, eventId: String): ChunkEntity? {
return findAllIncludingEvents(realm, roomId, listOf(eventId)).firstOrNull()
}

internal fun ChunkEntity.Companion.create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ private fun hasReadMissingEvent(realm: Realm,
userId: String,
eventId: String,
threadId: String? = ReadService.THREAD_ID_MAIN): Boolean {
return realm.doesEventExistInChunkHistory(eventId) && realm.hasReadReceiptInLatestChunk(latestChunkEntity, roomId, userId, threadId)
return realm.doesEventExistInChunkHistory(roomId, eventId) && realm.hasReadReceiptInLatestChunk(latestChunkEntity, roomId, userId, threadId)
}

private fun Realm.doesEventExistInChunkHistory(eventId: String): Boolean {
return ChunkEntity.findIncludingEvent(this, eventId) != null
private fun Realm.doesEventExistInChunkHistory(roomId: String, eventId: String): Boolean {
return ChunkEntity.findIncludingEvent(this, roomId, eventId) != null
}

private fun Realm.hasReadReceiptInLatestChunk(latestChunkEntity: ChunkEntity, roomId: String, userId: String, threadId: String?): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ internal class DefaultFetchTokenAndPaginateTask @Inject constructor(
?: throw IllegalStateException("No token found")

monarchy.awaitTransaction { realm ->
val chunkToUpdate = ChunkEntity.findIncludingEvent(realm, params.lastKnownEventId)
val chunkToUpdate = ChunkEntity.findIncludingEvent(realm, params.roomId, params.lastKnownEventId)
if (params.direction == PaginationDirection.FORWARDS) {
chunkToUpdate?.nextToken = fromToken
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ internal class LoadTimelineStrategy constructor(
.findAll()
}
is Mode.Permalink -> {
ChunkEntity.findAllIncludingEvents(realm, listOf(mode.originEventId))
ChunkEntity.findAllIncludingEvents(realm, roomId, listOf(mode.originEventId))
}
is Mode.Thread -> {
recreateThreadChunkEntity(realm, mode.rootThreadEventId)
Expand Down

0 comments on commit 8192bb5

Please sign in to comment.