diff --git a/changelog.d/7879.bugfix b/changelog.d/7879.bugfix
new file mode 100644
index 0000000000..be828ec2cc
--- /dev/null
+++ b/changelog.d/7879.bugfix
@@ -0,0 +1 @@
+Reduce number of crypto database transactions when handling the sync response
diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index 0bd7d0d97e..8064ee5b67 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -3506,4 +3506,7 @@
sent a video.
sent a sticker.
created a poll.
+
+ Access Token
+ Your access token gives full access to your account. Do not share it with anyone.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/UserIdentity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/UserIdentity.kt
new file mode 100644
index 0000000000..071db7f902
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/UserIdentity.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 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.api.session.crypto.crosssigning
+
+/**
+ * Container for the three cross signing keys: master, self signing and user signing.
+ */
+data class UserIdentity(
+ val masterKey: CryptoCrossSigningKey?,
+ val selfSigningKey: CryptoCrossSigningKey?,
+ val userSigningKey: CryptoCrossSigningKey?,
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
index 7862da1c17..50497e3a27 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
@@ -89,6 +89,7 @@ import org.matrix.android.sdk.internal.crypto.model.SessionInfo
import org.matrix.android.sdk.internal.crypto.model.toRest
import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
+import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask
import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask
@@ -192,21 +193,21 @@ internal class DefaultCryptoService @Inject constructor(
private val isStarting = AtomicBoolean(false)
private val isStarted = AtomicBoolean(false)
- fun onStateEvent(roomId: String, event: Event) {
+ fun onStateEvent(roomId: String, event: Event, cryptoStoreAggregator: CryptoStoreAggregator?) {
when (event.type) {
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
- EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
+ EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event, cryptoStoreAggregator)
}
}
- fun onLiveEvent(roomId: String, event: Event, isInitialSync: Boolean) {
+ fun onLiveEvent(roomId: String, event: Event, isInitialSync: Boolean, cryptoStoreAggregator: CryptoStoreAggregator?) {
// handle state events
if (event.isStateEvent()) {
when (event.type) {
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
- EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
+ EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event, cryptoStoreAggregator)
}
}
@@ -430,8 +431,10 @@ internal class DefaultCryptoService @Inject constructor(
* A sync response has been received.
*
* @param syncResponse the syncResponse
+ * @param cryptoStoreAggregator data aggregated during the sync response treatment to store
*/
- fun onSyncCompleted(syncResponse: SyncResponse) {
+ fun onSyncCompleted(syncResponse: SyncResponse, cryptoStoreAggregator: CryptoStoreAggregator) {
+ cryptoStore.storeData(cryptoStoreAggregator)
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
runCatching {
if (syncResponse.deviceLists != null) {
@@ -998,15 +1001,26 @@ internal class DefaultCryptoService @Inject constructor(
}
}
- private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event) {
+ private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event, cryptoStoreAggregator: CryptoStoreAggregator?) {
if (!event.isStateEvent()) return
val eventContent = event.content.toModel()
val historyVisibility = eventContent?.historyVisibility
if (historyVisibility == null) {
- cryptoStore.setShouldShareHistory(roomId, false)
+ if (cryptoStoreAggregator != null) {
+ cryptoStoreAggregator.setShouldShareHistoryData[roomId] = false
+ } else {
+ // Store immediately
+ cryptoStore.setShouldShareHistory(roomId, false)
+ }
} else {
- cryptoStore.setShouldEncryptForInvitedMembers(roomId, historyVisibility != RoomHistoryVisibility.JOINED)
- cryptoStore.setShouldShareHistory(roomId, historyVisibility.shouldShareHistory())
+ if (cryptoStoreAggregator != null) {
+ cryptoStoreAggregator.setShouldEncryptForInvitedMembersData[roomId] = historyVisibility != RoomHistoryVisibility.JOINED
+ cryptoStoreAggregator.setShouldShareHistoryData[roomId] = historyVisibility.shouldShareHistory()
+ } else {
+ // Store immediately
+ cryptoStore.setShouldEncryptForInvitedMembers(roomId, historyVisibility != RoomHistoryVisibility.JOINED)
+ cryptoStore.setShouldShareHistory(roomId, historyVisibility.shouldShareHistory())
+ }
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
index 7e9e156003..364d77f7ac 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
@@ -25,11 +25,13 @@ import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.extensions.measureMetric
import org.matrix.android.sdk.api.metrics.DownloadDeviceKeysMetricsPlugin
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
+import org.matrix.android.sdk.api.session.crypto.crosssigning.UserIdentity
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
import org.matrix.android.sdk.internal.crypto.model.CryptoInfoMapper
import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
+import org.matrix.android.sdk.internal.crypto.store.UserDataToStore
import org.matrix.android.sdk.internal.crypto.tasks.DownloadKeysForUsersTask
import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
@@ -371,6 +373,8 @@ internal class DeviceListManager @Inject constructor(
Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
}
+ val userDataToStore = UserDataToStore()
+
for (userId in filteredUsers) {
// al devices =
val models = response.deviceKeys?.get(userId)?.mapValues { entry -> CryptoInfoMapper.map(entry.value) }
@@ -404,7 +408,7 @@ internal class DeviceListManager @Inject constructor(
}
// Update the store
// Note that devices which aren't in the response will be removed from the stores
- cryptoStore.storeUserDevices(userId, workingCopy)
+ userDataToStore.userDevices[userId] = workingCopy
}
val masterKey = response.masterKeys?.get(userId)?.toCryptoModel().also {
@@ -416,14 +420,15 @@ internal class DeviceListManager @Inject constructor(
val userSigningKey = response.userSigningKeys?.get(userId)?.toCryptoModel()?.also {
Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : USK ${it.unpaddedBase64PublicKey}")
}
- cryptoStore.storeUserCrossSigningKeys(
- userId,
- masterKey,
- selfSigningKey,
- userSigningKey
+ userDataToStore.userIdentities[userId] = UserIdentity(
+ masterKey = masterKey,
+ selfSigningKey = selfSigningKey,
+ userSigningKey = userSigningKey
)
}
+ cryptoStore.storeData(userDataToStore)
+
// Update devices trust for these users
// dispatchDeviceChange(downloadUsers)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
index 21e3342365..0305f73a7b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
@@ -22,9 +22,9 @@ import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig
import org.matrix.android.sdk.api.session.crypto.NewSessionListener
import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest
import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
-import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo
+import org.matrix.android.sdk.api.session.crypto.crosssigning.UserIdentity
import org.matrix.android.sdk.api.session.crypto.keysbackup.SavedKeyBackupKeyInfo
import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
@@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper
+import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
import org.matrix.olm.OlmAccount
import org.matrix.olm.OlmOutboundGroupSession
@@ -230,11 +231,12 @@ internal interface IMXCryptoStore {
*/
fun storeUserDevices(userId: String, devices: Map?)
- fun storeUserCrossSigningKeys(
+ /**
+ * Store the cross signing keys for the user userId.
+ */
+ fun storeUserIdentity(
userId: String,
- masterKey: CryptoCrossSigningKey?,
- selfSigningKey: CryptoCrossSigningKey?,
- userSigningKey: CryptoCrossSigningKey?
+ userIdentity: UserIdentity
)
/**
@@ -290,6 +292,13 @@ internal interface IMXCryptoStore {
fun shouldEncryptForInvitedMembers(roomId: String): Boolean
+ /**
+ * Sets a boolean flag that will determine whether or not this device should encrypt Events for
+ * invited members.
+ *
+ * @param roomId the room id
+ * @param shouldEncryptForInvitedMembers The boolean flag
+ */
fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean)
fun shouldShareHistory(roomId: String): Boolean
@@ -580,4 +589,14 @@ internal interface IMXCryptoStore {
fun areDeviceKeysUploaded(): Boolean
fun tidyUpDataBase()
fun getOutgoingRoomKeyRequests(inStates: Set): List
+
+ /**
+ * Store a bunch of data collected during a sync response treatment. @See [CryptoStoreAggregator].
+ */
+ fun storeData(cryptoStoreAggregator: CryptoStoreAggregator)
+
+ /**
+ * Store a bunch of data related to the users. @See [UserDataToStore].
+ */
+ fun storeData(userDataToStore: UserDataToStore)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/UserDataToStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/UserDataToStore.kt
new file mode 100644
index 0000000000..914ce4704e
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/UserDataToStore.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2023 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.store
+
+import org.matrix.android.sdk.api.session.crypto.crosssigning.UserIdentity
+import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
+
+internal data class UserDataToStore(
+ /**
+ * Map of userId -> (Map of deviceId -> [CryptoDeviceInfo]).
+ */
+ val userDevices: MutableMap> = mutableMapOf(),
+ /**
+ * Map of userId -> [UserIdentity].
+ */
+ val userIdentities: MutableMap = mutableMapOf(),
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/CryptoStoreAggregator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/CryptoStoreAggregator.kt
new file mode 100644
index 0000000000..687ec95ec3
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/CryptoStoreAggregator.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2023 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.store.db
+
+data class CryptoStoreAggregator(
+ val setShouldShareHistoryData: MutableMap = mutableMapOf(),
+ val setShouldEncryptForInvitedMembersData: MutableMap = mutableMapOf(),
+) {
+ fun isEmpty(): Boolean {
+ return setShouldShareHistoryData.isEmpty() &&
+ setShouldEncryptForInvitedMembersData.isEmpty()
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt
index 2d66ce1488..6412df205f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt
@@ -20,10 +20,12 @@ import android.util.Base64
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.RealmObject
+import timber.log.Timber
import java.io.ByteArrayOutputStream
import java.io.ObjectOutputStream
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
+import kotlin.system.measureTimeMillis
/**
* Get realm, invoke the action, close realm, and return the result of the action.
@@ -55,10 +57,12 @@ internal fun doRealmQueryAndCopyList(realmConfiguration: Realm
/**
* Get realm instance, invoke the action in a transaction and close realm.
*/
-internal fun doRealmTransaction(realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) {
- Realm.getInstance(realmConfiguration).use { realm ->
- realm.executeTransaction { action.invoke(it) }
- }
+internal fun doRealmTransaction(tag: String, realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) {
+ measureTimeMillis {
+ Realm.getInstance(realmConfiguration).use { realm ->
+ realm.executeTransaction { action.invoke(it) }
+ }
+ }.also { Timber.w("doRealmTransaction for $tag took $it millis") }
}
internal fun doRealmTransactionAsync(realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt
index 1b52b79746..b4368467a2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt
@@ -33,9 +33,9 @@ import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig
import org.matrix.android.sdk.api.session.crypto.NewSessionListener
import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest
import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
-import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo
+import org.matrix.android.sdk.api.session.crypto.crosssigning.UserIdentity
import org.matrix.android.sdk.api.session.crypto.keysbackup.SavedKeyBackupKeyInfo
import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
@@ -55,6 +55,7 @@ import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrappe
import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
+import org.matrix.android.sdk.internal.crypto.store.UserDataToStore
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
import org.matrix.android.sdk.internal.crypto.store.db.mapper.MyDeviceLastSeenInfoEntityMapper
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntity
@@ -147,7 +148,7 @@ internal class RealmCryptoStore @Inject constructor(
init {
// Ensure CryptoMetadataEntity is inserted in DB
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("init", realmConfiguration) { realm ->
var currentMetadata = realm.where().findFirst()
var deleteAll = false
@@ -189,7 +190,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun deleteStore() {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("deleteStore", realmConfiguration) {
it.deleteAll()
}
}
@@ -218,7 +219,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun storeDeviceId(deviceId: String) {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("storeDeviceId", realmConfiguration) {
it.where().findFirst()?.deviceId = deviceId
}
}
@@ -230,7 +231,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun saveOlmAccount() {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("saveOlmAccount", realmConfiguration) {
it.where().findFirst()?.putOlmAccount(olmAccount)
}
}
@@ -248,7 +249,7 @@ internal class RealmCryptoStore @Inject constructor(
@Synchronized
override fun getOrCreateOlmAccount(): OlmAccount {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("getOrCreateOlmAccount", realmConfiguration) {
val metaData = it.where().findFirst()
val existing = metaData!!.getOlmAccount()
if (existing == null) {
@@ -288,129 +289,139 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun storeUserDevices(userId: String, devices: Map?) {
- doRealmTransaction(realmConfiguration) { realm ->
- if (devices == null) {
- Timber.d("Remove user $userId")
- // Remove the user
- UserEntity.delete(realm, userId)
- } else {
- val userEntity = UserEntity.getOrCreate(realm, userId)
- // First delete the removed devices
- val deviceIds = devices.keys
- userEntity.devices.toTypedArray().iterator().let {
- while (it.hasNext()) {
- val deviceInfoEntity = it.next()
- if (deviceInfoEntity.deviceId !in deviceIds) {
- Timber.d("Remove device ${deviceInfoEntity.deviceId} of user $userId")
- deviceInfoEntity.deleteOnCascade()
- }
+ doRealmTransaction("storeUserDevices", realmConfiguration) { realm ->
+ storeUserDevices(realm, userId, devices)
+ }
+ }
+
+ private fun storeUserDevices(realm: Realm, userId: String, devices: Map?) {
+ if (devices == null) {
+ Timber.d("Remove user $userId")
+ // Remove the user
+ UserEntity.delete(realm, userId)
+ } else {
+ val userEntity = UserEntity.getOrCreate(realm, userId)
+ // First delete the removed devices
+ val deviceIds = devices.keys
+ userEntity.devices.toTypedArray().iterator().let {
+ while (it.hasNext()) {
+ val deviceInfoEntity = it.next()
+ if (deviceInfoEntity.deviceId !in deviceIds) {
+ Timber.d("Remove device ${deviceInfoEntity.deviceId} of user $userId")
+ deviceInfoEntity.deleteOnCascade()
}
}
- // Then update existing devices or add new one
- devices.values.forEach { cryptoDeviceInfo ->
- val existingDeviceInfoEntity = userEntity.devices.firstOrNull { it.deviceId == cryptoDeviceInfo.deviceId }
- if (existingDeviceInfoEntity == null) {
- // Add the device
- Timber.d("Add device ${cryptoDeviceInfo.deviceId} of user $userId")
- val newEntity = CryptoMapper.mapToEntity(cryptoDeviceInfo)
- newEntity.firstTimeSeenLocalTs = clock.epochMillis()
- userEntity.devices.add(newEntity)
- } else {
- // Update the device
- Timber.d("Update device ${cryptoDeviceInfo.deviceId} of user $userId")
- CryptoMapper.updateDeviceInfoEntity(existingDeviceInfoEntity, cryptoDeviceInfo)
- }
+ }
+ // Then update existing devices or add new one
+ devices.values.forEach { cryptoDeviceInfo ->
+ val existingDeviceInfoEntity = userEntity.devices.firstOrNull { it.deviceId == cryptoDeviceInfo.deviceId }
+ if (existingDeviceInfoEntity == null) {
+ // Add the device
+ Timber.d("Add device ${cryptoDeviceInfo.deviceId} of user $userId")
+ val newEntity = CryptoMapper.mapToEntity(cryptoDeviceInfo)
+ newEntity.firstTimeSeenLocalTs = clock.epochMillis()
+ userEntity.devices.add(newEntity)
+ } else {
+ // Update the device
+ Timber.d("Update device ${cryptoDeviceInfo.deviceId} of user $userId")
+ CryptoMapper.updateDeviceInfoEntity(existingDeviceInfoEntity, cryptoDeviceInfo)
}
}
}
}
- override fun storeUserCrossSigningKeys(
+ override fun storeUserIdentity(
userId: String,
- masterKey: CryptoCrossSigningKey?,
- selfSigningKey: CryptoCrossSigningKey?,
- userSigningKey: CryptoCrossSigningKey?
+ userIdentity: UserIdentity,
) {
- doRealmTransaction(realmConfiguration) { realm ->
- UserEntity.getOrCreate(realm, userId)
- .let { userEntity ->
- if (masterKey == null || selfSigningKey == null) {
- // The user has disabled cross signing?
- userEntity.crossSigningInfoEntity?.deleteOnCascade()
- userEntity.crossSigningInfoEntity = null
- } else {
- var shouldResetMyDevicesLocalTrust = false
- CrossSigningInfoEntity.getOrCreate(realm, userId).let { signingInfo ->
- // What should we do if we detect a change of the keys?
- val existingMaster = signingInfo.getMasterKey()
- if (existingMaster != null && existingMaster.publicKeyBase64 == masterKey.unpaddedBase64PublicKey) {
- crossSigningKeysMapper.update(existingMaster, masterKey)
- } else {
- Timber.d("## CrossSigning MSK change for $userId")
- val keyEntity = crossSigningKeysMapper.map(masterKey)
- signingInfo.setMasterKey(keyEntity)
- if (userId == this.userId) {
- shouldResetMyDevicesLocalTrust = true
- // my msk has changed! clear my private key
- // Could we have some race here? e.g I am the one that did change the keys
- // could i get this update to early and clear the private keys?
- // -> initializeCrossSigning is guarding for that by storing all at once
- realm.where().findFirst()?.apply {
- xSignMasterPrivateKey = null
- }
+ doRealmTransaction("storeUserIdentity", realmConfiguration) { realm ->
+ storeUserIdentity(realm, userId, userIdentity)
+ }
+ }
+
+ private fun storeUserIdentity(
+ realm: Realm,
+ userId: String,
+ userIdentity: UserIdentity,
+ ) {
+ UserEntity.getOrCreate(realm, userId)
+ .let { userEntity ->
+ if (userIdentity.masterKey == null || userIdentity.selfSigningKey == null) {
+ // The user has disabled cross signing?
+ userEntity.crossSigningInfoEntity?.deleteOnCascade()
+ userEntity.crossSigningInfoEntity = null
+ } else {
+ var shouldResetMyDevicesLocalTrust = false
+ CrossSigningInfoEntity.getOrCreate(realm, userId).let { signingInfo ->
+ // What should we do if we detect a change of the keys?
+ val existingMaster = signingInfo.getMasterKey()
+ if (existingMaster != null && existingMaster.publicKeyBase64 == userIdentity.masterKey.unpaddedBase64PublicKey) {
+ crossSigningKeysMapper.update(existingMaster, userIdentity.masterKey)
+ } else {
+ Timber.d("## CrossSigning MSK change for $userId")
+ val keyEntity = crossSigningKeysMapper.map(userIdentity.masterKey)
+ signingInfo.setMasterKey(keyEntity)
+ if (userId == this.userId) {
+ shouldResetMyDevicesLocalTrust = true
+ // my msk has changed! clear my private key
+ // Could we have some race here? e.g I am the one that did change the keys
+ // could i get this update to early and clear the private keys?
+ // -> initializeCrossSigning is guarding for that by storing all at once
+ realm.where().findFirst()?.apply {
+ xSignMasterPrivateKey = null
}
}
-
- val existingSelfSigned = signingInfo.getSelfSignedKey()
- if (existingSelfSigned != null && existingSelfSigned.publicKeyBase64 == selfSigningKey.unpaddedBase64PublicKey) {
- crossSigningKeysMapper.update(existingSelfSigned, selfSigningKey)
- } else {
- Timber.d("## CrossSigning SSK change for $userId")
- val keyEntity = crossSigningKeysMapper.map(selfSigningKey)
- signingInfo.setSelfSignedKey(keyEntity)
- if (userId == this.userId) {
- shouldResetMyDevicesLocalTrust = true
- // my ssk has changed! clear my private key
- realm.where().findFirst()?.apply {
- xSignSelfSignedPrivateKey = null
- }
- }
- }
-
- // Only for me
- if (userSigningKey != null) {
- val existingUSK = signingInfo.getUserSigningKey()
- if (existingUSK != null && existingUSK.publicKeyBase64 == userSigningKey.unpaddedBase64PublicKey) {
- crossSigningKeysMapper.update(existingUSK, userSigningKey)
- } else {
- Timber.d("## CrossSigning USK change for $userId")
- val keyEntity = crossSigningKeysMapper.map(userSigningKey)
- signingInfo.setUserSignedKey(keyEntity)
- if (userId == this.userId) {
- shouldResetMyDevicesLocalTrust = true
- // my usk has changed! clear my private key
- realm.where().findFirst()?.apply {
- xSignUserPrivateKey = null
- }
- }
- }
- }
-
- // When my cross signing keys are reset, we consider clearing all existing device trust
- if (shouldResetMyDevicesLocalTrust) {
- realm.where()
- .equalTo(UserEntityFields.USER_ID, this.userId)
- .findFirst()
- ?.devices?.forEach {
- it?.trustLevelEntity?.crossSignedVerified = false
- it?.trustLevelEntity?.locallyVerified = it.deviceId == deviceId
- }
- }
- userEntity.crossSigningInfoEntity = signingInfo
}
+
+ val existingSelfSigned = signingInfo.getSelfSignedKey()
+ if (existingSelfSigned != null && existingSelfSigned.publicKeyBase64 == userIdentity.selfSigningKey.unpaddedBase64PublicKey) {
+ crossSigningKeysMapper.update(existingSelfSigned, userIdentity.selfSigningKey)
+ } else {
+ Timber.d("## CrossSigning SSK change for $userId")
+ val keyEntity = crossSigningKeysMapper.map(userIdentity.selfSigningKey)
+ signingInfo.setSelfSignedKey(keyEntity)
+ if (userId == this.userId) {
+ shouldResetMyDevicesLocalTrust = true
+ // my ssk has changed! clear my private key
+ realm.where().findFirst()?.apply {
+ xSignSelfSignedPrivateKey = null
+ }
+ }
+ }
+
+ // Only for me
+ if (userIdentity.userSigningKey != null) {
+ val existingUSK = signingInfo.getUserSigningKey()
+ if (existingUSK != null && existingUSK.publicKeyBase64 == userIdentity.userSigningKey.unpaddedBase64PublicKey) {
+ crossSigningKeysMapper.update(existingUSK, userIdentity.userSigningKey)
+ } else {
+ Timber.d("## CrossSigning USK change for $userId")
+ val keyEntity = crossSigningKeysMapper.map(userIdentity.userSigningKey)
+ signingInfo.setUserSignedKey(keyEntity)
+ if (userId == this.userId) {
+ shouldResetMyDevicesLocalTrust = true
+ // my usk has changed! clear my private key
+ realm.where().findFirst()?.apply {
+ xSignUserPrivateKey = null
+ }
+ }
+ }
+ }
+
+ // When my cross signing keys are reset, we consider clearing all existing device trust
+ if (shouldResetMyDevicesLocalTrust) {
+ realm.where()
+ .equalTo(UserEntityFields.USER_ID, this.userId)
+ .findFirst()
+ ?.devices?.forEach {
+ it?.trustLevelEntity?.crossSignedVerified = false
+ it?.trustLevelEntity?.locallyVerified = it.deviceId == deviceId
+ }
+ }
+ userEntity.crossSigningInfoEntity = signingInfo
}
}
- }
+ }
}
override fun getCrossSigningPrivateKeys(): PrivateKeysInfo? {
@@ -480,7 +491,7 @@ internal class RealmCryptoStore @Inject constructor(
override fun storePrivateKeysInfo(msk: String?, usk: String?, ssk: String?) {
Timber.v("## CRYPTO | *** storePrivateKeysInfo ${msk != null}, ${usk != null}, ${ssk != null}")
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("storePrivateKeysInfo", realmConfiguration) { realm ->
realm.where().findFirst()?.apply {
xSignMasterPrivateKey = msk
xSignUserPrivateKey = usk
@@ -490,7 +501,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun saveBackupRecoveryKey(recoveryKey: String?, version: String?) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("saveBackupRecoveryKey", realmConfiguration) { realm ->
realm.where().findFirst()?.apply {
keyBackupRecoveryKey = recoveryKey
keyBackupRecoveryKeyVersion = version
@@ -516,7 +527,7 @@ internal class RealmCryptoStore @Inject constructor(
override fun storeMSKPrivateKey(msk: String?) {
Timber.v("## CRYPTO | *** storeMSKPrivateKey ${msk != null} ")
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("storeMSKPrivateKey", realmConfiguration) { realm ->
realm.where().findFirst()?.apply {
xSignMasterPrivateKey = msk
}
@@ -525,7 +536,7 @@ internal class RealmCryptoStore @Inject constructor(
override fun storeSSKPrivateKey(ssk: String?) {
Timber.v("## CRYPTO | *** storeSSKPrivateKey ${ssk != null} ")
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("storeSSKPrivateKey", realmConfiguration) { realm ->
realm.where().findFirst()?.apply {
xSignSelfSignedPrivateKey = ssk
}
@@ -534,7 +545,7 @@ internal class RealmCryptoStore @Inject constructor(
override fun storeUSKPrivateKey(usk: String?) {
Timber.v("## CRYPTO | *** storeUSKPrivateKey ${usk != null} ")
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("storeUSKPrivateKey", realmConfiguration) { realm ->
realm.where().findFirst()?.apply {
xSignUserPrivateKey = usk
}
@@ -667,7 +678,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun storeRoomAlgorithm(roomId: String, algorithm: String?) {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("storeRoomAlgorithm", realmConfiguration) {
CryptoRoomEntity.getOrCreate(it, roomId).let { entity ->
entity.algorithm = algorithm
// store anyway the new algorithm, but mark the room
@@ -708,7 +719,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean) {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("setShouldEncryptForInvitedMembers", realmConfiguration) {
CryptoRoomEntity.getOrCreate(it, roomId).shouldEncryptForInvitedMembers = shouldEncryptForInvitedMembers
}
}
@@ -716,7 +727,7 @@ internal class RealmCryptoStore @Inject constructor(
override fun setShouldShareHistory(roomId: String, shouldShareHistory: Boolean) {
Timber.tag(loggerTag.value)
.v("setShouldShareHistory for room $roomId is $shouldShareHistory")
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("setShouldShareHistory", realmConfiguration) {
CryptoRoomEntity.getOrCreate(it, roomId).shouldShareHistory = shouldShareHistory
}
}
@@ -733,7 +744,7 @@ internal class RealmCryptoStore @Inject constructor(
if (sessionIdentifier != null) {
val key = OlmSessionEntity.createPrimaryKey(sessionIdentifier, deviceKey)
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("storeSession", realmConfiguration) {
val realmOlmSession = OlmSessionEntity().apply {
primaryKey = key
sessionId = sessionIdentifier
@@ -790,7 +801,7 @@ internal class RealmCryptoStore @Inject constructor(
return
}
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("storeInboundGroupSessions", realmConfiguration) { realm ->
sessions.forEach { wrapper ->
val sessionIdentifier = try {
@@ -914,7 +925,7 @@ internal class RealmCryptoStore @Inject constructor(
override fun removeInboundGroupSession(sessionId: String, senderKey: String) {
val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionId, senderKey)
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("removeInboundGroupSession", realmConfiguration) {
it.where()
.equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
.findAll()
@@ -933,7 +944,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun setKeyBackupVersion(keyBackupVersion: String?) {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("setKeyBackupVersion", realmConfiguration) {
it.where().findFirst()?.backupVersion = keyBackupVersion
}
}
@@ -945,7 +956,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun setKeysBackupData(keysBackupData: KeysBackupDataEntity?) {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("setKeysBackupData", realmConfiguration) {
if (keysBackupData == null) {
// Clear the table
it.where()
@@ -959,7 +970,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun resetBackupMarkers() {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("resetBackupMarkers", realmConfiguration) {
it.where()
.findAll()
.map { inboundGroupSession ->
@@ -973,7 +984,7 @@ internal class RealmCryptoStore @Inject constructor(
return
}
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("markBackupDoneForInboundGroupSessions", realmConfiguration) { realm ->
olmInboundGroupSessionWrappers.forEach { olmInboundGroupSessionWrapper ->
try {
val sessionIdentifier =
@@ -1032,13 +1043,13 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun setGlobalBlacklistUnverifiedDevices(block: Boolean) {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("setGlobalBlacklistUnverifiedDevices", realmConfiguration) {
it.where().findFirst()?.globalBlacklistUnverifiedDevices = block
}
}
override fun enableKeyGossiping(enable: Boolean) {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("enableKeyGossiping", realmConfiguration) {
it.where().findFirst()?.globalEnableKeyGossiping = enable
}
}
@@ -1062,13 +1073,13 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun enableShareKeyOnInvite(enable: Boolean) {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("enableShareKeyOnInvite", realmConfiguration) {
it.where().findFirst()?.enableKeyForwardingOnInvite = enable
}
}
override fun setDeviceKeysUploaded(uploaded: Boolean) {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("setDeviceKeysUploaded", realmConfiguration) {
it.where().findFirst()?.deviceKeysSentToServer = uploaded
}
}
@@ -1115,7 +1126,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun blockUnverifiedDevicesInRoom(roomId: String, block: Boolean) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("blockUnverifiedDevicesInRoom", realmConfiguration) { realm ->
CryptoRoomEntity.getById(realm, roomId)
?.blacklistUnverifiedDevices = block
}
@@ -1135,7 +1146,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun saveDeviceTrackingStatuses(deviceTrackingStatuses: Map) {
- doRealmTransaction(realmConfiguration) {
+ doRealmTransaction("saveDeviceTrackingStatuses", realmConfiguration) {
deviceTrackingStatuses
.map { entry ->
UserEntity.getOrCreate(it, entry.key)
@@ -1268,7 +1279,7 @@ internal class RealmCryptoStore @Inject constructor(
): OutgoingKeyRequest {
// Insert the request and return the one passed in parameter
lateinit var request: OutgoingKeyRequest
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("getOrAddOutgoingRoomKeyRequest", realmConfiguration) { realm ->
val existing = realm.where()
.equalTo(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, requestBody.sessionId)
@@ -1306,7 +1317,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun updateOutgoingRoomKeyRequestState(requestId: String, newState: OutgoingRoomKeyRequestState) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("updateOutgoingRoomKeyRequestState", realmConfiguration) { realm ->
realm.where()
.equalTo(OutgoingKeyRequestEntityFields.REQUEST_ID, requestId)
.findFirst()?.apply {
@@ -1320,7 +1331,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun updateOutgoingRoomKeyRequiredIndex(requestId: String, newIndex: Int) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("updateOutgoingRoomKeyRequiredIndex", realmConfiguration) { realm ->
realm.where()
.equalTo(OutgoingKeyRequestEntityFields.REQUEST_ID, requestId)
.findFirst()?.apply {
@@ -1337,7 +1348,7 @@ internal class RealmCryptoStore @Inject constructor(
fromDevice: String?,
event: Event
) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("updateOutgoingRoomKeyReply", realmConfiguration) { realm ->
realm.where()
.equalTo(OutgoingKeyRequestEntityFields.ROOM_ID, roomId)
.equalTo(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, sessionId)
@@ -1353,7 +1364,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun deleteOutgoingRoomKeyRequest(requestId: String) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("deleteOutgoingRoomKeyRequest", realmConfiguration) { realm ->
realm.where()
.equalTo(OutgoingKeyRequestEntityFields.REQUEST_ID, requestId)
.findFirst()?.deleteOnCascade()
@@ -1361,7 +1372,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun deleteOutgoingRoomKeyRequestInState(state: OutgoingRoomKeyRequestState) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("deleteOutgoingRoomKeyRequestInState", realmConfiguration) { realm ->
realm.where()
.equalTo(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, state.name)
.findAll()
@@ -1497,7 +1508,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun setMyCrossSigningInfo(info: MXCrossSigningInfo?) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("setMyCrossSigningInfo", realmConfiguration) { realm ->
realm.where().findFirst()?.userId?.let { userId ->
addOrUpdateCrossSigningInfo(realm, userId, info)
}
@@ -1505,7 +1516,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun setUserKeysAsTrusted(userId: String, trusted: Boolean) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("setUserKeysAsTrusted", realmConfiguration) { realm ->
val xInfoEntity = realm.where(CrossSigningInfoEntity::class.java)
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
.findFirst()
@@ -1525,7 +1536,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun setDeviceTrust(userId: String, deviceId: String, crossSignedVerified: Boolean, locallyVerified: Boolean?) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("setDeviceTrust", realmConfiguration) { realm ->
realm.where(DeviceInfoEntity::class.java)
.equalTo(DeviceInfoEntityFields.PRIMARY_KEY, DeviceInfoEntity.createPrimaryKey(userId, deviceId))
.findFirst()?.let { deviceInfoEntity ->
@@ -1545,7 +1556,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun clearOtherUserTrust() {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("clearOtherUserTrust", realmConfiguration) { realm ->
val xInfoEntities = realm.where(CrossSigningInfoEntity::class.java)
.findAll()
xInfoEntities?.forEach { info ->
@@ -1560,7 +1571,7 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun updateUsersTrust(check: (String) -> Boolean) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("updateUsersTrust", realmConfiguration) { realm ->
val xInfoEntities = realm.where(CrossSigningInfoEntity::class.java)
.findAll()
xInfoEntities?.forEach { xInfoEntity ->
@@ -1668,13 +1679,13 @@ internal class RealmCryptoStore @Inject constructor(
}
override fun setCrossSigningInfo(userId: String, info: MXCrossSigningInfo?) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("setCrossSigningInfo", realmConfiguration) { realm ->
addOrUpdateCrossSigningInfo(realm, userId, info)
}
}
override fun markMyMasterKeyAsLocallyTrusted(trusted: Boolean) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("markMyMasterKeyAsLocallyTrusted", realmConfiguration) { realm ->
realm.where().findFirst()?.userId?.let { myUserId ->
CrossSigningInfoEntity.get(realm, myUserId)?.getMasterKey()?.let { xInfoEntity ->
val level = xInfoEntity.trustLevelEntity
@@ -1713,7 +1724,7 @@ internal class RealmCryptoStore @Inject constructor(
val roomId = withHeldContent.roomId ?: return
val sessionId = withHeldContent.sessionId ?: return
if (withHeldContent.algorithm != MXCRYPTO_ALGORITHM_MEGOLM) return
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("addWithHeldMegolmSession", realmConfiguration) { realm ->
WithHeldSessionEntity.getOrCreate(realm, roomId, sessionId)?.let {
it.code = withHeldContent.code
it.senderKey = withHeldContent.senderKey
@@ -1745,7 +1756,7 @@ internal class RealmCryptoStore @Inject constructor(
deviceIdentityKey: String,
chainIndex: Int
) {
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("markedSessionAsShared", realmConfiguration) { realm ->
SharedSessionEntity.create(
realm = realm,
roomId = roomId,
@@ -1794,7 +1805,7 @@ internal class RealmCryptoStore @Inject constructor(
*/
override fun tidyUpDataBase() {
val prevWeekTs = clock.epochMillis() - 7 * 24 * 60 * 60 * 1_000
- doRealmTransaction(realmConfiguration) { realm ->
+ doRealmTransaction("tidyUpDataBase", realmConfiguration) { realm ->
// Clean the old ones?
realm.where()
@@ -1815,4 +1826,31 @@ internal class RealmCryptoStore @Inject constructor(
// Can we do something for WithHeldSessionEntity?
}
}
+
+ override fun storeData(cryptoStoreAggregator: CryptoStoreAggregator) {
+ if (cryptoStoreAggregator.isEmpty()) {
+ return
+ }
+ doRealmTransaction("storeData - CryptoStoreAggregator", realmConfiguration) { realm ->
+ // setShouldShareHistory
+ cryptoStoreAggregator.setShouldShareHistoryData.forEach {
+ CryptoRoomEntity.getOrCreate(realm, it.key).shouldShareHistory = it.value
+ }
+ // setShouldEncryptForInvitedMembers
+ cryptoStoreAggregator.setShouldEncryptForInvitedMembersData.forEach {
+ CryptoRoomEntity.getOrCreate(realm, it.key).shouldEncryptForInvitedMembers = it.value
+ }
+ }
+ }
+
+ override fun storeData(userDataToStore: UserDataToStore) {
+ doRealmTransaction("storeData - UserDataToStore", realmConfiguration) { realm ->
+ userDataToStore.userDevices.forEach {
+ storeUserDevices(realm, it.key, it.value)
+ }
+ userDataToStore.userIdentities.forEach {
+ storeUserIdentity(realm, it.key, it.value)
+ }
+ }
+ }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt
index cfc26045a0..ce34b0430e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt
@@ -42,14 +42,12 @@ internal class StreamEventsManager @Inject constructor() {
listeners.remove(listener)
}
- fun dispatchLiveEventReceived(event: Event, roomId: String, initialSync: Boolean) {
+ fun dispatchLiveEventReceived(event: Event, roomId: String) {
Timber.v("## dispatchLiveEventReceived ${event.eventId}")
coroutineScope.launch {
- if (!initialSync) {
- listeners.forEach {
- tryOrNull {
- it.onLiveEvent(roomId, event)
- }
+ listeners.forEach {
+ tryOrNull {
+ it.onLiveEvent(roomId, event)
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt
index 793c2573be..653069b3c8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt
@@ -176,7 +176,7 @@ internal class DefaultCreateLocalRoomTask @Inject constructor(
}
// Give info to crypto module
- cryptoService.onStateEvent(roomId, event)
+ cryptoService.onStateEvent(roomId, event, null)
}
roomMemberContentsByUser.getOrPut(event.senderId) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
index 05d50d9595..cb407bb1cb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
@@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
import org.matrix.android.sdk.internal.SessionManager
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
+import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.di.SessionId
import org.matrix.android.sdk.internal.session.SessionListeners
@@ -92,7 +93,7 @@ internal class SyncResponseHandler @Inject constructor(
postTreatmentSyncResponse(syncResponse, isInitialSync)
- markCryptoSyncCompleted(syncResponse)
+ markCryptoSyncCompleted(syncResponse, aggregator.cryptoStoreAggregator)
handlePostSync()
@@ -218,10 +219,10 @@ internal class SyncResponseHandler @Inject constructor(
}
}
- private fun markCryptoSyncCompleted(syncResponse: SyncResponse) {
+ private fun markCryptoSyncCompleted(syncResponse: SyncResponse, cryptoStoreAggregator: CryptoStoreAggregator) {
relevantPlugins.measureSpan("task", "crypto_sync_handler_onSyncCompleted") {
measureTimeMillis {
- cryptoSyncHandler.onSyncCompleted(syncResponse)
+ cryptoSyncHandler.onSyncCompleted(syncResponse, cryptoStoreAggregator)
}.also {
Timber.v("cryptoSyncHandler.onSyncCompleted took $it ms")
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt
index 2b7f936fa8..af05e08da3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt
@@ -16,6 +16,8 @@
package org.matrix.android.sdk.internal.session.sync
+import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
+
internal class SyncResponsePostTreatmentAggregator {
// List of RoomId
val ephemeralFilesToDelete = mutableListOf()
@@ -28,4 +30,7 @@ internal class SyncResponsePostTreatmentAggregator {
// Set of users to call `crossSigningService.checkTrustAndAffectedRoomShields` once per sync
val userIdsForCheckingTrustAndAffectedRoomShields = mutableSetOf()
+
+ // For the crypto store
+ val cryptoStoreAggregator = CryptoStoreAggregator()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt
index 551db52dbd..7224b0c29c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt
@@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
import org.matrix.android.sdk.api.session.sync.model.ToDeviceSyncResponse
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
+import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
import org.matrix.android.sdk.internal.crypto.tasks.toDeviceTracingId
import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService
import org.matrix.android.sdk.internal.session.sync.ProgressReporter
@@ -85,8 +86,8 @@ internal class CryptoSyncHandler @Inject constructor(
}
}
- fun onSyncCompleted(syncResponse: SyncResponse) {
- cryptoService.onSyncCompleted(syncResponse)
+ fun onSyncCompleted(syncResponse: SyncResponse, cryptoStoreAggregator: CryptoStoreAggregator) {
+ cryptoService.onSyncCompleted(syncResponse, cryptoStoreAggregator)
}
/**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt
index 4001ae2ccf..5e4886ce1e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt
@@ -258,7 +258,7 @@ internal class RoomSyncHandler @Inject constructor(
root = eventEntity
}
// Give info to crypto module
- cryptoService.onStateEvent(roomId, event)
+ cryptoService.onStateEvent(roomId, event, aggregator.cryptoStoreAggregator)
roomMemberEventHandler.handle(realm, roomId, event, isInitialSync, aggregator)
}
}
@@ -376,8 +376,15 @@ internal class RoomSyncHandler @Inject constructor(
roomEntity.chunks.clearWith { it.deleteOnCascade(deleteStateEvents = true, canDeleteRoot = true) }
roomTypingUsersHandler.handle(realm, roomId, null)
roomChangeMembershipStateDataSource.setMembershipFromSync(roomId, Membership.LEAVE)
- roomSummaryUpdater.update(realm, roomId, membership, roomSync.summary,
- roomSync.unreadNotifications, roomSync.unreadThreadNotifications, aggregator = aggregator)
+ roomSummaryUpdater.update(
+ realm,
+ roomId,
+ membership,
+ roomSync.summary,
+ roomSync.unreadNotifications,
+ roomSync.unreadThreadNotifications,
+ aggregator = aggregator,
+ )
return roomEntity
}
@@ -423,7 +430,9 @@ internal class RoomSyncHandler @Inject constructor(
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
eventIds.add(event.eventId)
- liveEventService.get().dispatchLiveEventReceived(event, roomId, isInitialSync)
+ if (!isInitialSync) {
+ liveEventService.get().dispatchLiveEventReceived(event, roomId)
+ }
if (event.isEncrypted() && !isInitialSync) {
try {
@@ -486,7 +495,7 @@ internal class RoomSyncHandler @Inject constructor(
}
}
// Give info to crypto module
- cryptoService.onLiveEvent(roomEntity.roomId, event, isInitialSync)
+ cryptoService.onLiveEvent(roomEntity.roomId, event, isInitialSync, aggregator.cryptoStoreAggregator)
// Try to remove local echo
event.unsignedData?.transactionId?.also { txId ->
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt
index b6fa997f41..514f2529e9 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt
@@ -25,6 +25,7 @@ import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.preference.VectorPreference
import im.vector.app.core.preference.VectorPreferenceCategory
import im.vector.app.core.preference.VectorSwitchPreference
+import im.vector.app.core.utils.copyToClipboard
import im.vector.app.features.analytics.plan.MobileScreen
import im.vector.app.features.home.NightlyProxy
import im.vector.app.features.rageshake.RageShake
@@ -64,6 +65,14 @@ class VectorSettingsAdvancedSettingsFragment :
override fun bindPref() {
setupRageShakeSection()
setupNightlySection()
+ setupDevToolsSection()
+ }
+
+ private fun setupDevToolsSection() {
+ findPreference("SETTINGS_ACCESS_TOKEN")?.setOnPreferenceClickListener {
+ copyToClipboard(requireActivity(), session.sessionParams.credentials.accessToken)
+ true
+ }
}
private fun setupRageShakeSection() {
diff --git a/vector/src/main/res/xml/vector_settings_advanced_settings.xml b/vector/src/main/res/xml/vector_settings_advanced_settings.xml
index 9260b33162..6399d54cbb 100644
--- a/vector/src/main/res/xml/vector_settings_advanced_settings.xml
+++ b/vector/src/main/res/xml/vector_settings_advanced_settings.xml
@@ -93,6 +93,12 @@
android:title="@string/settings_key_requests"
app:fragment="im.vector.app.features.settings.devtools.KeyRequestsFragment" />
+
+