Realm crypto: Update migration classes

This commit is contained in:
ganfra 2022-08-05 19:23:50 +02:00
parent 6cfac4526e
commit 7717637e57
19 changed files with 317 additions and 569 deletions

View File

@ -16,7 +16,7 @@
package org.matrix.android.sdk.internal.crypto.store.db package org.matrix.android.sdk.internal.crypto.store.db
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo001Legacy import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo001Legacy
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo002Legacy import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo002Legacy
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo003RiotX import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo003RiotX
@ -34,7 +34,8 @@ import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo015 import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo015
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo016 import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo016
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo017 import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo017
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo018
import org.matrix.android.sdk.internal.database.MatrixAutomaticSchemaMigration
import org.matrix.android.sdk.internal.util.time.Clock import org.matrix.android.sdk.internal.util.time.Clock
import javax.inject.Inject import javax.inject.Inject
@ -46,34 +47,36 @@ import javax.inject.Inject
*/ */
internal class RealmCryptoStoreMigration @Inject constructor( internal class RealmCryptoStoreMigration @Inject constructor(
private val clock: Clock, private val clock: Clock,
) : MatrixRealmMigration( ) : MatrixAutomaticSchemaMigration(
dbName = "Crypto", dbName = "Crypto",
schemaVersion = 17L, schemaVersion = 18L,
) { ) {
/** /**
* Forces all RealmCryptoStoreMigration instances to be equal. * Forces all RealmCryptoStoreMigration instances to be equal.
* Avoids Realm throwing when multiple instances of the migration are set. * Avoids migrationContext throwing when multiple instances of the migration are set.
*/ */
override fun equals(other: Any?) = other is RealmCryptoStoreMigration override fun equals(other: Any?) = other is RealmCryptoStoreMigration
override fun hashCode() = 5000 override fun hashCode() = 5000
override fun doMigrate(realm: DynamicRealm, oldVersion: Long) { override fun doMigrate(oldVersion: Long, migrationContext: AutomaticSchemaMigration.MigrationContext) {
if (oldVersion < 1) MigrateCryptoTo001Legacy(realm).perform() if (oldVersion < 1) MigrateCryptoTo001Legacy(migrationContext).perform()
if (oldVersion < 2) MigrateCryptoTo002Legacy(realm).perform() if (oldVersion < 2) MigrateCryptoTo002Legacy(migrationContext).perform()
if (oldVersion < 3) MigrateCryptoTo003RiotX(realm).perform() if (oldVersion < 3) MigrateCryptoTo003RiotX(migrationContext).perform()
if (oldVersion < 4) MigrateCryptoTo004(realm).perform() if (oldVersion < 4) MigrateCryptoTo004(migrationContext).perform()
if (oldVersion < 5) MigrateCryptoTo005(realm).perform() if (oldVersion < 5) MigrateCryptoTo005(migrationContext).perform()
if (oldVersion < 6) MigrateCryptoTo006(realm).perform() if (oldVersion < 6) MigrateCryptoTo006(migrationContext).perform()
if (oldVersion < 7) MigrateCryptoTo007(realm).perform() if (oldVersion < 7) MigrateCryptoTo007(migrationContext).perform()
if (oldVersion < 8) MigrateCryptoTo008(realm, clock).perform() if (oldVersion < 8) MigrateCryptoTo008(migrationContext, clock).perform()
if (oldVersion < 9) MigrateCryptoTo009(realm).perform() if (oldVersion < 9) MigrateCryptoTo009(migrationContext).perform()
if (oldVersion < 10) MigrateCryptoTo010(realm).perform() if (oldVersion < 10) MigrateCryptoTo010(migrationContext).perform()
if (oldVersion < 11) MigrateCryptoTo011(realm).perform() if (oldVersion < 11) MigrateCryptoTo011(migrationContext).perform()
if (oldVersion < 12) MigrateCryptoTo012(realm).perform() if (oldVersion < 12) MigrateCryptoTo012(migrationContext).perform()
if (oldVersion < 13) MigrateCryptoTo013(realm).perform() if (oldVersion < 13) MigrateCryptoTo013(migrationContext).perform()
if (oldVersion < 14) MigrateCryptoTo014(realm).perform() if (oldVersion < 14) MigrateCryptoTo014(migrationContext).perform()
if (oldVersion < 15) MigrateCryptoTo015(realm).perform() if (oldVersion < 15) MigrateCryptoTo015(migrationContext).perform()
if (oldVersion < 16) MigrateCryptoTo016(realm).perform() if (oldVersion < 16) MigrateCryptoTo016(migrationContext).perform()
if (oldVersion < 17) MigrateCryptoTo017(realm).perform() if (oldVersion < 17) MigrateCryptoTo017(migrationContext).perform()
if (oldVersion < 18) MigrateCryptoTo018(migrationContext).perform()
} }
} }

View File

@ -16,20 +16,13 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntityFields import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber import timber.log.Timber
internal class MigrateCryptoTo001Legacy(realm: DynamicRealm) : RealmMigrator(realm, 1) { internal class MigrateCryptoTo001Legacy(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 1) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Add field lastReceivedMessageTs (Long) and set the value to 0") 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)
}
} }
} }

