CryptoStore migration: step1: import migration from Riot-Android (not tested)

This commit is contained in:
Benoit Marty 2020-06-19 09:43:07 +02:00
parent fe8f79698c
commit 39022b3b66
1 changed files with 106 additions and 18 deletions

View File

@ -30,8 +30,10 @@ import im.vector.matrix.android.internal.crypto.store.db.model.DeviceInfoEntityF
import im.vector.matrix.android.internal.crypto.store.db.model.GossipingEventEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.IncomingGossipingRequestEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.KeyInfoEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.KeysBackupDataEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.OlmSessionEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.OutgoingGossipingRequestEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.TrustLevelEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.UserEntityFields
@ -43,27 +45,112 @@ import javax.inject.Inject
internal class RealmCryptoStoreMigration @Inject constructor(private val crossSigningKeysMapper: CrossSigningKeysMapper) : RealmMigration {
// Version 1L added Cross Signing info persistence
companion object {
const val CRYPTO_STORE_SCHEMA_VERSION = 6L
// 0, 1, 2: legacy Riot-Android
// 3: migrate to RiotX schema
// 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6)
const val CRYPTO_STORE_SCHEMA_VERSION = 9L
}
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
Timber.v("Migrating Realm Crypto from $oldVersion to $newVersion")
if (oldVersion <= 0) migrateTo1(realm)
if (oldVersion <= 1) migrateTo2(realm)
if (oldVersion <= 2) migrateTo3(realm)
if (oldVersion <= 0) migrateTo1Legacy(realm)
if (oldVersion <= 1) migrateTo2Legacy(realm)
if (oldVersion <= 2) migrateTo3RiotX(realm)
if (oldVersion <= 3) migrateTo4(realm)
if (oldVersion <= 4) migrateTo5(realm)
if (oldVersion <= 5) migrateTo6(realm)
if (oldVersion <= 6) migrateTo7(realm)
if (oldVersion <= 7) migrateTo8(realm)
if (oldVersion <= 8) migrateTo9(realm)
}
private fun migrateTo1(realm: DynamicRealm) {
private fun migrateTo1Legacy(realm: DynamicRealm) {
Timber.d("Step 0 -> 1")
Timber.d("Add field lastReceivedMessageTs (Long) and set the value to 0")
realm.schema.get("OlmSessionEntity")
?.addField(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, Long::class.java)
?.transform {
it.setLong(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, 0)
}
}
private fun migrateTo2Legacy(realm: DynamicRealm) {
Timber.d("Step 1 -> 2")
Timber.d("Update IncomingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields")
realm.schema.get("IncomingRoomKeyRequestEntity")
?.addField("requestBodyAlgorithm", String::class.java)
?.addField("requestBodyRoomId", String::class.java)
?.addField("requestBodySenderKey", String::class.java)
?.addField("requestBodySessionId", String::class.java)
?.transform { dynamicObject ->
val requestBodyString = dynamicObject.getString("requestBodyString")
try {
// It was a map before
val map: Map<String, String>? = deserializeFromRealm(requestBodyString)
map?.let {
dynamicObject.setString("requestBodyAlgorithm", it["algorithm"])
dynamicObject.setString("requestBodyRoomId", it["room_id"])
dynamicObject.setString("requestBodySenderKey", it["sender_key"])
dynamicObject.setString("requestBodySessionId", it["session_id"])
}
} catch (e: Exception) {
Timber.e(e, "Error")
}
}
?.removeField("requestBodyString")
Timber.d("Update IncomingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields")
realm.schema.get("OutgoingRoomKeyRequestEntity")
?.addField("requestBodyAlgorithm", String::class.java)
?.addField("requestBodyRoomId", String::class.java)
?.addField("requestBodySenderKey", String::class.java)
?.addField("requestBodySessionId", String::class.java)
?.transform { dynamicObject ->
val requestBodyString = dynamicObject.getString("requestBodyString")
try {
// It was a map before
val map: Map<String, String>? = deserializeFromRealm(requestBodyString)
map?.let {
dynamicObject.setString("requestBodyAlgorithm", it["algorithm"])
dynamicObject.setString("requestBodyRoomId", it["room_id"])
dynamicObject.setString("requestBodySenderKey", it["sender_key"])
dynamicObject.setString("requestBodySessionId", it["session_id"])
}
} catch (e: Exception) {
Timber.e(e, "Error")
}
}
?.removeField("requestBodyString")
Timber.d("Create KeysBackupDataEntity")
realm.schema.create("KeysBackupDataEntity")
.addField(KeysBackupDataEntityFields.PRIMARY_KEY, Integer::class.java)
.addPrimaryKey(KeysBackupDataEntityFields.PRIMARY_KEY)
.setRequired(KeysBackupDataEntityFields.PRIMARY_KEY, true)
.addField(KeysBackupDataEntityFields.BACKUP_LAST_SERVER_HASH, String::class.java)
.addField(KeysBackupDataEntityFields.BACKUP_LAST_SERVER_NUMBER_OF_KEYS, Integer::class.java)
}
private fun migrateTo3RiotX(realm: DynamicRealm) {
Timber.d("Step 2 -> 3")
// TODO Remove log of realm
Timber.d("Migrate to RiotX model $realm")
}
// Version 4L added Cross Signing info persistence
private fun migrateTo4(realm: DynamicRealm) {
Timber.d("Step 3 -> 4")
Timber.d("Create KeyInfoEntity")
val trustLevelentityEntitySchema = realm.schema.create("TrustLevelEntity")
val trustLevelEntityEntitySchema = realm.schema.create("TrustLevelEntity")
.addField(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, Boolean::class.java)
.setNullable(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, true)
.addField(TrustLevelEntityFields.LOCALLY_VERIFIED, Boolean::class.java)
@ -73,7 +160,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
.addField(KeyInfoEntityFields.PUBLIC_KEY_BASE64, String::class.java)
.addField(KeyInfoEntityFields.SIGNATURES, String::class.java)
.addRealmListField(KeyInfoEntityFields.USAGES.`$`, String::class.java)
.addRealmObjectField(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelentityEntitySchema)
.addRealmObjectField(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelEntityEntitySchema)
Timber.d("Create CrossSigningInfoEntity")
@ -112,7 +199,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
?.addField(DeviceInfoEntityFields.UNSIGNED_MAP_JSON, String::class.java)
?.addField(DeviceInfoEntityFields.IS_BLOCKED, Boolean::class.java)
?.setNullable(DeviceInfoEntityFields.IS_BLOCKED, true)
?.addRealmObjectField(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelentityEntitySchema)
?.addRealmObjectField(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelEntityEntitySchema)
?.transform { obj ->
try {
@ -158,8 +245,8 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
?.removeField("deviceInfoData")
}
private fun migrateTo2(realm: DynamicRealm) {
Timber.d("Step 1 -> 2")
private fun migrateTo5(realm: DynamicRealm) {
Timber.d("Step 4 -> 5")
realm.schema.remove("OutgoingRoomKeyRequestEntity")
realm.schema.remove("IncomingRoomKeyRequestEntity")
@ -199,16 +286,16 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
.addField(OutgoingGossipingRequestEntityFields.REQUEST_STATE_STR, String::class.java)
}
private fun migrateTo3(realm: DynamicRealm) {
Timber.d("Step 2 -> 3")
private fun migrateTo6(realm: DynamicRealm) {
Timber.d("Step 5 -> 6")
Timber.d("Updating CryptoMetadataEntity table")
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY, String::class.java)
?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY_VERSION, String::class.java)
}
private fun migrateTo4(realm: DynamicRealm) {
Timber.d("Step 3 -> 4")
private fun migrateTo7(realm: DynamicRealm) {
Timber.d("Step 6 -> 7")
Timber.d("Updating KeyInfoEntity table")
val keyInfoEntities = realm.where("KeyInfoEntity").findAll()
try {
@ -239,8 +326,8 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
}
}
private fun migrateTo5(realm: DynamicRealm) {
Timber.d("Step 4 -> 5")
private fun migrateTo8(realm: DynamicRealm) {
Timber.d("Step 7 -> 8")
realm.schema.create("MyDeviceLastSeenInfoEntity")
.addField(MyDeviceLastSeenInfoEntityFields.DEVICE_ID, String::class.java)
.addPrimaryKey(MyDeviceLastSeenInfoEntityFields.DEVICE_ID)
@ -261,7 +348,8 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
}
// Fixes duplicate devices in UserEntity#devices
private fun migrateTo6(realm: DynamicRealm) {
private fun migrateTo9(realm: DynamicRealm) {
Timber.d("Step 8 -> 9")
val userEntities = realm.where("UserEntity").findAll()
userEntities.forEach {
try {