From c4d7711d2f3cfe7e896b11c6300773837a317532 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 6 Jun 2019 19:10:04 +0200 Subject: [PATCH] Crypto: finally get a working encrypt/decrypt + SAS --- .../android/internal/crypto/CryptoManager.kt | 4 +- .../internal/crypto/DeviceListManager.kt | 3 - .../crypto/IncomingRoomKeyRequestManager.kt | 145 ++++++++---------- .../algorithms/megolm/MXMegolmDecryption.kt | 80 +++++----- .../algorithms/megolm/MXMegolmEncryption.kt | 27 ++-- .../DefaultSasVerificationService.kt | 2 +- .../IncomingSASVerificationTransaction.kt | 2 +- .../room/timeline/TimelineEventFactory.kt | 23 ++- .../session/sync/SyncResponseHandler.kt | 6 + 9 files changed, 141 insertions(+), 151 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt index 621f846309..5dc11c42fc 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt @@ -958,7 +958,7 @@ internal class CryptoManager( setRoomBlacklistUnverifiedDevices(roomId, false) } -// TODO Check if this method is still necessary + // TODO Check if this method is still necessary /** * Cancel any earlier room key request * @@ -974,7 +974,7 @@ internal class CryptoManager( * @param event the event to decrypt again. */ override fun reRequestRoomKeyForEvent(event: Event) { - val wireContent = event.content!! // Wireeventcontent? + val wireContent = event.content!! val algorithm = wireContent["algorithm"].toString() val senderKey = wireContent["sender_key"].toString() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt index 45b786a446..48ddb19772 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt @@ -280,11 +280,8 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore, /** * Download the devices keys for a set of users. - * It must be called in getEncryptingThreadHandler() thread. - * The callback is called in the UI thread. * * @param downloadUsers the user ids list - * @param callback the asynchronous callback */ private suspend fun doKeyDownloadForUsers(downloadUsers: MutableList): Try> { Timber.v("## doKeyDownloadForUsers() : doKeyDownloadForUsers $downloadUsers") diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt index de53f34f7d..37d76340cb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt @@ -25,6 +25,7 @@ import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyShare import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import timber.log.Timber import java.util.* +import kotlin.collections.ArrayList internal class IncomingRoomKeyRequestManager( private val credentials: Credentials, @@ -46,19 +47,15 @@ internal class IncomingRoomKeyRequestManager( /** * Called when we get an m.room_key_request event - * This method must be called on getEncryptingThreadHandler() thread. + * It must be called on CryptoThread * * @param event the announcement event. */ - fun onRoomKeyRequestEvent(event: Event) { + suspend fun onRoomKeyRequestEvent(event: Event) { val roomKeyShare = event.getClearContent().toModel() when (roomKeyShare?.action) { - RoomKeyShare.ACTION_SHARE_REQUEST -> synchronized(receivedRoomKeyRequests) { - receivedRoomKeyRequests.add(IncomingRoomKeyRequest(event)) - } - RoomKeyShare.ACTION_SHARE_CANCELLATION -> synchronized(receivedRoomKeyRequestCancellations) { - receivedRoomKeyRequestCancellations.add(IncomingRoomKeyRequestCancellation(event)) - } + RoomKeyShare.ACTION_SHARE_REQUEST -> receivedRoomKeyRequests.add(IncomingRoomKeyRequest(event)) + RoomKeyShare.ACTION_SHARE_CANCELLATION -> receivedRoomKeyRequestCancellations.add(IncomingRoomKeyRequestCancellation(event)) else -> Timber.e("## onRoomKeyRequestEvent() : unsupported action " + roomKeyShare?.action) } } @@ -66,86 +63,68 @@ internal class IncomingRoomKeyRequestManager( /** * Process any m.room_key_request events which were queued up during the * current sync. + * It must be called on CryptoThread */ fun processReceivedRoomKeyRequests() { - var receivedRoomKeyRequests: List? = null + val roomKeyRequestsToProcess = ArrayList(receivedRoomKeyRequests) + receivedRoomKeyRequests.clear() + for (request in roomKeyRequestsToProcess) { + val userId = request.userId + val deviceId = request.deviceId + val body = request.requestBody + val roomId = body!!.roomId + val alg = body.algorithm - synchronized(this.receivedRoomKeyRequests) { - if (this.receivedRoomKeyRequests.isNotEmpty()) { - receivedRoomKeyRequests = ArrayList(this.receivedRoomKeyRequests) - this.receivedRoomKeyRequests.clear() + Timber.v("m.room_key_request from " + userId + ":" + deviceId + " for " + roomId + " / " + body.sessionId + " id " + request.requestId) + if (userId == null || credentials.userId != userId) { + // TODO: determine if we sent this device the keys already: in + Timber.e("## processReceivedRoomKeyRequests() : Ignoring room key request from other user for now") + return } - } - - if (null != receivedRoomKeyRequests) { - for (request in receivedRoomKeyRequests!!) { - val userId = request.userId!! - val deviceId = request.deviceId - val body = request.requestBody - val roomId = body!!.roomId - val alg = body.algorithm - - Timber.v("m.room_key_request from " + userId + ":" + deviceId + " for " + roomId + " / " + body.sessionId + " id " + request.requestId) - - if (!TextUtils.equals(credentials.userId, userId)) { - // TODO: determine if we sent this device the keys already: in - Timber.e("## processReceivedRoomKeyRequests() : Ignoring room key request from other user for now") - return - } - - // todo: should we queue up requests we don't yet have keys for, - // in case they turn up later? - - // if we don't have a decryptor for this room/alg, we don't have - // the keys for the requested events, and can drop the requests. - - val decryptor = roomDecryptorProvider.getRoomDecryptor(roomId, alg) - - if (null == decryptor) { - Timber.e("## processReceivedRoomKeyRequests() : room key request for unknown $alg in room $roomId") - continue - } - - if (!decryptor.hasKeysForKeyRequest(request)) { - Timber.e("## processReceivedRoomKeyRequests() : room key request for unknown session " + body.sessionId!!) - cryptoStore.deleteIncomingRoomKeyRequest(request) - continue - } - - if (TextUtils.equals(deviceId, credentials.deviceId) && TextUtils.equals(credentials.userId, userId)) { - Timber.v("## processReceivedRoomKeyRequests() : oneself device - ignored") - cryptoStore.deleteIncomingRoomKeyRequest(request) - continue - } - - request.share = Runnable { - decryptor.shareKeysWithDevice(request) - cryptoStore.deleteIncomingRoomKeyRequest(request) - } - - request.ignore = Runnable { cryptoStore.deleteIncomingRoomKeyRequest(request) } - - // if the device is verified already, share the keys - val device = cryptoStore.getUserDevice(deviceId!!, userId) - - if (null != device) { - if (device.isVerified) { - Timber.v("## processReceivedRoomKeyRequests() : device is already verified: sharing keys") - cryptoStore.deleteIncomingRoomKeyRequest(request) - request.share?.run() - continue - } - - if (device.isBlocked) { - Timber.v("## processReceivedRoomKeyRequests() : device is blocked -> ignored") - cryptoStore.deleteIncomingRoomKeyRequest(request) - continue - } - } - - cryptoStore.storeIncomingRoomKeyRequest(request) - onRoomKeyRequest(request) + // todo: should we queue up requests we don't yet have keys for, in case they turn up later? + // if we don't have a decryptor for this room/alg, we don't have + // the keys for the requested events, and can drop the requests. + val decryptor = roomDecryptorProvider.getRoomDecryptor(roomId, alg) + if (null == decryptor) { + Timber.e("## processReceivedRoomKeyRequests() : room key request for unknown $alg in room $roomId") + continue } + if (!decryptor.hasKeysForKeyRequest(request)) { + Timber.e("## processReceivedRoomKeyRequests() : room key request for unknown session " + body.sessionId!!) + cryptoStore.deleteIncomingRoomKeyRequest(request) + continue + } + + if (TextUtils.equals(deviceId, credentials.deviceId) && TextUtils.equals(credentials.userId, userId)) { + Timber.v("## processReceivedRoomKeyRequests() : oneself device - ignored") + cryptoStore.deleteIncomingRoomKeyRequest(request) + continue + } + request.share = Runnable { + decryptor.shareKeysWithDevice(request) + cryptoStore.deleteIncomingRoomKeyRequest(request) + } + request.ignore = Runnable { + cryptoStore.deleteIncomingRoomKeyRequest(request) + } + // if the device is verified already, share the keys + val device = cryptoStore.getUserDevice(deviceId!!, userId) + if (device != null) { + if (device.isVerified) { + Timber.v("## processReceivedRoomKeyRequests() : device is already verified: sharing keys") + cryptoStore.deleteIncomingRoomKeyRequest(request) + request.share?.run() + continue + } + + if (device.isBlocked) { + Timber.v("## processReceivedRoomKeyRequests() : device is blocked -> ignored") + cryptoStore.deleteIncomingRoomKeyRequest(request) + continue + } + } + cryptoStore.storeIncomingRoomKeyRequest(request) + onRoomKeyRequest(request) } var receivedRoomKeyRequestCancellations: List? = null diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt index b39728e454..e4d1ce93f6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt @@ -194,25 +194,22 @@ internal class MXMegolmDecryption(private val credentials: Credentials, var senderKey: String? = event.getSenderKey() var keysClaimed: MutableMap = HashMap() - var forwarding_curve25519_key_chain: MutableList? = null + var forwardingCurve25519KeyChain: MutableList = ArrayList() if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.sessionId) || TextUtils.isEmpty(roomKeyContent.sessionKey)) { Timber.e("## onRoomKeyEvent() : Key event is missing fields") return } - if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) { Timber.v("## onRoomKeyEvent(), forward adding key : roomId " + roomKeyContent.roomId + " sessionId " + roomKeyContent.sessionId + " sessionKey " + roomKeyContent.sessionKey) // from " + event); val forwardedRoomKeyContent = event.getClearContent().toModel()!! - - if (null == forwardedRoomKeyContent.forwardingCurve25519KeyChain) { - forwarding_curve25519_key_chain = ArrayList() + forwardingCurve25519KeyChain = if (null == forwardedRoomKeyContent.forwardingCurve25519KeyChain) { + ArrayList() } else { - forwarding_curve25519_key_chain = ArrayList(forwardedRoomKeyContent.forwardingCurve25519KeyChain!!) + ArrayList(forwardedRoomKeyContent.forwardingCurve25519KeyChain!!) } - - forwarding_curve25519_key_chain.add(senderKey!!) + forwardingCurve25519KeyChain.add(senderKey!!) exportFormat = true senderKey = forwardedRoomKeyContent.senderKey @@ -239,8 +236,7 @@ internal class MXMegolmDecryption(private val credentials: Credentials, // inherit the claimed ed25519 key from the setup message keysClaimed = event.getKeysClaimed().toMutableMap() } - - val added = olmDevice.addInboundGroupSession(roomKeyContent.sessionId!!, roomKeyContent.sessionKey!!, roomKeyContent.roomId!!, senderKey, forwarding_curve25519_key_chain!!, keysClaimed, exportFormat) + val added = olmDevice.addInboundGroupSession(roomKeyContent.sessionId!!, roomKeyContent.sessionKey!!, roomKeyContent.roomId!!, senderKey, forwardingCurve25519KeyChain, keysClaimed, exportFormat) if (added) { keysBackup.maybeBackupKeys() @@ -318,41 +314,41 @@ internal class MXMegolmDecryption(private val credentials: Credentials, deviceListManager .downloadKeys(listOf(userId), false) .flatMap { - val deviceId = request.deviceId - val deviceInfo = cryptoStore.getUserDevice(deviceId!!, userId) - if (deviceInfo == null) { - throw RuntimeException() - } else { - val devicesByUser = HashMap>() - devicesByUser[userId] = ArrayList(Arrays.asList(deviceInfo)) - ensureOlmSessionsForDevicesAction - .handle(devicesByUser) - .flatMap { - val body = request.requestBody - val olmSessionResult = it.getObject(deviceId, userId) - if (olmSessionResult?.mSessionId == null) { - // no session with this device, probably because there - // were no one-time keys. - Try.just(Unit) + val deviceId = request.deviceId + val deviceInfo = cryptoStore.getUserDevice(deviceId!!, userId) + if (deviceInfo == null) { + throw RuntimeException() + } else { + val devicesByUser = HashMap>() + devicesByUser[userId] = ArrayList(Arrays.asList(deviceInfo)) + ensureOlmSessionsForDevicesAction + .handle(devicesByUser) + .flatMap { + val body = request.requestBody + val olmSessionResult = it.getObject(deviceId, userId) + if (olmSessionResult?.mSessionId == null) { + // no session with this device, probably because there + // were no one-time keys. + Try.just(Unit) + } + Timber.v("## shareKeysWithDevice() : sharing keys for session " + body!!.senderKey + "|" + body.sessionId + + " with device " + userId + ":" + deviceId) + val inboundGroupSession = olmDevice.getInboundGroupSession(body.sessionId, body.senderKey, body.roomId) + + val payloadJson = HashMap() + payloadJson["type"] = EventType.FORWARDED_ROOM_KEY + payloadJson["content"] = inboundGroupSession!!.exportKeys()!! + + val encodedPayload = messageEncrypter.encryptMessage(payloadJson, Arrays.asList(deviceInfo)) + val sendToDeviceMap = MXUsersDevicesMap() + sendToDeviceMap.setObject(encodedPayload, userId, deviceId) + Timber.v("## shareKeysWithDevice() : sending to $userId:$deviceId") + val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap) + sendToDeviceTask.execute(sendToDeviceParams) } - Timber.v("## shareKeysWithDevice() : sharing keys for session " + body!!.senderKey + "|" + body.sessionId - + " with device " + userId + ":" + deviceId) - val inboundGroupSession = olmDevice.getInboundGroupSession(body.sessionId, body.senderKey, body.roomId) - - val payloadJson = HashMap() - payloadJson["type"] = EventType.FORWARDED_ROOM_KEY - payloadJson["content"] = inboundGroupSession!!.exportKeys()!! - - val encodedPayload = messageEncrypter.encryptMessage(payloadJson, Arrays.asList(deviceInfo)) - val sendToDeviceMap = MXUsersDevicesMap() - sendToDeviceMap.setObject(encodedPayload, userId, deviceId) - Timber.v("## shareKeysWithDevice() : sending to $userId:$deviceId") - val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap) - sendToDeviceTask.execute(sendToDeviceParams) - } - } + } } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt index 6515dd1cea..33776bf604 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt @@ -88,7 +88,7 @@ internal class MXMegolmEncryption( keysClaimedMap["ed25519"] = olmDevice.deviceEd25519Key!! olmDevice.addInboundGroupSession(sessionId!!, olmDevice.getSessionKey(sessionId)!!, roomId, olmDevice.deviceCurve25519Key!!, - ArrayList(), keysClaimedMap, false) + ArrayList(), keysClaimedMap, false) keysBackup.maybeBackupKeys() @@ -103,10 +103,10 @@ internal class MXMegolmEncryption( private suspend fun ensureOutboundSession(devicesInRoom: MXUsersDevicesMap): Try { var session = outboundSession if (session == null - // Need to make a brand new session? - || session.needsRotation(sessionRotationPeriodMsgs, sessionRotationPeriodMs) - // Determine if we have shared with anyone we shouldn't have - || session.sharedWithTooManyDevices(devicesInRoom)) { + // Need to make a brand new session? + || session.needsRotation(sessionRotationPeriodMsgs, sessionRotationPeriodMs) + // Determine if we have shared with anyone we shouldn't have + || session.sharedWithTooManyDevices(devicesInRoom)) { session = prepareNewSessionInRoom() outboundSession = session } @@ -146,10 +146,11 @@ internal class MXMegolmEncryption( val userIds = ArrayList() var devicesCount = 0 for (userId in devicesByUsers.keys) { - val devicesList = devicesByUsers[userId] - userIds.add(userId) - subMap[userId] = devicesList!! - devicesCount += devicesList.size + devicesByUsers[userId]?.let { + userIds.add(userId) + subMap[userId] = it + devicesCount += it.size + } if (devicesCount > 100) { break } @@ -157,7 +158,7 @@ internal class MXMegolmEncryption( Timber.v("## shareKey() ; userId $userIds") return shareUserDevicesKey(session, subMap) .flatMap { - val remainingDevices = devicesByUsers.filterKeys { userIds.contains(it) } + val remainingDevices = devicesByUsers.filterKeys { userIds.contains(it).not() } shareKey(session, remainingDevices) } } @@ -191,7 +192,7 @@ internal class MXMegolmEncryption( return ensureOlmSessionsForDevicesAction.handle(devicesByUser) .flatMap { Timber.v("## shareUserDevicesKey() : ensureOlmSessionsForDevices succeeds after " - + (System.currentTimeMillis() - t0) + " ms") + + (System.currentTimeMillis() - t0) + " ms") val contentMap = MXUsersDevicesMap() var haveTargets = false val userIds = it.userIds @@ -226,7 +227,7 @@ internal class MXMegolmEncryption( sendToDeviceTask.execute(sendToDeviceParams) .map { Timber.v("## shareUserDevicesKey() : sendToDevice succeeds after " - + (System.currentTimeMillis() - t0) + " ms") + + (System.currentTimeMillis() - t0) + " ms") // Add the devices we have shared with to session.sharedWithDevices. // we deliberately iterate over devicesByUser (ie, the devices we @@ -292,7 +293,7 @@ internal class MXMegolmEncryption( .downloadKeys(userIds, false) .map { val encryptToVerifiedDevicesOnly = cryptoStore.getGlobalBlacklistUnverifiedDevices() - || cryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(roomId) + || cryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(roomId) val devicesInRoom = MXUsersDevicesMap() val unknownDevices = MXUsersDevicesMap() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt index 0f39f479a0..3789d83c74 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt @@ -223,7 +223,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia .fold( { error() }, { - if (it != null && it.getUserDeviceIds(otherUserId).contains(startReq.fromDevice)) { + if (it.getUserDeviceIds(otherUserId).contains(startReq.fromDevice)) { success(it) } else { error() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt index 09258b25b5..32843e0f5d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt @@ -118,7 +118,7 @@ internal class IncomingSASVerificationTransaction( } //Bob’s device ensures that it has a copy of Alice’s device key. - val mxDeviceInfo = mCryptoStore.getUserDevice(this.otherUserId, otherDeviceId!!) + val mxDeviceInfo = mCryptoStore.getUserDevice(deviceId = otherDeviceId!!, userId = otherUserId) if (mxDeviceInfo?.fingerprint() == null) { Timber.e("## Failed to find device key ") diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventFactory.kt index 1045399220..5f6425c43c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventFactory.kt @@ -16,36 +16,47 @@ package im.vector.matrix.android.internal.session.room.timeline -import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.internal.crypto.MXDecryptionException +import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.session.room.members.SenderRoomMemberExtractor import io.realm.Realm import timber.log.Timber +import java.util.* internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomMemberExtractor, private val cryptoService: CryptoService) { - private val cached = mutableMapOf() + private val timelineId = UUID.randomUUID().toString() + private val senderCache = mutableMapOf() + private val decryptionCache = mutableMapOf() fun create(eventEntity: EventEntity, realm: Realm = eventEntity.realm): TimelineEvent { val sender = eventEntity.sender val cacheKey = sender + eventEntity.stateIndex - val senderData = cached.getOrPut(cacheKey) { + val senderData = senderCache.getOrPut(cacheKey) { val senderRoomMember = roomMemberExtractor.extractFrom(eventEntity, realm) SenderData(senderRoomMember?.displayName, senderRoomMember?.avatarUrl) } val event = eventEntity.asDomain() if (event.getClearType() == EventType.ENCRYPTED) { try { - val result = cryptoService.decryptEvent(event, "TODO") + Timber.v("Encrypted event: try to decrypt ${event.eventId}") + val result = if (decryptionCache.containsKey(eventEntity.localId)) { + Timber.v("Encrypted event ${event.eventId} cached") + decryptionCache[eventEntity.localId] + } else { + cryptoService.decryptEvent(event, timelineId)?.also { + decryptionCache[eventEntity.localId] = it + } + } event.setClearData(result) } catch (e: Exception) { - Timber.e(e) + Timber.e(e, "Encrypted event: decryption failed") if (e is MXDecryptionException) { event.setCryptoError(e.cryptoError) } @@ -62,7 +73,7 @@ internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomM } fun clear() { - cached.clear() + senderCache.clear() } private data class SenderData( diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt index 1beccb6e50..13b91a30dd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt @@ -34,22 +34,28 @@ internal class SyncResponseHandler(private val roomSyncHandler: RoomSyncHandler, val measure = measureTimeMillis { // Handle the to device events before the room ones // to ensure to decrypt them properly + Timber.v("Handle toDevice") if (syncResponse.toDevice != null) { cryptoSyncHandler.handleToDevice(syncResponse.toDevice) } + Timber.v("Handle rooms") if (syncResponse.rooms != null) { roomSyncHandler.handle(syncResponse.rooms) } + Timber.v("Handle groups") if (syncResponse.groups != null) { groupSyncHandler.handle(syncResponse.groups) } + Timber.v("Handle accoundData") if (syncResponse.accountData != null) { userAccountDataSyncHandler.handle(syncResponse.accountData) } + Timber.v("On sync completed") cryptoSyncHandler.onSyncCompleted(syncResponse, fromToken, isCatchingUp) } val isInitialSync = fromToken == null if (!cryptoManager.isStarted()) { + Timber.v("Should start cryptoManager") cryptoManager.start(isInitialSync) } Timber.v("Finish handling sync in $measure ms")