mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-25 19:05:56 +03:00
Merge branch 'develop' into feature/bma/rr
This commit is contained in:
commit
431d450fec
13 changed files with 232 additions and 204 deletions
|
@ -6,9 +6,10 @@ Features ✨:
|
||||||
|
|
||||||
Improvements 🙌:
|
Improvements 🙌:
|
||||||
- Lazy storage of ReadReceipts
|
- Lazy storage of ReadReceipts
|
||||||
|
- Do not load room members in e2e after init sync
|
||||||
|
|
||||||
Bugfix 🐛:
|
Bugfix 🐛:
|
||||||
-
|
- Ensure message are decrypted in the room list after a clear cache
|
||||||
|
|
||||||
Translations 🗣:
|
Translations 🗣:
|
||||||
-
|
-
|
||||||
|
|
|
@ -38,7 +38,7 @@ internal class CryptoSessionInfoProvider @Inject constructor(
|
||||||
val encryptionEvent = monarchy.fetchCopied { realm ->
|
val encryptionEvent = monarchy.fetchCopied { realm ->
|
||||||
EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION)
|
EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION)
|
||||||
.contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"")
|
.contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"")
|
||||||
.isNotNull(EventEntityFields.STATE_KEY) // should be an empty key
|
.isEmpty(EventEntityFields.STATE_KEY)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
}
|
}
|
||||||
return encryptionEvent != null
|
return encryptionEvent != null
|
||||||
|
|
|
@ -856,17 +856,10 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||||
val params = LoadRoomMembersTask.Params(roomId)
|
|
||||||
try {
|
|
||||||
loadRoomMembersTask.execute(params)
|
|
||||||
} catch (throwable: Throwable) {
|
|
||||||
Timber.e(throwable, "## CRYPTO | onRoomEncryptionEvent ERROR FAILED TO SETUP CRYPTO ")
|
|
||||||
} finally {
|
|
||||||
val userIds = getRoomUserIds(roomId)
|
val userIds = getRoomUserIds(roomId)
|
||||||
setEncryptionInRoom(roomId, event.content?.get("algorithm")?.toString(), true, userIds)
|
setEncryptionInRoom(roomId, event.content?.get("algorithm")?.toString(), true, userIds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun getRoomUserIds(roomId: String): List<String> {
|
private fun getRoomUserIds(roomId: String): List<String> {
|
||||||
val encryptForInvitedMembers = isEncryptionEnabledForInvitedUser()
|
val encryptForInvitedMembers = isEncryptionEnabledForInvitedUser()
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.crypto
|
package org.matrix.android.sdk.internal.crypto
|
||||||
|
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.MatrixPatterns
|
import org.matrix.android.sdk.api.MatrixPatterns
|
||||||
import org.matrix.android.sdk.api.auth.data.Credentials
|
import org.matrix.android.sdk.api.auth.data.Credentials
|
||||||
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
|
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
|
||||||
|
@ -28,7 +29,7 @@ import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
|
import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
|
||||||
import org.matrix.android.sdk.internal.task.TaskExecutor
|
import org.matrix.android.sdk.internal.task.TaskExecutor
|
||||||
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
|
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
|
||||||
import kotlinx.coroutines.launch
|
import org.matrix.android.sdk.internal.util.logLimit
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -39,8 +40,9 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
private val syncTokenStore: SyncTokenStore,
|
private val syncTokenStore: SyncTokenStore,
|
||||||
private val credentials: Credentials,
|
private val credentials: Credentials,
|
||||||
private val downloadKeysForUsersTask: DownloadKeysForUsersTask,
|
private val downloadKeysForUsersTask: DownloadKeysForUsersTask,
|
||||||
|
private val cryptoSessionInfoProvider: CryptoSessionInfoProvider,
|
||||||
coroutineDispatchers: MatrixCoroutineDispatchers,
|
coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
taskExecutor: TaskExecutor) {
|
private val taskExecutor: TaskExecutor) {
|
||||||
|
|
||||||
interface UserDevicesUpdateListener {
|
interface UserDevicesUpdateListener {
|
||||||
fun onUsersDeviceUpdate(userIds: List<String>)
|
fun onUsersDeviceUpdate(userIds: List<String>)
|
||||||
|
@ -75,8 +77,10 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
// HS not ready for retry
|
// HS not ready for retry
|
||||||
private val notReadyToRetryHS = mutableSetOf<String>()
|
private val notReadyToRetryHS = mutableSetOf<String>()
|
||||||
|
|
||||||
|
private val cryptoCoroutineContext = coroutineDispatchers.crypto
|
||||||
|
|
||||||
init {
|
init {
|
||||||
taskExecutor.executorScope.launch(coroutineDispatchers.crypto) {
|
taskExecutor.executorScope.launch(cryptoCoroutineContext) {
|
||||||
var isUpdated = false
|
var isUpdated = false
|
||||||
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
||||||
for ((userId, status) in deviceTrackingStatuses) {
|
for ((userId, status) in deviceTrackingStatuses) {
|
||||||
|
@ -123,14 +127,24 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onRoomMembersLoadedFor(roomId: String) {
|
||||||
|
taskExecutor.executorScope.launch(cryptoCoroutineContext) {
|
||||||
|
if (cryptoSessionInfoProvider.isRoomEncrypted(roomId)) {
|
||||||
|
// It's OK to track also device for invited users
|
||||||
|
val userIds = cryptoSessionInfoProvider.getRoomUserIds(roomId, true)
|
||||||
|
startTrackingDeviceList(userIds)
|
||||||
|
refreshOutdatedDeviceLists()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark the cached device list for the given user outdated
|
* Mark the cached device list for the given user outdated
|
||||||
* flag the given user for device-list tracking, if they are not already.
|
* flag the given user for device-list tracking, if they are not already.
|
||||||
*
|
*
|
||||||
* @param userIds the user ids list
|
* @param userIds the user ids list
|
||||||
*/
|
*/
|
||||||
fun startTrackingDeviceList(userIds: List<String>?) {
|
fun startTrackingDeviceList(userIds: List<String>) {
|
||||||
if (null != userIds) {
|
|
||||||
var isUpdated = false
|
var isUpdated = false
|
||||||
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
||||||
|
|
||||||
|
@ -146,7 +160,6 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
|
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the devices list statuses
|
* Update the devices list statuses
|
||||||
|
@ -307,7 +320,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
* @param downloadUsers the user ids list
|
* @param downloadUsers the user ids list
|
||||||
*/
|
*/
|
||||||
private suspend fun doKeyDownloadForUsers(downloadUsers: List<String>): MXUsersDevicesMap<CryptoDeviceInfo> {
|
private suspend fun doKeyDownloadForUsers(downloadUsers: List<String>): MXUsersDevicesMap<CryptoDeviceInfo> {
|
||||||
Timber.v("## CRYPTO | doKeyDownloadForUsers() : doKeyDownloadForUsers $downloadUsers")
|
Timber.v("## CRYPTO | doKeyDownloadForUsers() : doKeyDownloadForUsers ${downloadUsers.logLimit()}")
|
||||||
// get the user ids which did not already trigger a keys download
|
// get the user ids which did not already trigger a keys download
|
||||||
val filteredUsers = downloadUsers.filter { MatrixPatterns.isUserId(it) }
|
val filteredUsers = downloadUsers.filter { MatrixPatterns.isUserId(it) }
|
||||||
if (filteredUsers.isEmpty()) {
|
if (filteredUsers.isEmpty()) {
|
||||||
|
|
|
@ -312,7 +312,7 @@ internal class MXOlmDevice @Inject constructor(
|
||||||
* @param theirDeviceIdentityKey the Curve25519 identity key for the remote device.
|
* @param theirDeviceIdentityKey the Curve25519 identity key for the remote device.
|
||||||
* @return a list of known session ids for the device.
|
* @return a list of known session ids for the device.
|
||||||
*/
|
*/
|
||||||
fun getSessionIds(theirDeviceIdentityKey: String): Set<String>? {
|
fun getSessionIds(theirDeviceIdentityKey: String): List<String>? {
|
||||||
return store.getDeviceSessionIds(theirDeviceIdentityKey)
|
return store.getDeviceSessionIds(theirDeviceIdentityKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ internal class MXOlmDecryption(
|
||||||
* @return payload, if decrypted successfully.
|
* @return payload, if decrypted successfully.
|
||||||
*/
|
*/
|
||||||
private fun decryptMessage(message: JsonDict, theirDeviceIdentityKey: String): String? {
|
private fun decryptMessage(message: JsonDict, theirDeviceIdentityKey: String): String? {
|
||||||
val sessionIds = olmDevice.getSessionIds(theirDeviceIdentityKey) ?: emptySet()
|
val sessionIds = olmDevice.getSessionIds(theirDeviceIdentityKey).orEmpty()
|
||||||
|
|
||||||
val messageBody = message["body"] as? String ?: return null
|
val messageBody = message["body"] as? String ?: return null
|
||||||
val messageType = when (val typeAsVoid = message["type"]) {
|
val messageType = when (val typeAsVoid = message["type"]) {
|
||||||
|
|
|
@ -33,15 +33,18 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMapper
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
|
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
|
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
|
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.awaitTransaction
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
|
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
|
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
import org.matrix.android.sdk.internal.database.query.where
|
import org.matrix.android.sdk.internal.database.query.where
|
||||||
import org.matrix.android.sdk.internal.di.CryptoDatabase
|
import org.matrix.android.sdk.internal.di.CryptoDatabase
|
||||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||||
import org.matrix.android.sdk.internal.di.UserId
|
import org.matrix.android.sdk.internal.di.UserId
|
||||||
import org.matrix.android.sdk.internal.session.SessionComponent
|
import org.matrix.android.sdk.internal.session.SessionComponent
|
||||||
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
|
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
|
||||||
|
import org.matrix.android.sdk.internal.util.logLimit
|
||||||
import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
|
import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
|
||||||
import org.matrix.android.sdk.internal.worker.SessionWorkerParams
|
import org.matrix.android.sdk.internal.worker.SessionWorkerParams
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
@ -65,11 +68,16 @@ internal class UpdateTrustWorker(context: Context,
|
||||||
@Inject lateinit var crossSigningService: DefaultCrossSigningService
|
@Inject lateinit var crossSigningService: DefaultCrossSigningService
|
||||||
|
|
||||||
// It breaks the crypto store contract, but we need to batch things :/
|
// It breaks the crypto store contract, but we need to batch things :/
|
||||||
@CryptoDatabase @Inject lateinit var realmConfiguration: RealmConfiguration
|
@CryptoDatabase
|
||||||
@UserId @Inject lateinit var myUserId: String
|
@Inject lateinit var cryptoRealmConfiguration: RealmConfiguration
|
||||||
|
|
||||||
|
@SessionDatabase
|
||||||
|
@Inject lateinit var sessionRealmConfiguration: RealmConfiguration
|
||||||
|
|
||||||
|
@UserId
|
||||||
|
@Inject lateinit var myUserId: String
|
||||||
@Inject lateinit var crossSigningKeysMapper: CrossSigningKeysMapper
|
@Inject lateinit var crossSigningKeysMapper: CrossSigningKeysMapper
|
||||||
@Inject lateinit var updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository
|
@Inject lateinit var updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository
|
||||||
@SessionDatabase @Inject lateinit var sessionRealmConfiguration: RealmConfiguration
|
|
||||||
|
|
||||||
// @Inject lateinit var roomSummaryUpdater: RoomSummaryUpdater
|
// @Inject lateinit var roomSummaryUpdater: RoomSummaryUpdater
|
||||||
@Inject lateinit var cryptoStore: IMXCryptoStore
|
@Inject lateinit var cryptoStore: IMXCryptoStore
|
||||||
|
@ -79,31 +87,38 @@ internal class UpdateTrustWorker(context: Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun doSafeWork(params: Params): Result {
|
override suspend fun doSafeWork(params: Params): Result {
|
||||||
var userList = params.filename
|
val userList = params.filename
|
||||||
?.let { updateTrustWorkerDataRepository.getParam(it) }
|
?.let { updateTrustWorkerDataRepository.getParam(it) }
|
||||||
?.userIds
|
?.userIds
|
||||||
?: params.updatedUserIds.orEmpty()
|
?: params.updatedUserIds.orEmpty()
|
||||||
|
|
||||||
if (userList.isEmpty()) {
|
// List should not be empty, but let's avoid go further in case of empty list
|
||||||
// This should not happen, but let's avoid go further in case of empty list
|
if (userList.isNotEmpty()) {
|
||||||
|
// Unfortunately we don't have much info on what did exactly changed (is it the cross signing keys of that user,
|
||||||
|
// or a new device?) So we check all again :/
|
||||||
|
Timber.d("## CrossSigning - Updating trust for users: ${userList.logLimit()}")
|
||||||
|
|
||||||
|
Realm.getInstance(cryptoRealmConfiguration).use { cryptoRealm ->
|
||||||
|
Realm.getInstance(sessionRealmConfiguration).use {
|
||||||
|
updateTrust(userList, cryptoRealm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cleanup(params)
|
cleanup(params)
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unfortunately we don't have much info on what did exactly changed (is it the cross signing keys of that user,
|
private suspend fun updateTrust(userListParam: List<String>,
|
||||||
// or a new device?) So we check all again :/
|
cRealm: Realm) {
|
||||||
|
var userList = userListParam
|
||||||
Timber.d("## CrossSigning - Updating trust for $userList")
|
var myCrossSigningInfo: MXCrossSigningInfo? = null
|
||||||
|
|
||||||
// First we check that the users MSK are trusted by mine
|
// First we check that the users MSK are trusted by mine
|
||||||
// After that we check the trust chain for each devices of each users
|
// After that we check the trust chain for each devices of each users
|
||||||
Realm.getInstance(realmConfiguration).use { realm ->
|
awaitTransaction(cryptoRealmConfiguration) { cryptoRealm ->
|
||||||
realm.executeTransaction {
|
|
||||||
// By mapping here to model, this object is not live
|
// By mapping here to model, this object is not live
|
||||||
// I should update it if needed
|
// I should update it if needed
|
||||||
var myCrossSigningInfo = realm.where(CrossSigningInfoEntity::class.java)
|
myCrossSigningInfo = getCrossSigningInfo(cryptoRealm, myUserId)
|
||||||
.equalTo(CrossSigningInfoEntityFields.USER_ID, myUserId)
|
|
||||||
.findFirst()?.let { mapCrossSigningInfoEntity(it) }
|
|
||||||
|
|
||||||
var myTrustResult: UserTrustResult? = null
|
var myTrustResult: UserTrustResult? = null
|
||||||
|
|
||||||
|
@ -112,67 +127,58 @@ internal class UpdateTrustWorker(context: Context,
|
||||||
// i am in the list.. but i don't know exactly the delta of change :/
|
// i am in the list.. but i don't know exactly the delta of change :/
|
||||||
// If it's my cross signing keys we should refresh all trust
|
// If it's my cross signing keys we should refresh all trust
|
||||||
// do it anyway ?
|
// do it anyway ?
|
||||||
userList = realm.where(CrossSigningInfoEntity::class.java)
|
userList = cryptoRealm.where(CrossSigningInfoEntity::class.java)
|
||||||
.findAll().mapNotNull { it.userId }
|
.findAll()
|
||||||
Timber.d("## CrossSigning - Updating trust for all $userList")
|
.mapNotNull { it.userId }
|
||||||
|
|
||||||
// check right now my keys and mark it as trusted as other trust depends on it
|
// check right now my keys and mark it as trusted as other trust depends on it
|
||||||
val myDevices = realm.where<UserEntity>()
|
val myDevices = cryptoRealm.where<UserEntity>()
|
||||||
.equalTo(UserEntityFields.USER_ID, myUserId)
|
.equalTo(UserEntityFields.USER_ID, myUserId)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
?.devices
|
?.devices
|
||||||
?.map { deviceInfo ->
|
?.map { CryptoMapper.mapToModel(it) }
|
||||||
CryptoMapper.mapToModel(deviceInfo)
|
|
||||||
}
|
myTrustResult = crossSigningService.checkSelfTrust(myCrossSigningInfo, myDevices)
|
||||||
myTrustResult = crossSigningService.checkSelfTrust(myCrossSigningInfo, myDevices).also {
|
updateCrossSigningKeysTrust(cryptoRealm, myUserId, myTrustResult.isVerified())
|
||||||
updateCrossSigningKeysTrust(realm, myUserId, it.isVerified())
|
|
||||||
// update model reference
|
// update model reference
|
||||||
myCrossSigningInfo = realm.where(CrossSigningInfoEntity::class.java)
|
myCrossSigningInfo = getCrossSigningInfo(cryptoRealm, myUserId)
|
||||||
.equalTo(CrossSigningInfoEntityFields.USER_ID, myUserId)
|
|
||||||
.findFirst()?.let { mapCrossSigningInfoEntity(it) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val otherInfos = userList.map {
|
val otherInfos = userList.associateWith { userId ->
|
||||||
it to realm.where(CrossSigningInfoEntity::class.java)
|
getCrossSigningInfo(cryptoRealm, userId)
|
||||||
.equalTo(CrossSigningInfoEntityFields.USER_ID, it)
|
|
||||||
.findFirst()?.let { mapCrossSigningInfoEntity(it) }
|
|
||||||
}
|
}
|
||||||
.toMap()
|
|
||||||
|
|
||||||
val trusts = otherInfos.map { infoEntry ->
|
val trusts = otherInfos.mapValues { entry ->
|
||||||
infoEntry.key to when (infoEntry.key) {
|
when (entry.key) {
|
||||||
myUserId -> myTrustResult
|
myUserId -> myTrustResult
|
||||||
else -> {
|
else -> {
|
||||||
crossSigningService.checkOtherMSKTrusted(myCrossSigningInfo, infoEntry.value).also {
|
crossSigningService.checkOtherMSKTrusted(myCrossSigningInfo, entry.value).also {
|
||||||
Timber.d("## CrossSigning - user:${infoEntry.key} result:$it")
|
Timber.d("## CrossSigning - user:${entry.key} result:$it")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.toMap()
|
|
||||||
|
|
||||||
// TODO! if it's me and my keys has changed... I have to reset trust for everyone!
|
// TODO! if it's me and my keys has changed... I have to reset trust for everyone!
|
||||||
// i have all the new trusts, update DB
|
// i have all the new trusts, update DB
|
||||||
trusts.forEach {
|
trusts.forEach {
|
||||||
val verified = it.value?.isVerified() == true
|
val verified = it.value?.isVerified() == true
|
||||||
updateCrossSigningKeysTrust(realm, it.key, verified)
|
updateCrossSigningKeysTrust(cryptoRealm, it.key, verified)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ok so now we have to check device trust for all these users..
|
// Ok so now we have to check device trust for all these users..
|
||||||
Timber.v("## CrossSigning - Updating devices cross trust users ${trusts.keys}")
|
Timber.v("## CrossSigning - Updating devices cross trust users: ${trusts.keys.logLimit()}")
|
||||||
trusts.keys.forEach {
|
trusts.keys.forEach { userId ->
|
||||||
val devicesEntities = realm.where<UserEntity>()
|
val devicesEntities = cryptoRealm.where<UserEntity>()
|
||||||
.equalTo(UserEntityFields.USER_ID, it)
|
.equalTo(UserEntityFields.USER_ID, userId)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
?.devices
|
?.devices
|
||||||
|
|
||||||
val trustMap = devicesEntities?.map { device ->
|
val trustMap = devicesEntities?.associateWith { device ->
|
||||||
// get up to date from DB has could have been updated
|
// get up to date from DB has could have been updated
|
||||||
val otherInfo = realm.where(CrossSigningInfoEntity::class.java)
|
val otherInfo = getCrossSigningInfo(cryptoRealm, userId)
|
||||||
.equalTo(CrossSigningInfoEntityFields.USER_ID, it)
|
crossSigningService.checkDeviceTrust(myCrossSigningInfo, otherInfo, CryptoMapper.mapToModel(device))
|
||||||
.findFirst()?.let { mapCrossSigningInfoEntity(it) }
|
}
|
||||||
device to crossSigningService.checkDeviceTrust(myCrossSigningInfo, otherInfo, CryptoMapper.mapToModel(device))
|
|
||||||
}?.toMap()
|
|
||||||
|
|
||||||
// Update trust if needed
|
// Update trust if needed
|
||||||
devicesEntities?.forEach { device ->
|
devicesEntities?.forEach { device ->
|
||||||
|
@ -183,10 +189,9 @@ internal class UpdateTrustWorker(context: Context,
|
||||||
// need to save
|
// need to save
|
||||||
val trustEntity = device.trustLevelEntity
|
val trustEntity = device.trustLevelEntity
|
||||||
if (trustEntity == null) {
|
if (trustEntity == null) {
|
||||||
realm.createObject(TrustLevelEntity::class.java).let {
|
device.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also {
|
||||||
it.locallyVerified = false
|
it.locallyVerified = false
|
||||||
it.crossSignedVerified = crossSignedVerified
|
it.crossSignedVerified = crossSignedVerified
|
||||||
device.trustLevelEntity = it
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
trustEntity.crossSignedVerified = crossSignedVerified
|
trustEntity.crossSignedVerified = crossSignedVerified
|
||||||
|
@ -195,27 +200,32 @@ internal class UpdateTrustWorker(context: Context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// So Cross Signing keys trust is updated, device trust is updated
|
// So Cross Signing keys trust is updated, device trust is updated
|
||||||
// We can now update room shields? in the session DB?
|
// We can now update room shields? in the session DB?
|
||||||
|
|
||||||
Timber.d("## CrossSigning - Updating shields for impacted rooms...")
|
Timber.d("## CrossSigning - Updating shields for impacted rooms...")
|
||||||
Realm.getInstance(sessionRealmConfiguration).use { it ->
|
awaitTransaction(sessionRealmConfiguration) { sessionRealm ->
|
||||||
it.executeTransaction { realm ->
|
sessionRealm.where(RoomMemberSummaryEntity::class.java)
|
||||||
val distinctRoomIds = realm.where(RoomMemberSummaryEntity::class.java)
|
|
||||||
.`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray())
|
.`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray())
|
||||||
.distinct(RoomMemberSummaryEntityFields.ROOM_ID)
|
.distinct(RoomMemberSummaryEntityFields.ROOM_ID)
|
||||||
.findAll()
|
.findAll()
|
||||||
.map { it.roomId }
|
.map { it.roomId }
|
||||||
Timber.d("## CrossSigning - ... impacted rooms $distinctRoomIds")
|
.also { Timber.d("## CrossSigning - ... impacted rooms ${it.logLimit()}") }
|
||||||
distinctRoomIds.forEach { roomId ->
|
.forEach { roomId ->
|
||||||
val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
|
RoomSummaryEntity.where(sessionRealm, roomId)
|
||||||
if (roomSummary?.isEncrypted == true) {
|
.equalTo(RoomSummaryEntityFields.IS_ENCRYPTED, true)
|
||||||
|
.findFirst()
|
||||||
|
?.let { roomSummary ->
|
||||||
Timber.d("## CrossSigning - Check shield state for room $roomId")
|
Timber.d("## CrossSigning - Check shield state for room $roomId")
|
||||||
val allActiveRoomMembers = RoomMemberHelper(realm, roomId).getActiveRoomMemberIds()
|
val allActiveRoomMembers = RoomMemberHelper(sessionRealm, roomId).getActiveRoomMemberIds()
|
||||||
try {
|
try {
|
||||||
val updatedTrust = computeRoomShield(allActiveRoomMembers, roomSummary)
|
val updatedTrust = computeRoomShield(
|
||||||
|
myCrossSigningInfo,
|
||||||
|
cRealm,
|
||||||
|
allActiveRoomMembers,
|
||||||
|
roomSummary
|
||||||
|
)
|
||||||
if (roomSummary.roomEncryptionTrustLevel != updatedTrust) {
|
if (roomSummary.roomEncryptionTrustLevel != updatedTrust) {
|
||||||
Timber.d("## CrossSigning - Shield change detected for $roomId -> $updatedTrust")
|
Timber.d("## CrossSigning - Shield change detected for $roomId -> $updatedTrust")
|
||||||
roomSummary.roomEncryptionTrustLevel = updatedTrust
|
roomSummary.roomEncryptionTrustLevel = updatedTrust
|
||||||
|
@ -228,8 +238,11 @@ internal class UpdateTrustWorker(context: Context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup(params)
|
private fun getCrossSigningInfo(cryptoRealm: Realm, userId: String): MXCrossSigningInfo? {
|
||||||
return Result.success()
|
return cryptoRealm.where(CrossSigningInfoEntity::class.java)
|
||||||
|
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
|
||||||
|
.findFirst()
|
||||||
|
?.let { mapCrossSigningInfoEntity(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cleanup(params: Params) {
|
private fun cleanup(params: Params) {
|
||||||
|
@ -237,20 +250,21 @@ internal class UpdateTrustWorker(context: Context,
|
||||||
?.let { updateTrustWorkerDataRepository.delete(it) }
|
?.let { updateTrustWorkerDataRepository.delete(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateCrossSigningKeysTrust(realm: Realm, userId: String, verified: Boolean) {
|
private fun updateCrossSigningKeysTrust(cryptoRealm: Realm, userId: String, verified: Boolean) {
|
||||||
val xInfoEntity = realm.where(CrossSigningInfoEntity::class.java)
|
cryptoRealm.where(CrossSigningInfoEntity::class.java)
|
||||||
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
|
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
xInfoEntity?.crossSigningKeys?.forEach { info ->
|
?.crossSigningKeys
|
||||||
|
?.forEach { info ->
|
||||||
// optimization to avoid trigger updates when there is no change..
|
// optimization to avoid trigger updates when there is no change..
|
||||||
if (info.trustLevelEntity?.isVerified() != verified) {
|
if (info.trustLevelEntity?.isVerified() != verified) {
|
||||||
Timber.d("## CrossSigning - Trust change for $userId : $verified")
|
Timber.d("## CrossSigning - Trust change for $userId : $verified")
|
||||||
val level = info.trustLevelEntity
|
val level = info.trustLevelEntity
|
||||||
if (level == null) {
|
if (level == null) {
|
||||||
val newLevel = realm.createObject(TrustLevelEntity::class.java)
|
info.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also {
|
||||||
newLevel.locallyVerified = verified
|
it.locallyVerified = verified
|
||||||
newLevel.crossSignedVerified = verified
|
it.crossSignedVerified = verified
|
||||||
info.trustLevelEntity = newLevel
|
}
|
||||||
} else {
|
} else {
|
||||||
level.locallyVerified = verified
|
level.locallyVerified = verified
|
||||||
level.crossSignedVerified = verified
|
level.crossSignedVerified = verified
|
||||||
|
@ -259,8 +273,11 @@ internal class UpdateTrustWorker(context: Context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeRoomShield(activeMemberUserIds: List<String>, roomSummaryEntity: RoomSummaryEntity): RoomEncryptionTrustLevel {
|
private fun computeRoomShield(myCrossSigningInfo: MXCrossSigningInfo?,
|
||||||
Timber.d("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} -> $activeMemberUserIds")
|
cryptoRealm: Realm,
|
||||||
|
activeMemberUserIds: List<String>,
|
||||||
|
roomSummaryEntity: RoomSummaryEntity): RoomEncryptionTrustLevel {
|
||||||
|
Timber.d("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} -> ${activeMemberUserIds.logLimit()}")
|
||||||
// The set of “all users” depends on the type of room:
|
// The set of “all users” depends on the type of room:
|
||||||
// For regular / topic rooms which have more than 2 members (including yourself) are considered when decorating a room
|
// For regular / topic rooms which have more than 2 members (including yourself) are considered when decorating a room
|
||||||
// For 1:1 and group DM rooms, all other users (i.e. excluding yourself) are considered when decorating a room
|
// For 1:1 and group DM rooms, all other users (i.e. excluding yourself) are considered when decorating a room
|
||||||
|
@ -272,16 +289,7 @@ internal class UpdateTrustWorker(context: Context,
|
||||||
|
|
||||||
val allTrustedUserIds = listToCheck
|
val allTrustedUserIds = listToCheck
|
||||||
.filter { userId ->
|
.filter { userId ->
|
||||||
Realm.getInstance(realmConfiguration).use {
|
getCrossSigningInfo(cryptoRealm, userId)?.isTrusted() == true
|
||||||
it.where(CrossSigningInfoEntity::class.java)
|
|
||||||
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
|
|
||||||
.findFirst()?.let { mapCrossSigningInfoEntity(it) }?.isTrusted() == true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val myCrossKeys = Realm.getInstance(realmConfiguration).use {
|
|
||||||
it.where(CrossSigningInfoEntity::class.java)
|
|
||||||
.equalTo(CrossSigningInfoEntityFields.USER_ID, myUserId)
|
|
||||||
.findFirst()?.let { mapCrossSigningInfoEntity(it) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (allTrustedUserIds.isEmpty()) {
|
return if (allTrustedUserIds.isEmpty()) {
|
||||||
|
@ -291,21 +299,17 @@ internal class UpdateTrustWorker(context: Context,
|
||||||
// If all devices of all verified users are trusted -> green
|
// If all devices of all verified users are trusted -> green
|
||||||
// else -> black
|
// else -> black
|
||||||
allTrustedUserIds
|
allTrustedUserIds
|
||||||
.mapNotNull { uid ->
|
.mapNotNull { userId ->
|
||||||
Realm.getInstance(realmConfiguration).use {
|
cryptoRealm.where<UserEntity>()
|
||||||
it.where<UserEntity>()
|
.equalTo(UserEntityFields.USER_ID, userId)
|
||||||
.equalTo(UserEntityFields.USER_ID, uid)
|
|
||||||
.findFirst()
|
.findFirst()
|
||||||
?.devices
|
?.devices
|
||||||
?.map {
|
?.map { CryptoMapper.mapToModel(it) }
|
||||||
CryptoMapper.mapToModel(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.flatten()
|
.flatten()
|
||||||
.let { allDevices ->
|
.let { allDevices ->
|
||||||
Timber.v("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} devices ${allDevices.map { it.deviceId }}")
|
Timber.v("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} devices ${allDevices.map { it.deviceId }.logLimit()}")
|
||||||
if (myCrossKeys != null) {
|
if (myCrossSigningInfo != null) {
|
||||||
allDevices.any { !it.trustLevel?.crossSigningVerified.orFalse() }
|
allDevices.any { !it.trustLevel?.crossSigningVerified.orFalse() }
|
||||||
} else {
|
} else {
|
||||||
// Legacy method
|
// Legacy method
|
||||||
|
|
|
@ -259,7 +259,7 @@ internal interface IMXCryptoStore {
|
||||||
* @param deviceKey the public key of the other device.
|
* @param deviceKey the public key of the other device.
|
||||||
* @return A set of sessionId, or null if device is not known
|
* @return A set of sessionId, or null if device is not known
|
||||||
*/
|
*/
|
||||||
fun getDeviceSessionIds(deviceKey: String): Set<String>?
|
fun getDeviceSessionIds(deviceKey: String): List<String>?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve an end-to-end session between the logged-in user and another
|
* Retrieve an end-to-end session between the logged-in user and another
|
||||||
|
|
|
@ -692,7 +692,7 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDeviceSessionIds(deviceKey: String): MutableSet<String> {
|
override fun getDeviceSessionIds(deviceKey: String): List<String> {
|
||||||
return doWithRealm(realmConfiguration) {
|
return doWithRealm(realmConfiguration) {
|
||||||
it.where<OlmSessionEntity>()
|
it.where<OlmSessionEntity>()
|
||||||
.equalTo(OlmSessionEntityFields.DEVICE_KEY, deviceKey)
|
.equalTo(OlmSessionEntityFields.DEVICE_KEY, deviceKey)
|
||||||
|
@ -701,7 +701,6 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
sessionEntity.sessionId
|
sessionEntity.sessionId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.toMutableSet()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun storeInboundGroupSessions(sessions: List<OlmInboundGroupSessionWrapper2>) {
|
override fun storeInboundGroupSessions(sessions: List<OlmInboundGroupSessionWrapper2>) {
|
||||||
|
@ -801,7 +800,7 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
* Note: the result will be only use to export all the keys and not to use the OlmInboundGroupSessionWrapper2,
|
* Note: the result will be only use to export all the keys and not to use the OlmInboundGroupSessionWrapper2,
|
||||||
* so there is no need to use or update `inboundGroupSessionToRelease` for native memory management
|
* so there is no need to use or update `inboundGroupSessionToRelease` for native memory management
|
||||||
*/
|
*/
|
||||||
override fun getInboundGroupSessions(): MutableList<OlmInboundGroupSessionWrapper2> {
|
override fun getInboundGroupSessions(): List<OlmInboundGroupSessionWrapper2> {
|
||||||
return doWithRealm(realmConfiguration) {
|
return doWithRealm(realmConfiguration) {
|
||||||
it.where<OlmInboundGroupSessionEntity>()
|
it.where<OlmInboundGroupSessionEntity>()
|
||||||
.findAll()
|
.findAll()
|
||||||
|
@ -809,7 +808,6 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
inboundGroupSessionEntity.getInboundGroupSession()
|
inboundGroupSessionEntity.getInboundGroupSession()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.toMutableList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeInboundGroupSession(sessionId: String, senderKey: String) {
|
override fun removeInboundGroupSession(sessionId: String, senderKey: String) {
|
||||||
|
@ -964,7 +962,7 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRoomsListBlacklistUnverifiedDevices(): MutableList<String> {
|
override fun getRoomsListBlacklistUnverifiedDevices(): List<String> {
|
||||||
return doWithRealm(realmConfiguration) {
|
return doWithRealm(realmConfiguration) {
|
||||||
it.where<CryptoRoomEntity>()
|
it.where<CryptoRoomEntity>()
|
||||||
.equalTo(CryptoRoomEntityFields.BLACKLIST_UNVERIFIED_DEVICES, true)
|
.equalTo(CryptoRoomEntityFields.BLACKLIST_UNVERIFIED_DEVICES, true)
|
||||||
|
@ -973,10 +971,9 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
cryptoRoom.roomId
|
cryptoRoom.roomId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.toMutableList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDeviceTrackingStatuses(): MutableMap<String, Int> {
|
override fun getDeviceTrackingStatuses(): Map<String, Int> {
|
||||||
return doWithRealm(realmConfiguration) {
|
return doWithRealm(realmConfiguration) {
|
||||||
it.where<UserEntity>()
|
it.where<UserEntity>()
|
||||||
.findAll()
|
.findAll()
|
||||||
|
@ -987,7 +984,6 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
entry.value.deviceTrackingStatus
|
entry.value.deviceTrackingStatus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.toMutableMap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveDeviceTrackingStatuses(deviceTrackingStatuses: Map<String, Int>) {
|
override fun saveDeviceTrackingStatuses(deviceTrackingStatuses: Map<String, Int>) {
|
||||||
|
|
|
@ -22,6 +22,8 @@ import io.realm.kotlin.createObject
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||||
|
import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider
|
||||||
|
import org.matrix.android.sdk.internal.crypto.DeviceListManager
|
||||||
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
||||||
import org.matrix.android.sdk.internal.database.mapper.toEntity
|
import org.matrix.android.sdk.internal.database.mapper.toEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
|
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
|
||||||
|
@ -57,6 +59,8 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
|
||||||
private val syncTokenStore: SyncTokenStore,
|
private val syncTokenStore: SyncTokenStore,
|
||||||
private val roomSummaryUpdater: RoomSummaryUpdater,
|
private val roomSummaryUpdater: RoomSummaryUpdater,
|
||||||
private val roomMemberEventHandler: RoomMemberEventHandler,
|
private val roomMemberEventHandler: RoomMemberEventHandler,
|
||||||
|
private val cryptoSessionInfoProvider: CryptoSessionInfoProvider,
|
||||||
|
private val deviceListManager: DeviceListManager,
|
||||||
private val globalErrorReceiver: GlobalErrorReceiver
|
private val globalErrorReceiver: GlobalErrorReceiver
|
||||||
) : LoadRoomMembersTask {
|
) : LoadRoomMembersTask {
|
||||||
|
|
||||||
|
@ -124,6 +128,10 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
|
||||||
roomEntity.membersLoadStatus = RoomMembersLoadStatusType.LOADED
|
roomEntity.membersLoadStatus = RoomMembersLoadStatusType.LOADED
|
||||||
roomSummaryUpdater.update(realm, roomId, updateMembers = true)
|
roomSummaryUpdater.update(realm, roomId, updateMembers = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cryptoSessionInfoProvider.isRoomEncrypted(roomId)) {
|
||||||
|
deviceListManager.onRoomMembersLoadedFor(roomId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRoomMembersLoadStatus(roomId: String): RoomMembersLoadStatusType {
|
private fun getRoomMembersLoadStatus(roomId: String): RoomMembersLoadStatusType {
|
||||||
|
|
|
@ -131,8 +131,8 @@ internal class RoomSummaryUpdater @Inject constructor(
|
||||||
// mmm i want to decrypt now or is it ok to do it async?
|
// mmm i want to decrypt now or is it ok to do it async?
|
||||||
tryOrNull {
|
tryOrNull {
|
||||||
eventDecryptor.decryptEvent(root.asDomain(), "")
|
eventDecryptor.decryptEvent(root.asDomain(), "")
|
||||||
// eventDecryptor.decryptEventAsync(root.asDomain(), "", NoOpMatrixCallback())
|
|
||||||
}
|
}
|
||||||
|
?.let { root.setDecryptionResult(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateMembers) {
|
if (updateMembers) {
|
||||||
|
@ -144,7 +144,7 @@ internal class RoomSummaryUpdater @Inject constructor(
|
||||||
|
|
||||||
roomSummaryEntity.otherMemberIds.clear()
|
roomSummaryEntity.otherMemberIds.clear()
|
||||||
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
|
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
|
||||||
if (roomSummaryEntity.isEncrypted) {
|
if (roomSummaryEntity.isEncrypted && otherRoomMembers.isNotEmpty()) {
|
||||||
// mmm maybe we could only refresh shield instead of checking trust also?
|
// mmm maybe we could only refresh shield instead of checking trust also?
|
||||||
crossSigningService.onUsersDeviceUpdate(otherRoomMembers)
|
crossSigningService.onUsersDeviceUpdate(otherRoomMembers)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,18 @@ package org.matrix.android.sdk.internal.util
|
||||||
import org.matrix.android.sdk.BuildConfig
|
import org.matrix.android.sdk.BuildConfig
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
internal fun <T> Collection<T>.logLimit(maxQuantity: Int = 5): String {
|
||||||
|
return buildString {
|
||||||
|
append(size)
|
||||||
|
append(" item(s)")
|
||||||
|
if (size > maxQuantity) {
|
||||||
|
append(", first $maxQuantity items")
|
||||||
|
}
|
||||||
|
append(": ")
|
||||||
|
append(this@logLimit.take(maxQuantity))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal suspend fun <T> logDuration(message: String,
|
internal suspend fun <T> logDuration(message: String,
|
||||||
block: suspend () -> T): T {
|
block: suspend () -> T): T {
|
||||||
Timber.v("$message -- BEGIN")
|
Timber.v("$message -- BEGIN")
|
||||||
|
|
|
@ -92,7 +92,8 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
||||||
return RoomSummaryItem_()
|
return RoomSummaryItem_()
|
||||||
.id(roomSummary.roomId)
|
.id(roomSummary.roomId)
|
||||||
.avatarRenderer(avatarRenderer)
|
.avatarRenderer(avatarRenderer)
|
||||||
.encryptionTrustLevel(roomSummary.roomEncryptionTrustLevel)
|
// We do not display shield in the room list anymore
|
||||||
|
// .encryptionTrustLevel(roomSummary.roomEncryptionTrustLevel)
|
||||||
.matrixItem(roomSummary.toMatrixItem())
|
.matrixItem(roomSummary.toMatrixItem())
|
||||||
.lastEventTime(latestEventTime)
|
.lastEventTime(latestEventTime)
|
||||||
.typingMessage(typingMessage)
|
.typingMessage(typingMessage)
|
||||||
|
|
Loading…
Reference in a new issue