View File

@ -16,71 +16,16 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber import timber.log.Timber
internal class MigrateCryptoTo002Legacy(realm: DynamicRealm) : RealmMigrator(realm, 2) { internal class MigrateCryptoTo002Legacy(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 2) {
override fun doMigrate(realm: DynamicRealm) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Update IncomingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields") Timber.d("Update IncomingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields")
realm.schema.get("IncomingRoomKeyRequestEntity") Timber.d("Update OutgoingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields")
?.addFieldIfNotExists("requestBodyAlgorithm", String::class.java)
?.addFieldIfNotExists("requestBodyRoomId", String::class.java)
?.addFieldIfNotExists("requestBodySenderKey", String::class.java)
?.addFieldIfNotExists("requestBodySessionId", String::class.java)
?.transform { dynamicObject ->
try {
val requestBodyString = dynamicObject.getString("requestBodyString")
// 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")
}
}
?.removeFieldIfExists("requestBodyString")
Timber.d("Update IncomingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields")
realm.schema.get("OutgoingRoomKeyRequestEntity")
?.addFieldIfNotExists("requestBodyAlgorithm", String::class.java)
?.addFieldIfNotExists("requestBodyRoomId", String::class.java)
?.addFieldIfNotExists("requestBodySenderKey", String::class.java)
?.addFieldIfNotExists("requestBodySessionId", String::class.java)
?.transform { dynamicObject ->
try {
val requestBodyString = dynamicObject.getString("requestBodyString")
// 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")
}
}
?.removeFieldIfExists("requestBodyString")
Timber.d("Create KeysBackupDataEntity") Timber.d("Create KeysBackupDataEntity")
if (!realm.schema.contains("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)
}
} }
} }

View File

