From 46293533144f9356a356750b07cce7a9c36df9a8 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 26 Jan 2022 15:10:12 +0000 Subject: [PATCH 1/5] removing noop newSession from base decryption interface, it's only relevant for Megolm sessions --- .../internal/crypto/actions/MegolmSessionDataImporter.kt | 8 +++++++- .../sdk/internal/crypto/algorithms/IMXDecrypting.kt | 8 -------- .../crypto/algorithms/megolm/MXMegolmDecryption.kt | 6 +++--- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt index 0d78f68e5c..33c56ba422 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt @@ -22,6 +22,8 @@ import org.matrix.android.sdk.internal.crypto.MXOlmDevice import org.matrix.android.sdk.internal.crypto.MegolmSessionData import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager import org.matrix.android.sdk.internal.crypto.RoomDecryptorProvider +import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXMegolmDecryption +import org.matrix.android.sdk.internal.crypto.algorithms.olm.MXOlmDecryption import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore @@ -76,7 +78,11 @@ internal class MegolmSessionDataImporter @Inject constructor(private val olmDevi outgoingGossipingRequestManager.cancelRoomKeyRequest(roomKeyRequestBody) // Have another go at decrypting events sent with this session - decrypting.onNewSession(megolmSessionData.senderKey!!, sessionId!!) + when (decrypting) { + is MXMegolmDecryption -> { + decrypting.onNewSession(megolmSessionData.roomId, megolmSessionData.senderKey!!, sessionId!!) + } + } } catch (e: Exception) { Timber.e(e, "## importRoomKeys() : onNewSession failed") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt index b6c1d99aa5..51ddd74442 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt @@ -45,14 +45,6 @@ internal interface IMXDecrypting { */ fun onRoomKeyEvent(event: Event, defaultKeysBackupService: DefaultKeysBackupService) {} - /** - * Check if the some messages can be decrypted with a new session - * - * @param senderKey the session sender key - * @param sessionId the session id - */ - fun onNewSession(senderKey: String, sessionId: String) {} - /** * Determine if we have the keys necessary to respond to a room key request * diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt index e94daa0e76..fff0ba3477 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt @@ -318,7 +318,7 @@ internal class MXMegolmDecryption(private val userId: String, outgoingGossipingRequestManager.cancelRoomKeyRequest(content) - onNewSession(senderKey, roomKeyContent.sessionId) + onNewSession(roomKeyContent.roomId, senderKey, roomKeyContent.sessionId) } } @@ -328,9 +328,9 @@ internal class MXMegolmDecryption(private val userId: String, * @param senderKey the session sender key * @param sessionId the session id */ - override fun onNewSession(senderKey: String, sessionId: String) { + fun onNewSession(roomId: String?, senderKey: String, sessionId: String) { Timber.tag(loggerTag.value).v("ON NEW SESSION $sessionId - $senderKey") - newSessionListener?.onNewSession(null, senderKey, sessionId) + newSessionListener?.onNewSession(roomId, senderKey, sessionId) } override fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean { From ced621d46963a11ed1a702974af1907c52f0c6ea Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 27 Jan 2022 11:30:53 +0000 Subject: [PATCH 2/5] refreshing the room summaries when new crypto sessions are recieved - matches the same flow as the timeline by starting observing in the ViewModel init --- .../sdk/api/session/crypto/CryptoService.kt | 1 - .../sdk/api/session/room/RoomService.kt | 8 ++++ .../crypto/crosssigning/UpdateTrustWorker.kt | 2 +- .../query/RoomSummaryEntityQueries.kt | 4 ++ .../session/room/DefaultRoomService.kt | 21 ++++++++++ .../room/summary/RoomSummaryUpdater.kt | 42 ++++++++++++------- .../app/features/home/HomeDetailViewModel.kt | 9 ++++ 7 files changed, 70 insertions(+), 17 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index 65f69e17c9..a5b442dc4a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -140,7 +140,6 @@ interface CryptoService { fun getLiveCryptoDeviceInfo(userIds: List): LiveData> fun addNewSessionListener(newSessionListener: NewSessionListener) - fun removeSessionListener(listener: NewSessionListener) fun getOutgoingRoomKeyRequests(): List diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt index aec358218b..c1c1a385b5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt @@ -242,4 +242,12 @@ interface RoomService { */ fun getFlattenRoomSummaryChildrenOfLive(spaceId: String?, memberships: List = Membership.activeMemberships()): LiveData> + + /** + * Refreshes the RoomSummary LatestPreviewContent for the given @param roomId + * If the roomId is null, all rooms are updated + * + * This is useful for refreshing summary content with encrypted messages after receiving new room keys + */ + fun refreshJoinedRoomSummaryPreviews(roomId: String?) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt index 9325355d28..794ab04533 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt @@ -52,7 +52,7 @@ import timber.log.Timber import javax.inject.Inject internal class UpdateTrustWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) : - SessionSafeCoroutineWorker(context, params, sessionManager, Params::class.java) { + SessionSafeCoroutineWorker(context, params, sessionManager, Params::class.java) { @JsonClass(generateAdapter = true) internal data class Params( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt index d1b05a4932..8993c36a30 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt @@ -49,6 +49,10 @@ internal fun RoomSummaryEntity.Companion.getOrCreate(realm: Realm, roomId: Strin return where(realm, roomId).findFirst() ?: realm.createObject(roomId) } +internal fun RoomSummaryEntity.Companion.getOrNull(realm: Realm, roomId: String): RoomSummaryEntity? { + return where(realm, roomId).findFirst() +} + internal fun RoomSummaryEntity.Companion.getDirectRooms(realm: Realm, excludeRoomIds: Set? = null): RealmResults { return RoomSummaryEntity.where(realm) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt index 1bc98015aa..c79c41069b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt @@ -20,6 +20,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import androidx.paging.PagedList import com.zhuinden.monarchy.Monarchy +import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.RoomService @@ -32,6 +33,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.peeking.PeekResult +import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional @@ -51,6 +53,7 @@ import org.matrix.android.sdk.internal.session.room.peeking.PeekRoomTask import org.matrix.android.sdk.internal.session.room.peeking.ResolveRoomStateTask import org.matrix.android.sdk.internal.session.room.read.MarkAllRoomsReadTask import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource +import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater import org.matrix.android.sdk.internal.session.user.accountdata.UpdateBreadcrumbsTask import org.matrix.android.sdk.internal.util.fetchCopied import javax.inject.Inject @@ -69,6 +72,7 @@ internal class DefaultRoomService @Inject constructor( private val roomSummaryDataSource: RoomSummaryDataSource, private val roomChangeMembershipStateDataSource: RoomChangeMembershipStateDataSource, private val leaveRoomTask: LeaveRoomTask, + private val roomSummaryUpdater: RoomSummaryUpdater ) : RoomService { override suspend fun createRoom(createRoomParams: CreateRoomParams): String { @@ -92,6 +96,23 @@ internal class DefaultRoomService @Inject constructor( return roomSummaryDataSource.getRoomSummaries(queryParams, sortOrder) } + override fun refreshJoinedRoomSummaryPreviews(roomId: String?) { + val roomSummaries = getRoomSummaries(roomSummaryQueryParams { + if (roomId != null) { + this.roomId = QueryStringValue.Equals(roomId) + } + memberships = listOf(Membership.JOIN) + }) + + if (roomSummaries.isNotEmpty()) { + monarchy.runTransactionSync { realm -> + roomSummaries.forEach { + roomSummaryUpdater.refreshLatestPreviewContent(realm, it.roomId) + } + } + } + } + override fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams, sortOrder: RoomSortOrder): LiveData> { return roomSummaryDataSource.getRoomSummariesLive(queryParams, sortOrder) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt index c9712c5721..c9d84b1b93 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt @@ -64,7 +64,6 @@ import org.matrix.android.sdk.internal.session.room.accountdata.RoomAccountDataD import org.matrix.android.sdk.internal.session.room.membership.RoomDisplayNameResolver import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper import org.matrix.android.sdk.internal.session.room.relationship.RoomChildRelationInfo -import org.matrix.android.sdk.internal.util.Normalizer import timber.log.Timber import javax.inject.Inject import kotlin.system.measureTimeMillis @@ -75,8 +74,16 @@ internal class RoomSummaryUpdater @Inject constructor( private val roomAvatarResolver: RoomAvatarResolver, private val eventDecryptor: EventDecryptor, private val crossSigningService: DefaultCrossSigningService, - private val roomAccountDataDataSource: RoomAccountDataDataSource, - private val normalizer: Normalizer) { + private val roomAccountDataDataSource: RoomAccountDataDataSource +) { + + fun refreshLatestPreviewContent(realm: Realm, roomId: String) { + val roomSummaryEntity = RoomSummaryEntity.getOrNull(realm, roomId) + if (roomSummaryEntity != null) { + val latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) + latestPreviewableEvent?.attemptToDecrypt() + } + } fun update(realm: Realm, roomId: String, @@ -128,6 +135,7 @@ internal class RoomSummaryUpdater @Inject constructor( val lastActivityFromEvent = latestPreviewableEvent?.root?.originServerTs if (lastActivityFromEvent != null) { roomSummaryEntity.lastActivityTime = lastActivityFromEvent + latestPreviewableEvent.attemptToDecrypt() } roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0 || @@ -161,18 +169,6 @@ internal class RoomSummaryUpdater @Inject constructor( } roomSummaryEntity.updateHasFailedSending() - val root = latestPreviewableEvent?.root - if (root?.type == EventType.ENCRYPTED && root.decryptionResultJson == null) { - Timber.v("Should decrypt ${latestPreviewableEvent.eventId}") - // mmm i want to decrypt now or is it ok to do it async? - tryOrNull { - runBlocking { - eventDecryptor.decryptEvent(root.asDomain(), "") - } - } - ?.let { root.setDecryptionResult(it) } - } - if (updateMembers) { val otherRoomMembers = RoomMemberHelper(realm, roomId) .queryActiveRoomMembersEvent() @@ -189,6 +185,22 @@ internal class RoomSummaryUpdater @Inject constructor( } } + private fun TimelineEventEntity.attemptToDecrypt() { + when (val root = this.root) { + null -> { + Timber.v("Decryption skipped due to missing root event $eventId") + } + else -> { + if (root.type == EventType.ENCRYPTED && root.decryptionResultJson == null) { + Timber.v("Should decrypt $eventId") + tryOrNull { + runBlocking { eventDecryptor.decryptEvent(root.asDomain(), "") } + }?.let { root.setDecryptionResult(it) } + } + } + } + } + private fun RoomSummaryEntity.updateHasFailedSending() { hasFailedSending = TimelineEventEntity.findAllInRoomWithSendStates(realm, roomId, SendState.HAS_FAILED_STATES).isNotEmpty() } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt index 01d91f3edc..e70e7b8acb 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt @@ -54,6 +54,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.internal.crypto.NewSessionListener import timber.log.Timber /** @@ -88,9 +89,16 @@ class HomeDetailViewModel @AssistedInject constructor( } } + private val refreshRoomSummariesOnCryptoSessionChange = object : NewSessionListener { + override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) { + session.refreshJoinedRoomSummaryPreviews(roomId) + } + } + init { observeSyncState() observeRoomGroupingMethod() + session.cryptoService().addNewSessionListener(refreshRoomSummariesOnCryptoSessionChange) observeRoomSummaries() updatePstnSupportFlag() observeDataStore() @@ -150,6 +158,7 @@ class HomeDetailViewModel @AssistedInject constructor( override fun onCleared() { super.onCleared() callManager.removeProtocolsCheckerListener(this) + session.cryptoService().removeSessionListener(refreshRoomSummariesOnCryptoSessionChange) } override fun onPSTNSupportUpdated() { From 1d0a87be140f0446ec663a50a3c1ebfb9253226d Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 27 Jan 2022 11:48:56 +0000 Subject: [PATCH 3/5] adding changelog entry --- changelog.d/4867.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/4867.bugfix diff --git a/changelog.d/4867.bugfix b/changelog.d/4867.bugfix new file mode 100644 index 0000000000..272811694c --- /dev/null +++ b/changelog.d/4867.bugfix @@ -0,0 +1 @@ +Fixes room summaries showing encrypted content after verifying device \ No newline at end of file From eb72587238a02abcf8268ec078147f9806992062 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 27 Jan 2022 12:02:15 +0000 Subject: [PATCH 4/5] removing unused import --- .../sdk/internal/crypto/actions/MegolmSessionDataImporter.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt index 33c56ba422..f79b97b081 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt @@ -23,7 +23,6 @@ import org.matrix.android.sdk.internal.crypto.MegolmSessionData import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager import org.matrix.android.sdk.internal.crypto.RoomDecryptorProvider import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXMegolmDecryption -import org.matrix.android.sdk.internal.crypto.algorithms.olm.MXOlmDecryption import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore From 57bf044df0092e9bd9306d17264cfe49e16e4495 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 31 Mar 2022 17:33:55 +0100 Subject: [PATCH 5/5] adding documentation to the new session listener --- .../android/sdk/internal/crypto/NewSessionListener.kt | 9 +++++++++ .../crypto/algorithms/megolm/MXMegolmDecryption.kt | 1 + 2 files changed, 10 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/NewSessionListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/NewSessionListener.kt index 301729680c..9b39a8ab25 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/NewSessionListener.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/NewSessionListener.kt @@ -15,6 +15,15 @@ */ package org.matrix.android.sdk.internal.crypto +/** + * This listener notifies on new Megolm sessions being created + */ interface NewSessionListener { + + /** + * @param roomId the room id where the new Megolm session has been created for, may be null when importing from external sessions + * @param senderKey the sender key of the device which the Megolm session is shared with + * @param sessionId the session id of the Megolm session + */ fun onNewSession(roomId: String?, senderKey: String, sessionId: String) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt index fff0ba3477..72df59023a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt @@ -325,6 +325,7 @@ internal class MXMegolmDecryption(private val userId: String, /** * Check if the some messages can be decrypted with a new session * + * @param roomId the room id where the new Megolm session has been created for, may be null when importing from external sessions * @param senderKey the session sender key * @param sessionId the session id */