Fix sending encrypted messages after someone logged out a device

Removing devices in foreach resulted in an exception, thus the device
did not get properly removed, which resulted in following issues:
- In the room settings, members would show with unverified devices,
  where devices were actually logged out
- Sending encrypted messages to contacts who logged out a device did
  lead to a "Message failed to send" with Retry button showing

E/ /Tag: ## CRYPTO | refreshOutdatedDeviceLists() : ERROR updating device keys for users [@redacted:somematrixserver.com]
java.util.NoSuchElementException: Cannot access index 10 when size is 9. Remember to check hasNext() before using next().
	at io.realm.RealmList$RealmItr.next(RealmList.java:9)
	at org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore$storeUserDevices$1.invoke(RealmCryptoStore.kt:41)
	at org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore$storeUserDevices$1.invoke(RealmCryptoStore.kt:1)
	at org.matrix.android.sdk.internal.crypto.store.db.-$$Lambda$HelperKt$XtYpPdQTMtzbOWZdtlMV_aWM9XY.execute(lambda:2)
	at io.realm.Realm.executeTransaction(Realm.java:9)
	at org.matrix.android.sdk.api.MatrixCallback$DefaultImpls.doRealmTransaction(MatrixCallback.kt:2)
	at org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore.storeUserDevices(RealmCryptoStore.kt:1)
	at org.matrix.android.sdk.internal.crypto.DeviceListManager.doKeyDownloadForUsers(DeviceListManager.kt:120)
	at org.matrix.android.sdk.internal.crypto.DeviceListManager$doKeyDownloadForUsers$1.invokeSuspend(DeviceListManager.kt:1)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:3)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:18)
	at android.os.Handler.handleCallback(Handler.java:883)
	at android.os.Handler.dispatchMessage(Handler.java:100)
	at android.os.Looper.loop(Looper.java:237)
	at android.os.HandlerThread.run(HandlerThread.java:67)

Change-Id: Icd3e21f15c6672673fec58e0fc617fa8c57ba18e
This commit is contained in:
SpiritCroc 2021-08-03 12:00:52 +02:00
parent b58f9cedbd
commit d268930a5c

View File

@ -286,12 +286,17 @@ internal class RealmCryptoStore @Inject constructor(
val userEntity = UserEntity.getOrCreate(realm, userId)
// First delete the removed devices
val deviceIds = devices.keys
val devicesToDelete = ArrayList<DeviceInfoEntity>()
userEntity.devices.iterator().forEach { deviceInfoEntity ->
if (deviceInfoEntity.deviceId !in deviceIds) {
Timber.d("Remove device ${deviceInfoEntity.deviceId} of user $userId")
deviceInfoEntity.deleteOnCascade()
devicesToDelete.add(deviceInfoEntity)
}
}
while (devicesToDelete.isNotEmpty()) {
val device = devicesToDelete.removeAt(0)
device.deleteOnCascade()
}
// Then update existing devices or add new one
devices.values.forEach { cryptoDeviceInfo ->
val existingDeviceInfoEntity = userEntity.devices.firstOrNull { it.deviceId == cryptoDeviceInfo.deviceId }