Compare commits
15 Commits
develop
...
feature/bm
Author | SHA1 | Date |
---|---|---|
Benoit Marty | dbf3b76331 | |
Benoit Marty | 27d32188bf | |
Benoit Marty | 30940cb937 | |
Benoit Marty | 7e26c4b6f2 | |
Benoit Marty | 437b93cc18 | |
Benoit Marty | 06f3c11010 | |
Benoit Marty | 02e7157206 | |
Benoit Marty | 4c4ef0d73e | |
Benoit Marty | f26178fc21 | |
Benoit Marty | a386a4762c | |
Benoit Marty | c1a8bf828b | |
Benoit Marty | 6f384c799f | |
Benoit Marty | 0e504e9014 | |
Benoit Marty | 837590104d | |
Benoit Marty | 56986c3a77 |
|
@ -0,0 +1 @@
|
|||
Reduce number of crypto database transactions when handling the sync response
|
|
@ -3501,4 +3501,7 @@
|
|||
<string name="message_reply_to_sender_sent_video">sent a video.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">sent a sticker.</string>
|
||||
<string name="message_reply_to_sender_created_poll">created a poll.</string>
|
||||
|
||||
<string name="settings_access_token">Access Token</string>
|
||||
<string name="settings_access_token_summary">Your access token gives full access to your account. Do not share it with anyone.</string>
|
||||
</resources>
|
||||
|
|
|
@ -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?,
|
||||
)
|
|
@ -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<RoomHistoryVisibilityContent>()
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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<String, CryptoDeviceInfo>?)
|
||||
|
||||
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<OutgoingRoomKeyRequestState>): List<OutgoingKeyRequest>
|
||||
|
||||
/**
|
||||
* 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)
|
||||
}
|
||||
|
|
|
@ -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<String, Map<String, CryptoDeviceInfo>> = mutableMapOf(),
|
||||
/**
|
||||
* Map of userId -> [UserIdentity].
|
||||
*/
|
||||
val userIdentities: MutableMap<String, UserIdentity> = mutableMapOf(),
|
||||
)
|
|
@ -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<String, Boolean> = mutableMapOf(),
|
||||
val setShouldEncryptForInvitedMembersData: MutableMap<String, Boolean> = mutableMapOf(),
|
||||
) {
|
||||
fun isEmpty(): Boolean {
|
||||
return setShouldShareHistoryData.isEmpty() &&
|
||||
setShouldEncryptForInvitedMembersData.isEmpty()
|
||||
}
|
||||
}
|
|
@ -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 <T : RealmObject> 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) {
|
||||
|
|
|
@ -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<CryptoMetadataEntity>().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<CryptoMetadataEntity>().findFirst()?.deviceId = deviceId
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +231,7 @@ internal class RealmCryptoStore @Inject constructor(
|
|||
}
|
||||
|
||||
override fun saveOlmAccount() {
|
||||
doRealmTransaction(realmConfiguration) {
|
||||
doRealmTransaction("saveOlmAccount", realmConfiguration) {
|
||||
it.where<CryptoMetadataEntity>().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<CryptoMetadataEntity>().findFirst()
|
||||
val existing = metaData!!.getOlmAccount()
|
||||
if (existing == null) {
|
||||
|
@ -288,129 +289,139 @@ internal class RealmCryptoStore @Inject constructor(
|
|||
}
|
||||
|
||||
override fun storeUserDevices(userId: String, devices: Map<String, CryptoDeviceInfo>?) {
|
||||
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<String, CryptoDeviceInfo>?) {
|
||||
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<CryptoMetadataEntity>().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<CryptoMetadataEntity>().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<CryptoMetadataEntity>().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<CryptoMetadataEntity>().findFirst()?.apply {
|
||||
xSignUserPrivateKey = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When my cross signing keys are reset, we consider clearing all existing device trust
|
||||
if (shouldResetMyDevicesLocalTrust) {
|
||||
realm.where<UserEntity>()
|
||||
.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<CryptoMetadataEntity>().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<CryptoMetadataEntity>().findFirst()?.apply {
|
||||
xSignUserPrivateKey = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When my cross signing keys are reset, we consider clearing all existing device trust
|
||||
if (shouldResetMyDevicesLocalTrust) {
|
||||
realm.where<UserEntity>()
|
||||
.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<CryptoMetadataEntity>().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<CryptoMetadataEntity>().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<CryptoMetadataEntity>().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<CryptoMetadataEntity>().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<CryptoMetadataEntity>().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<OlmInboundGroupSessionEntity>()
|
||||
.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<CryptoMetadataEntity>().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<KeysBackupDataEntity>()
|
||||
|
@ -959,7 +970,7 @@ internal class RealmCryptoStore @Inject constructor(
|
|||
}
|
||||
|
||||
override fun resetBackupMarkers() {
|
||||
doRealmTransaction(realmConfiguration) {
|
||||
doRealmTransaction("resetBackupMarkers", realmConfiguration) {
|
||||
it.where<OlmInboundGroupSessionEntity>()
|
||||
.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<CryptoMetadataEntity>().findFirst()?.globalBlacklistUnverifiedDevices = block
|
||||
}
|
||||
}
|
||||
|
||||
override fun enableKeyGossiping(enable: Boolean) {
|
||||
doRealmTransaction(realmConfiguration) {
|
||||
doRealmTransaction("enableKeyGossiping", realmConfiguration) {
|
||||
it.where<CryptoMetadataEntity>().findFirst()?.globalEnableKeyGossiping = enable
|
||||
}
|
||||
}
|
||||
|
@ -1062,13 +1073,13 @@ internal class RealmCryptoStore @Inject constructor(
|
|||
}
|
||||
|
||||
override fun enableShareKeyOnInvite(enable: Boolean) {
|
||||
doRealmTransaction(realmConfiguration) {
|
||||
doRealmTransaction("enableShareKeyOnInvite", realmConfiguration) {
|
||||
it.where<CryptoMetadataEntity>().findFirst()?.enableKeyForwardingOnInvite = enable
|
||||
}
|
||||
}
|
||||
|
||||
override fun setDeviceKeysUploaded(uploaded: Boolean) {
|
||||
doRealmTransaction(realmConfiguration) {
|
||||
doRealmTransaction("setDeviceKeysUploaded", realmConfiguration) {
|
||||
it.where<CryptoMetadataEntity>().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<String, Int>) {
|
||||
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<OutgoingKeyRequestEntity>()
|
||||
.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<OutgoingKeyRequestEntity>()
|
||||
.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<OutgoingKeyRequestEntity>()
|
||||
.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<OutgoingKeyRequestEntity>()
|
||||
.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<OutgoingKeyRequestEntity>()
|
||||
.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<OutgoingKeyRequestEntity>()
|
||||
.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<CryptoMetadataEntity>().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<CryptoMetadataEntity>().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<OutgoingKeyRequestEntity>()
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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<String>()
|
||||
|
@ -28,4 +30,7 @@ internal class SyncResponsePostTreatmentAggregator {
|
|||
|
||||
// Set of users to call `crossSigningService.checkTrustAndAffectedRoomShields` once per sync
|
||||
val userIdsForCheckingTrustAndAffectedRoomShields = mutableSetOf<String>()
|
||||
|
||||
// For the crypto store
|
||||
val cryptoStoreAggregator = CryptoStoreAggregator()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 ->
|
||||
|
|
|
@ -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<VectorPreference>("SETTINGS_ACCESS_TOKEN")?.setOnPreferenceClickListener {
|
||||
copyToClipboard(requireActivity(), session.sessionParams.credentials.accessToken)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupRageShakeSection() {
|
||||
|
|
|
@ -93,6 +93,12 @@
|
|||
android:title="@string/settings_key_requests"
|
||||
app:fragment="im.vector.app.features.settings.devtools.KeyRequestsFragment" />
|
||||
|
||||
<im.vector.app.core.preference.VectorPreference
|
||||
android:key="SETTINGS_ACCESS_TOKEN"
|
||||
android:persistent="false"
|
||||
android:summary="@string/settings_access_token_summary"
|
||||
android:title="@string/settings_access_token" />
|
||||
|
||||
</im.vector.app.core.preference.VectorPreferenceCategory>
|
||||
|
||||
<im.vector.app.core.preference.VectorPreferenceCategory
|
||||
|
|
Loading…
Reference in New Issue