mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Extract common crypto interface for all flavors
This commit is contained in:
parent
8f69e411d7
commit
3bf5c0cc1b
@ -59,6 +59,7 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreRoomSessionD
|
|||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreRoomSessionsDataTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreRoomSessionsDataTask
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.IMXCommonCryptoStore
|
||||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore
|
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreMigration
|
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreMigration
|
||||||
@ -254,6 +255,9 @@ internal abstract class CryptoModule {
|
|||||||
@Binds
|
@Binds
|
||||||
abstract fun bindCryptoStore(store: RealmCryptoStore): IMXCryptoStore
|
abstract fun bindCryptoStore(store: RealmCryptoStore): IMXCryptoStore
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindCommonCryptoStore(store: RealmCryptoStore): IMXCommonCryptoStore
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindSendEventTask(task: DefaultSendEventTask): SendEventTask
|
abstract fun bindSendEventTask(task: DefaultSendEventTask): SendEventTask
|
||||||
|
|
||||||
|
@ -506,10 +506,7 @@ internal class DefaultCryptoService @Inject constructor(
|
|||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
withContext(coroutineDispatchers.io) {
|
withContext(coroutineDispatchers.io) {
|
||||||
cryptoStore.deviceWithIdentityKey(senderKey).takeIf {
|
cryptoStore.deviceWithIdentityKey(userId, senderKey)
|
||||||
// check that the claimed user id matches
|
|
||||||
it?.userId == userId
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,20 +28,16 @@ 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.keysbackup.SavedKeyBackupKeyInfo
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
|
import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoRoomInfo
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
|
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
|
import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.TrailType
|
import org.matrix.android.sdk.api.session.crypto.model.TrailType
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
|
import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
|
||||||
import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
|
import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
|
||||||
import org.matrix.android.sdk.api.util.Optional
|
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.MXInboundMegolmSessionWrapper
|
||||||
import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
|
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.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.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
|
||||||
import org.matrix.olm.OlmAccount
|
import org.matrix.olm.OlmAccount
|
||||||
import org.matrix.olm.OlmOutboundGroupSession
|
import org.matrix.olm.OlmOutboundGroupSession
|
||||||
@ -49,7 +45,7 @@ import org.matrix.olm.OlmOutboundGroupSession
|
|||||||
/**
|
/**
|
||||||
* The crypto data store.
|
* The crypto data store.
|
||||||
*/
|
*/
|
||||||
internal interface IMXCryptoStore {
|
internal interface IMXCryptoStore : IMXCommonCryptoStore {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the device id
|
* @return the device id
|
||||||
@ -78,21 +74,6 @@ internal interface IMXCryptoStore {
|
|||||||
*/
|
*/
|
||||||
fun getInboundGroupSessions(roomId: String): List<MXInboundMegolmSessionWrapper>
|
fun getInboundGroupSessions(roomId: String): List<MXInboundMegolmSessionWrapper>
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true to unilaterally blacklist all unverified devices.
|
|
||||||
*/
|
|
||||||
fun getGlobalBlacklistUnverifiedDevices(): Boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the global override for whether the client should ever send encrypted
|
|
||||||
* messages to unverified devices.
|
|
||||||
* If false, it can still be overridden per-room.
|
|
||||||
* If true, it overrides the per-room settings.
|
|
||||||
*
|
|
||||||
* @param block true to unilaterally blacklist all
|
|
||||||
*/
|
|
||||||
fun setGlobalBlacklistUnverifiedDevices(block: Boolean)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable or disable key gossiping.
|
* Enable or disable key gossiping.
|
||||||
* Default is true.
|
* Default is true.
|
||||||
@ -123,28 +104,6 @@ internal interface IMXCryptoStore {
|
|||||||
*/
|
*/
|
||||||
fun getRoomsListBlacklistUnverifiedDevices(): List<String>
|
fun getRoomsListBlacklistUnverifiedDevices(): List<String>
|
||||||
|
|
||||||
/**
|
|
||||||
* A live status regarding sharing keys for unverified devices in this room.
|
|
||||||
*
|
|
||||||
* @return Live status
|
|
||||||
*/
|
|
||||||
fun getLiveBlockUnverifiedDevices(roomId: String): LiveData<Boolean>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell if unverified devices should be blacklisted when sending keys.
|
|
||||||
*
|
|
||||||
* @return true if should not send keys to unverified devices
|
|
||||||
*/
|
|
||||||
fun getBlockUnverifiedDevices(roomId: String): Boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define if encryption keys should be sent to unverified devices in this room.
|
|
||||||
*
|
|
||||||
* @param roomId the roomId
|
|
||||||
* @param block if true will not send keys to unverified devices
|
|
||||||
*/
|
|
||||||
fun blockUnverifiedDevicesInRoom(roomId: String, block: Boolean)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current keys backup version.
|
* Get the current keys backup version.
|
||||||
*/
|
*/
|
||||||
@ -186,16 +145,6 @@ internal interface IMXCryptoStore {
|
|||||||
*/
|
*/
|
||||||
fun deleteStore()
|
fun deleteStore()
|
||||||
|
|
||||||
/**
|
|
||||||
* open any existing crypto store.
|
|
||||||
*/
|
|
||||||
fun open()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the store.
|
|
||||||
*/
|
|
||||||
fun close()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store the device id.
|
* Store the device id.
|
||||||
*
|
*
|
||||||
@ -262,14 +211,6 @@ internal interface IMXCryptoStore {
|
|||||||
|
|
||||||
fun getLiveDeviceWithId(deviceId: String): LiveData<Optional<CryptoDeviceInfo>>
|
fun getLiveDeviceWithId(deviceId: String): LiveData<Optional<CryptoDeviceInfo>>
|
||||||
|
|
||||||
fun getMyDevicesInfo(): List<DeviceInfo>
|
|
||||||
|
|
||||||
fun getLiveMyDevicesInfo(): LiveData<List<DeviceInfo>>
|
|
||||||
|
|
||||||
fun getLiveMyDevicesInfo(deviceId: String): LiveData<Optional<DeviceInfo>>
|
|
||||||
|
|
||||||
fun saveMyDevicesInfo(info: List<DeviceInfo>)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store the crypto algorithm for a room.
|
* Store the crypto algorithm for a room.
|
||||||
*
|
*
|
||||||
@ -278,47 +219,8 @@ internal interface IMXCryptoStore {
|
|||||||
*/
|
*/
|
||||||
fun storeRoomAlgorithm(roomId: String, algorithm: String?)
|
fun storeRoomAlgorithm(roomId: String, algorithm: String?)
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides the algorithm used in a dedicated room.
|
|
||||||
*
|
|
||||||
* @param roomId the room id
|
|
||||||
* @return the algorithm, null is the room is not encrypted
|
|
||||||
*/
|
|
||||||
fun getRoomAlgorithm(roomId: String): String?
|
|
||||||
|
|
||||||
fun getRoomCryptoInfo(roomId: String): CryptoRoomInfo?
|
|
||||||
fun setAlgorithmInfo(roomId: String, encryption: EncryptionEventContent?)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a bit different than isRoomEncrypted.
|
|
||||||
* A room is encrypted when there is a m.room.encryption state event in the room (malformed/invalid or not).
|
|
||||||
* But the crypto layer has additional guaranty to ensure that encryption would never been reverted.
|
|
||||||
* It's defensive coding out of precaution (if ever state is reset).
|
|
||||||
*/
|
|
||||||
fun roomWasOnceEncrypted(roomId: String): Boolean
|
|
||||||
|
|
||||||
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
|
fun shouldShareHistory(roomId: String): Boolean
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a boolean flag that will determine whether or not room history (existing inbound sessions)
|
|
||||||
* will be shared to new user invites.
|
|
||||||
*
|
|
||||||
* @param roomId the room id
|
|
||||||
* @param shouldShareHistory The boolean flag
|
|
||||||
*/
|
|
||||||
fun setShouldShareHistory(roomId: String, shouldShareHistory: Boolean)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store a session between the logged-in user and another device.
|
* Store a session between the logged-in user and another device.
|
||||||
*
|
*
|
||||||
@ -361,15 +263,6 @@ internal interface IMXCryptoStore {
|
|||||||
*/
|
*/
|
||||||
fun storeInboundGroupSessions(sessions: List<MXInboundMegolmSessionWrapper>)
|
fun storeInboundGroupSessions(sessions: List<MXInboundMegolmSessionWrapper>)
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve an inbound group session.
|
|
||||||
*
|
|
||||||
* @param sessionId the session identifier.
|
|
||||||
* @param senderKey the base64-encoded curve25519 key of the sender.
|
|
||||||
* @return an inbound group session.
|
|
||||||
*/
|
|
||||||
fun getInboundGroupSession(sessionId: String, senderKey: String): MXInboundMegolmSessionWrapper?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve an inbound group session, filtering shared history.
|
* Retrieve an inbound group session, filtering shared history.
|
||||||
*
|
*
|
||||||
@ -552,7 +445,6 @@ internal interface IMXCryptoStore {
|
|||||||
// fun getCrossSigningPrivateKeysFlow(): Flow<Optional<PrivateKeysInfo>>
|
// fun getCrossSigningPrivateKeysFlow(): Flow<Optional<PrivateKeysInfo>>
|
||||||
|
|
||||||
fun getGlobalCryptoConfig(): GlobalCryptoConfig
|
fun getGlobalCryptoConfig(): GlobalCryptoConfig
|
||||||
fun getLiveGlobalCryptoConfig(): LiveData<GlobalCryptoConfig>
|
|
||||||
|
|
||||||
fun saveBackupRecoveryKey(recoveryKey: String?, version: String?)
|
fun saveBackupRecoveryKey(recoveryKey: String?, version: String?)
|
||||||
fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo?
|
fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo?
|
||||||
@ -597,14 +489,8 @@ internal interface IMXCryptoStore {
|
|||||||
|
|
||||||
fun setDeviceKeysUploaded(uploaded: Boolean)
|
fun setDeviceKeysUploaded(uploaded: Boolean)
|
||||||
fun areDeviceKeysUploaded(): Boolean
|
fun areDeviceKeysUploaded(): Boolean
|
||||||
fun tidyUpDataBase()
|
|
||||||
fun getOutgoingRoomKeyRequests(inStates: Set<OutgoingRoomKeyRequestState>): List<OutgoingKeyRequest>
|
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].
|
* Store a bunch of data related to the users. @See [UserDataToStore].
|
||||||
*/
|
*/
|
@ -280,6 +280,19 @@ internal class RealmCryptoStore @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deviceWithIdentityKey(userId: String, identityKey: String): CryptoDeviceInfo? {
|
||||||
|
return doWithRealm(realmConfiguration) { realm ->
|
||||||
|
realm.where<DeviceInfoEntity>()
|
||||||
|
.equalTo(DeviceInfoEntityFields.USER_ID, userId)
|
||||||
|
.contains(DeviceInfoEntityFields.KEYS_MAP_JSON, identityKey)
|
||||||
|
.findAll()
|
||||||
|
.mapNotNull { CryptoMapper.mapToModel(it) }
|
||||||
|
.firstOrNull {
|
||||||
|
it.identityKey() == identityKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun storeUserDevices(userId: String, devices: Map<String, CryptoDeviceInfo>?) {
|
override fun storeUserDevices(userId: String, devices: Map<String, CryptoDeviceInfo>?) {
|
||||||
doRealmTransaction("storeUserDevices", realmConfiguration) { realm ->
|
doRealmTransaction("storeUserDevices", realmConfiguration) { realm ->
|
||||||
storeUserDevices(realm, userId, devices)
|
storeUserDevices(realm, userId, devices)
|
@ -17,11 +17,11 @@
|
|||||||
package org.matrix.android.sdk.internal.crypto
|
package org.matrix.android.sdk.internal.crypto
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.crypto.MXCryptoConfig
|
import org.matrix.android.sdk.api.crypto.MXCryptoConfig
|
||||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
import org.matrix.android.sdk.internal.crypto.store.IMXCommonCryptoStore
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class ShouldEncryptForInvitedMembersUseCase @Inject constructor(private val cryptoConfig: MXCryptoConfig,
|
internal class ShouldEncryptForInvitedMembersUseCase @Inject constructor(private val cryptoConfig: MXCryptoConfig,
|
||||||
private val cryptoStore: IMXCryptoStore) {
|
private val cryptoStore: IMXCommonCryptoStore) {
|
||||||
|
|
||||||
operator fun invoke(roomId: String): Boolean {
|
operator fun invoke(roomId: String): Boolean {
|
||||||
return cryptoConfig.enableEncryptionForInvitedMembers && cryptoStore.shouldEncryptForInvitedMembers(roomId)
|
return cryptoConfig.enableEncryptionForInvitedMembers && cryptoStore.shouldEncryptForInvitedMembers(roomId)
|
||||||
|
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* 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.internal.crypto.store
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.model.CryptoRoomInfo
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent
|
||||||
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
|
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As a temporary measure rust and kotlin flavor are still using realm to store some crypto
|
||||||
|
* related information. In the near future rust flavor will complitly stop using realm, as soon
|
||||||
|
* as the missing bits are store in rust side (like room encryption settings, ..)
|
||||||
|
* This interface defines what's now used by both flavors.
|
||||||
|
* The actual implementation are moved in each flavors
|
||||||
|
*/
|
||||||
|
interface IMXCommonCryptoStore {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the algorithm used in a dedicated room.
|
||||||
|
*
|
||||||
|
* @param roomId the room id
|
||||||
|
* @return the algorithm, null is the room is not encrypted
|
||||||
|
*/
|
||||||
|
fun getRoomAlgorithm(roomId: String): String?
|
||||||
|
|
||||||
|
fun getRoomCryptoInfo(roomId: String): CryptoRoomInfo?
|
||||||
|
|
||||||
|
fun setAlgorithmInfo(roomId: String, encryption: EncryptionEventContent?)
|
||||||
|
|
||||||
|
fun roomWasOnceEncrypted(roomId: String): Boolean
|
||||||
|
|
||||||
|
fun saveMyDevicesInfo(info: List<DeviceInfo>)
|
||||||
|
|
||||||
|
// questionable that it's stored in crypto store
|
||||||
|
fun getMyDevicesInfo(): List<DeviceInfo>
|
||||||
|
|
||||||
|
// questionable that it's stored in crypto store
|
||||||
|
fun getLiveMyDevicesInfo(): LiveData<List<DeviceInfo>>
|
||||||
|
|
||||||
|
// questionable that it's stored in crypto store
|
||||||
|
fun getLiveMyDevicesInfo(deviceId: String): LiveData<Optional<DeviceInfo>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* open any existing crypto store.
|
||||||
|
*/
|
||||||
|
fun open()
|
||||||
|
fun tidyUpDataBase()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the store.
|
||||||
|
*/
|
||||||
|
fun close()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store a bunch of data collected during a sync response treatment. @See [CryptoStoreAggregator].
|
||||||
|
*/
|
||||||
|
fun storeData(cryptoStoreAggregator: CryptoStoreAggregator)
|
||||||
|
|
||||||
|
fun shouldEncryptForInvitedMembers(roomId: String): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a boolean flag that will determine whether or not room history (existing inbound sessions)
|
||||||
|
* will be shared to new user invites.
|
||||||
|
*
|
||||||
|
* @param roomId the room id
|
||||||
|
* @param shouldShareHistory The boolean flag
|
||||||
|
*/
|
||||||
|
fun setShouldShareHistory(roomId: String, shouldShareHistory: 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)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define if encryption keys should be sent to unverified devices in this room.
|
||||||
|
*
|
||||||
|
* @param roomId the roomId
|
||||||
|
* @param block if true will not send keys to unverified devices
|
||||||
|
*/
|
||||||
|
fun blockUnverifiedDevicesInRoom(roomId: String, block: Boolean)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the global override for whether the client should ever send encrypted
|
||||||
|
* messages to unverified devices.
|
||||||
|
* If false, it can still be overridden per-room.
|
||||||
|
* If true, it overrides the per-room settings.
|
||||||
|
*
|
||||||
|
* @param block true to unilaterally blacklist all
|
||||||
|
*/
|
||||||
|
fun setGlobalBlacklistUnverifiedDevices(block: Boolean)
|
||||||
|
|
||||||
|
fun getLiveGlobalCryptoConfig(): LiveData<GlobalCryptoConfig>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true to unilaterally blacklist all unverified devices.
|
||||||
|
*/
|
||||||
|
fun getGlobalBlacklistUnverifiedDevices(): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A live status regarding sharing keys for unverified devices in this room.
|
||||||
|
*
|
||||||
|
* @return Live status
|
||||||
|
*/
|
||||||
|
fun getLiveBlockUnverifiedDevices(roomId: String): LiveData<Boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell if unverified devices should be blacklisted when sending keys.
|
||||||
|
*
|
||||||
|
* @return true if should not send keys to unverified devices
|
||||||
|
*/
|
||||||
|
fun getBlockUnverifiedDevices(roomId: String): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a device by its identity key.
|
||||||
|
*
|
||||||
|
* @param userId the device owner
|
||||||
|
* @param identityKey the device identity key (`MXDeviceInfo.identityKey`)
|
||||||
|
* @return the device or null if not found
|
||||||
|
*/
|
||||||
|
fun deviceWithIdentityKey(userId: String, identityKey: String): CryptoDeviceInfo?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an inbound group session.
|
||||||
|
* Used in rust for lazy migration
|
||||||
|
*
|
||||||
|
* @param sessionId the session identifier.
|
||||||
|
* @param senderKey the base64-encoded curve25519 key of the sender.
|
||||||
|
* @return an inbound group session.
|
||||||
|
*/
|
||||||
|
fun getInboundGroupSession(sessionId: String, senderKey: String): MXInboundMegolmSessionWrapper?
|
||||||
|
}
|
@ -26,11 +26,11 @@ import org.matrix.android.sdk.api.session.events.model.toModel
|
|||||||
import org.matrix.android.sdk.api.session.events.model.toValidDecryptedEvent
|
import org.matrix.android.sdk.api.session.events.model.toValidDecryptedEvent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
||||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
import org.matrix.android.sdk.internal.crypto.store.IMXCommonCryptoStore
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class EventEditValidator @Inject constructor(val cryptoStore: IMXCryptoStore) {
|
internal class EventEditValidator @Inject constructor(val cryptoStore: IMXCommonCryptoStore) {
|
||||||
|
|
||||||
sealed class EditValidity {
|
sealed class EditValidity {
|
||||||
object Valid : EditValidity()
|
object Valid : EditValidity()
|
||||||
@ -80,25 +80,21 @@ internal class EventEditValidator @Inject constructor(val cryptoStore: IMXCrypto
|
|||||||
val replaceDecrypted = replaceEvent.toValidDecryptedEvent()
|
val replaceDecrypted = replaceEvent.toValidDecryptedEvent()
|
||||||
?: return EditValidity.Unknown // UTD can't decide
|
?: return EditValidity.Unknown // UTD can't decide
|
||||||
|
|
||||||
val originalCryptoSenderId = cryptoStore.deviceWithIdentityKey(originalDecrypted.cryptoSenderKey)?.userId
|
if (originalEvent.senderId != replaceEvent.senderId) {
|
||||||
val editCryptoSenderId = cryptoStore.deviceWithIdentityKey(replaceDecrypted.cryptoSenderKey)?.userId
|
return EditValidity.Invalid("original event and replacement event must have the same sender")
|
||||||
|
}
|
||||||
|
|
||||||
|
val originalSendingDevice = originalEvent.senderId?.let { cryptoStore.deviceWithIdentityKey(it, originalDecrypted.cryptoSenderKey) }
|
||||||
|
val editSendingDevice = originalEvent.senderId?.let { cryptoStore.deviceWithIdentityKey(it, replaceDecrypted.cryptoSenderKey) }
|
||||||
|
|
||||||
if (originalDecrypted.getRelationContent()?.type == RelationType.REPLACE) {
|
if (originalDecrypted.getRelationContent()?.type == RelationType.REPLACE) {
|
||||||
return EditValidity.Invalid("The original event must not, itself, have a rel_type of m.replace ")
|
return EditValidity.Invalid("The original event must not, itself, have a rel_type of m.replace ")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (originalCryptoSenderId == null || editCryptoSenderId == null) {
|
if (originalSendingDevice == null || editSendingDevice == null) {
|
||||||
// mm what can we do? we don't know if it's cryptographically from same user?
|
// mm what can we do? we don't know if it's cryptographically from same user?
|
||||||
// let valid and UI should display send by deleted device warning?
|
// maybe it's a deleted device or a not yet downloaded one?
|
||||||
val bestEffortOriginal = originalCryptoSenderId ?: originalEvent.senderId
|
return EditValidity.Unknown
|
||||||
val bestEffortEdit = editCryptoSenderId ?: replaceEvent.senderId
|
|
||||||
if (bestEffortOriginal != bestEffortEdit) {
|
|
||||||
return EditValidity.Invalid("original event and replacement event must have the same sender")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (originalCryptoSenderId != editCryptoSenderId) {
|
|
||||||
return EditValidity.Invalid("Crypto: original event and replacement event must have the same sender")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (originalDecrypted.type != replaceDecrypted.type) {
|
if (originalDecrypted.type != replaceDecrypted.type) {
|
||||||
|
@ -49,7 +49,7 @@ import org.matrix.android.sdk.api.util.CancelableBag
|
|||||||
import org.matrix.android.sdk.api.util.JsonDict
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
import org.matrix.android.sdk.api.util.NoOpCancellable
|
import org.matrix.android.sdk.api.util.NoOpCancellable
|
||||||
import org.matrix.android.sdk.api.util.TextContent
|
import org.matrix.android.sdk.api.util.TextContent
|
||||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
import org.matrix.android.sdk.internal.crypto.store.IMXCommonCryptoStore
|
||||||
import org.matrix.android.sdk.internal.di.SessionId
|
import org.matrix.android.sdk.internal.di.SessionId
|
||||||
import org.matrix.android.sdk.internal.di.WorkManagerProvider
|
import org.matrix.android.sdk.internal.di.WorkManagerProvider
|
||||||
import org.matrix.android.sdk.internal.session.content.UploadContentWorker
|
import org.matrix.android.sdk.internal.session.content.UploadContentWorker
|
||||||
@ -69,7 +69,7 @@ internal class DefaultSendService @AssistedInject constructor(
|
|||||||
private val workManagerProvider: WorkManagerProvider,
|
private val workManagerProvider: WorkManagerProvider,
|
||||||
@SessionId private val sessionId: String,
|
@SessionId private val sessionId: String,
|
||||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||||
private val cryptoStore: IMXCryptoStore,
|
private val cryptoStore: IMXCommonCryptoStore,
|
||||||
private val taskExecutor: TaskExecutor,
|
private val taskExecutor: TaskExecutor,
|
||||||
private val localEchoRepository: LocalEchoRepository,
|
private val localEchoRepository: LocalEchoRepository,
|
||||||
private val eventSenderProcessor: EventSenderProcessor,
|
private val eventSenderProcessor: EventSenderProcessor,
|
||||||
|
@ -28,7 +28,7 @@ import org.matrix.android.sdk.api.failure.isLimitExceededError
|
|||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.api.util.Cancelable
|
import org.matrix.android.sdk.api.util.Cancelable
|
||||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
import org.matrix.android.sdk.internal.crypto.store.IMXCommonCryptoStore
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
import org.matrix.android.sdk.internal.task.CoroutineSequencer
|
import org.matrix.android.sdk.internal.task.CoroutineSequencer
|
||||||
import org.matrix.android.sdk.internal.task.SemaphoreCoroutineSequencer
|
import org.matrix.android.sdk.internal.task.SemaphoreCoroutineSequencer
|
||||||
@ -54,7 +54,7 @@ private const val MAX_RETRY_COUNT = 3
|
|||||||
*/
|
*/
|
||||||
@SessionScope
|
@SessionScope
|
||||||
internal class EventSenderProcessorCoroutine @Inject constructor(
|
internal class EventSenderProcessorCoroutine @Inject constructor(
|
||||||
private val cryptoStore: IMXCryptoStore,
|
private val cryptoStore: IMXCommonCryptoStore,
|
||||||
private val sessionParams: SessionParams,
|
private val sessionParams: SessionParams,
|
||||||
private val queuedTaskFactory: QueuedTaskFactory,
|
private val queuedTaskFactory: QueuedTaskFactory,
|
||||||
private val taskExecutor: TaskExecutor,
|
private val taskExecutor: TaskExecutor,
|
||||||
|
@ -58,8 +58,8 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreRoomSessionD
|
|||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreRoomSessionsDataTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreRoomSessionsDataTask
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
|
||||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
import org.matrix.android.sdk.internal.crypto.store.IMXCommonCryptoStore
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore
|
import org.matrix.android.sdk.internal.crypto.store.RustCryptoStore
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreMigration
|
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreMigration
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule
|
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask
|
import org.matrix.android.sdk.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask
|
||||||
@ -246,7 +246,7 @@ internal abstract class CryptoModule {
|
|||||||
abstract fun bindVerificationService(service: RustVerificationService): VerificationService
|
abstract fun bindVerificationService(service: RustVerificationService): VerificationService
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindCryptoStore(store: RealmCryptoStore): IMXCryptoStore
|
abstract fun bindCryptoStore(store: RustCryptoStore): IMXCommonCryptoStore
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindSendEventTask(task: DefaultSendEventTask): SendEventTask
|
abstract fun bindSendEventTask(task: DefaultSendEventTask): SendEventTask
|
||||||
|
@ -54,6 +54,7 @@ import org.matrix.android.sdk.api.util.toOptional
|
|||||||
import org.matrix.android.sdk.internal.coroutines.builder.safeInvokeOnClose
|
import org.matrix.android.sdk.internal.coroutines.builder.safeInvokeOnClose
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.DefaultKeysAlgorithmAndData
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.DefaultKeysAlgorithmAndData
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysAlgorithmAndData
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysAlgorithmAndData
|
||||||
|
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
|
||||||
import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.SasVerification
|
import org.matrix.android.sdk.internal.crypto.verification.SasVerification
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest
|
import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest
|
||||||
@ -312,10 +313,10 @@ internal class OlmMachine @Inject constructor(
|
|||||||
/**
|
/**
|
||||||
* Used for lazy migration of inboundGroupSession from EA to ER
|
* Used for lazy migration of inboundGroupSession from EA to ER
|
||||||
*/
|
*/
|
||||||
suspend fun importRoomKey(inbound: InboundGroupSessionHolder): Result<Unit> {
|
suspend fun importRoomKey(inbound: MXInboundMegolmSessionWrapper): Result<Unit> {
|
||||||
Timber.v("Migration:: Tentative lazy migration")
|
Timber.v("Migration:: Tentative lazy migration")
|
||||||
return withContext(coroutineDispatchers.io) {
|
return withContext(coroutineDispatchers.io) {
|
||||||
val export = inbound.wrapper.exportKeys()
|
val export = inbound.exportKeys()
|
||||||
?: return@withContext Result.failure(Exception("Failed to export key"))
|
?: return@withContext Result.failure(Exception("Failed to export key"))
|
||||||
val result = importDecryptedKeys(listOf(export), null).also {
|
val result = importDecryptedKeys(listOf(export), null).also {
|
||||||
Timber.v("Migration:: Tentative lazy migration result: ${it.totalNumberOfKeys}")
|
Timber.v("Migration:: Tentative lazy migration result: ${it.totalNumberOfKeys}")
|
||||||
|
@ -28,7 +28,7 @@ import org.matrix.android.sdk.api.logger.LoggerTag
|
|||||||
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
|
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.RustKeyBackupService
|
import org.matrix.android.sdk.internal.crypto.keysbackup.RustKeyBackupService
|
||||||
import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
||||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
import org.matrix.android.sdk.internal.crypto.store.IMXCommonCryptoStore
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask
|
import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask
|
||||||
import org.matrix.rustcomponents.sdk.crypto.EncryptionSettings
|
import org.matrix.rustcomponents.sdk.crypto.EncryptionSettings
|
||||||
@ -47,7 +47,7 @@ private val loggerTag = LoggerTag("PrepareToEncryptUseCase", LoggerTag.CRYPTO)
|
|||||||
internal class PrepareToEncryptUseCase @Inject constructor(
|
internal class PrepareToEncryptUseCase @Inject constructor(
|
||||||
private val olmMachine: OlmMachine,
|
private val olmMachine: OlmMachine,
|
||||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
private val cryptoStore: IMXCryptoStore,
|
private val cryptoStore: IMXCommonCryptoStore,
|
||||||
private val getRoomUserIds: GetRoomUserIdsUseCase,
|
private val getRoomUserIds: GetRoomUserIdsUseCase,
|
||||||
private val requestSender: RequestSender,
|
private val requestSender: RequestSender,
|
||||||
private val loadRoomMembersTask: LoadRoomMembersTask,
|
private val loadRoomMembersTask: LoadRoomMembersTask,
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
package org.matrix.android.sdk.internal.crypto
|
package org.matrix.android.sdk.internal.crypto
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.annotation.VisibleForTesting
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.map
|
import androidx.lifecycle.map
|
||||||
import androidx.paging.PagedList
|
import androidx.paging.PagedList
|
||||||
@ -76,7 +75,7 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.RustKeyBackupService
|
|||||||
import org.matrix.android.sdk.internal.crypto.model.SessionInfo
|
import org.matrix.android.sdk.internal.crypto.model.SessionInfo
|
||||||
import org.matrix.android.sdk.internal.crypto.network.OutgoingRequestsProcessor
|
import org.matrix.android.sdk.internal.crypto.network.OutgoingRequestsProcessor
|
||||||
import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
|
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.IMXCommonCryptoStore
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
|
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.DeleteDeviceTask
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
|
import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
|
||||||
@ -111,7 +110,7 @@ internal class RustCryptoService @Inject constructor(
|
|||||||
@UserId private val myUserId: String,
|
@UserId private val myUserId: String,
|
||||||
@DeviceId private val deviceId: String,
|
@DeviceId private val deviceId: String,
|
||||||
// the crypto store
|
// the crypto store
|
||||||
private val cryptoStore: IMXCryptoStore,
|
private val cryptoStore: IMXCommonCryptoStore,
|
||||||
// Set of parameters used to configure/customize the end-to-end crypto.
|
// Set of parameters used to configure/customize the end-to-end crypto.
|
||||||
private val mxCryptoConfig: MXCryptoConfig,
|
private val mxCryptoConfig: MXCryptoConfig,
|
||||||
// Actions
|
// Actions
|
||||||
@ -903,13 +902,6 @@ internal class RustCryptoService @Inject constructor(
|
|||||||
// TODO("Not yet implemented")
|
// TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================================
|
|
||||||
* For test only
|
|
||||||
* ========================================================================================== */
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
val cryptoStoreForTesting = cryptoStore
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS = 3_600_000 // one hour
|
const val CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS = 3_600_000 // one hour
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
||||||
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.failure.Failure
|
import org.matrix.android.sdk.api.failure.Failure
|
||||||
import org.matrix.android.sdk.api.failure.MatrixError
|
import org.matrix.android.sdk.api.failure.MatrixError
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupLastVersionResult
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupLastVersionResult
|
||||||
@ -36,7 +37,6 @@ import org.matrix.android.sdk.api.session.events.model.Event
|
|||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.api.session.uia.UiaResult
|
import org.matrix.android.sdk.api.session.uia.UiaResult
|
||||||
import org.matrix.android.sdk.internal.auth.registration.handleUIA
|
import org.matrix.android.sdk.internal.auth.registration.handleUIA
|
||||||
import org.matrix.android.sdk.internal.crypto.InboundGroupSessionStore
|
|
||||||
import org.matrix.android.sdk.internal.crypto.OlmMachine
|
import org.matrix.android.sdk.internal.crypto.OlmMachine
|
||||||
import org.matrix.android.sdk.internal.crypto.PerSessionBackupQueryRateLimiter
|
import org.matrix.android.sdk.internal.crypto.PerSessionBackupQueryRateLimiter
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.BackupKeysResult
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.BackupKeysResult
|
||||||
@ -59,6 +59,7 @@ import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadBody
|
|||||||
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
|
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.RestKeyInfo
|
import org.matrix.android.sdk.internal.crypto.model.rest.RestKeyInfo
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.SignatureUploadResponse
|
import org.matrix.android.sdk.internal.crypto.model.rest.SignatureUploadResponse
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.IMXCommonCryptoStore
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask
|
import org.matrix.android.sdk.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.DefaultSendVerificationMessageTask
|
import org.matrix.android.sdk.internal.crypto.tasks.DefaultSendVerificationMessageTask
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.DownloadKeysForUsersTask
|
import org.matrix.android.sdk.internal.crypto.tasks.DownloadKeysForUsersTask
|
||||||
@ -102,7 +103,7 @@ internal class RequestSender @Inject constructor(
|
|||||||
private val moshi: Moshi,
|
private val moshi: Moshi,
|
||||||
cryptoCoroutineScope: CoroutineScope,
|
cryptoCoroutineScope: CoroutineScope,
|
||||||
private val rateLimiter: PerSessionBackupQueryRateLimiter,
|
private val rateLimiter: PerSessionBackupQueryRateLimiter,
|
||||||
private val inboundGroupSessionStore: InboundGroupSessionStore,
|
private val cryptoStore: IMXCommonCryptoStore,
|
||||||
private val localEchoRepository: LocalEchoRepository,
|
private val localEchoRepository: LocalEchoRepository,
|
||||||
private val olmMachine: Lazy<OlmMachine>,
|
private val olmMachine: Lazy<OlmMachine>,
|
||||||
) {
|
) {
|
||||||
@ -266,7 +267,9 @@ internal class RequestSender @Inject constructor(
|
|||||||
val senderKey = requestBody?.get("sender_key") as? String
|
val senderKey = requestBody?.get("sender_key") as? String
|
||||||
if (roomId != null && sessionId != null) {
|
if (roomId != null && sessionId != null) {
|
||||||
// try to perform a lazy migration from legacy store
|
// try to perform a lazy migration from legacy store
|
||||||
val legacy = inboundGroupSessionStore.getInboundGroupSession(sessionId, senderKey.orEmpty())
|
val legacy = tryOrNull("Failed to access legacy crypto store") {
|
||||||
|
cryptoStore.getInboundGroupSession(sessionId, senderKey.orEmpty())
|
||||||
|
}
|
||||||
if (legacy == null || olmMachine.get().importRoomKey(legacy).isFailure) {
|
if (legacy == null || olmMachine.get().importRoomKey(legacy).isFailure) {
|
||||||
rateLimiter.tryFromBackupIfPossible(sessionId, roomId)
|
rateLimiter.tryFromBackupIfPossible(sessionId, roomId)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,351 @@
|
|||||||
|
/*
|
||||||
|
* 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.internal.crypto.store
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.Transformations
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import io.realm.Realm
|
||||||
|
import io.realm.RealmConfiguration
|
||||||
|
import io.realm.kotlin.where
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||||
|
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||||
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.model.CryptoRoomInfo
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent
|
||||||
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
|
import org.matrix.android.sdk.api.util.toOptional
|
||||||
|
import org.matrix.android.sdk.internal.crypto.OlmMachine
|
||||||
|
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.doRealmTransaction
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.doRealmTransactionAsync
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.doWithRealm
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CryptoRoomInfoMapper
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.mapper.MyDeviceLastSeenInfoEntityMapper
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntity
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntity
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.createPrimaryKey
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.query.getById
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.query.getOrCreate
|
||||||
|
import org.matrix.android.sdk.internal.di.CryptoDatabase
|
||||||
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
|
import org.matrix.android.sdk.internal.util.time.Clock
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private val loggerTag = LoggerTag("RealmCryptoStore", LoggerTag.CRYPTO)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In the transition phase, the rust SDK is still using parts to the realm crypto store,
|
||||||
|
* this should be removed after full migration
|
||||||
|
*/
|
||||||
|
@SessionScope
|
||||||
|
internal class RustCryptoStore @Inject constructor(
|
||||||
|
@CryptoDatabase private val realmConfiguration: RealmConfiguration,
|
||||||
|
private val clock: Clock,
|
||||||
|
private val myDeviceLastSeenInfoEntityMapper: MyDeviceLastSeenInfoEntityMapper,
|
||||||
|
private val olmMachine: dagger.Lazy<OlmMachine>,
|
||||||
|
private val matrixCoroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
|
) : IMXCommonCryptoStore {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a device by its identity key.
|
||||||
|
*
|
||||||
|
* @param identityKey the device identity key (`MXDeviceInfo.identityKey`)
|
||||||
|
* @return the device or null if not found
|
||||||
|
*/
|
||||||
|
override fun deviceWithIdentityKey(userId: String, identityKey: String): CryptoDeviceInfo? {
|
||||||
|
// XXX make this suspendable?
|
||||||
|
val knownDevices = runBlocking(matrixCoroutineDispatchers.io) {
|
||||||
|
olmMachine.get().getUserDevices(userId)
|
||||||
|
}
|
||||||
|
return knownDevices
|
||||||
|
.map { it.toCryptoDeviceInfo() }
|
||||||
|
.firstOrNull {
|
||||||
|
it.identityKey() == identityKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Needed for lazy migration of sessions from the legacy store
|
||||||
|
*/
|
||||||
|
override fun getInboundGroupSession(sessionId: String, senderKey: String): MXInboundMegolmSessionWrapper? {
|
||||||
|
val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionId, senderKey)
|
||||||
|
|
||||||
|
return doWithRealm(realmConfiguration) { realm ->
|
||||||
|
realm.where<OlmInboundGroupSessionEntity>()
|
||||||
|
.equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
|
||||||
|
.findFirst()
|
||||||
|
?.toModel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================================
|
||||||
|
// Things that should be migrated to another store than realm
|
||||||
|
// ================================================
|
||||||
|
|
||||||
|
private val monarchyWriteAsyncExecutor = Executors.newSingleThreadExecutor()
|
||||||
|
|
||||||
|
private val monarchy = Monarchy.Builder()
|
||||||
|
.setRealmConfiguration(realmConfiguration)
|
||||||
|
.setWriteAsyncExecutor(monarchyWriteAsyncExecutor)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
override fun open() {
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tidyUpDataBase() {
|
||||||
|
// These entities are not used in rust actually, but as they are not yet cleaned up, this will do it with time
|
||||||
|
val prevWeekTs = clock.epochMillis() - 7 * 24 * 60 * 60 * 1_000
|
||||||
|
doRealmTransaction("tidyUpDataBase", realmConfiguration) { realm ->
|
||||||
|
|
||||||
|
// Clean the old ones?
|
||||||
|
realm.where<OutgoingKeyRequestEntity>()
|
||||||
|
.lessThan(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, prevWeekTs)
|
||||||
|
.findAll()
|
||||||
|
.also { Timber.i("## Crypto Clean up ${it.size} OutgoingKeyRequestEntity") }
|
||||||
|
.deleteAllFromRealm()
|
||||||
|
|
||||||
|
// Only keep one month history
|
||||||
|
|
||||||
|
val prevMonthTs = clock.epochMillis() - 4 * 7 * 24 * 60 * 60 * 1_000L
|
||||||
|
realm.where<AuditTrailEntity>()
|
||||||
|
.lessThan(AuditTrailEntityFields.AGE_LOCAL_TS, prevMonthTs)
|
||||||
|
.findAll()
|
||||||
|
.also { Timber.i("## Crypto Clean up ${it.size} AuditTrailEntity") }
|
||||||
|
.deleteAllFromRealm()
|
||||||
|
|
||||||
|
// Can we do something for WithHeldSessionEntity?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
val tasks = monarchyWriteAsyncExecutor.shutdownNow()
|
||||||
|
Timber.w("Closing RealmCryptoStore, ${tasks.size} async task(s) cancelled")
|
||||||
|
tryOrNull("Interrupted") {
|
||||||
|
// Wait 1 minute max
|
||||||
|
monarchyWriteAsyncExecutor.awaitTermination(1, TimeUnit.MINUTES)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRoomAlgorithm(roomId: String): String? {
|
||||||
|
return doWithRealm(realmConfiguration) {
|
||||||
|
CryptoRoomEntity.getById(it, roomId)?.algorithm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRoomCryptoInfo(roomId: String): CryptoRoomInfo? {
|
||||||
|
return doWithRealm(realmConfiguration) { realm ->
|
||||||
|
CryptoRoomEntity.getById(realm, roomId)?.let {
|
||||||
|
CryptoRoomInfoMapper.map(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a bit different than isRoomEncrypted.
|
||||||
|
* A room is encrypted when there is a m.room.encryption state event in the room (malformed/invalid or not).
|
||||||
|
* But the crypto layer has additional guaranty to ensure that encryption would never been reverted.
|
||||||
|
* It's defensive coding out of precaution (if ever state is reset).
|
||||||
|
*/
|
||||||
|
override fun roomWasOnceEncrypted(roomId: String): Boolean {
|
||||||
|
return doWithRealm(realmConfiguration) {
|
||||||
|
CryptoRoomEntity.getById(it, roomId)?.wasEncryptedOnce ?: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setAlgorithmInfo(roomId: String, encryption: EncryptionEventContent?) {
|
||||||
|
doRealmTransaction("setAlgorithmInfo", realmConfiguration) {
|
||||||
|
CryptoRoomEntity.getOrCreate(it, roomId).let { entity ->
|
||||||
|
entity.algorithm = encryption?.algorithm
|
||||||
|
// store anyway the new algorithm, but mark the room
|
||||||
|
// as having been encrypted once whatever, this can never
|
||||||
|
// go back to false
|
||||||
|
if (encryption?.algorithm == MXCRYPTO_ALGORITHM_MEGOLM) {
|
||||||
|
entity.wasEncryptedOnce = true
|
||||||
|
entity.rotationPeriodMs = encryption.rotationPeriodMs
|
||||||
|
entity.rotationPeriodMsgs = encryption.rotationPeriodMsgs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveMyDevicesInfo(info: List<DeviceInfo>) {
|
||||||
|
val entities = info.map { myDeviceLastSeenInfoEntityMapper.map(it) }
|
||||||
|
doRealmTransactionAsync(realmConfiguration) { realm ->
|
||||||
|
realm.where<MyDeviceLastSeenInfoEntity>().findAll().deleteAllFromRealm()
|
||||||
|
entities.forEach {
|
||||||
|
realm.insertOrUpdate(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMyDevicesInfo(): List<DeviceInfo> {
|
||||||
|
return monarchy.fetchAllCopiedSync {
|
||||||
|
it.where<MyDeviceLastSeenInfoEntity>()
|
||||||
|
}.map {
|
||||||
|
DeviceInfo(
|
||||||
|
deviceId = it.deviceId,
|
||||||
|
lastSeenIp = it.lastSeenIp,
|
||||||
|
lastSeenTs = it.lastSeenTs,
|
||||||
|
displayName = it.displayName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLiveMyDevicesInfo(): LiveData<List<DeviceInfo>> {
|
||||||
|
return monarchy.findAllMappedWithChanges(
|
||||||
|
{ realm: Realm ->
|
||||||
|
realm.where<MyDeviceLastSeenInfoEntity>()
|
||||||
|
},
|
||||||
|
{ entity -> myDeviceLastSeenInfoEntityMapper.map(entity) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLiveMyDevicesInfo(deviceId: String): LiveData<Optional<DeviceInfo>> {
|
||||||
|
val liveData = monarchy.findAllMappedWithChanges(
|
||||||
|
{ realm: Realm ->
|
||||||
|
realm.where<MyDeviceLastSeenInfoEntity>()
|
||||||
|
.equalTo(MyDeviceLastSeenInfoEntityFields.DEVICE_ID, deviceId)
|
||||||
|
},
|
||||||
|
{ entity -> myDeviceLastSeenInfoEntityMapper.map(entity) }
|
||||||
|
)
|
||||||
|
|
||||||
|
return Transformations.map(liveData) {
|
||||||
|
it.firstOrNull().toOptional()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun storeData(cryptoStoreAggregator: CryptoStoreAggregator) {
|
||||||
|
if (cryptoStoreAggregator.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
doRealmTransaction("storeData - CryptoStoreAggregator", realmConfiguration) { realm ->
|
||||||
|
// setShouldShareHistory
|
||||||
|
cryptoStoreAggregator.setShouldShareHistoryData.forEach {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.v("setShouldShareHistory for room ${it.key} is ${it.value}")
|
||||||
|
CryptoRoomEntity.getOrCreate(realm, it.key).shouldShareHistory = it.value
|
||||||
|
}
|
||||||
|
// setShouldEncryptForInvitedMembers
|
||||||
|
cryptoStoreAggregator.setShouldEncryptForInvitedMembersData.forEach {
|
||||||
|
CryptoRoomEntity.getOrCreate(realm, it.key).shouldEncryptForInvitedMembers = it.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldEncryptForInvitedMembers(roomId: String): Boolean {
|
||||||
|
return doWithRealm(realmConfiguration) {
|
||||||
|
CryptoRoomEntity.getById(it, roomId)?.shouldEncryptForInvitedMembers
|
||||||
|
}
|
||||||
|
?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setShouldShareHistory(roomId: String, shouldShareHistory: Boolean) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.v("setShouldShareHistory for room $roomId is $shouldShareHistory")
|
||||||
|
doRealmTransaction("setShouldShareHistory", realmConfiguration) {
|
||||||
|
CryptoRoomEntity.getOrCreate(it, roomId).shouldShareHistory = shouldShareHistory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean) {
|
||||||
|
doRealmTransaction("setShouldEncryptForInvitedMembers", realmConfiguration) {
|
||||||
|
CryptoRoomEntity.getOrCreate(it, roomId).shouldEncryptForInvitedMembers = shouldEncryptForInvitedMembers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun blockUnverifiedDevicesInRoom(roomId: String, block: Boolean) {
|
||||||
|
doRealmTransaction("blockUnverifiedDevicesInRoom", realmConfiguration) { realm ->
|
||||||
|
CryptoRoomEntity.getById(realm, roomId)
|
||||||
|
?.blacklistUnverifiedDevices = block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setGlobalBlacklistUnverifiedDevices(block: Boolean) {
|
||||||
|
doRealmTransaction("setGlobalBlacklistUnverifiedDevices", realmConfiguration) {
|
||||||
|
it.where<CryptoMetadataEntity>().findFirst()?.globalBlacklistUnverifiedDevices = block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLiveGlobalCryptoConfig(): LiveData<GlobalCryptoConfig> {
|
||||||
|
val liveData = monarchy.findAllMappedWithChanges(
|
||||||
|
{ realm: Realm ->
|
||||||
|
realm
|
||||||
|
.where<CryptoMetadataEntity>()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GlobalCryptoConfig(
|
||||||
|
globalBlockUnverifiedDevices = it.globalBlacklistUnverifiedDevices,
|
||||||
|
globalEnableKeyGossiping = it.globalEnableKeyGossiping,
|
||||||
|
enableKeyForwardingOnInvite = it.enableKeyForwardingOnInvite
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return Transformations.map(liveData) {
|
||||||
|
it.firstOrNull() ?: GlobalCryptoConfig(false, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getGlobalBlacklistUnverifiedDevices(): Boolean {
|
||||||
|
return doWithRealm(realmConfiguration) {
|
||||||
|
it.where<CryptoMetadataEntity>().findFirst()?.globalBlacklistUnverifiedDevices
|
||||||
|
} ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLiveBlockUnverifiedDevices(roomId: String): LiveData<Boolean> {
|
||||||
|
val liveData = monarchy.findAllMappedWithChanges(
|
||||||
|
{ realm: Realm ->
|
||||||
|
realm.where<CryptoRoomEntity>()
|
||||||
|
.equalTo(CryptoRoomEntityFields.ROOM_ID, roomId)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
it.blacklistUnverifiedDevices
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return Transformations.map(liveData) {
|
||||||
|
it.firstOrNull() ?: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getBlockUnverifiedDevices(roomId: String): Boolean {
|
||||||
|
return doWithRealm(realmConfiguration) { realm ->
|
||||||
|
realm.where<CryptoRoomEntity>()
|
||||||
|
.equalTo(CryptoRoomEntityFields.ROOM_ID, roomId)
|
||||||
|
.findFirst()
|
||||||
|
?.blacklistUnverifiedDevices ?: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@ import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
|||||||
import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
|
import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
import org.matrix.android.sdk.internal.crypto.store.IMXCommonCryptoStore
|
||||||
|
|
||||||
class EventEditValidatorTest {
|
class EventEditValidatorTest {
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ class EventEditValidatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `edit should be valid`() {
|
fun `edit should be valid`() {
|
||||||
val mockCryptoStore = mockk<IMXCryptoStore>()
|
val mockCryptoStore = mockk<IMXCommonCryptoStore>()
|
||||||
val validator = EventEditValidator(mockCryptoStore)
|
val validator = EventEditValidator(mockCryptoStore)
|
||||||
|
|
||||||
validator
|
validator
|
||||||
@ -71,7 +71,7 @@ class EventEditValidatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `original event and replacement event must have the same sender`() {
|
fun `original event and replacement event must have the same sender`() {
|
||||||
val mockCryptoStore = mockk<IMXCryptoStore>()
|
val mockCryptoStore = mockk<IMXCommonCryptoStore>()
|
||||||
val validator = EventEditValidator(mockCryptoStore)
|
val validator = EventEditValidator(mockCryptoStore)
|
||||||
|
|
||||||
validator
|
validator
|
||||||
@ -83,7 +83,7 @@ class EventEditValidatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `original event and replacement event must have the same room_id`() {
|
fun `original event and replacement event must have the same room_id`() {
|
||||||
val mockCryptoStore = mockk<IMXCryptoStore>()
|
val mockCryptoStore = mockk<IMXCommonCryptoStore>()
|
||||||
val validator = EventEditValidator(mockCryptoStore)
|
val validator = EventEditValidator(mockCryptoStore)
|
||||||
|
|
||||||
validator
|
validator
|
||||||
@ -101,7 +101,7 @@ class EventEditValidatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `replacement and original events must not have a state_key property`() {
|
fun `replacement and original events must not have a state_key property`() {
|
||||||
val mockCryptoStore = mockk<IMXCryptoStore>()
|
val mockCryptoStore = mockk<IMXCommonCryptoStore>()
|
||||||
val validator = EventEditValidator(mockCryptoStore)
|
val validator = EventEditValidator(mockCryptoStore)
|
||||||
|
|
||||||
validator
|
validator
|
||||||
@ -119,8 +119,8 @@ class EventEditValidatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `replacement event must have an new_content property`() {
|
fun `replacement event must have an new_content property`() {
|
||||||
val mockCryptoStore = mockk<IMXCryptoStore> {
|
val mockCryptoStore = mockk<IMXCommonCryptoStore> {
|
||||||
every { deviceWithIdentityKey("R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
every { deviceWithIdentityKey("@alice:example.com", "R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
||||||
mockk<CryptoDeviceInfo> {
|
mockk<CryptoDeviceInfo> {
|
||||||
every { userId } returns "@alice:example.com"
|
every { userId } returns "@alice:example.com"
|
||||||
}
|
}
|
||||||
@ -157,8 +157,8 @@ class EventEditValidatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `The original event must not itself have a rel_type of m_replace`() {
|
fun `The original event must not itself have a rel_type of m_replace`() {
|
||||||
val mockCryptoStore = mockk<IMXCryptoStore> {
|
val mockCryptoStore = mockk<IMXCommonCryptoStore> {
|
||||||
every { deviceWithIdentityKey("R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
every { deviceWithIdentityKey("@alice:example.com", "R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
||||||
mockk<CryptoDeviceInfo> {
|
mockk<CryptoDeviceInfo> {
|
||||||
every { userId } returns "@alice:example.com"
|
every { userId } returns "@alice:example.com"
|
||||||
}
|
}
|
||||||
@ -207,8 +207,8 @@ class EventEditValidatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `valid e2ee edit`() {
|
fun `valid e2ee edit`() {
|
||||||
val mockCryptoStore = mockk<IMXCryptoStore> {
|
val mockCryptoStore = mockk<IMXCommonCryptoStore> {
|
||||||
every { deviceWithIdentityKey("R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
every { deviceWithIdentityKey("@alice:example.com", "R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
||||||
mockk<CryptoDeviceInfo> {
|
mockk<CryptoDeviceInfo> {
|
||||||
every { userId } returns "@alice:example.com"
|
every { userId } returns "@alice:example.com"
|
||||||
}
|
}
|
||||||
@ -224,8 +224,8 @@ class EventEditValidatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `If the original event was encrypted, the replacement should be too`() {
|
fun `If the original event was encrypted, the replacement should be too`() {
|
||||||
val mockCryptoStore = mockk<IMXCryptoStore> {
|
val mockCryptoStore = mockk<IMXCommonCryptoStore> {
|
||||||
every { deviceWithIdentityKey("R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
every { deviceWithIdentityKey("@alice:example.com", "R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
||||||
mockk<CryptoDeviceInfo> {
|
mockk<CryptoDeviceInfo> {
|
||||||
every { userId } returns "@alice:example.com"
|
every { userId } returns "@alice:example.com"
|
||||||
}
|
}
|
||||||
@ -241,12 +241,12 @@ class EventEditValidatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `encrypted, original event and replacement event must have the same sender`() {
|
fun `encrypted, original event and replacement event must have the same sender`() {
|
||||||
val mockCryptoStore = mockk<IMXCryptoStore> {
|
val mockCryptoStore = mockk<IMXCommonCryptoStore> {
|
||||||
every { deviceWithIdentityKey("R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
every { deviceWithIdentityKey("@alice:example.com", "R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
||||||
mockk {
|
mockk {
|
||||||
every { userId } returns "@alice:example.com"
|
every { userId } returns "@alice:example.com"
|
||||||
}
|
}
|
||||||
every { deviceWithIdentityKey("7V5e/2O93mf4GeW7Mtq4YWcRNpYS9NhQbdJMgdnIPUI") } returns
|
every { deviceWithIdentityKey("@bob:example.com", "7V5e/2O93mf4GeW7Mtq4YWcRNpYS9NhQbdJMgdnIPUI") } returns
|
||||||
mockk {
|
mockk {
|
||||||
every { userId } returns "@bob:example.com"
|
every { userId } returns "@bob:example.com"
|
||||||
}
|
}
|
||||||
@ -256,7 +256,9 @@ class EventEditValidatorTest {
|
|||||||
validator
|
validator
|
||||||
.validateEdit(
|
.validateEdit(
|
||||||
encryptedEvent,
|
encryptedEvent,
|
||||||
encryptedEditEvent.copy().apply {
|
encryptedEditEvent.copy(
|
||||||
|
senderId = "@bob:example.com"
|
||||||
|
).apply {
|
||||||
mxDecryptionResult = encryptedEditEvent.mxDecryptionResult!!.copy(
|
mxDecryptionResult = encryptedEditEvent.mxDecryptionResult!!.copy(
|
||||||
senderKey = "7V5e/2O93mf4GeW7Mtq4YWcRNpYS9NhQbdJMgdnIPUI"
|
senderKey = "7V5e/2O93mf4GeW7Mtq4YWcRNpYS9NhQbdJMgdnIPUI"
|
||||||
)
|
)
|
||||||
@ -269,12 +271,12 @@ class EventEditValidatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `encrypted, sent fom a deleted device, original event and replacement event must have the same sender`() {
|
fun `encrypted, sent fom a deleted device, original event and replacement event must have the same sender`() {
|
||||||
val mockCryptoStore = mockk<IMXCryptoStore> {
|
val mockCryptoStore = mockk<IMXCommonCryptoStore> {
|
||||||
every { deviceWithIdentityKey("R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
every { deviceWithIdentityKey("@alice:example.com", "R0s/7Aindgg/RNWqUGJyJOXtCz5H7Gx7fInFuroq1xo") } returns
|
||||||
mockk {
|
mockk {
|
||||||
every { userId } returns "@alice:example.com"
|
every { userId } returns "@alice:example.com"
|
||||||
}
|
}
|
||||||
every { deviceWithIdentityKey("7V5e/2O93mf4GeW7Mtq4YWcRNpYS9NhQbdJMgdnIPUI") } returns
|
every { deviceWithIdentityKey(any(), "7V5e/2O93mf4GeW7Mtq4YWcRNpYS9NhQbdJMgdnIPUI") } returns
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
val validator = EventEditValidator(mockCryptoStore)
|
val validator = EventEditValidator(mockCryptoStore)
|
||||||
@ -288,7 +290,7 @@ class EventEditValidatorTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
) shouldBeInstanceOf EventEditValidator.EditValidity.Valid::class
|
) shouldBeInstanceOf EventEditValidator.EditValidity.Unknown::class
|
||||||
|
|
||||||
validator
|
validator
|
||||||
.validateEdit(
|
.validateEdit(
|
||||||
|
Loading…
Reference in New Issue
Block a user