diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt index d6d8b06b5f..9e116d8223 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt @@ -21,7 +21,7 @@ import im.vector.matrix.android.api.session.crypto.MXCryptoError import im.vector.matrix.android.api.util.JSON_DICT_PARAMETERIZED_TYPE import im.vector.matrix.android.api.util.JsonDict import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult -import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.model.OlmSessionWrapper import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.di.MoshiProvider @@ -488,7 +488,7 @@ internal class MXOlmDevice @Inject constructor( forwardingCurve25519KeyChain: List, keysClaimed: Map, exportFormat: Boolean): Boolean { - val session = OlmInboundGroupSessionWrapper(sessionKey, exportFormat) + val session = OlmInboundGroupSessionWrapper2(sessionKey, exportFormat) runCatching { getInboundGroupSession(sessionId, senderKey, roomId) } .fold( { @@ -543,18 +543,18 @@ internal class MXOlmDevice @Inject constructor( * @param megolmSessionsData the megolm sessions data * @return the successfully imported sessions. */ - fun importInboundGroupSessions(megolmSessionsData: List): List { - val sessions = ArrayList(megolmSessionsData.size) + fun importInboundGroupSessions(megolmSessionsData: List): List { + val sessions = ArrayList(megolmSessionsData.size) for (megolmSessionData in megolmSessionsData) { val sessionId = megolmSessionData.sessionId val senderKey = megolmSessionData.senderKey val roomId = megolmSessionData.roomId - var session: OlmInboundGroupSessionWrapper? = null + var session: OlmInboundGroupSessionWrapper2? = null try { - session = OlmInboundGroupSessionWrapper(megolmSessionData) + session = OlmInboundGroupSessionWrapper2(megolmSessionData) } catch (e: Exception) { Timber.e(e, "## importInboundGroupSession() : Update for megolm session $senderKey/$sessionId") } @@ -741,7 +741,7 @@ internal class MXOlmDevice @Inject constructor( * @param senderKey the base64-encoded curve25519 key of the sender. * @return the inbound group session. */ - fun getInboundGroupSession(sessionId: String?, senderKey: String?, roomId: String?): OlmInboundGroupSessionWrapper { + fun getInboundGroupSession(sessionId: String?, senderKey: String?, roomId: String?): OlmInboundGroupSessionWrapper2 { if (sessionId.isNullOrBlank() || senderKey.isNullOrBlank()) { throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_SENDER_KEY, MXCryptoError.ERROR_MISSING_PROPERTY_REASON) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt index ebef751925..38dae20a83 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt @@ -66,7 +66,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.tasks.UpdateKeysBacku import im.vector.matrix.android.internal.crypto.keysbackup.util.computeRecoveryKey import im.vector.matrix.android.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult -import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.SavedKeyBackupKeyInfo import im.vector.matrix.android.internal.crypto.store.db.model.KeysBackupDataEntity @@ -1318,7 +1318,7 @@ internal class DefaultKeysBackupService @Inject constructor( @VisibleForTesting @WorkerThread - fun encryptGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper): KeyBackupData { + fun encryptGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2): KeyBackupData { // Gather information for each key val device = cryptoStore.deviceWithIdentityKey(olmInboundGroupSessionWrapper.senderKey!!) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt index 9be08d9f2d..cf1a3b237a 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt @@ -103,11 +103,10 @@ class OlmInboundGroupSessionWrapper : Serializable { /** * Export the inbound group session keys - * @param index the index to export. If null, the first known index will be used * * @return the inbound group session as MegolmSessionData if the operation succeeds */ - fun exportKeys(index: Long? = null): MegolmSessionData? { + fun exportKeys(): MegolmSessionData? { return try { if (null == forwardingCurve25519KeyChain) { forwardingCurve25519KeyChain = ArrayList() @@ -117,8 +116,6 @@ class OlmInboundGroupSessionWrapper : Serializable { return null } - val wantedIndex = index ?: olmInboundGroupSession!!.firstKnownIndex - MegolmSessionData( senderClaimedEd25519Key = keysClaimed?.get("ed25519"), forwardingCurve25519KeyChain = ArrayList(forwardingCurve25519KeyChain!!), @@ -126,7 +123,7 @@ class OlmInboundGroupSessionWrapper : Serializable { senderClaimedKeys = keysClaimed, roomId = roomId, sessionId = olmInboundGroupSession!!.sessionIdentifier(), - sessionKey = olmInboundGroupSession!!.export(wantedIndex), + sessionKey = olmInboundGroupSession!!.export(olmInboundGroupSession!!.firstKnownIndex), algorithm = MXCRYPTO_ALGORITHM_MEGOLM ) } catch (e: Exception) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt new file mode 100755 index 0000000000..c51e707aeb --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * 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 im.vector.matrix.android.internal.crypto.model + +import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM +import im.vector.matrix.android.internal.crypto.MegolmSessionData +import org.matrix.olm.OlmInboundGroupSession +import timber.log.Timber +import java.io.Serializable + +/** + * This class adds more context to a OlmInboundGroupSession object. + * This allows additional checks. The class implements Serializable so that the context can be stored. + */ +class OlmInboundGroupSessionWrapper2 : Serializable { + + // The associated olm inbound group session. + var olmInboundGroupSession: OlmInboundGroupSession? = null + + // The room in which this session is used. + var roomId: String? = null + + // The base64-encoded curve25519 key of the sender. + var senderKey: String? = null + + // Other keys the sender claims. + var keysClaimed: Map? = null + + // Devices which forwarded this session to us (normally empty). + var forwardingCurve25519KeyChain: List? = ArrayList() + + /** + * @return the first known message index + */ + val firstKnownIndex: Long? + get() { + if (null != olmInboundGroupSession) { + try { + return olmInboundGroupSession!!.firstKnownIndex + } catch (e: Exception) { + Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed") + } + } + + return null + } + + /** + * Constructor + * + * @param sessionKey the session key + * @param isImported true if it is an imported session key + */ + constructor(sessionKey: String, isImported: Boolean) { + try { + if (!isImported) { + olmInboundGroupSession = OlmInboundGroupSession(sessionKey) + } else { + olmInboundGroupSession = OlmInboundGroupSession.importSession(sessionKey) + } + } catch (e: Exception) { + Timber.e(e, "Cannot create") + } + } + + constructor() { + // empty + } + /** + * Create a new instance from the provided keys map. + * + * @param megolmSessionData the megolm session data + * @throws Exception if the data are invalid + */ + @Throws(Exception::class) + constructor(megolmSessionData: MegolmSessionData) { + try { + olmInboundGroupSession = OlmInboundGroupSession.importSession(megolmSessionData.sessionKey!!) + + if (olmInboundGroupSession!!.sessionIdentifier() != megolmSessionData.sessionId) { + throw Exception("Mismatched group session Id") + } + + senderKey = megolmSessionData.senderKey + keysClaimed = megolmSessionData.senderClaimedKeys + roomId = megolmSessionData.roomId + } catch (e: Exception) { + throw Exception(e.message) + } + } + + /** + * Export the inbound group session keys + * @param index the index to export. If null, the first known index will be used + * + * @return the inbound group session as MegolmSessionData if the operation succeeds + */ + fun exportKeys(index: Long? = null): MegolmSessionData? { + return try { + if (null == forwardingCurve25519KeyChain) { + forwardingCurve25519KeyChain = ArrayList() + } + + if (keysClaimed == null) { + return null + } + + val wantedIndex = index ?: olmInboundGroupSession!!.firstKnownIndex + + MegolmSessionData( + senderClaimedEd25519Key = keysClaimed?.get("ed25519"), + forwardingCurve25519KeyChain = ArrayList(forwardingCurve25519KeyChain!!), + senderKey = senderKey, + senderClaimedKeys = keysClaimed, + roomId = roomId, + sessionId = olmInboundGroupSession!!.sessionIdentifier(), + sessionKey = olmInboundGroupSession!!.export(wantedIndex), + algorithm = MXCRYPTO_ALGORITHM_MEGOLM + ) + } catch (e: Exception) { + Timber.e(e, "## export() : senderKey $senderKey failed") + null + } + } + + /** + * Export the session for a message index. + * + * @param messageIndex the message index + * @return the exported data + */ + fun exportSession(messageIndex: Long): String? { + if (null != olmInboundGroupSession) { + try { + return olmInboundGroupSession!!.export(messageIndex) + } catch (e: Exception) { + Timber.e(e, "## exportSession() : export failed") + } + } + + return null + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt index 18c85f78fb..888e436ea0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt @@ -30,7 +30,7 @@ import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest import im.vector.matrix.android.internal.crypto.OutgoingSecretRequest import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo -import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.model.OlmSessionWrapper import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody @@ -59,7 +59,7 @@ internal interface IMXCryptoStore { * * @return the list of all known group sessions, to export them. */ - fun getInboundGroupSessions(): List + fun getInboundGroupSessions(): List /** * @return true to unilaterally blacklist all unverified devices. @@ -282,7 +282,7 @@ internal interface IMXCryptoStore { * * @param sessions the inbound group sessions to store. */ - fun storeInboundGroupSessions(sessions: List) + fun storeInboundGroupSessions(sessions: List) /** * Retrieve an inbound group session. @@ -291,7 +291,7 @@ internal interface IMXCryptoStore { * @param senderKey the base64-encoded curve25519 key of the sender. * @return an inbound group session. */ - fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper? + fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper2? /** * Remove an inbound group session @@ -315,7 +315,7 @@ internal interface IMXCryptoStore { * * @param sessions the sessions */ - fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List) + fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List) /** * Retrieve inbound group sessions that are not yet backed up. @@ -323,7 +323,7 @@ internal interface IMXCryptoStore { * @param limit the maximum number of sessions to return. * @return an array of non backed up inbound group sessions. */ - fun inboundGroupSessionsToBackup(limit: Int): List + fun inboundGroupSessionsToBackup(limit: Int): List /** * Number of stored inbound group sessions. diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt index b033272448..ac7f00b531 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt @@ -38,7 +38,7 @@ import im.vector.matrix.android.internal.crypto.OutgoingSecretRequest import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo -import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.model.OlmSessionWrapper import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody @@ -108,7 +108,7 @@ internal class RealmCryptoStore @Inject constructor( private val olmSessionsToRelease = HashMap() // Cache for InboundGroupSession, to release them properly - private val inboundGroupSessionToRelease = HashMap() + private val inboundGroupSessionToRelease = HashMap() private val newSessionListeners = ArrayList() @@ -654,7 +654,7 @@ internal class RealmCryptoStore @Inject constructor( .toMutableSet() } - override fun storeInboundGroupSessions(sessions: List) { + override fun storeInboundGroupSessions(sessions: List) { if (sessions.isEmpty()) { return } @@ -692,7 +692,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper? { + override fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper2? { val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionId, senderKey) // If not in cache (or not found), try to read it from realm @@ -712,10 +712,10 @@ internal class RealmCryptoStore @Inject constructor( } /** - * Note: the result will be only use to export all the keys and not to use the OlmInboundGroupSessionWrapper, + * Note: the result will be only use to export all the keys and not to use the OlmInboundGroupSessionWrapper2, * so there is no need to use or update `inboundGroupSessionToRelease` for native memory management */ - override fun getInboundGroupSessions(): MutableList { + override fun getInboundGroupSessions(): MutableList { return doWithRealm(realmConfiguration) { it.where() .findAll() @@ -787,7 +787,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List) { + override fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List) { if (olmInboundGroupSessionWrappers.isEmpty()) { return } @@ -810,7 +810,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun inboundGroupSessionsToBackup(limit: Int): List { + override fun inboundGroupSessionsToBackup(limit: Int): List { return doWithRealm(realmConfiguration) { it.where() .equalTo(OlmInboundGroupSessionEntityFields.BACKED_UP, false) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt index c1897c76d9..c604250be7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt @@ -21,6 +21,8 @@ import com.squareup.moshi.Types import im.vector.matrix.android.api.extensions.tryThis import im.vector.matrix.android.api.util.JsonDict import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.store.db.mapper.CrossSigningKeysMapper import im.vector.matrix.android.internal.crypto.store.db.model.CrossSigningInfoEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.CryptoMetadataEntityFields @@ -29,6 +31,7 @@ import im.vector.matrix.android.internal.crypto.store.db.model.GossipingEventEnt import im.vector.matrix.android.internal.crypto.store.db.model.IncomingGossipingRequestEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.KeyInfoEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields +import im.vector.matrix.android.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.OutgoingGossipingRequestEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.TrustLevelEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.UserEntityFields @@ -214,6 +217,23 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi } } catch (failure: Throwable) { } + + // Migrate frozen classes + val inboundGroupSessions = realm.where("OlmInboundGroupSessionEntity").findAll() + inboundGroupSessions.forEach { dynamicObject -> + dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { serializedObject -> + try { + deserializeFromRealm(serializedObject)?.let { oldFormat -> + val newFormat = oldFormat.exportKeys()?.let { + OlmInboundGroupSessionWrapper2(it) + } + dynamicObject.setString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA, serializeForRealm(newFormat)) + } + } catch (failure: Throwable) { + Timber.e(failure, "## OlmInboundGroupSessionEntity migration failed") + } + } + } } private fun migrateTo5(realm: DynamicRealm) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt index 763e852cd1..125fc94d1e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt @@ -16,12 +16,12 @@ package im.vector.matrix.android.internal.crypto.store.db.model -import im.vector.matrix.android.api.extensions.tryThis -import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.store.db.deserializeFromRealm import im.vector.matrix.android.internal.crypto.store.db.serializeForRealm import io.realm.RealmObject import io.realm.annotations.PrimaryKey +import timber.log.Timber internal fun OlmInboundGroupSessionEntity.Companion.createPrimaryKey(sessionId: String?, senderKey: String?) = "$sessionId|$senderKey" @@ -36,11 +36,16 @@ internal open class OlmInboundGroupSessionEntity( var backedUp: Boolean = false) : RealmObject() { - fun getInboundGroupSession(): OlmInboundGroupSessionWrapper? { - return tryThis { deserializeFromRealm(olmInboundGroupSessionData) } + fun getInboundGroupSession(): OlmInboundGroupSessionWrapper2? { + return try { + deserializeFromRealm(olmInboundGroupSessionData) + } catch (failure: Throwable) { + Timber.e(failure, "## Deserialization failure") + return null + } } - fun putInboundGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper?) { + fun putInboundGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2?) { olmInboundGroupSessionData = serializeForRealm(olmInboundGroupSessionWrapper) } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt index 0947c144d8..e334603b74 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt @@ -15,7 +15,6 @@ */ package im.vector.riotx.features.crypto.keysbackup.restore -import android.content.Context import android.os.Bundle import android.text.Editable import android.text.SpannableString @@ -70,7 +69,7 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase mPassphraseInputLayout.error = newValue }) - helperTextWithLink.text = spannableStringForHelperText(context!!) + helperTextWithLink.text = spannableStringForHelperText() viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer { val shouldBeVisible = it ?: false @@ -87,9 +86,9 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase } } - private fun spannableStringForHelperText(context: Context): SpannableString { - val clickableText = context.getString(R.string.keys_backup_restore_use_recovery_key) - val helperText = context.getString(R.string.keys_backup_restore_with_passphrase_helper_with_link, clickableText) + private fun spannableStringForHelperText(): SpannableString { + val clickableText = getString(R.string.keys_backup_restore_use_recovery_key) + val helperText = getString(R.string.keys_backup_restore_with_passphrase_helper_with_link, clickableText) val spanString = SpannableString(helperText) @@ -117,7 +116,7 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase fun onRestoreBackup() { val value = viewModel.passphrase.value if (value.isNullOrBlank()) { - viewModel.passphraseErrorText.value = context?.getString(R.string.passphrase_empty_error_message) + viewModel.passphraseErrorText.value = getString(R.string.passphrase_empty_error_message) } else { viewModel.recoverKeys(sharedViewModel) } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt index 46e8d5fa18..9c9c12b824 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt @@ -51,7 +51,7 @@ class KeysBackupRestoreFromPassphraseViewModel @Inject constructor( try { sharedViewModel.recoverUsingBackupPass(passphrase.value!!) } catch (failure: Throwable) { - passphraseErrorText.value = stringProvider.getString(R.string.keys_backup_passphrase_error_decrypt) + passphraseErrorText.postValue(stringProvider.getString(R.string.keys_backup_passphrase_error_decrypt)) } } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index 6b44b9f3d3..695da73f89 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -25,6 +25,7 @@ import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.api.session.room.model.ReferencesAggregatedContent import im.vector.matrix.android.api.session.room.model.message.MessageVerificationRequestContent +import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent import im.vector.matrix.android.api.session.room.timeline.hasBeenEdited @@ -123,7 +124,9 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses } private fun getE2EDecoration(room: Room?, event: TimelineEvent): E2EDecoration { - return if (room?.isEncrypted() == true + return if ( + event.root.sendState == SendState.SYNCED + && room?.isEncrypted() == true // is user verified && session.cryptoService().crossSigningService().getUserCrossSigningKeys(event.root.senderId ?: "")?.isTrusted() == true) { val ts = room.roomSummary()?.encryptionEventTs ?: 0