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
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()
}
}

View File

@ -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)
}
}
}

View File

@ -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<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("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)
}
}
}

View File

@ -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<MXDeviceInfo>(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<MXDeviceInfo>(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<MXOlmInboundGroupSession2>(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<MXOlmInboundGroupSession2>(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")
}
}
}
}

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.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<List<String>>(
@ -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<MXDeviceInfo>(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<MXDeviceInfo>(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..
}
}
}
}

View File

@ -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")
}
}

View File

@ -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)
}
}

View File

@ -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<String, Map<String, String>>? = 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<OlmInboundGroupSessionWrapper?>(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")

View File

@ -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)
}
}
}

View File

@ -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)

View File

@ -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")
}
}

View File

@ -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")
}
}

View File

@ -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")
}
}

View File

@ -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<TrustLevelEntity>()
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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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")
}
}

View File

@ -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<org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2?>(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<org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2?>(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")
}
}
}
}

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")
}
}