diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt index c36d572da6..f55a450606 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt @@ -16,7 +16,7 @@ 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.MigrateCryptoTo002Legacy 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.MigrateCryptoTo016 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 javax.inject.Inject @@ -46,34 +47,36 @@ import javax.inject.Inject */ internal class RealmCryptoStoreMigration @Inject constructor( private val clock: Clock, -) : MatrixRealmMigration( +) : MatrixAutomaticSchemaMigration( dbName = "Crypto", - schemaVersion = 17L, + schemaVersion = 18L, ) { + /** * 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 hashCode() = 5000 - override fun doMigrate(realm: DynamicRealm, oldVersion: Long) { - if (oldVersion < 1) MigrateCryptoTo001Legacy(realm).perform() - if (oldVersion < 2) MigrateCryptoTo002Legacy(realm).perform() - if (oldVersion < 3) MigrateCryptoTo003RiotX(realm).perform() - if (oldVersion < 4) MigrateCryptoTo004(realm).perform() - if (oldVersion < 5) MigrateCryptoTo005(realm).perform() - if (oldVersion < 6) MigrateCryptoTo006(realm).perform() - if (oldVersion < 7) MigrateCryptoTo007(realm).perform() - if (oldVersion < 8) MigrateCryptoTo008(realm, clock).perform() - if (oldVersion < 9) MigrateCryptoTo009(realm).perform() - if (oldVersion < 10) MigrateCryptoTo010(realm).perform() - if (oldVersion < 11) MigrateCryptoTo011(realm).perform() - if (oldVersion < 12) MigrateCryptoTo012(realm).perform() - if (oldVersion < 13) MigrateCryptoTo013(realm).perform() - if (oldVersion < 14) MigrateCryptoTo014(realm).perform() - if (oldVersion < 15) MigrateCryptoTo015(realm).perform() - if (oldVersion < 16) MigrateCryptoTo016(realm).perform() - if (oldVersion < 17) MigrateCryptoTo017(realm).perform() + override fun doMigrate(oldVersion: Long, migrationContext: AutomaticSchemaMigration.MigrationContext) { + if (oldVersion < 1) MigrateCryptoTo001Legacy(migrationContext).perform() + if (oldVersion < 2) MigrateCryptoTo002Legacy(migrationContext).perform() + if (oldVersion < 3) MigrateCryptoTo003RiotX(migrationContext).perform() + if (oldVersion < 4) MigrateCryptoTo004(migrationContext).perform() + if (oldVersion < 5) MigrateCryptoTo005(migrationContext).perform() + if (oldVersion < 6) MigrateCryptoTo006(migrationContext).perform() + if (oldVersion < 7) MigrateCryptoTo007(migrationContext).perform() + if (oldVersion < 8) MigrateCryptoTo008(migrationContext, clock).perform() + if (oldVersion < 9) MigrateCryptoTo009(migrationContext).perform() + if (oldVersion < 10) MigrateCryptoTo010(migrationContext).perform() + if (oldVersion < 11) MigrateCryptoTo011(migrationContext).perform() + if (oldVersion < 12) MigrateCryptoTo012(migrationContext).perform() + if (oldVersion < 13) MigrateCryptoTo013(migrationContext).perform() + if (oldVersion < 14) MigrateCryptoTo014(migrationContext).perform() + if (oldVersion < 15) MigrateCryptoTo015(migrationContext).perform() + if (oldVersion < 16) MigrateCryptoTo016(migrationContext).perform() + if (oldVersion < 17) MigrateCryptoTo017(migrationContext).perform() + if (oldVersion < 18) MigrateCryptoTo018(migrationContext).perform() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo001Legacy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo001Legacy.kt index 7dee42e51a..23c4162ce2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo001Legacy.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo001Legacy.kt @@ -16,20 +16,13 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator 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") - - realm.schema.get("OlmSessionEntity") - ?.addField(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, Long::class.java) - ?.transform { - it.setLong(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, 0) - } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo002Legacy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo002Legacy.kt index 1b53e1928a..f97773e696 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo002Legacy.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo002Legacy.kt @@ -16,71 +16,16 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator 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") - realm.schema.get("IncomingRoomKeyRequestEntity") - ?.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? = 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? = 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 OutgoingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields") 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) - } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo003RiotX.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo003RiotX.kt index 34d1afa2d8..f79befb5cc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo003RiotX.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo003RiotX.kt @@ -16,68 +16,61 @@ 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.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.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.MXOlmInboundGroupSession2 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") - 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. - realm.schema.get("DeviceInfoEntity") - ?.transform { obj -> - try { - val oldSerializedData = obj.getString("deviceInfoData") - deserializeFromRealm(oldSerializedData)?.let { legacyMxDeviceInfo -> - val newMxDeviceInfo = org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo( - deviceId = legacyMxDeviceInfo.deviceId, - userId = legacyMxDeviceInfo.userId, - algorithms = legacyMxDeviceInfo.algorithms, - keys = legacyMxDeviceInfo.keys, - signatures = legacyMxDeviceInfo.signatures, - unsigned = legacyMxDeviceInfo.unsigned, - verified = legacyMxDeviceInfo.mVerified - ) - - obj.setString("deviceInfoData", serializeForRealm(newMxDeviceInfo)) - } - } catch (e: Exception) { - Timber.e(e, "Error") - } + migrationContext.safeEnumerate("DeviceInfoEntity") { oldObject, newObject -> + try { + val oldSerializedData = oldObject.getNullableValue("deviceInfoData", String::class) + deserializeFromRealm(oldSerializedData)?.let { legacyMxDeviceInfo -> + val newMxDeviceInfo = org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo( + deviceId = legacyMxDeviceInfo.deviceId, + userId = legacyMxDeviceInfo.userId, + algorithms = legacyMxDeviceInfo.algorithms, + keys = legacyMxDeviceInfo.keys, + signatures = legacyMxDeviceInfo.signatures, + unsigned = legacyMxDeviceInfo.unsigned, + verified = legacyMxDeviceInfo.mVerified + ) + newObject?.set("deviceInfoData", serializeForRealm(newMxDeviceInfo)) } + } catch (e: Exception) { + Timber.e(e, "Error") + } + } // Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper - realm.schema.get("OlmInboundGroupSessionEntity") - ?.transform { obj -> - try { - val oldSerializedData = obj.getString("olmInboundGroupSessionData") - deserializeFromRealm(oldSerializedData)?.let { mxOlmInboundGroupSession2 -> - val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier() - val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false) - .apply { - olmInboundGroupSession = mxOlmInboundGroupSession2.mSession - roomId = mxOlmInboundGroupSession2.mRoomId - senderKey = mxOlmInboundGroupSession2.mSenderKey - keysClaimed = mxOlmInboundGroupSession2.mKeysClaimed - forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain - } + migrationContext.enumerate("OlmInboundGroupSessionEntity") { oldObject, newObject -> + try { + val oldSerializedData = oldObject.getNullableValue("olmInboundGroupSessionData", String::class) + deserializeFromRealm(oldSerializedData)?.let { mxOlmInboundGroupSession2 -> + val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier() + val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false) + .apply { + olmInboundGroupSession = mxOlmInboundGroupSession2.mSession + roomId = mxOlmInboundGroupSession2.mRoomId + senderKey = mxOlmInboundGroupSession2.mSenderKey + keysClaimed = mxOlmInboundGroupSession2.mKeysClaimed + forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain + } - obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper)) - } - } catch (e: Exception) { - Timber.e(e, "Error") - } + newObject?.set("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper)) } + } catch (e: Exception) { + Timber.e(e, "Error") + } + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt index 0a986892d9..93dc9c00d7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt @@ -18,58 +18,28 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration import com.squareup.moshi.Moshi 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.util.JsonDict 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.CryptoMetadataEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields -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.crypto.store.db.model.TrustLevelEntity +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator +import org.matrix.android.sdk.internal.database.safeEnumerate import org.matrix.android.sdk.internal.di.SerializeNulls -import org.matrix.android.sdk.internal.util.database.RealmMigrator import timber.log.Timber // 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) { - if (realm.schema.contains("TrustLevelEntity")) { + override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) { + if (migrationContext.oldRealm.schema()["TrustLevelEntity"] != null) { Timber.d("Skipping Step 3 -> 4 because entities already exist") return } - 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") - - 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") - realm.schema.get("UserEntity") - ?.addRealmObjectField(UserEntityFields.CROSS_SIGNING_INFO_ENTITY.`$`, crossSigningInfoSchema) - 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 listMigrationAdapter = moshi.adapter>( @@ -87,57 +57,46 @@ internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) ) ) - realm.schema.get("DeviceInfoEntity") - ?.addField(DeviceInfoEntityFields.USER_ID, String::class.java) - ?.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 { - val oldSerializedData = obj.getString("deviceInfoData") - deserializeFromRealm(oldSerializedData)?.let { oldDevice -> - - val trustLevel = realm.createObject("TrustLevelEntity") - when (oldDevice.verified) { - MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> { - obj.setNull(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`) - } - MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> { - trustLevel.setNull(TrustLevelEntityFields.LOCALLY_VERIFIED) - trustLevel.setNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED) - obj.setBoolean(DeviceInfoEntityFields.IS_BLOCKED, oldDevice.isBlocked) - obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel) - } - MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED -> { - trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, false) - trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false) - obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel) - } - MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> { - trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, true) - trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false) - obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel) - } - } - - obj.setString(DeviceInfoEntityFields.USER_ID, oldDevice.userId) - obj.setString(DeviceInfoEntityFields.IDENTITY_KEY, oldDevice.identityKey()) - obj.setString(DeviceInfoEntityFields.ALGORITHM_LIST_JSON, listMigrationAdapter.toJson(oldDevice.algorithms)) - obj.setString(DeviceInfoEntityFields.KEYS_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.keys)) - obj.setString(DeviceInfoEntityFields.SIGNATURE_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.signatures)) - obj.setString(DeviceInfoEntityFields.UNSIGNED_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.unsigned)) + migrationContext.safeEnumerate("DeviceInfoEntity") { oldObject, newObject -> + if (newObject == null) return@safeEnumerate + try { + val oldSerializedData = oldObject.getNullableValue("deviceInfoData", String::class) + deserializeFromRealm(oldSerializedData)?.let { oldDevice -> + val trustLevel = TrustLevelEntity() + when (oldDevice.verified) { + MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> { + newObject.set("trustLevelEntity", null) + } + MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> { + trustLevel.locallyVerified = null + trustLevel.crossSignedVerified = null + newObject.set("isBlocked", oldDevice.isBlocked) + newObject.set("trustLevelEntity", trustLevel) + } + MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED -> { + trustLevel.locallyVerified = false + trustLevel.crossSignedVerified = false + newObject.set("trustLevelEntity", trustLevel) + } + MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> { + trustLevel.locallyVerified = true + trustLevel.crossSignedVerified = false + newObject.set("trustLevelEntity", trustLevel) } - } catch (failure: Throwable) { - Timber.w(failure, "Crypto Data base migration error") - // an unfortunate refactor did modify that class, making deserialization failing - // so we just skip and ignore.. } + newObject.set("userId", oldDevice.userId) + newObject.set("identityKey", oldDevice.identityKey()) + newObject.set("algorithmListJson", listMigrationAdapter.toJson(oldDevice.algorithms)) + newObject.set("keysMapJson", mapMigrationAdapter.toJson(oldDevice.keys)) + newObject.set("signatureMapJson", mapMigrationAdapter.toJson(oldDevice.signatures)) + newObject.set("unsignedMapJson", mapMigrationAdapter.toJson(oldDevice.unsigned)) } - ?.removeField("deviceInfoData") + } catch (failure: Throwable) { + Timber.w(failure, "Crypto Data base migration error") + // an unfortunate refactor did modify that class, making deserialization failing + // so we just skip and ignore.. + } + + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo005.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo005.kt index 8ec2932a8f..5d1ec1d74e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo005.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo005.kt @@ -16,47 +16,17 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.util.database.RealmMigrator +import io.realm.kotlin.migration.AutomaticSchemaMigration +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) { - realm.schema.remove("OutgoingRoomKeyRequestEntity") - realm.schema.remove("IncomingRoomKeyRequestEntity") - - // Not need to migrate existing request, just start fresh? - realm.schema.create("GossipingEventEntity") - .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) + override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) { + Timber.d("Remove OutgoingRoomKeyRequestEntity") + Timber.d("Remove IncomingRoomKeyRequestEntity") + Timber.d("Create GossipingEventEntity") + Timber.d("Create IncomingGossipingRequestEntity") + Timber.d("Create OutgoingGossipingRequestEntity") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo006.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo006.kt index 39b2898514..b57f14891c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo006.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo006.kt @@ -16,17 +16,13 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator 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") - realm.schema.get("CryptoMetadataEntity") - ?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY, String::class.java) - ?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY_VERSION, String::class.java) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo007.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo007.kt index 0e221e78f3..8996a271de 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo007.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo007.kt @@ -16,45 +16,43 @@ 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.OlmInboundGroupSessionWrapper2 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.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.database.KotlinRealmMigrator import org.matrix.android.sdk.internal.di.MoshiProvider -import org.matrix.android.sdk.internal.util.database.RealmMigrator 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") val crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi()) - - val keyInfoEntities = realm.where("KeyInfoEntity").findAll() + val keyInfoEntities = migrationContext.newRealm.query("KeyInfoEntity").find() try { keyInfoEntities.forEach { - val stringSignatures = it.getString(KeyInfoEntityFields.SIGNATURES) + val stringSignatures: String? = it.getNullableValue("signatures") val objectSignatures: Map>? = deserializeFromRealm(stringSignatures) val jsonSignatures = crossSigningKeysMapper.serializeSignatures(objectSignatures) - it.setString(KeyInfoEntityFields.SIGNATURES, jsonSignatures) + it.set("signatures", jsonSignatures) } } catch (ignore: Throwable) { } // Migrate frozen classes - val inboundGroupSessions = realm.where("OlmInboundGroupSessionEntity").findAll() + val inboundGroupSessions = migrationContext.newRealm.query("OlmInboundGroupSessionEntity").find() inboundGroupSessions.forEach { dynamicObject -> - dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { serializedObject -> + dynamicObject.getNullableValue("olmInboundGroupSessionData", String::class)?.let { serializedObject -> try { deserializeFromRealm(serializedObject)?.let { oldFormat -> val newFormat = oldFormat.exportKeys()?.let { OlmInboundGroupSessionWrapper2(it) } - dynamicObject.setString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA, serializeForRealm(newFormat)) + dynamicObject.set("olmInboundGroupSessionData", serializeForRealm(newFormat)) } } catch (failure: Throwable) { Timber.e(failure, "## OlmInboundGroupSessionEntity migration failed") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo008.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo008.kt index ad195e6e55..f19e8fcadb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo008.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo008.kt @@ -16,35 +16,20 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.api.extensions.tryOrNull -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator +import org.matrix.android.sdk.internal.database.safeEnumerate import org.matrix.android.sdk.internal.util.time.Clock +import timber.log.Timber -internal class MigrateCryptoTo008( - 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) +internal class MigrateCryptoTo008(context: AutomaticSchemaMigration.MigrationContext, private val clock: Clock) : KotlinRealmMigrator(context, 8) { + override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) { + Timber.d("Create MyDeviceLastSeenInfoEntity") + Timber.d("Update DeviceInfoEntity") val now = clock.epochMillis() - realm.schema.get("DeviceInfoEntity") - ?.addField(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, Long::class.java) - ?.setNullable(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, true) - ?.transform { deviceInfoEntity -> - tryOrNull { - deviceInfoEntity.setLong(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, now) - } - } + migrationContext.safeEnumerate("DeviceInfoEntity") { _, newObject -> + newObject?.set("firstTimeSeenLocalTs", now) + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo009.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo009.kt index 8d9d24dfba..6095c166e7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo009.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo009.kt @@ -16,22 +16,20 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator import timber.log.Timber -// Fixes duplicate devices in UserEntity#devices -internal class MigrateCryptoTo009(realm: DynamicRealm) : RealmMigrator(realm, 9) { +internal class MigrateCryptoTo009(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 9) { - override fun doMigrate(realm: DynamicRealm) { - val userEntities = realm.where("UserEntity").findAll() + override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) { + Timber.d("Fixes duplicate devices in UserEntity#devices") + val userEntities = migrationContext.newRealm.query("UserEntity").find() userEntities.forEach { try { - val deviceList = it.getList(UserEntityFields.DEVICES.`$`) - ?: return@forEach - val distinct = deviceList.distinctBy { it.getString(DeviceInfoEntityFields.DEVICE_ID) } + val deviceList = it.getValueList("devices", DeviceInfoEntity::class) + val distinct = deviceList.distinctBy { it.deviceId } if (distinct.size != deviceList.size) { deviceList.clear() deviceList.addAll(distinct) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo010.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo010.kt index faf0d58832..a76392cf07 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo010.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo010.kt @@ -16,35 +16,16 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator +import timber.log.Timber // 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) { - realm.schema.create("WithHeldSessionEntity") - .addField(WithHeldSessionEntityFields.ROOM_ID, String::class.java) - .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) + override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) { + Timber.d("Create WithHeldSessionEntity") + Timber.d("Create SharedSessionEntity") } + } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo011.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo011.kt index feaab4bb19..d1a4afb1a9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo011.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo011.kt @@ -16,15 +16,15 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator +import timber.log.Timber // 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) { - realm.schema.get("CryptoMetadataEntity") - ?.addField(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER, Boolean::class.java) + override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) { + Timber.d("Update CryptoMetadataEntity") } + } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo012.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo012.kt index 4626757a06..80cfc2514d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo012.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo012.kt @@ -16,21 +16,15 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator +import timber.log.Timber // 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) { - val outboundEntitySchema = realm.schema.create("OutboundGroupSessionInfoEntity") - .addField(OutboundGroupSessionInfoEntityFields.SERIALIZED_OUTBOUND_SESSION_DATA, String::class.java) - .addField(OutboundGroupSessionInfoEntityFields.CREATION_TIME, Long::class.java) - .setNullable(OutboundGroupSessionInfoEntityFields.CREATION_TIME, true) - - realm.schema.get("CryptoRoomEntity") - ?.addRealmObjectField(CryptoRoomEntityFields.OUTBOUND_SESSION_INFO.`$`, outboundEntitySchema) + override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) { + Timber.d("Create OutboundGroupSessionInfoEntity") + Timber.d("Update CryptoRoomEntity") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo013.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo013.kt index dc8984da41..ea73e08d21 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo013.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo013.kt @@ -16,63 +16,26 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import timber.log.Timber +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator // 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) { - // Use a trick to do that... Ref: https://stackoverflow.com/questions/55221366 - val trustLevelEntitySchema = realm.schema.get("TrustLevelEntity") - - /* - Creating a new temp field called isLinked which is set to true for those which are - references by other objects. Rest of them are set to false. Then removing all - those which are false and hence duplicate and unnecessary. Then removing the temp field - 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) + override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) { + val trustLevelEntities = migrationContext.newRealm.query("TrustLevelEntity").find() + val linkedTrustLevelEntities = mutableSetOf() + val deviceInfoEntities = migrationContext.newRealm.query("DeviceInfoEntity").find() + deviceInfoEntities.forEach { + val trustLevelEntity = it.getNullableValue("trustLevelEntity", TrustLevelEntity::class) + if (trustLevelEntity != null) { + linkedTrustLevelEntities.add(trustLevelEntity) + } } - - realm.schema.get("KeyInfoEntity")?.transform { obj -> - // Setting to true for those which are referenced in KeyInfoEntity - 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...") + val unreferencedTrustLevelEntities = trustLevelEntities.subtract(linkedTrustLevelEntities) + unreferencedTrustLevelEntities.forEach { + migrationContext.newRealm.delete(it) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo014.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo014.kt index 548672790a..2dfb48d3cb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo014.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo014.kt @@ -16,26 +16,28 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator +import org.matrix.android.sdk.internal.database.safeEnumerate +import timber.log.Timber // 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) { - realm.schema.get("SharedSessionEntity") - ?.addField(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, String::class.java) - ?.addIndex(SharedSessionEntityFields.DEVICE_IDENTITY_KEY) - ?.transform { - val sharedUserId = it.getString(SharedSessionEntityFields.USER_ID) - val sharedDeviceId = it.getString(SharedSessionEntityFields.DEVICE_ID) - val knownDevice = realm.where("DeviceInfoEntity") - .equalTo(DeviceInfoEntityFields.USER_ID, sharedUserId) - .equalTo(DeviceInfoEntityFields.DEVICE_ID, sharedDeviceId) - .findFirst() - it.setString(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, knownDevice?.getString(DeviceInfoEntityFields.IDENTITY_KEY)) - } + override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) { + Timber.d("Update SharedSessionEntity") + migrationContext.safeEnumerate("SharedSessionEntity") { oldObject, newObject -> + if(newObject == null) return@safeEnumerate + val sharedUserId = oldObject.getNullableValue("userId", String::class) + val sharedDeviceId = oldObject.getNullableValue("deviceId", String::class) + val knownDevice = migrationContext.newRealm.query("DeviceInfoEntity") + .query("userId == $0", sharedUserId) + .query("deviceId == $0", sharedDeviceId) + .first() + .find() + + val deviceIdentityKey = knownDevice?.getNullableValue("identityKey", String::class) + newObject.set("deviceIdentityKey", deviceIdentityKey) + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo015.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo015.kt index bca02c2e6e..29be3f62a5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo015.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo015.kt @@ -16,21 +16,21 @@ 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.internal.crypto.store.db.model.CryptoRoomEntityFields -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 timber.log.Timber // 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) { - realm.schema.get("CryptoRoomEntity") - ?.addField(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, Boolean::class.java) - ?.setNullable(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, true) - ?.transform { - val currentAlgorithm = it.getString(CryptoRoomEntityFields.ALGORITHM) - it.set(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, currentAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM) - } + override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) { + Timber.d("Update CryptoRoomEntity") + migrationContext.safeEnumerate("CryptoRoomEntity") { oldObject, newObject -> + if(newObject == null) return@safeEnumerate + val currentAlgorithm = oldObject.getNullableValue("algorithm", String::class) + newObject.set("wasEncryptedOnce", currentAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM) + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo016.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo016.kt index 5a14ebf85a..f02607f189 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo016.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo016.kt @@ -16,55 +16,21 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields -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 +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator +import timber.log.Timber -internal class MigrateCryptoTo016(realm: DynamicRealm) : RealmMigrator(realm, 16) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.remove("OutgoingGossipingRequestEntity") - realm.schema.remove("IncomingGossipingRequestEntity") - realm.schema.remove("GossipingEventEntity") +internal class MigrateCryptoTo016(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 16) { + 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 + Timber.d("Create GossipingEventEntity") + Timber.d("Create GossipingEventEntity") + Timber.d("Create GossipingEventEntity") - val replySchema = realm.schema.create("KeyRequestReplyEntity") - .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) - } + Timber.d("Update CryptoMetadataEntity") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt index 8904c412cd..c8d73ee603 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt @@ -16,86 +16,60 @@ 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.crypto.model.InboundGroupSessionData 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.database.KotlinRealmMigrator +import org.matrix.android.sdk.internal.database.safeEnumerate import org.matrix.android.sdk.internal.di.MoshiProvider -import org.matrix.android.sdk.internal.util.database.RealmMigrator import timber.log.Timber /** * Version 17L enhance OlmInboundGroupSessionEntity to support shared history for MSC3061. * Also migrates how megolm session are stored to avoid additional serialized frozen class. */ -internal class MigrateCryptoTo017(realm: DynamicRealm) : RealmMigrator(realm, 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) - } +internal class MigrateCryptoTo017(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 17) { + 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) - - realm.schema.get("OlmInboundGroupSessionEntity") - ?.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 { - // we want to convert the old wrapper frozen class into a - // map of sessionData & the pickled session herself - dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { oldData -> - val oldWrapper = tryOrNull("Failed to convert megolm inbound group data") { - @Suppress("DEPRECATION") - deserializeFromRealm(oldData) - } - val groupSession = oldWrapper?.olmInboundGroupSession - ?: return@transform Unit.also { - Timber.w("Failed to migrate megolm session, no olmInboundGroupSession") - } - // now convert to new data - val data = InboundGroupSessionData( - senderKey = oldWrapper.senderKey, - roomId = oldWrapper.roomId, - keysClaimed = oldWrapper.keysClaimed, - forwardingCurve25519KeyChain = oldWrapper.forwardingCurve25519KeyChain, - sharedHistory = false, - ) - - dynamicObject.setString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, moshiAdapter.toJson(data)) - dynamicObject.setString(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, serializeForRealm(groupSession)) - - // denormalized fields - dynamicObject.setString(OlmInboundGroupSessionEntityFields.ROOM_ID, oldWrapper.roomId) - dynamicObject.setBoolean(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, false) - } - } catch (failure: Throwable) { - Timber.e(failure, "Failed to migrate megolm session") + migrationContext.safeEnumerate("OlmInboundGroupSessionEntity") { oldObject, newObject -> + if (newObject == null) return@safeEnumerate + try { + // we want to convert the old wrapper frozen class into a + // map of sessionData & the pickled session herself + oldObject.getNullableValue("olmInboundGroupSessionData", String::class)?.let { oldData -> + val oldWrapper = tryOrNull("Failed to convert megolm inbound group data") { + @Suppress("DEPRECATION") + deserializeFromRealm(oldData) } + val groupSession = oldWrapper?.olmInboundGroupSession + ?: return@safeEnumerate Unit.also { + Timber.w("Failed to migrate megolm session, no olmInboundGroupSession") + } + // now convert to new data + val data = InboundGroupSessionData( + senderKey = oldWrapper.senderKey, + roomId = oldWrapper.roomId, + keysClaimed = oldWrapper.keysClaimed, + forwardingCurve25519KeyChain = oldWrapper.forwardingCurve25519KeyChain, + sharedHistory = false, + ) + + newObject.set("inboundGroupSessionDataJson", moshiAdapter.toJson(data)) + newObject.set("serializedOlmInboundGroupSession", serializeForRealm(groupSession)) + + // denormalized fields + newObject.set("roomId", oldWrapper.roomId) } + } catch (failure: Throwable) { + Timber.e(failure, "Failed to migrate megolm session") + } + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo018.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo018.kt new file mode 100644 index 0000000000..c4707a6c30 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo018.kt @@ -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") + } +}