diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt index c69a859016..d78f4a3107 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt @@ -62,7 +62,9 @@ import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreMigration import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule import org.matrix.android.sdk.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask +import org.matrix.android.sdk.internal.crypto.tasks.CreateUnableToDecryptEventEntityTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultClaimOneTimeKeysForUsersDevice +import org.matrix.android.sdk.internal.crypto.tasks.DefaultCreateUnableToDecryptEventEntityTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultDeleteDeviceTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultDownloadKeysForUsers import org.matrix.android.sdk.internal.crypto.tasks.DefaultEncryptEventTask @@ -253,4 +255,7 @@ internal abstract class CryptoModule { @Binds abstract fun bindSendEventTask(task: DefaultSendEventTask): SendEventTask + + @Binds + abstract fun bindCreateUnableToDecryptEventEntityTask(task: DefaultCreateUnableToDecryptEventEntityTask): CreateUnableToDecryptEventEntityTask } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt index c9eabeab48..524db32670 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt @@ -38,6 +38,7 @@ 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.store.IMXCryptoStore +import org.matrix.android.sdk.internal.crypto.tasks.CreateUnableToDecryptEventEntityTask 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 @@ -59,7 +60,8 @@ internal class EventDecryptor @Inject constructor( private val sendToDeviceTask: SendToDeviceTask, private val deviceListManager: DeviceListManager, private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction, - private val cryptoStore: IMXCryptoStore + private val cryptoStore: IMXCryptoStore, + private val createUnableToDecryptEventEntityTask: CreateUnableToDecryptEventEntityTask, ) { /** @@ -136,6 +138,7 @@ internal class EventDecryptor @Inject constructor( val eventContent = event.content if (eventContent == null) { Timber.tag(loggerTag.value).e("decryptEvent : empty event content") + createUnableToDecryptEventEntity(event.eventId) throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON) } else if (event.isRedacted()) { // we shouldn't attempt to decrypt a redacted event because the content is cleared and decryption will fail because of null algorithm @@ -153,6 +156,7 @@ internal class EventDecryptor @Inject constructor( if (alg == null) { val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, algorithm) Timber.tag(loggerTag.value).e("decryptEvent() : $reason") + createUnableToDecryptEventEntity(event.eventId) throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, reason) } else { try { @@ -171,12 +175,20 @@ internal class EventDecryptor @Inject constructor( } } } + createUnableToDecryptEventEntity(event.eventId) throw mxCryptoError } } } } + private suspend fun createUnableToDecryptEventEntity(eventId: String?) { + eventId?.let { + val params = CreateUnableToDecryptEventEntityTask.Params(eventId = it) + createUnableToDecryptEventEntityTask.execute(params) + } + } + private suspend fun markOlmSessionForUnwedging(senderId: String, senderKey: String) { wedgedMutex.withLock { val info = WedgedDeviceInfo(senderId, senderKey) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/CreateUnableToDecryptEventEntityTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/CreateUnableToDecryptEventEntityTask.kt new file mode 100644 index 0000000000..17c7ae5ccd --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/CreateUnableToDecryptEventEntityTask.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 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.tasks + +import io.realm.RealmConfiguration +import org.matrix.android.sdk.internal.crypto.store.db.doRealmTransactionAsync +import org.matrix.android.sdk.internal.database.model.UnableToDecryptEventEntity +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.task.Task +import javax.inject.Inject + +/** + * This task create a dedicated entity for UTD events so that it can be processed later. + */ +internal interface CreateUnableToDecryptEventEntityTask : Task { + data class Params( + val eventId: String, + ) +} + +// TODO add unit tests +internal class DefaultCreateUnableToDecryptEventEntityTask @Inject constructor( + @SessionDatabase val realmConfiguration: RealmConfiguration, +) : CreateUnableToDecryptEventEntityTask { + + override suspend fun execute(params: CreateUnableToDecryptEventEntityTask.Params) { + val utdEventEntity = UnableToDecryptEventEntity(eventId = params.eventId) + doRealmTransactionAsync(realmConfiguration) { realm -> + realm.insert(utdEventEntity) + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt index e18495c924..0f1c226044 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt @@ -25,7 +25,6 @@ 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.EventInsertEntity import org.matrix.android.sdk.internal.database.model.EventInsertType -import org.matrix.android.sdk.internal.database.model.UnableToDecryptEventEntity internal fun EventEntity.copyToRealmOrIgnore(realm: Realm, insertType: EventInsertType): EventEntity { val eventEntity = realm.where() @@ -33,17 +32,11 @@ internal fun EventEntity.copyToRealmOrIgnore(realm: Realm, insertType: EventInse .equalTo(EventEntityFields.ROOM_ID, roomId) .findFirst() return if (eventEntity == null) { - val isEncrypted = type == EventType.ENCRYPTED && decryptionResultJson == null - val canBeProcessed = isEncrypted.not() + val canBeProcessed = type != EventType.ENCRYPTED || decryptionResultJson != null val insertEntity = EventInsertEntity(eventId = eventId, eventType = type, canBeProcessed = canBeProcessed).apply { this.insertType = insertType } realm.insert(insertEntity) - // TODO check with others if it is the right spot to detect UTD events - if (isEncrypted) { - val utdEventEntity = UnableToDecryptEventEntity(eventId = eventId) - realm.insert(utdEventEntity) - } // copy this event entity and return it realm.copyToRealm(this) } else {