Upload device keys only once to the homeserver and fix crash when no network (#1629)

This commit is contained in:
Benoit Marty 2020-07-06 17:12:47 +02:00
parent 92ecfafa0d
commit f998cb6b18
6 changed files with 43 additions and 9 deletions

View File

@ -5,7 +5,7 @@ Features ✨:
- -
Improvements 🙌: Improvements 🙌:
- - Upload device keys only once to the homeserver and fix crash when no network (#1629)
Bugfix 🐛: Bugfix 🐛:
- Fix crash when coming from a notification (#1601) - Fix crash when coming from a notification (#1601)

View File

@ -70,7 +70,6 @@ import im.vector.matrix.android.internal.crypto.model.event.RoomKeyWithHeldConte
import im.vector.matrix.android.internal.crypto.model.event.SecretSendEventContent import im.vector.matrix.android.internal.crypto.model.event.SecretSendEventContent
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
import im.vector.matrix.android.internal.crypto.model.toRest import im.vector.matrix.android.internal.crypto.model.toRest
import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository
@ -343,8 +342,11 @@ internal class DefaultCryptoService @Inject constructor(
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
// Open the store // Open the store
cryptoStore.open() cryptoStore.open()
// TODO why do that everytime? we should mark that it was done // this can throw if no network
tryThis {
uploadDeviceKeys() uploadDeviceKeys()
}
oneTimeKeysUploader.maybeUploadOneTimeKeys() oneTimeKeysUploader.maybeUploadOneTimeKeys()
// this can throw if no backup // this can throw if no backup
tryThis { tryThis {
@ -980,7 +982,11 @@ internal class DefaultCryptoService @Inject constructor(
/** /**
* Upload my user's device keys. * Upload my user's device keys.
*/ */
private suspend fun uploadDeviceKeys(): KeysUploadResponse { private suspend fun uploadDeviceKeys() {
if (cryptoStore.getDeviceKeysUploaded()) {
Timber.d("Keys already uploaded, nothing to do")
return
}
// Prepare the device keys data to send // Prepare the device keys data to send
// Sign it // Sign it
val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary()) val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary())
@ -991,7 +997,9 @@ internal class DefaultCryptoService @Inject constructor(
) )
val uploadDeviceKeysParams = UploadKeysTask.Params(rest, null) val uploadDeviceKeysParams = UploadKeysTask.Params(rest, null)
return uploadKeysTask.execute(uploadDeviceKeysParams) uploadKeysTask.execute(uploadDeviceKeysParams)
cryptoStore.setDeviceKeysUploaded(true)
} }
/** /**

View File

@ -433,4 +433,7 @@ internal interface IMXCryptoStore {
fun getOutgoingSecretRequest(secretName: String): OutgoingSecretRequest? fun getOutgoingSecretRequest(secretName: String): OutgoingSecretRequest?
fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest> fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest>
fun getGossipingEventsTrail(): List<Event> fun getGossipingEventsTrail(): List<Event>
fun setDeviceKeysUploaded(uploaded: Boolean)
fun getDeviceKeysUploaded(): Boolean
} }

View File

@ -842,6 +842,18 @@ internal class RealmCryptoStore @Inject constructor(
} ?: false } ?: false
} }
override fun setDeviceKeysUploaded(uploaded: Boolean) {
doRealmTransaction(realmConfiguration) {
it.where<CryptoMetadataEntity>().findFirst()?.deviceKeysSentToServer = uploaded
}
}
override fun getDeviceKeysUploaded(): Boolean {
return doWithRealm(realmConfiguration) {
it.where<CryptoMetadataEntity>().findFirst()?.deviceKeysSentToServer
} ?: false
}
override fun setRoomsListBlacklistUnverifiedDevices(roomIds: List<String>) { override fun setRoomsListBlacklistUnverifiedDevices(roomIds: List<String>) {
doRealmTransaction(realmConfiguration) { doRealmTransaction(realmConfiguration) {
// Reset all // Reset all

View File

@ -54,7 +54,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
// 0, 1, 2: legacy Riot-Android // 0, 1, 2: legacy Riot-Android
// 3: migrate to RiotX schema // 3: migrate to RiotX schema
// 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6) // 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6)
const val CRYPTO_STORE_SCHEMA_VERSION = 10L const val CRYPTO_STORE_SCHEMA_VERSION = 11L
} }
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
@ -70,6 +70,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
if (oldVersion <= 7) migrateTo8(realm) if (oldVersion <= 7) migrateTo8(realm)
if (oldVersion <= 8) migrateTo9(realm) if (oldVersion <= 8) migrateTo9(realm)
if (oldVersion <= 9) migrateTo10(realm) if (oldVersion <= 9) migrateTo10(realm)
if (oldVersion <= 10) migrateTo11(realm)
} }
private fun migrateTo1Legacy(realm: DynamicRealm) { private fun migrateTo1Legacy(realm: DynamicRealm) {
@ -446,4 +447,11 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
.addField(SharedSessionEntityFields.CHAIN_INDEX, Long::class.java) .addField(SharedSessionEntityFields.CHAIN_INDEX, Long::class.java)
.setNullable(SharedSessionEntityFields.CHAIN_INDEX, true) .setNullable(SharedSessionEntityFields.CHAIN_INDEX, true)
} }
// Version 11L added deviceKeysSentToServer boolean to CryptoMetadataEntity
private fun migrateTo11(realm: DynamicRealm) {
Timber.d("Step 10 -> 11")
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER, Boolean::class.java)
}
} }

View File

@ -36,6 +36,9 @@ internal open class CryptoMetadataEntity(
// The keys backup version currently used. Null means no backup. // The keys backup version currently used. Null means no backup.
var backupVersion: String? = null, var backupVersion: String? = null,
// The device keys has been sent to the homeserver
var deviceKeysSentToServer: Boolean = false,
var xSignMasterPrivateKey: String? = null, var xSignMasterPrivateKey: String? = null,
var xSignUserPrivateKey: String? = null, var xSignUserPrivateKey: String? = null,
var xSignSelfSignedPrivateKey: String? = null, var xSignSelfSignedPrivateKey: String? = null,