@ -16,29 +16,24 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
import org.matrix.android.sdk.internal.util.database.RealmMigrator import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.database.safeEnumerate
import org.matrix.androidsdk.crypto.data.MXDeviceInfo import org.matrix.androidsdk.crypto.data.MXDeviceInfo
import org.matrix.androidsdk.crypto.data.MXOlmInboundGroupSession2 import org.matrix.androidsdk.crypto.data.MXOlmInboundGroupSession2
import timber.log.Timber import timber.log.Timber
internal class MigrateCryptoTo003RiotX(realm: DynamicRealm) : RealmMigrator(realm, 3) { internal class MigrateCryptoTo003RiotX(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 3) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Migrate to RiotX model") Timber.d("Migrate to RiotX model")
realm.schema.get("CryptoRoomEntity")
?.addFieldIfNotExists(CryptoRoomEntityFields.SHOULD_ENCRYPT_FOR_INVITED_MEMBERS, Boolean::class.java)
?.setRequiredIfNotAlready(CryptoRoomEntityFields.SHOULD_ENCRYPT_FOR_INVITED_MEMBERS, false)
// Convert format of MXDeviceInfo, package has to be the same. // Convert format of MXDeviceInfo, package has to be the same.
realm.schema.get("DeviceInfoEntity") migrationContext.safeEnumerate("DeviceInfoEntity") { oldObject, newObject ->
?.transform { obj ->
try { try {
val oldSerializedData = obj.getString("deviceInfoData") val oldSerializedData = oldObject.getNullableValue("deviceInfoData", String::class)
deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { legacyMxDeviceInfo -> deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { legacyMxDeviceInfo ->
val newMxDeviceInfo = org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo( val newMxDeviceInfo = org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo(
deviceId = legacyMxDeviceInfo.deviceId, deviceId = legacyMxDeviceInfo.deviceId,
@ -49,8 +44,7 @@ internal class MigrateCryptoTo003RiotX(realm: DynamicRealm) : RealmMigrator(real
unsigned = legacyMxDeviceInfo.unsigned, unsigned = legacyMxDeviceInfo.unsigned,
verified = legacyMxDeviceInfo.mVerified verified = legacyMxDeviceInfo.mVerified
) )
newObject?.set("deviceInfoData", serializeForRealm(newMxDeviceInfo))
obj.setString("deviceInfoData", serializeForRealm(newMxDeviceInfo))
} }
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "Error") Timber.e(e, "Error")
@ -58,10 +52,9 @@ internal class MigrateCryptoTo003RiotX(realm: DynamicRealm) : RealmMigrator(real
} }
// Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper // Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper
realm.schema.get("OlmInboundGroupSessionEntity") migrationContext.enumerate("OlmInboundGroupSessionEntity") { oldObject, newObject ->
?.transform { obj ->
try { try {
val oldSerializedData = obj.getString("olmInboundGroupSessionData") val oldSerializedData = oldObject.getNullableValue("olmInboundGroupSessionData", String::class)
deserializeFromRealm<MXOlmInboundGroupSession2>(oldSerializedData)?.let { mxOlmInboundGroupSession2 -> deserializeFromRealm<MXOlmInboundGroupSession2>(oldSerializedData)?.let { mxOlmInboundGroupSession2 ->
val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier() val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier()
val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false) val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false)
@ -73,7 +66,7 @@ internal class MigrateCryptoTo003RiotX(realm: DynamicRealm) : RealmMigrator(real
forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain
} }
obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper)) newObject?.set("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper))
} }
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "Error") Timber.e(e, "Error")

View File

@ -18,58 +18,28 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import com.squareup.moshi.Types import com.squareup.moshi.Types
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo
import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields import org.matrix.android.sdk.internal.database.safeEnumerate
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
import org.matrix.android.sdk.internal.di.SerializeNulls import org.matrix.android.sdk.internal.di.SerializeNulls
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber import timber.log.Timber
// Version 4L added Cross Signing info persistence // Version 4L added Cross Signing info persistence
internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) { internal class MigrateCryptoTo004(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 4) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
if (realm.schema.contains("TrustLevelEntity")) { if (migrationContext.oldRealm.schema()["TrustLevelEntity"] != null) {
Timber.d("Skipping Step 3 -> 4 because entities already exist") Timber.d("Skipping Step 3 -> 4 because entities already exist")
return return
} }
Timber.d("Create KeyInfoEntity") Timber.d("Create KeyInfoEntity")
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)
.setNullable(TrustLevelEntityFields.LOCALLY_VERIFIED, true)
val keyInfoEntitySchema = realm.schema.create("KeyInfoEntity")
.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)
Timber.d("Create CrossSigningInfoEntity") Timber.d("Create CrossSigningInfoEntity")
val crossSigningInfoSchema = realm.schema.create("CrossSigningInfoEntity")
.addField(CrossSigningInfoEntityFields.USER_ID, String::class.java)
.addPrimaryKey(CrossSigningInfoEntityFields.USER_ID)
.addRealmListField(CrossSigningInfoEntityFields.CROSS_SIGNING_KEYS.`$`, keyInfoEntitySchema)
Timber.d("Updating UserEntity table") Timber.d("Updating UserEntity table")
realm.schema.get("UserEntity")
?.addRealmObjectField(UserEntityFields.CROSS_SIGNING_INFO_ENTITY.`$`, crossSigningInfoSchema)
Timber.d("Updating CryptoMetadataEntity table") Timber.d("Updating CryptoMetadataEntity table")
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.X_SIGN_MASTER_PRIVATE_KEY, String::class.java)
?.addField(CryptoMetadataEntityFields.X_SIGN_USER_PRIVATE_KEY, String::class.java)
?.addField(CryptoMetadataEntityFields.X_SIGN_SELF_SIGNED_PRIVATE_KEY, String::class.java)
val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build() val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build()
val listMigrationAdapter = moshi.adapter<List<String>>( val listMigrationAdapter = moshi.adapter<List<String>>(
@ -87,57 +57,46 @@ internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4)
) )
) )
realm.schema.get("DeviceInfoEntity") migrationContext.safeEnumerate("DeviceInfoEntity") { oldObject, newObject ->
?.addField(DeviceInfoEntityFields.USER_ID, String::class.java) if (newObject == null) return@safeEnumerate
?.addField(DeviceInfoEntityFields.ALGORITHM_LIST_JSON, String::class.java)
?.addField(DeviceInfoEntityFields.KEYS_MAP_JSON, String::class.java)
?.addField(DeviceInfoEntityFields.SIGNATURE_MAP_JSON, String::class.java)
?.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)
?.transform { obj ->
try { try {
val oldSerializedData = obj.getString("deviceInfoData") val oldSerializedData = oldObject.getNullableValue("deviceInfoData", String::class)
deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { oldDevice -> deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { oldDevice ->
val trustLevel = TrustLevelEntity()
val trustLevel = realm.createObject("TrustLevelEntity")
when (oldDevice.verified) { when (oldDevice.verified) {
MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> { MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> {
obj.setNull(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`) newObject.set("trustLevelEntity", null)
} }
MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> { MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> {
trustLevel.setNull(TrustLevelEntityFields.LOCALLY_VERIFIED) trustLevel.locallyVerified = null
trustLevel.setNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED) trustLevel.crossSignedVerified = null
obj.setBoolean(DeviceInfoEntityFields.IS_BLOCKED, oldDevice.isBlocked) newObject.set("isBlocked", oldDevice.isBlocked)
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel) newObject.set("trustLevelEntity", trustLevel)
} }
MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED -> { MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED -> {
trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, false) trustLevel.locallyVerified = false
trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false) trustLevel.crossSignedVerified = false
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel) newObject.set("trustLevelEntity", trustLevel)
} }
MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> { MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> {
trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, true) trustLevel.locallyVerified = true
trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false) trustLevel.crossSignedVerified = false
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel) newObject.set("trustLevelEntity", trustLevel)
} }
} }
newObject.set("userId", oldDevice.userId)
obj.setString(DeviceInfoEntityFields.USER_ID, oldDevice.userId) newObject.set("identityKey", oldDevice.identityKey())
obj.setString(DeviceInfoEntityFields.IDENTITY_KEY, oldDevice.identityKey()) newObject.set("algorithmListJson", listMigrationAdapter.toJson(oldDevice.algorithms))
obj.setString(DeviceInfoEntityFields.ALGORITHM_LIST_JSON, listMigrationAdapter.toJson(oldDevice.algorithms)) newObject.set("keysMapJson", mapMigrationAdapter.toJson(oldDevice.keys))
obj.setString(DeviceInfoEntityFields.KEYS_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.keys)) newObject.set("signatureMapJson", mapMigrationAdapter.toJson(oldDevice.signatures))
obj.setString(DeviceInfoEntityFields.SIGNATURE_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.signatures)) newObject.set("unsignedMapJson", mapMigrationAdapter.toJson(oldDevice.unsigned))
obj.setString(DeviceInfoEntityFields.UNSIGNED_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.unsigned))
} }
} catch (failure: Throwable) { } catch (failure: Throwable) {
Timber.w(failure, "Crypto Data base migration error") Timber.w(failure, "Crypto Data base migration error")
// an unfortunate refactor did modify that class, making deserialization failing // an unfortunate refactor did modify that class, making deserialization failing
// so we just skip and ignore.. // so we just skip and ignore..
} }
} }
?.removeField("deviceInfoData")
} }
} }

View File

@ -16,47 +16,17 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.util.database.RealmMigrator import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import timber.log.Timber
internal class MigrateCryptoTo005(realm: DynamicRealm) : RealmMigrator(realm, 5) { internal class MigrateCryptoTo005(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 5) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
realm.schema.remove("OutgoingRoomKeyRequestEntity") Timber.d("Remove OutgoingRoomKeyRequestEntity")
realm.schema.remove("IncomingRoomKeyRequestEntity") Timber.d("Remove IncomingRoomKeyRequestEntity")
Timber.d("Create GossipingEventEntity")
// Not need to migrate existing request, just start fresh? Timber.d("Create IncomingGossipingRequestEntity")
realm.schema.create("GossipingEventEntity") Timber.d("Create OutgoingGossipingRequestEntity")
.addField("type", String::class.java)
.addIndex("type")
.addField("content", String::class.java)
.addField("sender", String::class.java)
.addIndex("sender")
.addField("decryptionResultJson", String::class.java)
.addField("decryptionErrorCode", String::class.java)
.addField("ageLocalTs", Long::class.java)
.setNullable("ageLocalTs", true)
.addField("sendStateStr", String::class.java)
realm.schema.create("IncomingGossipingRequestEntity")
.addField("requestId", String::class.java)
.addIndex("requestId")
.addField("typeStr", String::class.java)
.addIndex("typeStr")
.addField("otherUserId", String::class.java)
.addField("requestedInfoStr", String::class.java)
.addField("otherDeviceId", String::class.java)
.addField("requestStateStr", String::class.java)
.addField("localCreationTimestamp", Long::class.java)
.setNullable("localCreationTimestamp", true)
realm.schema.create("OutgoingGossipingRequestEntity")
.addField("requestId", String::class.java)
.addIndex("requestId")
.addField("recipientsData", String::class.java)
.addField("requestedInfoStr", String::class.java)
.addField("typeStr", String::class.java)
.addIndex("typeStr")
.addField("requestStateStr", String::class.java)
} }
} }

View File

@ -16,17 +16,13 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber import timber.log.Timber
internal class MigrateCryptoTo006(realm: DynamicRealm) : RealmMigrator(realm, 6) { internal class MigrateCryptoTo006(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 6) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Updating CryptoMetadataEntity table") 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)
} }
} }

View File

@ -16,45 +16,43 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.dynamic.getNullableValue
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2 import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber import timber.log.Timber
internal class MigrateCryptoTo007(realm: DynamicRealm) : RealmMigrator(realm, 7) { internal class MigrateCryptoTo007(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 7) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Updating KeyInfoEntity table") Timber.d("Updating KeyInfoEntity table")
val crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi()) val crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi())
val keyInfoEntities = migrationContext.newRealm.query("KeyInfoEntity").find()
val keyInfoEntities = realm.where("KeyInfoEntity").findAll()
try { try {
keyInfoEntities.forEach { keyInfoEntities.forEach {
val stringSignatures = it.getString(KeyInfoEntityFields.SIGNATURES) val stringSignatures: String? = it.getNullableValue("signatures")
val objectSignatures: Map<String, Map<String, String>>? = deserializeFromRealm(stringSignatures) val objectSignatures: Map<String, Map<String, String>>? = deserializeFromRealm(stringSignatures)
val jsonSignatures = crossSigningKeysMapper.serializeSignatures(objectSignatures) val jsonSignatures = crossSigningKeysMapper.serializeSignatures(objectSignatures)
it.setString(KeyInfoEntityFields.SIGNATURES, jsonSignatures) it.set("signatures", jsonSignatures)
} }
} catch (ignore: Throwable) { } catch (ignore: Throwable) {
} }
// Migrate frozen classes // Migrate frozen classes
val inboundGroupSessions = realm.where("OlmInboundGroupSessionEntity").findAll() val inboundGroupSessions = migrationContext.newRealm.query("OlmInboundGroupSessionEntity").find()
inboundGroupSessions.forEach { dynamicObject -> inboundGroupSessions.forEach { dynamicObject ->
dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { serializedObject -> dynamicObject.getNullableValue("olmInboundGroupSessionData", String::class)?.let { serializedObject ->
try { try {
deserializeFromRealm<OlmInboundGroupSessionWrapper?>(serializedObject)?.let { oldFormat -> deserializeFromRealm<OlmInboundGroupSessionWrapper?>(serializedObject)?.let { oldFormat ->
val newFormat = oldFormat.exportKeys()?.let { val newFormat = oldFormat.exportKeys()?.let {
OlmInboundGroupSessionWrapper2(it) OlmInboundGroupSessionWrapper2(it)
} }
dynamicObject.setString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA, serializeForRealm(newFormat)) dynamicObject.set("olmInboundGroupSessionData", serializeForRealm(newFormat))
} }
} catch (failure: Throwable) { } catch (failure: Throwable) {
Timber.e(failure, "## OlmInboundGroupSessionEntity migration failed") Timber.e(failure, "## OlmInboundGroupSessionEntity migration failed")

View File

@ -16,35 +16,20 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields import org.matrix.android.sdk.internal.database.safeEnumerate
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import org.matrix.android.sdk.internal.util.time.Clock import org.matrix.android.sdk.internal.util.time.Clock
import timber.log.Timber
internal class MigrateCryptoTo008( internal class MigrateCryptoTo008(context: AutomaticSchemaMigration.MigrationContext, private val clock: Clock) : KotlinRealmMigrator(context, 8) {
realm: DynamicRealm,
private val clock: Clock,
) : RealmMigrator(realm, 8) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.create("MyDeviceLastSeenInfoEntity")
.addField(MyDeviceLastSeenInfoEntityFields.DEVICE_ID, String::class.java)
.addPrimaryKey(MyDeviceLastSeenInfoEntityFields.DEVICE_ID)
.addField(MyDeviceLastSeenInfoEntityFields.DISPLAY_NAME, String::class.java)
.addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_IP, String::class.java)
.addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_TS, Long::class.java)
.setNullable(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_TS, true)
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Create MyDeviceLastSeenInfoEntity")
Timber.d("Update DeviceInfoEntity")
val now = clock.epochMillis() val now = clock.epochMillis()
realm.schema.get("DeviceInfoEntity") migrationContext.safeEnumerate("DeviceInfoEntity") { _, newObject ->
?.addField(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, Long::class.java) newObject?.set("firstTimeSeenLocalTs", now)
?.setNullable(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, true)
?.transform { deviceInfoEntity ->
tryOrNull {
deviceInfoEntity.setLong(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, now)
}
} }
} }
} }

View File

@ -16,22 +16,20 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber import timber.log.Timber
// Fixes duplicate devices in UserEntity#devices internal class MigrateCryptoTo009(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 9) {
internal class MigrateCryptoTo009(realm: DynamicRealm) : RealmMigrator(realm, 9) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
val userEntities = realm.where("UserEntity").findAll() Timber.d("Fixes duplicate devices in UserEntity#devices")
val userEntities = migrationContext.newRealm.query("UserEntity").find()
userEntities.forEach { userEntities.forEach {
try { try {
val deviceList = it.getList(UserEntityFields.DEVICES.`$`) val deviceList = it.getValueList("devices", DeviceInfoEntity::class)
?: return@forEach val distinct = deviceList.distinctBy { it.deviceId }
val distinct = deviceList.distinctBy { it.getString(DeviceInfoEntityFields.DEVICE_ID) }
if (distinct.size != deviceList.size) { if (distinct.size != deviceList.size) {
deviceList.clear() deviceList.clear()
deviceList.addAll(distinct) deviceList.addAll(distinct)

View File

@ -16,35 +16,16 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntityFields import timber.log.Timber
import org.matrix.android.sdk.internal.util.database.RealmMigrator
// Version 10L added WithHeld Keys Info (MSC2399) // Version 10L added WithHeld Keys Info (MSC2399)
internal class MigrateCryptoTo010(realm: DynamicRealm) : RealmMigrator(realm, 10) { internal class MigrateCryptoTo010(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 10) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
realm.schema.create("WithHeldSessionEntity") Timber.d("Create WithHeldSessionEntity")
.addField(WithHeldSessionEntityFields.ROOM_ID, String::class.java) Timber.d("Create SharedSessionEntity")
.addField(WithHeldSessionEntityFields.ALGORITHM, String::class.java)
.addField(WithHeldSessionEntityFields.SESSION_ID, String::class.java)
.addIndex(WithHeldSessionEntityFields.SESSION_ID)
.addField(WithHeldSessionEntityFields.SENDER_KEY, String::class.java)
.addIndex(WithHeldSessionEntityFields.SENDER_KEY)
.addField(WithHeldSessionEntityFields.CODE_STRING, String::class.java)
.addField(WithHeldSessionEntityFields.REASON, String::class.java)
realm.schema.create("SharedSessionEntity")
.addField(SharedSessionEntityFields.ROOM_ID, String::class.java)
.addField(SharedSessionEntityFields.ALGORITHM, String::class.java)
.addField(SharedSessionEntityFields.SESSION_ID, String::class.java)
.addIndex(SharedSessionEntityFields.SESSION_ID)
.addField(SharedSessionEntityFields.USER_ID, String::class.java)
.addIndex(SharedSessionEntityFields.USER_ID)
.addField(SharedSessionEntityFields.DEVICE_ID, String::class.java)
.addIndex(SharedSessionEntityFields.DEVICE_ID)
.addField(SharedSessionEntityFields.CHAIN_INDEX, Long::class.java)
.setNullable(SharedSessionEntityFields.CHAIN_INDEX, true)
} }
} }

View File

@ -16,15 +16,15 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.util.database.RealmMigrator import timber.log.Timber
// Version 11L added deviceKeysSentToServer boolean to CryptoMetadataEntity // Version 11L added deviceKeysSentToServer boolean to CryptoMetadataEntity
internal class MigrateCryptoTo011(realm: DynamicRealm) : RealmMigrator(realm, 11) { internal class MigrateCryptoTo011(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 11) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
realm.schema.get("CryptoMetadataEntity") Timber.d("Update CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER, Boolean::class.java)
} }
} }

View File

@ -16,21 +16,15 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields import timber.log.Timber
import org.matrix.android.sdk.internal.util.database.RealmMigrator
// Version 12L added outbound group session persistence // Version 12L added outbound group session persistence
internal class MigrateCryptoTo012(realm: DynamicRealm) : RealmMigrator(realm, 12) { internal class MigrateCryptoTo012(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 12) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
val outboundEntitySchema = realm.schema.create("OutboundGroupSessionInfoEntity") Timber.d("Create OutboundGroupSessionInfoEntity")
.addField(OutboundGroupSessionInfoEntityFields.SERIALIZED_OUTBOUND_SESSION_DATA, String::class.java) Timber.d("Update CryptoRoomEntity")
.addField(OutboundGroupSessionInfoEntityFields.CREATION_TIME, Long::class.java)
.setNullable(OutboundGroupSessionInfoEntityFields.CREATION_TIME, true)
realm.schema.get("CryptoRoomEntity")
?.addRealmObjectField(CryptoRoomEntityFields.OUTBOUND_SESSION_INFO.`$`, outboundEntitySchema)
} }
} }

View File

@ -16,63 +16,26 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.util.database.RealmMigrator import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
import timber.log.Timber import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
// Version 13L delete unreferenced TrustLevelEntity // Version 13L delete unreferenced TrustLevelEntity
internal class MigrateCryptoTo013(realm: DynamicRealm) : RealmMigrator(realm, 13) { internal class MigrateCryptoTo013(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 13) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
// Use a trick to do that... Ref: https://stackoverflow.com/questions/55221366 val trustLevelEntities = migrationContext.newRealm.query("TrustLevelEntity").find()
val trustLevelEntitySchema = realm.schema.get("TrustLevelEntity") val linkedTrustLevelEntities = mutableSetOf<TrustLevelEntity>()
val deviceInfoEntities = migrationContext.newRealm.query("DeviceInfoEntity").find()
/* deviceInfoEntities.forEach {
Creating a new temp field called isLinked which is set to true for those which are val trustLevelEntity = it.getNullableValue("trustLevelEntity", TrustLevelEntity::class)
references by other objects. Rest of them are set to false. Then removing all if (trustLevelEntity != null) {
those which are false and hence duplicate and unnecessary. Then removing the temp field linkedTrustLevelEntities.add(trustLevelEntity)
isLinked
*/
var mainCounter = 0
var deviceInfoCounter = 0
var keyInfoCounter = 0
val deleteCounter: Int
trustLevelEntitySchema
?.addField("isLinked", Boolean::class.java)
?.transform { obj ->
// Setting to false for all by default
obj.set("isLinked", false)
mainCounter++
} }
realm.schema.get("DeviceInfoEntity")?.transform { obj ->
// Setting to true for those which are referenced in DeviceInfoEntity
deviceInfoCounter++
obj.getObject("trustLevelEntity")?.set("isLinked", true)
} }
val unreferencedTrustLevelEntities = trustLevelEntities.subtract(linkedTrustLevelEntities)
realm.schema.get("KeyInfoEntity")?.transform { obj -> unreferencedTrustLevelEntities.forEach {
// Setting to true for those which are referenced in KeyInfoEntity migrationContext.newRealm.delete(it)
keyInfoCounter++
obj.getObject("trustLevelEntity")?.set("isLinked", true)
}
// Removing all those which are set as false
realm.where("TrustLevelEntity")
.equalTo("isLinked", false)
.findAll()
.also { deleteCounter = it.size }
.deleteAllFromRealm()
trustLevelEntitySchema?.removeField("isLinked")
Timber.w("TrustLevelEntity cleanup: $mainCounter entities")
Timber.w("TrustLevelEntity cleanup: $deviceInfoCounter entities referenced in DeviceInfoEntities")
Timber.w("TrustLevelEntity cleanup: $keyInfoCounter entities referenced in KeyInfoEntity")
Timber.w("TrustLevelEntity cleanup: $deleteCounter entities deleted!")
if (mainCounter != deviceInfoCounter + keyInfoCounter + deleteCounter) {
Timber.e("TrustLevelEntity cleanup: Something is not correct...")
} }
} }
} }

View File

@ -16,26 +16,28 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields import org.matrix.android.sdk.internal.database.safeEnumerate
import org.matrix.android.sdk.internal.util.database.RealmMigrator import timber.log.Timber
// Version 14L Update the way we remember key sharing // Version 14L Update the way we remember key sharing
internal class MigrateCryptoTo014(realm: DynamicRealm) : RealmMigrator(realm, 14) { internal class MigrateCryptoTo014(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 14) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
realm.schema.get("SharedSessionEntity") Timber.d("Update SharedSessionEntity")
?.addField(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, String::class.java) migrationContext.safeEnumerate("SharedSessionEntity") { oldObject, newObject ->
?.addIndex(SharedSessionEntityFields.DEVICE_IDENTITY_KEY) if(newObject == null) return@safeEnumerate
?.transform { val sharedUserId = oldObject.getNullableValue("userId", String::class)
val sharedUserId = it.getString(SharedSessionEntityFields.USER_ID) val sharedDeviceId = oldObject.getNullableValue("deviceId", String::class)
val sharedDeviceId = it.getString(SharedSessionEntityFields.DEVICE_ID) val knownDevice = migrationContext.newRealm.query("DeviceInfoEntity")
val knownDevice = realm.where("DeviceInfoEntity") .query("userId == $0", sharedUserId)
.equalTo(DeviceInfoEntityFields.USER_ID, sharedUserId) .query("deviceId == $0", sharedDeviceId)
.equalTo(DeviceInfoEntityFields.DEVICE_ID, sharedDeviceId) .first()
.findFirst() .find()
it.setString(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, knownDevice?.getString(DeviceInfoEntityFields.IDENTITY_KEY))
val deviceIdentityKey = knownDevice?.getNullableValue("identityKey", String::class)
newObject.set("deviceIdentityKey", deviceIdentityKey)
} }
} }
} }

View File

@ -16,21 +16,21 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.util.database.RealmMigrator import org.matrix.android.sdk.internal.database.safeEnumerate
import timber.log.Timber
// Version 15L adds wasEncryptedOnce field to CryptoRoomEntity // Version 15L adds wasEncryptedOnce field to CryptoRoomEntity
internal class MigrateCryptoTo015(realm: DynamicRealm) : RealmMigrator(realm, 15) { internal class MigrateCryptoTo015(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 15) {
override fun doMigrate(realm: DynamicRealm) { override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
realm.schema.get("CryptoRoomEntity") Timber.d("Update CryptoRoomEntity")
?.addField(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, Boolean::class.java) migrationContext.safeEnumerate("CryptoRoomEntity") { oldObject, newObject ->
?.setNullable(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, true) if(newObject == null) return@safeEnumerate
?.transform { val currentAlgorithm = oldObject.getNullableValue("algorithm", String::class)
val currentAlgorithm = it.getString(CryptoRoomEntityFields.ALGORITHM) newObject.set("wasEncryptedOnce", currentAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM)
it.set(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, currentAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM)
} }
} }
} }

View File

@ -16,55 +16,21 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields import timber.log.Timber
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyRequestReplyEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateCryptoTo016(realm: DynamicRealm) : RealmMigrator(realm, 16) { internal class MigrateCryptoTo016(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 16) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.remove("OutgoingGossipingRequestEntity")
realm.schema.remove("IncomingGossipingRequestEntity")
realm.schema.remove("GossipingEventEntity")
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Remove OutgoingGossipingRequestEntity")
Timber.d("Remove IncomingGossipingRequestEntity")
Timber.d("Remove GossipingEventEntity")
// No need to migrate existing request, just start fresh // No need to migrate existing request, just start fresh
Timber.d("Create GossipingEventEntity")
Timber.d("Create GossipingEventEntity")
Timber.d("Create GossipingEventEntity")
val replySchema = realm.schema.create("KeyRequestReplyEntity") Timber.d("Update CryptoMetadataEntity")
.addField(KeyRequestReplyEntityFields.SENDER_ID, String::class.java)
.addField(KeyRequestReplyEntityFields.FROM_DEVICE, String::class.java)
.addField(KeyRequestReplyEntityFields.EVENT_JSON, String::class.java)
realm.schema.create("OutgoingKeyRequestEntity")
.addField(OutgoingKeyRequestEntityFields.REQUEST_ID, String::class.java)
.addIndex(OutgoingKeyRequestEntityFields.REQUEST_ID)
.addField(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, String::class.java)
.addIndex(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID)
.addRealmListField(OutgoingKeyRequestEntityFields.REPLIES.`$`, replySchema)
.addField(OutgoingKeyRequestEntityFields.RECIPIENTS_DATA, String::class.java)
.addField(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, String::class.java)
.addIndex(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR)
.addField(OutgoingKeyRequestEntityFields.REQUESTED_INFO_STR, String::class.java)
.addField(OutgoingKeyRequestEntityFields.ROOM_ID, String::class.java)
.addIndex(OutgoingKeyRequestEntityFields.ROOM_ID)
.addField(OutgoingKeyRequestEntityFields.REQUESTED_INDEX, Integer::class.java)
.addField(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, Long::class.java)
.setNullable(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, true)
realm.schema.create("AuditTrailEntity")
.addField(AuditTrailEntityFields.AGE_LOCAL_TS, Long::class.java)
.setNullable(AuditTrailEntityFields.AGE_LOCAL_TS, true)
.addField(AuditTrailEntityFields.CONTENT_JSON, String::class.java)
.addField(AuditTrailEntityFields.TYPE, String::class.java)
.addIndex(AuditTrailEntityFields.TYPE)
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, Boolean::class.java)
?.transform {
// set the default value to true
it.setBoolean(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, true)
}
} }
} }

View File

@ -16,65 +16,40 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.database.safeEnumerate
import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber import timber.log.Timber
/** /**
* Version 17L enhance OlmInboundGroupSessionEntity to support shared history for MSC3061. * Version 17L enhance OlmInboundGroupSessionEntity to support shared history for MSC3061.
* Also migrates how megolm session are stored to avoid additional serialized frozen class. * Also migrates how megolm session are stored to avoid additional serialized frozen class.
*/ */
internal class MigrateCryptoTo017(realm: DynamicRealm) : RealmMigrator(realm, 17) { internal class MigrateCryptoTo017(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 17) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("CryptoRoomEntity")
?.addField(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform {
// We don't have access to the session database to check for the state here and set the good value.
// But for now as it's behind a lab flag, will set to false and force initial sync when enabled
it.setBoolean(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, false)
}
realm.schema.get("OutboundGroupSessionInfoEntity")
?.addField(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform {
// We don't have access to the session database to check for the state here and set the good value.
// But for now as it's behind a lab flag, will set to false and force initial sync when enabled
it.setBoolean(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, false)
}
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, Boolean::class.java)
?.transform { obj ->
// default to false
obj.setBoolean(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, false)
}
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Update CryptoRoomEntity")
Timber.d("Update OutboundGroupSessionInfoEntity")
Timber.d("Update CryptoMetadataEntity")
Timber.d("Update OlmInboundGroupSessionEntity")
val moshiAdapter = MoshiProvider.providesMoshi().adapter(InboundGroupSessionData::class.java) val moshiAdapter = MoshiProvider.providesMoshi().adapter(InboundGroupSessionData::class.java)
migrationContext.safeEnumerate("OlmInboundGroupSessionEntity") { oldObject, newObject ->
realm.schema.get("OlmInboundGroupSessionEntity") if (newObject == null) return@safeEnumerate
?.addField(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, Boolean::class.java)
?.addField(OlmInboundGroupSessionEntityFields.ROOM_ID, String::class.java)
?.addField(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, String::class.java)
?.addField(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, String::class.java)
?.transform { dynamicObject ->
try { try {
// we want to convert the old wrapper frozen class into a // we want to convert the old wrapper frozen class into a
// map of sessionData & the pickled session herself // map of sessionData & the pickled session herself
dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { oldData -> oldObject.getNullableValue("olmInboundGroupSessionData", String::class)?.let { oldData ->
val oldWrapper = tryOrNull("Failed to convert megolm inbound group data") { val oldWrapper = tryOrNull("Failed to convert megolm inbound group data") {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
deserializeFromRealm<org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2?>(oldData) deserializeFromRealm<org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2?>(oldData)
} }
val groupSession = oldWrapper?.olmInboundGroupSession val groupSession = oldWrapper?.olmInboundGroupSession
?: return@transform Unit.also { ?: return@safeEnumerate Unit.also {
Timber.w("Failed to migrate megolm session, no olmInboundGroupSession") Timber.w("Failed to migrate megolm session, no olmInboundGroupSession")
} }
// now convert to new data // now convert to new data
@ -86,12 +61,11 @@ internal class MigrateCryptoTo017(realm: DynamicRealm) : RealmMigrator(realm, 17
sharedHistory = false, sharedHistory = false,
) )
dynamicObject.setString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, moshiAdapter.toJson(data)) newObject.set("inboundGroupSessionDataJson", moshiAdapter.toJson(data))
dynamicObject.setString(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, serializeForRealm(groupSession)) newObject.set("serializedOlmInboundGroupSession", serializeForRealm(groupSession))
// denormalized fields // denormalized fields
dynamicObject.setString(OlmInboundGroupSessionEntityFields.ROOM_ID, oldWrapper.roomId) newObject.set("roomId", oldWrapper.roomId)
dynamicObject.setBoolean(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, false)
} }
} catch (failure: Throwable) { } catch (failure: Throwable) {
Timber.e(failure, "Failed to migrate megolm session") Timber.e(failure, "Failed to migrate megolm session")

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2022 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.db.migration
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import timber.log.Timber
internal class MigrateCryptoTo018(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 18) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Migrate to realm-kotlin")
}
}