Remove EventDecryptor and inject the cryptoService when needed
Not used anymore in RoomSummaryUpdater, to avoid a DI dependency loop. let's see if this is a problem
This commit is contained in:
parent
f609bfaf10
commit
b26aba9fc0
|
@ -642,7 +642,6 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
*/
|
*/
|
||||||
@Throws(MXCryptoError::class)
|
@Throws(MXCryptoError::class)
|
||||||
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
|
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
|
||||||
|
|
||||||
return runBlocking {
|
return runBlocking {
|
||||||
olmMachine!!.decryptRoomEvent(event)
|
olmMachine!!.decryptRoomEvent(event)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.crypto
|
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.matrix.android.sdk.api.MatrixCallback
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
|
||||||
import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
|
|
||||||
import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
|
|
||||||
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
|
||||||
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
|
|
||||||
import org.matrix.android.sdk.internal.crypto.model.event.OlmEventContent
|
|
||||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
|
|
||||||
import org.matrix.android.sdk.internal.extensions.foldToCallback
|
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
|
||||||
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
|
|
||||||
import timber.log.Timber
|
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlin.jvm.Throws
|
|
||||||
|
|
||||||
@SessionScope
|
|
||||||
internal class EventDecryptor @Inject constructor(
|
|
||||||
private val cryptoCoroutineScope: CoroutineScope,
|
|
||||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
|
||||||
private val roomDecryptorProvider: RoomDecryptorProvider,
|
|
||||||
private val messageEncrypter: MessageEncrypter,
|
|
||||||
private val sendToDeviceTask: SendToDeviceTask,
|
|
||||||
private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
|
|
||||||
private val cryptoStore: IMXCryptoStore
|
|
||||||
) {
|
|
||||||
|
|
||||||
// The date of the last time we forced establishment
|
|
||||||
// of a new session for each user:device.
|
|
||||||
private val lastNewSessionForcedDates = MXUsersDevicesMap<Long>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypt an event
|
|
||||||
*
|
|
||||||
* @param event the raw event.
|
|
||||||
* @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
|
|
||||||
* @return the MXEventDecryptionResult data, or throw in case of error
|
|
||||||
*/
|
|
||||||
@Throws(MXCryptoError::class)
|
|
||||||
fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
|
|
||||||
return internalDecryptEvent(event, timeline)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypt an event asynchronously
|
|
||||||
*
|
|
||||||
* @param event the raw event.
|
|
||||||
* @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
|
|
||||||
* @param callback the callback to return data or null
|
|
||||||
*/
|
|
||||||
fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult>) {
|
|
||||||
// is it needed to do that on the crypto scope??
|
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
|
||||||
runCatching {
|
|
||||||
internalDecryptEvent(event, timeline)
|
|
||||||
}.foldToCallback(callback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypt an event
|
|
||||||
*
|
|
||||||
* @param event the raw event.
|
|
||||||
* @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
|
|
||||||
* @return the MXEventDecryptionResult data, or null in case of error
|
|
||||||
*/
|
|
||||||
@Throws(MXCryptoError::class)
|
|
||||||
private fun internalDecryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
|
|
||||||
val eventContent = event.content
|
|
||||||
if (eventContent == null) {
|
|
||||||
Timber.e("## CRYPTO | decryptEvent : empty event content")
|
|
||||||
throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON)
|
|
||||||
} else {
|
|
||||||
val algorithm = eventContent["algorithm"]?.toString()
|
|
||||||
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, algorithm)
|
|
||||||
if (alg == null) {
|
|
||||||
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, algorithm)
|
|
||||||
Timber.e("## CRYPTO | decryptEvent() : $reason")
|
|
||||||
throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, reason)
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return alg.decryptEvent(event, timeline)
|
|
||||||
} catch (mxCryptoError: MXCryptoError) {
|
|
||||||
Timber.v("## CRYPTO | internalDecryptEvent : Failed to decrypt ${event.eventId} reason: $mxCryptoError")
|
|
||||||
if (algorithm == MXCRYPTO_ALGORITHM_OLM) {
|
|
||||||
if (mxCryptoError is MXCryptoError.Base
|
|
||||||
&& mxCryptoError.errorType == MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE) {
|
|
||||||
// need to find sending device
|
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
|
||||||
val olmContent = event.content.toModel<OlmEventContent>()
|
|
||||||
cryptoStore.getUserDevices(event.senderId ?: "")
|
|
||||||
?.values
|
|
||||||
?.firstOrNull { it.identityKey() == olmContent?.senderKey }
|
|
||||||
?.let {
|
|
||||||
markOlmSessionForUnwedging(event.senderId ?: "", it)
|
|
||||||
}
|
|
||||||
?: run {
|
|
||||||
Timber.i("## CRYPTO | internalDecryptEvent() : Failed to find sender crypto device for unwedging")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw mxCryptoError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// coroutineDispatchers.crypto scope
|
|
||||||
private fun markOlmSessionForUnwedging(senderId: String, deviceInfo: CryptoDeviceInfo) {
|
|
||||||
val deviceKey = deviceInfo.identityKey()
|
|
||||||
|
|
||||||
val lastForcedDate = lastNewSessionForcedDates.getObject(senderId, deviceKey) ?: 0
|
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
if (now - lastForcedDate < DefaultCryptoService.CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
|
|
||||||
Timber.w("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Timber.i("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
|
|
||||||
lastNewSessionForcedDates.setObject(senderId, deviceKey, now)
|
|
||||||
|
|
||||||
// offload this from crypto thread (?)
|
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
|
|
||||||
val ensured = ensureOlmSessionsForDevicesAction.handle(mapOf(senderId to listOf(deviceInfo)), force = true)
|
|
||||||
|
|
||||||
Timber.i("## CRYPTO | markOlmSessionForUnwedging() : ensureOlmSessionsForDevicesAction isEmpty:${ensured.isEmpty}")
|
|
||||||
|
|
||||||
// Now send a blank message on that session so the other side knows about it.
|
|
||||||
// (The keyshare request is sent in the clear so that won't do)
|
|
||||||
// We send this first such that, as long as the toDevice messages arrive in the
|
|
||||||
// same order we sent them, the other end will get this first, set up the new session,
|
|
||||||
// then get the keyshare request and send the key over this new session (because it
|
|
||||||
// is the session it has most recently received a message on).
|
|
||||||
val payloadJson = mapOf<String, Any>("type" to EventType.DUMMY)
|
|
||||||
|
|
||||||
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
|
|
||||||
val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
|
||||||
sendToDeviceMap.setObject(senderId, deviceInfo.deviceId, encodedPayload)
|
|
||||||
Timber.i("## CRYPTO | markOlmSessionForUnwedging() : sending dummy to $senderId:${deviceInfo.deviceId}")
|
|
||||||
withContext(coroutineDispatchers.io) {
|
|
||||||
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
|
|
||||||
try {
|
|
||||||
sendToDeviceTask.execute(sendToDeviceParams)
|
|
||||||
} catch (failure: Throwable) {
|
|
||||||
Timber.e(failure, "## CRYPTO | markOlmSessionForUnwedging() : failed to send dummy to $senderId:${deviceInfo.deviceId}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,6 +17,9 @@
|
||||||
package org.matrix.android.sdk.internal.database
|
package org.matrix.android.sdk.internal.database
|
||||||
|
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import io.realm.RealmConfiguration
|
||||||
|
import io.realm.RealmResults
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.internal.database.mapper.asDomain
|
import org.matrix.android.sdk.internal.database.mapper.asDomain
|
||||||
import org.matrix.android.sdk.internal.database.model.EventEntity
|
import org.matrix.android.sdk.internal.database.model.EventEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.EventInsertEntity
|
import org.matrix.android.sdk.internal.database.model.EventInsertEntity
|
||||||
|
@ -24,17 +27,13 @@ import org.matrix.android.sdk.internal.database.model.EventInsertEntityFields
|
||||||
import org.matrix.android.sdk.internal.database.query.where
|
import org.matrix.android.sdk.internal.database.query.where
|
||||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||||
import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor
|
import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor
|
||||||
import io.realm.RealmConfiguration
|
|
||||||
import io.realm.RealmResults
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.matrix.android.sdk.internal.crypto.EventDecryptor
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class EventInsertLiveObserver @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration,
|
internal class EventInsertLiveObserver @Inject constructor(
|
||||||
private val processors: Set<@JvmSuppressWildcards EventInsertLiveProcessor>,
|
@SessionDatabase realmConfiguration: RealmConfiguration,
|
||||||
private val eventDecryptor: EventDecryptor)
|
private val processors: Set<@JvmSuppressWildcards EventInsertLiveProcessor>
|
||||||
: RealmLiveEntityObserver<EventInsertEntity>(realmConfiguration) {
|
) : RealmLiveEntityObserver<EventInsertEntity>(realmConfiguration) {
|
||||||
|
|
||||||
override val query = Monarchy.Query<EventInsertEntity> {
|
override val query = Monarchy.Query<EventInsertEntity> {
|
||||||
it.where(EventInsertEntity::class.java)
|
it.where(EventInsertEntity::class.java)
|
||||||
|
@ -86,23 +85,6 @@ internal class EventInsertLiveObserver @Inject constructor(@SessionDatabase real
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private fun decryptIfNeeded(event: Event) {
|
|
||||||
// if (event.isEncrypted() && event.mxDecryptionResult == null) {
|
|
||||||
// try {
|
|
||||||
// val result = eventDecryptor.decryptEvent(event, event.roomId ?: "")
|
|
||||||
// event.mxDecryptionResult = OlmDecryptionResult(
|
|
||||||
// payload = result.clearEvent,
|
|
||||||
// senderKey = result.senderCurve25519Key,
|
|
||||||
// keysClaimed = result.claimedEd25519Key?.let { k -> mapOf("ed25519" to k) },
|
|
||||||
// forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
|
|
||||||
// )
|
|
||||||
// } catch (e: MXCryptoError) {
|
|
||||||
// Timber.v("Failed to decrypt event")
|
|
||||||
// // TODO -> we should keep track of this and retry, or some processing will never be handled
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private fun shouldProcess(eventInsertEntity: EventInsertEntity): Boolean {
|
private fun shouldProcess(eventInsertEntity: EventInsertEntity): Boolean {
|
||||||
return processors.any {
|
return processors.any {
|
||||||
it.shouldProcess(eventInsertEntity.eventId, eventInsertEntity.eventType, eventInsertEntity.insertType)
|
it.shouldProcess(eventInsertEntity.eventId, eventInsertEntity.eventType, eventInsertEntity.insertType)
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.session.room.summary
|
||||||
|
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.kotlin.createObject
|
import io.realm.kotlin.createObject
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes
|
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes
|
||||||
|
@ -32,11 +31,9 @@ import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||||
import org.matrix.android.sdk.api.session.room.model.VersioningState
|
import org.matrix.android.sdk.api.session.room.model.VersioningState
|
||||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||||
import org.matrix.android.sdk.internal.crypto.EventDecryptor
|
|
||||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||||
import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultCrossSigningService
|
import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultCrossSigningService
|
||||||
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
|
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
|
||||||
import org.matrix.android.sdk.internal.database.mapper.asDomain
|
|
||||||
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
|
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.EventEntity
|
import org.matrix.android.sdk.internal.database.model.EventEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
||||||
|
@ -71,7 +68,6 @@ internal class RoomSummaryUpdater @Inject constructor(
|
||||||
@UserId private val userId: String,
|
@UserId private val userId: String,
|
||||||
private val roomDisplayNameResolver: RoomDisplayNameResolver,
|
private val roomDisplayNameResolver: RoomDisplayNameResolver,
|
||||||
private val roomAvatarResolver: RoomAvatarResolver,
|
private val roomAvatarResolver: RoomAvatarResolver,
|
||||||
private val eventDecryptor: EventDecryptor,
|
|
||||||
private val crossSigningService: DefaultCrossSigningService,
|
private val crossSigningService: DefaultCrossSigningService,
|
||||||
private val roomAccountDataDataSource: RoomAccountDataDataSource) {
|
private val roomAccountDataDataSource: RoomAccountDataDataSource) {
|
||||||
|
|
||||||
|
@ -156,15 +152,7 @@ internal class RoomSummaryUpdater @Inject constructor(
|
||||||
}
|
}
|
||||||
roomSummaryEntity.updateHasFailedSending()
|
roomSummaryEntity.updateHasFailedSending()
|
||||||
|
|
||||||
val root = latestPreviewableEvent?.root
|
// We do not decrypt Event anymore here, let's see if this is OK
|
||||||
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 {
|
|
||||||
eventDecryptor.decryptEvent(root.asDomain(), "")
|
|
||||||
}
|
|
||||||
?.let { root.setDecryptionResult(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateMembers) {
|
if (updateMembers) {
|
||||||
val otherRoomMembers = RoomMemberHelper(realm, roomId)
|
val otherRoomMembers = RoomMemberHelper(realm, roomId)
|
||||||
|
|
|
@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.session.room.timeline
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.internal.crypto.EventDecryptor
|
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
|
||||||
import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult
|
import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult
|
||||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||||
import org.matrix.android.sdk.internal.network.executeRequest
|
import org.matrix.android.sdk.internal.network.executeRequest
|
||||||
|
@ -36,7 +36,7 @@ internal interface GetEventTask : Task<GetEventTask.Params, Event> {
|
||||||
internal class DefaultGetEventTask @Inject constructor(
|
internal class DefaultGetEventTask @Inject constructor(
|
||||||
private val roomAPI: RoomAPI,
|
private val roomAPI: RoomAPI,
|
||||||
private val globalErrorReceiver: GlobalErrorReceiver,
|
private val globalErrorReceiver: GlobalErrorReceiver,
|
||||||
private val eventDecryptor: EventDecryptor
|
private val cryptoService: DefaultCryptoService
|
||||||
) : GetEventTask {
|
) : GetEventTask {
|
||||||
|
|
||||||
override suspend fun execute(params: GetEventTask.Params): Event {
|
override suspend fun execute(params: GetEventTask.Params): Event {
|
||||||
|
@ -47,7 +47,7 @@ internal class DefaultGetEventTask @Inject constructor(
|
||||||
// Try to decrypt the Event
|
// Try to decrypt the Event
|
||||||
if (event.isEncrypted()) {
|
if (event.isEncrypted()) {
|
||||||
tryOrNull(message = "Unable to decrypt the event") {
|
tryOrNull(message = "Unable to decrypt the event") {
|
||||||
eventDecryptor.decryptEvent(event, "")
|
cryptoService.decryptEvent(event, "")
|
||||||
}
|
}
|
||||||
?.let { result ->
|
?.let { result ->
|
||||||
event.mxDecryptionResult = OlmDecryptionResult(
|
event.mxDecryptionResult = OlmDecryptionResult(
|
||||||
|
|
Loading…
Reference in New Issue