Merge pull request #5134 from vector-im/feature/bma/realmMigrations
Refactor realm migrations
This commit is contained in:
commit
5af56f6b5d
@ -46,7 +46,9 @@ internal abstract class AuthModule {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Provides
|
@Provides
|
||||||
@AuthDatabase
|
@AuthDatabase
|
||||||
fun providesRealmConfiguration(context: Context, realmKeysUtils: RealmKeysUtils): RealmConfiguration {
|
fun providesRealmConfiguration(context: Context,
|
||||||
|
realmKeysUtils: RealmKeysUtils,
|
||||||
|
authRealmMigration: AuthRealmMigration): RealmConfiguration {
|
||||||
val old = File(context.filesDir, "matrix-sdk-auth")
|
val old = File(context.filesDir, "matrix-sdk-auth")
|
||||||
if (old.exists()) {
|
if (old.exists()) {
|
||||||
old.renameTo(File(context.filesDir, "matrix-sdk-auth.realm"))
|
old.renameTo(File(context.filesDir, "matrix-sdk-auth.realm"))
|
||||||
@ -58,8 +60,8 @@ internal abstract class AuthModule {
|
|||||||
}
|
}
|
||||||
.name("matrix-sdk-auth.realm")
|
.name("matrix-sdk-auth.realm")
|
||||||
.modules(AuthRealmModule())
|
.modules(AuthRealmModule())
|
||||||
.schemaVersion(AuthRealmMigration.SCHEMA_VERSION)
|
.schemaVersion(authRealmMigration.schemaVersion)
|
||||||
.migration(AuthRealmMigration)
|
.migration(authRealmMigration)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,102 +16,31 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.auth.db
|
package org.matrix.android.sdk.internal.auth.db
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import io.realm.DynamicRealm
|
import io.realm.DynamicRealm
|
||||||
import io.realm.RealmMigration
|
import io.realm.RealmMigration
|
||||||
import org.matrix.android.sdk.api.auth.data.Credentials
|
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo001
|
||||||
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo002
|
||||||
import org.matrix.android.sdk.api.auth.data.sessionId
|
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo003
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo004
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal object AuthRealmMigration : RealmMigration {
|
internal class AuthRealmMigration @Inject constructor() : RealmMigration {
|
||||||
|
/**
|
||||||
|
* Forces all AuthRealmMigration instances to be equal
|
||||||
|
* Avoids Realm throwing when multiple instances of the migration are set
|
||||||
|
*/
|
||||||
|
override fun equals(other: Any?) = other is AuthRealmMigration
|
||||||
|
override fun hashCode() = 4000
|
||||||
|
|
||||||
// Current schema version
|
val schemaVersion = 4L
|
||||||
const val SCHEMA_VERSION = 4L
|
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
Timber.d("Migrating Auth Realm from $oldVersion to $newVersion")
|
Timber.d("Migrating Auth Realm from $oldVersion to $newVersion")
|
||||||
|
|
||||||
if (oldVersion <= 0) migrateTo1(realm)
|
if (oldVersion < 1) MigrateAuthTo001(realm).perform()
|
||||||
if (oldVersion <= 1) migrateTo2(realm)
|
if (oldVersion < 2) MigrateAuthTo002(realm).perform()
|
||||||
if (oldVersion <= 2) migrateTo3(realm)
|
if (oldVersion < 3) MigrateAuthTo003(realm).perform()
|
||||||
if (oldVersion <= 3) migrateTo4(realm)
|
if (oldVersion < 4) MigrateAuthTo004(realm).perform()
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo1(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 0 -> 1")
|
|
||||||
Timber.d("Create PendingSessionEntity")
|
|
||||||
|
|
||||||
realm.schema.create("PendingSessionEntity")
|
|
||||||
.addField(PendingSessionEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, String::class.java)
|
|
||||||
.setRequired(PendingSessionEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, true)
|
|
||||||
.addField(PendingSessionEntityFields.CLIENT_SECRET, String::class.java)
|
|
||||||
.setRequired(PendingSessionEntityFields.CLIENT_SECRET, true)
|
|
||||||
.addField(PendingSessionEntityFields.SEND_ATTEMPT, Integer::class.java)
|
|
||||||
.setRequired(PendingSessionEntityFields.SEND_ATTEMPT, true)
|
|
||||||
.addField(PendingSessionEntityFields.RESET_PASSWORD_DATA_JSON, String::class.java)
|
|
||||||
.addField(PendingSessionEntityFields.CURRENT_SESSION, String::class.java)
|
|
||||||
.addField(PendingSessionEntityFields.IS_REGISTRATION_STARTED, Boolean::class.java)
|
|
||||||
.addField(PendingSessionEntityFields.CURRENT_THREE_PID_DATA_JSON, String::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo2(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 1 -> 2")
|
|
||||||
Timber.d("Add boolean isTokenValid in SessionParamsEntity, with value true")
|
|
||||||
|
|
||||||
realm.schema.get("SessionParamsEntity")
|
|
||||||
?.addField(SessionParamsEntityFields.IS_TOKEN_VALID, Boolean::class.java)
|
|
||||||
?.transform { it.set(SessionParamsEntityFields.IS_TOKEN_VALID, true) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo3(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 2 -> 3")
|
|
||||||
Timber.d("Update SessionParamsEntity primary key, to allow several sessions with the same userId")
|
|
||||||
|
|
||||||
realm.schema.get("SessionParamsEntity")
|
|
||||||
?.removePrimaryKey()
|
|
||||||
?.addField(SessionParamsEntityFields.SESSION_ID, String::class.java)
|
|
||||||
?.setRequired(SessionParamsEntityFields.SESSION_ID, true)
|
|
||||||
?.transform {
|
|
||||||
val credentialsJson = it.getString(SessionParamsEntityFields.CREDENTIALS_JSON)
|
|
||||||
|
|
||||||
val credentials = MoshiProvider.providesMoshi()
|
|
||||||
.adapter(Credentials::class.java)
|
|
||||||
.fromJson(credentialsJson)
|
|
||||||
|
|
||||||
it.set(SessionParamsEntityFields.SESSION_ID, credentials!!.sessionId())
|
|
||||||
}
|
|
||||||
?.addPrimaryKey(SessionParamsEntityFields.SESSION_ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo4(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 3 -> 4")
|
|
||||||
Timber.d("Update SessionParamsEntity to add HomeServerConnectionConfig.homeServerUriBase value")
|
|
||||||
|
|
||||||
val adapter = MoshiProvider.providesMoshi()
|
|
||||||
.adapter(HomeServerConnectionConfig::class.java)
|
|
||||||
|
|
||||||
realm.schema.get("SessionParamsEntity")
|
|
||||||
?.transform {
|
|
||||||
val homeserverConnectionConfigJson = it.getString(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON)
|
|
||||||
|
|
||||||
val homeserverConnectionConfig = adapter
|
|
||||||
.fromJson(homeserverConnectionConfigJson)
|
|
||||||
|
|
||||||
val homeserverUrl = homeserverConnectionConfig?.homeServerUri?.toString()
|
|
||||||
// Special case for matrix.org. Old session may use "https://matrix.org", newer one may use
|
|
||||||
// "https://matrix-client.matrix.org". So fix that here
|
|
||||||
val alteredHomeserverConnectionConfig =
|
|
||||||
if (homeserverUrl == "https://matrix.org" || homeserverUrl == "https://matrix-client.matrix.org") {
|
|
||||||
homeserverConnectionConfig.copy(
|
|
||||||
homeServerUri = Uri.parse("https://matrix.org"),
|
|
||||||
homeServerUriBase = Uri.parse("https://matrix-client.matrix.org")
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
homeserverConnectionConfig
|
|
||||||
}
|
|
||||||
it.set(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, adapter.toJson(alteredHomeserverConnectionConfig))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.auth.db.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.auth.db.PendingSessionEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class MigrateAuthTo001(realm: DynamicRealm) : RealmMigrator(realm, 1) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
Timber.d("Create PendingSessionEntity")
|
||||||
|
|
||||||
|
realm.schema.create("PendingSessionEntity")
|
||||||
|
.addField(PendingSessionEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, String::class.java)
|
||||||
|
.setRequired(PendingSessionEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, true)
|
||||||
|
.addField(PendingSessionEntityFields.CLIENT_SECRET, String::class.java)
|
||||||
|
.setRequired(PendingSessionEntityFields.CLIENT_SECRET, true)
|
||||||
|
.addField(PendingSessionEntityFields.SEND_ATTEMPT, Integer::class.java)
|
||||||
|
.setRequired(PendingSessionEntityFields.SEND_ATTEMPT, true)
|
||||||
|
.addField(PendingSessionEntityFields.RESET_PASSWORD_DATA_JSON, String::class.java)
|
||||||
|
.addField(PendingSessionEntityFields.CURRENT_SESSION, String::class.java)
|
||||||
|
.addField(PendingSessionEntityFields.IS_REGISTRATION_STARTED, Boolean::class.java)
|
||||||
|
.addField(PendingSessionEntityFields.CURRENT_THREE_PID_DATA_JSON, String::class.java)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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.auth.db.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class MigrateAuthTo002(realm: DynamicRealm) : RealmMigrator(realm, 2) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
Timber.d("Add boolean isTokenValid in SessionParamsEntity, with value true")
|
||||||
|
|
||||||
|
realm.schema.get("SessionParamsEntity")
|
||||||
|
?.addField(SessionParamsEntityFields.IS_TOKEN_VALID, Boolean::class.java)
|
||||||
|
?.transform { it.set(SessionParamsEntityFields.IS_TOKEN_VALID, true) }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.auth.db.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.api.auth.data.Credentials
|
||||||
|
import org.matrix.android.sdk.api.auth.data.sessionId
|
||||||
|
import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class MigrateAuthTo003(realm: DynamicRealm) : RealmMigrator(realm, 3) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
Timber.d("Update SessionParamsEntity primary key, to allow several sessions with the same userId")
|
||||||
|
|
||||||
|
realm.schema.get("SessionParamsEntity")
|
||||||
|
?.removePrimaryKey()
|
||||||
|
?.addField(SessionParamsEntityFields.SESSION_ID, String::class.java)
|
||||||
|
?.setRequired(SessionParamsEntityFields.SESSION_ID, true)
|
||||||
|
?.transform {
|
||||||
|
val credentialsJson = it.getString(SessionParamsEntityFields.CREDENTIALS_JSON)
|
||||||
|
|
||||||
|
val credentials = MoshiProvider.providesMoshi()
|
||||||
|
.adapter(Credentials::class.java)
|
||||||
|
.fromJson(credentialsJson)
|
||||||
|
|
||||||
|
it.set(SessionParamsEntityFields.SESSION_ID, credentials!!.sessionId())
|
||||||
|
}
|
||||||
|
?.addPrimaryKey(SessionParamsEntityFields.SESSION_ID)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* 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.auth.db.migration
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||||
|
import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class MigrateAuthTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
Timber.d("Update SessionParamsEntity to add HomeServerConnectionConfig.homeServerUriBase value")
|
||||||
|
|
||||||
|
val adapter = MoshiProvider.providesMoshi()
|
||||||
|
.adapter(HomeServerConnectionConfig::class.java)
|
||||||
|
|
||||||
|
realm.schema.get("SessionParamsEntity")
|
||||||
|
?.transform {
|
||||||
|
val homeserverConnectionConfigJson = it.getString(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON)
|
||||||
|
|
||||||
|
val homeserverConnectionConfig = adapter
|
||||||
|
.fromJson(homeserverConnectionConfigJson)
|
||||||
|
|
||||||
|
val homeserverUrl = homeserverConnectionConfig?.homeServerUri?.toString()
|
||||||
|
// Special case for matrix.org. Old session may use "https://matrix.org", newer one may use
|
||||||
|
// "https://matrix-client.matrix.org". So fix that here
|
||||||
|
val alteredHomeserverConnectionConfig =
|
||||||
|
if (homeserverUrl == "https://matrix.org" || homeserverUrl == "https://matrix-client.matrix.org") {
|
||||||
|
homeserverConnectionConfig.copy(
|
||||||
|
homeServerUri = Uri.parse("https://matrix.org"),
|
||||||
|
homeServerUriBase = Uri.parse("https://matrix-client.matrix.org")
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
homeserverConnectionConfig
|
||||||
|
}
|
||||||
|
it.set(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, adapter.toJson(alteredHomeserverConnectionConfig))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -112,7 +112,8 @@ internal abstract class CryptoModule {
|
|||||||
@SessionScope
|
@SessionScope
|
||||||
fun providesRealmConfiguration(@SessionFilesDirectory directory: File,
|
fun providesRealmConfiguration(@SessionFilesDirectory directory: File,
|
||||||
@UserMd5 userMd5: String,
|
@UserMd5 userMd5: String,
|
||||||
realmKeysUtils: RealmKeysUtils): RealmConfiguration {
|
realmKeysUtils: RealmKeysUtils,
|
||||||
|
realmCryptoStoreMigration: RealmCryptoStoreMigration): RealmConfiguration {
|
||||||
return RealmConfiguration.Builder()
|
return RealmConfiguration.Builder()
|
||||||
.directory(directory)
|
.directory(directory)
|
||||||
.apply {
|
.apply {
|
||||||
@ -121,8 +122,8 @@ internal abstract class CryptoModule {
|
|||||||
.name("crypto_store.realm")
|
.name("crypto_store.realm")
|
||||||
.modules(RealmCryptoStoreModule())
|
.modules(RealmCryptoStoreModule())
|
||||||
.allowWritesOnUiThread(true)
|
.allowWritesOnUiThread(true)
|
||||||
.schemaVersion(RealmCryptoStoreMigration.CRYPTO_STORE_SCHEMA_VERSION)
|
.schemaVersion(realmCryptoStoreMigration.schemaVersion)
|
||||||
.migration(RealmCryptoStoreMigration)
|
.migration(realmCryptoStoreMigration)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,560 +16,54 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.crypto.store.db
|
package org.matrix.android.sdk.internal.crypto.store.db
|
||||||
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import com.squareup.moshi.Types
|
|
||||||
import io.realm.DynamicRealm
|
import io.realm.DynamicRealm
|
||||||
import io.realm.RealmMigration
|
import io.realm.RealmMigration
|
||||||
import io.realm.RealmObjectSchema
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo001Legacy
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo002Legacy
|
||||||
import org.matrix.android.sdk.api.util.JsonDict
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo003RiotX
|
||||||
import org.matrix.android.sdk.internal.crypto.model.MXDeviceInfo
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo004
|
||||||
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo005
|
||||||
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo006
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo007
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo008
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo009
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo010
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo011
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.GossipingEventEntityFields
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo012
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.IncomingGossipingRequestEntityFields
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo013
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo014
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntityFields
|
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields
|
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
|
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntityFields
|
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields
|
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingGossipingRequestEntityFields
|
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields
|
|
||||||
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.WithHeldSessionEntityFields
|
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
|
||||||
import org.matrix.android.sdk.internal.di.SerializeNulls
|
|
||||||
import org.matrix.androidsdk.crypto.data.MXOlmInboundGroupSession2
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import org.matrix.androidsdk.crypto.data.MXDeviceInfo as LegacyMXDeviceInfo
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal object RealmCryptoStoreMigration : RealmMigration {
|
internal class RealmCryptoStoreMigration @Inject constructor() : RealmMigration {
|
||||||
|
/**
|
||||||
|
* Forces all RealmCryptoStoreMigration instances to be equal
|
||||||
|
* Avoids Realm throwing when multiple instances of the migration are set
|
||||||
|
*/
|
||||||
|
override fun equals(other: Any?) = other is RealmCryptoStoreMigration
|
||||||
|
override fun hashCode() = 5000
|
||||||
|
|
||||||
// 0, 1, 2: legacy Riot-Android
|
// 0, 1, 2: legacy Riot-Android
|
||||||
// 3: migrate to RiotX schema
|
// 3: migrate to RiotX schema
|
||||||
// 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6)
|
// 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6)
|
||||||
const val CRYPTO_STORE_SCHEMA_VERSION = 14L
|
val schemaVersion = 14L
|
||||||
|
|
||||||
private fun RealmObjectSchema.addFieldIfNotExists(fieldName: String, fieldType: Class<*>): RealmObjectSchema {
|
|
||||||
if (!hasField(fieldName)) {
|
|
||||||
addField(fieldName, fieldType)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun RealmObjectSchema.removeFieldIfExists(fieldName: String): RealmObjectSchema {
|
|
||||||
if (hasField(fieldName)) {
|
|
||||||
removeField(fieldName)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun RealmObjectSchema.setRequiredIfNotAlready(fieldName: String, isRequired: Boolean): RealmObjectSchema {
|
|
||||||
if (isRequired != isRequired(fieldName)) {
|
|
||||||
setRequired(fieldName, isRequired)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
Timber.v("Migrating Realm Crypto from $oldVersion to $newVersion")
|
Timber.d("Migrating Realm Crypto from $oldVersion to $newVersion")
|
||||||
|
|
||||||
if (oldVersion <= 0) migrateTo1Legacy(realm)
|
if (oldVersion < 1) MigrateCryptoTo001Legacy(realm).perform()
|
||||||
if (oldVersion <= 1) migrateTo2Legacy(realm)
|
if (oldVersion < 2) MigrateCryptoTo002Legacy(realm).perform()
|
||||||
if (oldVersion <= 2) migrateTo3RiotX(realm)
|
if (oldVersion < 3) MigrateCryptoTo003RiotX(realm).perform()
|
||||||
if (oldVersion <= 3) migrateTo4(realm)
|
if (oldVersion < 4) MigrateCryptoTo004(realm).perform()
|
||||||
if (oldVersion <= 4) migrateTo5(realm)
|
if (oldVersion < 5) MigrateCryptoTo005(realm).perform()
|
||||||
if (oldVersion <= 5) migrateTo6(realm)
|
if (oldVersion < 6) MigrateCryptoTo006(realm).perform()
|
||||||
if (oldVersion <= 6) migrateTo7(realm)
|
if (oldVersion < 7) MigrateCryptoTo007(realm).perform()
|
||||||
if (oldVersion <= 7) migrateTo8(realm)
|
if (oldVersion < 8) MigrateCryptoTo008(realm).perform()
|
||||||
if (oldVersion <= 8) migrateTo9(realm)
|
if (oldVersion < 9) MigrateCryptoTo009(realm).perform()
|
||||||
if (oldVersion <= 9) migrateTo10(realm)
|
if (oldVersion < 10) MigrateCryptoTo010(realm).perform()
|
||||||
if (oldVersion <= 10) migrateTo11(realm)
|
if (oldVersion < 11) MigrateCryptoTo011(realm).perform()
|
||||||
if (oldVersion <= 11) migrateTo12(realm)
|
if (oldVersion < 12) MigrateCryptoTo012(realm).perform()
|
||||||
if (oldVersion <= 12) migrateTo13(realm)
|
if (oldVersion < 13) MigrateCryptoTo013(realm).perform()
|
||||||
if (oldVersion <= 13) migrateTo14(realm)
|
if (oldVersion < 14) MigrateCryptoTo014(realm).perform()
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo1Legacy(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 0 -> 1")
|
|
||||||
Timber.d("Add field lastReceivedMessageTs (Long) and set the value to 0")
|
|
||||||
|
|
||||||
realm.schema.get("OlmSessionEntity")
|
|
||||||
?.addField(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, Long::class.java)
|
|
||||||
?.transform {
|
|
||||||
it.setLong(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo2Legacy(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 1 -> 2")
|
|
||||||
Timber.d("Update IncomingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields")
|
|
||||||
|
|
||||||
realm.schema.get("IncomingRoomKeyRequestEntity")
|
|
||||||
?.addFieldIfNotExists("requestBodyAlgorithm", String::class.java)
|
|
||||||
?.addFieldIfNotExists("requestBodyRoomId", String::class.java)
|
|
||||||
?.addFieldIfNotExists("requestBodySenderKey", String::class.java)
|
|
||||||
?.addFieldIfNotExists("requestBodySessionId", String::class.java)
|
|
||||||
?.transform { dynamicObject ->
|
|
||||||
try {
|
|
||||||
val requestBodyString = dynamicObject.getString("requestBodyString")
|
|
||||||
// It was a map before
|
|
||||||
val map: Map<String, String>? = deserializeFromRealm(requestBodyString)
|
|
||||||
|
|
||||||
map?.let {
|
|
||||||
dynamicObject.setString("requestBodyAlgorithm", it["algorithm"])
|
|
||||||
dynamicObject.setString("requestBodyRoomId", it["room_id"])
|
|
||||||
dynamicObject.setString("requestBodySenderKey", it["sender_key"])
|
|
||||||
dynamicObject.setString("requestBodySessionId", it["session_id"])
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?.removeFieldIfExists("requestBodyString")
|
|
||||||
|
|
||||||
Timber.d("Update IncomingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields")
|
|
||||||
|
|
||||||
realm.schema.get("OutgoingRoomKeyRequestEntity")
|
|
||||||
?.addFieldIfNotExists("requestBodyAlgorithm", String::class.java)
|
|
||||||
?.addFieldIfNotExists("requestBodyRoomId", String::class.java)
|
|
||||||
?.addFieldIfNotExists("requestBodySenderKey", String::class.java)
|
|
||||||
?.addFieldIfNotExists("requestBodySessionId", String::class.java)
|
|
||||||
?.transform { dynamicObject ->
|
|
||||||
try {
|
|
||||||
val requestBodyString = dynamicObject.getString("requestBodyString")
|
|
||||||
// It was a map before
|
|
||||||
val map: Map<String, String>? = deserializeFromRealm(requestBodyString)
|
|
||||||
|
|
||||||
map?.let {
|
|
||||||
dynamicObject.setString("requestBodyAlgorithm", it["algorithm"])
|
|
||||||
dynamicObject.setString("requestBodyRoomId", it["room_id"])
|
|
||||||
dynamicObject.setString("requestBodySenderKey", it["sender_key"])
|
|
||||||
dynamicObject.setString("requestBodySessionId", it["session_id"])
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?.removeFieldIfExists("requestBodyString")
|
|
||||||
|
|
||||||
Timber.d("Create KeysBackupDataEntity")
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo3RiotX(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 2 -> 3")
|
|
||||||
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<LegacyMXDeviceInfo>(oldSerializedData)?.let { legacyMxDeviceInfo ->
|
|
||||||
val newMxDeviceInfo = 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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper))
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version 4L added Cross Signing info persistence
|
|
||||||
private fun migrateTo4(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 3 -> 4")
|
|
||||||
|
|
||||||
if (realm.schema.contains("TrustLevelEntity")) {
|
|
||||||
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>>(Types.newParameterizedType(
|
|
||||||
List::class.java,
|
|
||||||
String::class.java,
|
|
||||||
Any::class.java
|
|
||||||
))
|
|
||||||
val mapMigrationAdapter = moshi.adapter<JsonDict>(Types.newParameterizedType(
|
|
||||||
Map::class.java,
|
|
||||||
String::class.java,
|
|
||||||
Any::class.java
|
|
||||||
))
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
} 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..
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?.removeField("deviceInfoData")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo5(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 4 -> 5")
|
|
||||||
realm.schema.remove("OutgoingRoomKeyRequestEntity")
|
|
||||||
realm.schema.remove("IncomingRoomKeyRequestEntity")
|
|
||||||
|
|
||||||
// Not need to migrate existing request, just start fresh?
|
|
||||||
|
|
||||||
realm.schema.create("GossipingEventEntity")
|
|
||||||
.addField(GossipingEventEntityFields.TYPE, String::class.java)
|
|
||||||
.addIndex(GossipingEventEntityFields.TYPE)
|
|
||||||
.addField(GossipingEventEntityFields.CONTENT, String::class.java)
|
|
||||||
.addField(GossipingEventEntityFields.SENDER, String::class.java)
|
|
||||||
.addIndex(GossipingEventEntityFields.SENDER)
|
|
||||||
.addField(GossipingEventEntityFields.DECRYPTION_RESULT_JSON, String::class.java)
|
|
||||||
.addField(GossipingEventEntityFields.DECRYPTION_ERROR_CODE, String::class.java)
|
|
||||||
.addField(GossipingEventEntityFields.AGE_LOCAL_TS, Long::class.java)
|
|
||||||
.setNullable(GossipingEventEntityFields.AGE_LOCAL_TS, true)
|
|
||||||
.addField(GossipingEventEntityFields.SEND_STATE_STR, String::class.java)
|
|
||||||
|
|
||||||
realm.schema.create("IncomingGossipingRequestEntity")
|
|
||||||
.addField(IncomingGossipingRequestEntityFields.REQUEST_ID, String::class.java)
|
|
||||||
.addIndex(IncomingGossipingRequestEntityFields.REQUEST_ID)
|
|
||||||
.addField(IncomingGossipingRequestEntityFields.TYPE_STR, String::class.java)
|
|
||||||
.addIndex(IncomingGossipingRequestEntityFields.TYPE_STR)
|
|
||||||
.addField(IncomingGossipingRequestEntityFields.OTHER_USER_ID, String::class.java)
|
|
||||||
.addField(IncomingGossipingRequestEntityFields.REQUESTED_INFO_STR, String::class.java)
|
|
||||||
.addField(IncomingGossipingRequestEntityFields.OTHER_DEVICE_ID, String::class.java)
|
|
||||||
.addField(IncomingGossipingRequestEntityFields.REQUEST_STATE_STR, String::class.java)
|
|
||||||
.addField(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, Long::class.java)
|
|
||||||
.setNullable(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, true)
|
|
||||||
|
|
||||||
realm.schema.create("OutgoingGossipingRequestEntity")
|
|
||||||
.addField(OutgoingGossipingRequestEntityFields.REQUEST_ID, String::class.java)
|
|
||||||
.addIndex(OutgoingGossipingRequestEntityFields.REQUEST_ID)
|
|
||||||
.addField(OutgoingGossipingRequestEntityFields.RECIPIENTS_DATA, String::class.java)
|
|
||||||
.addField(OutgoingGossipingRequestEntityFields.REQUESTED_INFO_STR, String::class.java)
|
|
||||||
.addField(OutgoingGossipingRequestEntityFields.TYPE_STR, String::class.java)
|
|
||||||
.addIndex(OutgoingGossipingRequestEntityFields.TYPE_STR)
|
|
||||||
.addField(OutgoingGossipingRequestEntityFields.REQUEST_STATE_STR, String::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo6(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 5 -> 6")
|
|
||||||
Timber.d("Updating CryptoMetadataEntity table")
|
|
||||||
realm.schema.get("CryptoMetadataEntity")
|
|
||||||
?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY, String::class.java)
|
|
||||||
?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY_VERSION, String::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo7(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 6 -> 7")
|
|
||||||
Timber.d("Updating KeyInfoEntity table")
|
|
||||||
val crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi())
|
|
||||||
|
|
||||||
val keyInfoEntities = realm.where("KeyInfoEntity").findAll()
|
|
||||||
try {
|
|
||||||
keyInfoEntities.forEach {
|
|
||||||
val stringSignatures = it.getString(KeyInfoEntityFields.SIGNATURES)
|
|
||||||
val objectSignatures: Map<String, Map<String, String>>? = deserializeFromRealm(stringSignatures)
|
|
||||||
val jsonSignatures = crossSigningKeysMapper.serializeSignatures(objectSignatures)
|
|
||||||
it.setString(KeyInfoEntityFields.SIGNATURES, jsonSignatures)
|
|
||||||
}
|
|
||||||
} catch (failure: Throwable) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Migrate frozen classes
|
|
||||||
val inboundGroupSessions = realm.where("OlmInboundGroupSessionEntity").findAll()
|
|
||||||
inboundGroupSessions.forEach { dynamicObject ->
|
|
||||||
dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.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))
|
|
||||||
}
|
|
||||||
} catch (failure: Throwable) {
|
|
||||||
Timber.e(failure, "## OlmInboundGroupSessionEntity migration failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo8(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 7 -> 8")
|
|
||||||
realm.schema.create("MyDeviceLastSeenInfoEntity")
|
|
||||||
.addField(MyDeviceLastSeenInfoEntityFields.DEVICE_ID, String::class.java)
|
|
||||||
.addPrimaryKey(MyDeviceLastSeenInfoEntityFields.DEVICE_ID)
|
|
||||||
.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)
|
|
||||||
|
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fixes duplicate devices in UserEntity#devices
|
|
||||||
private fun migrateTo9(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 8 -> 9")
|
|
||||||
val userEntities = realm.where("UserEntity").findAll()
|
|
||||||
userEntities.forEach {
|
|
||||||
try {
|
|
||||||
val deviceList = it.getList(UserEntityFields.DEVICES.`$`)
|
|
||||||
?: return@forEach
|
|
||||||
val distinct = deviceList.distinctBy { it.getString(DeviceInfoEntityFields.DEVICE_ID) }
|
|
||||||
if (distinct.size != deviceList.size) {
|
|
||||||
deviceList.clear()
|
|
||||||
deviceList.addAll(distinct)
|
|
||||||
}
|
|
||||||
} catch (failure: Throwable) {
|
|
||||||
Timber.w(failure, "Crypto Data base migration error for migrateTo9")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version 10L added WithHeld Keys Info (MSC2399)
|
|
||||||
private fun migrateTo10(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 9 -> 10")
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version 11L added deviceKeysSentToServer boolean to CryptoMetadataEntity
|
|
||||||
private fun migrateTo11(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 10 -> 11")
|
|
||||||
realm.schema.get("CryptoMetadataEntity")
|
|
||||||
?.addField(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER, Boolean::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version 12L added outbound group session persistence
|
|
||||||
private fun migrateTo12(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 11 -> 12")
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version 13L delete unreferenced TrustLevelEntity
|
|
||||||
private fun migrateTo13(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 12 -> 13")
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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...")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version 14L Update the way we remember key sharing
|
|
||||||
private fun migrateTo14(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 13 -> 14")
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class MigrateCryptoTo001Legacy(realm: DynamicRealm) : RealmMigrator(realm, 1) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* 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.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 timber.log.Timber
|
||||||
|
|
||||||
|
class MigrateCryptoTo002Legacy(realm: DynamicRealm) : RealmMigrator(realm, 2) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
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("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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* 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.DynamicRealm
|
||||||
|
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.androidsdk.crypto.data.MXDeviceInfo
|
||||||
|
import org.matrix.androidsdk.crypto.data.MXOlmInboundGroupSession2
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class MigrateCryptoTo003RiotX(realm: DynamicRealm) : RealmMigrator(realm, 3) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
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.internal.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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper))
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.squareup.moshi.Moshi
|
||||||
|
import com.squareup.moshi.Types
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
|
import org.matrix.android.sdk.internal.crypto.model.MXDeviceInfo
|
||||||
|
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.di.SerializeNulls
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
// Version 4L added Cross Signing info persistence
|
||||||
|
class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
if (realm.schema.contains("TrustLevelEntity")) {
|
||||||
|
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>>(Types.newParameterizedType(
|
||||||
|
List::class.java,
|
||||||
|
String::class.java,
|
||||||
|
Any::class.java
|
||||||
|
))
|
||||||
|
val mapMigrationAdapter = moshi.adapter<JsonDict>(Types.newParameterizedType(
|
||||||
|
Map::class.java,
|
||||||
|
String::class.java,
|
||||||
|
Any::class.java
|
||||||
|
))
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
} 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..
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?.removeField("deviceInfoData")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.GossipingEventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.IncomingGossipingRequestEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingGossipingRequestEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateCryptoTo005(realm: DynamicRealm) : RealmMigrator(realm, 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(GossipingEventEntityFields.TYPE, String::class.java)
|
||||||
|
.addIndex(GossipingEventEntityFields.TYPE)
|
||||||
|
.addField(GossipingEventEntityFields.CONTENT, String::class.java)
|
||||||
|
.addField(GossipingEventEntityFields.SENDER, String::class.java)
|
||||||
|
.addIndex(GossipingEventEntityFields.SENDER)
|
||||||
|
.addField(GossipingEventEntityFields.DECRYPTION_RESULT_JSON, String::class.java)
|
||||||
|
.addField(GossipingEventEntityFields.DECRYPTION_ERROR_CODE, String::class.java)
|
||||||
|
.addField(GossipingEventEntityFields.AGE_LOCAL_TS, Long::class.java)
|
||||||
|
.setNullable(GossipingEventEntityFields.AGE_LOCAL_TS, true)
|
||||||
|
.addField(GossipingEventEntityFields.SEND_STATE_STR, String::class.java)
|
||||||
|
|
||||||
|
realm.schema.create("IncomingGossipingRequestEntity")
|
||||||
|
.addField(IncomingGossipingRequestEntityFields.REQUEST_ID, String::class.java)
|
||||||
|
.addIndex(IncomingGossipingRequestEntityFields.REQUEST_ID)
|
||||||
|
.addField(IncomingGossipingRequestEntityFields.TYPE_STR, String::class.java)
|
||||||
|
.addIndex(IncomingGossipingRequestEntityFields.TYPE_STR)
|
||||||
|
.addField(IncomingGossipingRequestEntityFields.OTHER_USER_ID, String::class.java)
|
||||||
|
.addField(IncomingGossipingRequestEntityFields.REQUESTED_INFO_STR, String::class.java)
|
||||||
|
.addField(IncomingGossipingRequestEntityFields.OTHER_DEVICE_ID, String::class.java)
|
||||||
|
.addField(IncomingGossipingRequestEntityFields.REQUEST_STATE_STR, String::class.java)
|
||||||
|
.addField(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, Long::class.java)
|
||||||
|
.setNullable(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, true)
|
||||||
|
|
||||||
|
realm.schema.create("OutgoingGossipingRequestEntity")
|
||||||
|
.addField(OutgoingGossipingRequestEntityFields.REQUEST_ID, String::class.java)
|
||||||
|
.addIndex(OutgoingGossipingRequestEntityFields.REQUEST_ID)
|
||||||
|
.addField(OutgoingGossipingRequestEntityFields.RECIPIENTS_DATA, String::class.java)
|
||||||
|
.addField(OutgoingGossipingRequestEntityFields.REQUESTED_INFO_STR, String::class.java)
|
||||||
|
.addField(OutgoingGossipingRequestEntityFields.TYPE_STR, String::class.java)
|
||||||
|
.addIndex(OutgoingGossipingRequestEntityFields.TYPE_STR)
|
||||||
|
.addField(OutgoingGossipingRequestEntityFields.REQUEST_STATE_STR, String::class.java)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class MigrateCryptoTo006(realm: DynamicRealm) : RealmMigrator(realm, 6) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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.DynamicRealm
|
||||||
|
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.di.MoshiProvider
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class MigrateCryptoTo007(realm: DynamicRealm) : RealmMigrator(realm, 7) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
Timber.d("Updating KeyInfoEntity table")
|
||||||
|
val crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi())
|
||||||
|
|
||||||
|
val keyInfoEntities = realm.where("KeyInfoEntity").findAll()
|
||||||
|
try {
|
||||||
|
keyInfoEntities.forEach {
|
||||||
|
val stringSignatures = it.getString(KeyInfoEntityFields.SIGNATURES)
|
||||||
|
val objectSignatures: Map<String, Map<String, String>>? = deserializeFromRealm(stringSignatures)
|
||||||
|
val jsonSignatures = crossSigningKeysMapper.serializeSignatures(objectSignatures)
|
||||||
|
it.setString(KeyInfoEntityFields.SIGNATURES, jsonSignatures)
|
||||||
|
}
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate frozen classes
|
||||||
|
val inboundGroupSessions = realm.where("OlmInboundGroupSessionEntity").findAll()
|
||||||
|
inboundGroupSessions.forEach { dynamicObject ->
|
||||||
|
dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.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))
|
||||||
|
}
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
Timber.e(failure, "## OlmInboundGroupSessionEntity migration failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.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
|
||||||
|
|
||||||
|
class MigrateCryptoTo008(realm: DynamicRealm) : 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)
|
||||||
|
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.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 timber.log.Timber
|
||||||
|
|
||||||
|
// Fixes duplicate devices in UserEntity#devices
|
||||||
|
class MigrateCryptoTo009(realm: DynamicRealm) : RealmMigrator(realm, 9) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
val userEntities = realm.where("UserEntity").findAll()
|
||||||
|
userEntities.forEach {
|
||||||
|
try {
|
||||||
|
val deviceList = it.getList(UserEntityFields.DEVICES.`$`)
|
||||||
|
?: return@forEach
|
||||||
|
val distinct = deviceList.distinctBy { it.getString(DeviceInfoEntityFields.DEVICE_ID) }
|
||||||
|
if (distinct.size != deviceList.size) {
|
||||||
|
deviceList.clear()
|
||||||
|
deviceList.addAll(distinct)
|
||||||
|
}
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
Timber.w(failure, "Crypto Data base migration error for migrateTo9")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.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
|
||||||
|
|
||||||
|
// Version 10L added WithHeld Keys Info (MSC2399)
|
||||||
|
class MigrateCryptoTo010(realm: DynamicRealm) : RealmMigrator(realm, 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)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
// Version 11L added deviceKeysSentToServer boolean to CryptoMetadataEntity
|
||||||
|
class MigrateCryptoTo011(realm: DynamicRealm) : RealmMigrator(realm, 11) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("CryptoMetadataEntity")
|
||||||
|
?.addField(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER, Boolean::class.java)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.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
|
||||||
|
|
||||||
|
// Version 12L added outbound group session persistence
|
||||||
|
class MigrateCryptoTo012(realm: DynamicRealm) : RealmMigrator(realm, 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)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
// Version 13L delete unreferenced TrustLevelEntity
|
||||||
|
class MigrateCryptoTo013(realm: DynamicRealm) : RealmMigrator(realm, 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.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
|
||||||
|
|
||||||
|
// Version 14L Update the way we remember key sharing
|
||||||
|
class MigrateCryptoTo014(realm: DynamicRealm) : RealmMigrator(realm, 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,37 +17,31 @@
|
|||||||
package org.matrix.android.sdk.internal.database
|
package org.matrix.android.sdk.internal.database
|
||||||
|
|
||||||
import io.realm.DynamicRealm
|
import io.realm.DynamicRealm
|
||||||
import io.realm.FieldAttribute
|
|
||||||
import io.realm.RealmMigration
|
import io.realm.RealmMigration
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo001
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo002
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo003
|
||||||
import org.matrix.android.sdk.api.session.room.model.VersioningState
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo004
|
||||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo005
|
||||||
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo006
|
||||||
import org.matrix.android.sdk.api.session.threads.ThreadNotificationState
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo007
|
||||||
import org.matrix.android.sdk.internal.crypto.model.event.EncryptionEventContent
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo008
|
||||||
import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo009
|
||||||
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo010
|
||||||
import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo011
|
||||||
import org.matrix.android.sdk.internal.database.model.EditionOfEventFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo012
|
||||||
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo013
|
||||||
import org.matrix.android.sdk.internal.database.model.EventInsertEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo014
|
||||||
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo015
|
||||||
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo016
|
||||||
import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo017
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomAccountDataEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo018
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo019
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo020
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo021
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo022
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomTagEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo023
|
||||||
import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntityFields
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo024
|
||||||
import org.matrix.android.sdk.internal.database.model.SpaceParentSummaryEntityFields
|
|
||||||
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
|
|
||||||
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntityFields
|
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
|
||||||
import org.matrix.android.sdk.internal.query.process
|
|
||||||
import org.matrix.android.sdk.internal.util.Normalizer
|
import org.matrix.android.sdk.internal.util.Normalizer
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -55,11 +49,6 @@ import javax.inject.Inject
|
|||||||
internal class RealmSessionStoreMigration @Inject constructor(
|
internal class RealmSessionStoreMigration @Inject constructor(
|
||||||
private val normalizer: Normalizer
|
private val normalizer: Normalizer
|
||||||
) : RealmMigration {
|
) : RealmMigration {
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val SESSION_STORE_SCHEMA_VERSION = 24L
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces all RealmSessionStoreMigration instances to be equal
|
* Forces all RealmSessionStoreMigration instances to be equal
|
||||||
* Avoids Realm throwing when multiple instances of the migration are set
|
* Avoids Realm throwing when multiple instances of the migration are set
|
||||||
@ -67,426 +56,34 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||||||
override fun equals(other: Any?) = other is RealmSessionStoreMigration
|
override fun equals(other: Any?) = other is RealmSessionStoreMigration
|
||||||
override fun hashCode() = 1000
|
override fun hashCode() = 1000
|
||||||
|
|
||||||
|
val schemaVersion = 24L
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
Timber.v("Migrating Realm Session from $oldVersion to $newVersion")
|
Timber.d("Migrating Realm Session from $oldVersion to $newVersion")
|
||||||
|
|
||||||
if (oldVersion <= 0) migrateTo1(realm)
|
if (oldVersion < 1) MigrateSessionTo001(realm).perform()
|
||||||
if (oldVersion <= 1) migrateTo2(realm)
|
if (oldVersion < 2) MigrateSessionTo002(realm).perform()
|
||||||
if (oldVersion <= 2) migrateTo3(realm)
|
if (oldVersion < 3) MigrateSessionTo003(realm).perform()
|
||||||
if (oldVersion <= 3) migrateTo4(realm)
|
if (oldVersion < 4) MigrateSessionTo004(realm).perform()
|
||||||
if (oldVersion <= 4) migrateTo5(realm)
|
if (oldVersion < 5) MigrateSessionTo005(realm).perform()
|
||||||
if (oldVersion <= 5) migrateTo6(realm)
|
if (oldVersion < 6) MigrateSessionTo006(realm).perform()
|
||||||
if (oldVersion <= 6) migrateTo7(realm)
|
if (oldVersion < 7) MigrateSessionTo007(realm).perform()
|
||||||
if (oldVersion <= 7) migrateTo8(realm)
|
if (oldVersion < 8) MigrateSessionTo008(realm).perform()
|
||||||
if (oldVersion <= 8) migrateTo9(realm)
|
if (oldVersion < 9) MigrateSessionTo009(realm).perform()
|
||||||
if (oldVersion <= 9) migrateTo10(realm)
|
if (oldVersion < 10) MigrateSessionTo010(realm).perform()
|
||||||
if (oldVersion <= 10) migrateTo11(realm)
|
if (oldVersion < 11) MigrateSessionTo011(realm).perform()
|
||||||
if (oldVersion <= 11) migrateTo12(realm)
|
if (oldVersion < 12) MigrateSessionTo012(realm).perform()
|
||||||
if (oldVersion <= 12) migrateTo13(realm)
|
if (oldVersion < 13) MigrateSessionTo013(realm).perform()
|
||||||
if (oldVersion <= 13) migrateTo14(realm)
|
if (oldVersion < 14) MigrateSessionTo014(realm).perform()
|
||||||
if (oldVersion <= 14) migrateTo15(realm)
|
if (oldVersion < 15) MigrateSessionTo015(realm).perform()
|
||||||
if (oldVersion <= 15) migrateTo16(realm)
|
if (oldVersion < 16) MigrateSessionTo016(realm).perform()
|
||||||
if (oldVersion <= 16) migrateTo17(realm)
|
if (oldVersion < 17) MigrateSessionTo017(realm).perform()
|
||||||
if (oldVersion <= 17) migrateTo18(realm)
|
if (oldVersion < 18) MigrateSessionTo018(realm).perform()
|
||||||
if (oldVersion <= 18) migrateTo19(realm)
|
if (oldVersion < 19) MigrateSessionTo019(realm, normalizer).perform()
|
||||||
if (oldVersion <= 19) migrateTo20(realm)
|
if (oldVersion < 20) MigrateSessionTo020(realm).perform()
|
||||||
if (oldVersion <= 20) migrateTo21(realm)
|
if (oldVersion < 21) MigrateSessionTo021(realm).perform()
|
||||||
if (oldVersion <= 21) migrateTo22(realm)
|
if (oldVersion < 22) MigrateSessionTo022(realm).perform()
|
||||||
if (oldVersion <= 22) migrateTo23(realm)
|
if (oldVersion < 23) MigrateSessionTo023(realm).perform()
|
||||||
if (oldVersion <= 23) migrateTo24(realm)
|
if (oldVersion < 24) MigrateSessionTo024(realm).perform()
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo1(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 0 -> 1")
|
|
||||||
// Add hasFailedSending in RoomSummary and a small warning icon on room list
|
|
||||||
|
|
||||||
realm.schema.get("RoomSummaryEntity")
|
|
||||||
?.addField(RoomSummaryEntityFields.HAS_FAILED_SENDING, Boolean::class.java)
|
|
||||||
?.transform { obj ->
|
|
||||||
obj.setBoolean(RoomSummaryEntityFields.HAS_FAILED_SENDING, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo2(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 1 -> 2")
|
|
||||||
realm.schema.get("HomeServerCapabilitiesEntity")
|
|
||||||
?.addField("adminE2EByDefault", Boolean::class.java)
|
|
||||||
?.transform { obj ->
|
|
||||||
obj.setBoolean("adminE2EByDefault", true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo3(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 2 -> 3")
|
|
||||||
realm.schema.get("HomeServerCapabilitiesEntity")
|
|
||||||
?.addField("preferredJitsiDomain", String::class.java)
|
|
||||||
?.transform { obj ->
|
|
||||||
// Schedule a refresh of the capabilities
|
|
||||||
obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo4(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 3 -> 4")
|
|
||||||
realm.schema.create("PendingThreePidEntity")
|
|
||||||
.addField(PendingThreePidEntityFields.CLIENT_SECRET, String::class.java)
|
|
||||||
.setRequired(PendingThreePidEntityFields.CLIENT_SECRET, true)
|
|
||||||
.addField(PendingThreePidEntityFields.EMAIL, String::class.java)
|
|
||||||
.addField(PendingThreePidEntityFields.MSISDN, String::class.java)
|
|
||||||
.addField(PendingThreePidEntityFields.SEND_ATTEMPT, Int::class.java)
|
|
||||||
.addField(PendingThreePidEntityFields.SID, String::class.java)
|
|
||||||
.setRequired(PendingThreePidEntityFields.SID, true)
|
|
||||||
.addField(PendingThreePidEntityFields.SUBMIT_URL, String::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo5(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 4 -> 5")
|
|
||||||
realm.schema.get("HomeServerCapabilitiesEntity")
|
|
||||||
?.removeField("adminE2EByDefault")
|
|
||||||
?.removeField("preferredJitsiDomain")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo6(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 5 -> 6")
|
|
||||||
realm.schema.create("PreviewUrlCacheEntity")
|
|
||||||
.addField(PreviewUrlCacheEntityFields.URL, String::class.java)
|
|
||||||
.setRequired(PreviewUrlCacheEntityFields.URL, true)
|
|
||||||
.addPrimaryKey(PreviewUrlCacheEntityFields.URL)
|
|
||||||
.addField(PreviewUrlCacheEntityFields.URL_FROM_SERVER, String::class.java)
|
|
||||||
.addField(PreviewUrlCacheEntityFields.SITE_NAME, String::class.java)
|
|
||||||
.addField(PreviewUrlCacheEntityFields.TITLE, String::class.java)
|
|
||||||
.addField(PreviewUrlCacheEntityFields.DESCRIPTION, String::class.java)
|
|
||||||
.addField(PreviewUrlCacheEntityFields.MXC_URL, String::class.java)
|
|
||||||
.addField(PreviewUrlCacheEntityFields.LAST_UPDATED_TIMESTAMP, Long::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo7(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 6 -> 7")
|
|
||||||
realm.schema.get("RoomEntity")
|
|
||||||
?.addField(RoomEntityFields.MEMBERS_LOAD_STATUS_STR, String::class.java)
|
|
||||||
?.transform { obj ->
|
|
||||||
if (obj.getBoolean("areAllMembersLoaded")) {
|
|
||||||
obj.setString("membersLoadStatusStr", RoomMembersLoadStatusType.LOADED.name)
|
|
||||||
} else {
|
|
||||||
obj.setString("membersLoadStatusStr", RoomMembersLoadStatusType.NONE.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?.removeField("areAllMembersLoaded")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo8(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 7 -> 8")
|
|
||||||
|
|
||||||
val editionOfEventSchema = realm.schema.create("EditionOfEvent")
|
|
||||||
.addField(EditionOfEventFields.CONTENT, String::class.java)
|
|
||||||
.addField(EditionOfEventFields.EVENT_ID, String::class.java)
|
|
||||||
.setRequired(EditionOfEventFields.EVENT_ID, true)
|
|
||||||
.addField(EditionOfEventFields.SENDER_ID, String::class.java)
|
|
||||||
.setRequired(EditionOfEventFields.SENDER_ID, true)
|
|
||||||
.addField(EditionOfEventFields.TIMESTAMP, Long::class.java)
|
|
||||||
.addField(EditionOfEventFields.IS_LOCAL_ECHO, Boolean::class.java)
|
|
||||||
|
|
||||||
realm.schema.get("EditAggregatedSummaryEntity")
|
|
||||||
?.removeField("aggregatedContent")
|
|
||||||
?.removeField("sourceEvents")
|
|
||||||
?.removeField("lastEditTs")
|
|
||||||
?.removeField("sourceLocalEchoEvents")
|
|
||||||
?.addRealmListField(EditAggregatedSummaryEntityFields.EDITIONS.`$`, editionOfEventSchema)
|
|
||||||
|
|
||||||
// This has to be done once a parent use the model as a child
|
|
||||||
// See https://github.com/realm/realm-java/issues/7402
|
|
||||||
editionOfEventSchema.isEmbedded = true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo9(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 8 -> 9")
|
|
||||||
|
|
||||||
realm.schema.get("RoomSummaryEntity")
|
|
||||||
?.addField(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Long::class.java, FieldAttribute.INDEXED)
|
|
||||||
?.setNullable(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, true)
|
|
||||||
?.addIndex(RoomSummaryEntityFields.MEMBERSHIP_STR)
|
|
||||||
?.addIndex(RoomSummaryEntityFields.IS_DIRECT)
|
|
||||||
?.addIndex(RoomSummaryEntityFields.VERSIONING_STATE_STR)
|
|
||||||
|
|
||||||
?.addField(RoomSummaryEntityFields.IS_FAVOURITE, Boolean::class.java)
|
|
||||||
?.addIndex(RoomSummaryEntityFields.IS_FAVOURITE)
|
|
||||||
?.addField(RoomSummaryEntityFields.IS_LOW_PRIORITY, Boolean::class.java)
|
|
||||||
?.addIndex(RoomSummaryEntityFields.IS_LOW_PRIORITY)
|
|
||||||
?.addField(RoomSummaryEntityFields.IS_SERVER_NOTICE, Boolean::class.java)
|
|
||||||
?.addIndex(RoomSummaryEntityFields.IS_SERVER_NOTICE)
|
|
||||||
|
|
||||||
?.transform { obj ->
|
|
||||||
val isFavorite = obj.getList(RoomSummaryEntityFields.TAGS.`$`).any {
|
|
||||||
it.getString(RoomTagEntityFields.TAG_NAME) == RoomTag.ROOM_TAG_FAVOURITE
|
|
||||||
}
|
|
||||||
obj.setBoolean(RoomSummaryEntityFields.IS_FAVOURITE, isFavorite)
|
|
||||||
|
|
||||||
val isLowPriority = obj.getList(RoomSummaryEntityFields.TAGS.`$`).any {
|
|
||||||
it.getString(RoomTagEntityFields.TAG_NAME) == RoomTag.ROOM_TAG_LOW_PRIORITY
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.setBoolean(RoomSummaryEntityFields.IS_LOW_PRIORITY, isLowPriority)
|
|
||||||
|
|
||||||
// XXX migrate last message origin server ts
|
|
||||||
obj.getObject(RoomSummaryEntityFields.LATEST_PREVIEWABLE_EVENT.`$`)
|
|
||||||
?.getObject(TimelineEventEntityFields.ROOT.`$`)
|
|
||||||
?.getLong(EventEntityFields.ORIGIN_SERVER_TS)?.let {
|
|
||||||
obj.setLong(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo10(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 9 -> 10")
|
|
||||||
realm.schema.create("SpaceChildSummaryEntity")
|
|
||||||
?.addField(SpaceChildSummaryEntityFields.ORDER, String::class.java)
|
|
||||||
?.addField(SpaceChildSummaryEntityFields.CHILD_ROOM_ID, String::class.java)
|
|
||||||
?.addField(SpaceChildSummaryEntityFields.AUTO_JOIN, Boolean::class.java)
|
|
||||||
?.setNullable(SpaceChildSummaryEntityFields.AUTO_JOIN, true)
|
|
||||||
?.addRealmObjectField(SpaceChildSummaryEntityFields.CHILD_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
|
|
||||||
?.addRealmListField(SpaceChildSummaryEntityFields.VIA_SERVERS.`$`, String::class.java)
|
|
||||||
|
|
||||||
realm.schema.create("SpaceParentSummaryEntity")
|
|
||||||
?.addField(SpaceParentSummaryEntityFields.PARENT_ROOM_ID, String::class.java)
|
|
||||||
?.addField(SpaceParentSummaryEntityFields.CANONICAL, Boolean::class.java)
|
|
||||||
?.setNullable(SpaceParentSummaryEntityFields.CANONICAL, true)
|
|
||||||
?.addRealmObjectField(SpaceParentSummaryEntityFields.PARENT_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
|
|
||||||
?.addRealmListField(SpaceParentSummaryEntityFields.VIA_SERVERS.`$`, String::class.java)
|
|
||||||
|
|
||||||
val creationContentAdapter = MoshiProvider.providesMoshi().adapter(RoomCreateContent::class.java)
|
|
||||||
realm.schema.get("RoomSummaryEntity")
|
|
||||||
?.addField(RoomSummaryEntityFields.ROOM_TYPE, String::class.java)
|
|
||||||
?.addField(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, String::class.java)
|
|
||||||
?.addField(RoomSummaryEntityFields.GROUP_IDS, String::class.java)
|
|
||||||
?.transform { obj ->
|
|
||||||
|
|
||||||
val creationEvent = realm.where("CurrentStateEventEntity")
|
|
||||||
.equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
|
|
||||||
.equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_CREATE)
|
|
||||||
.findFirst()
|
|
||||||
|
|
||||||
val roomType = creationEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
|
|
||||||
?.getString(EventEntityFields.CONTENT)?.let {
|
|
||||||
creationContentAdapter.fromJson(it)?.type
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.setString(RoomSummaryEntityFields.ROOM_TYPE, roomType)
|
|
||||||
}
|
|
||||||
?.addRealmListField(RoomSummaryEntityFields.PARENTS.`$`, realm.schema.get("SpaceParentSummaryEntity")!!)
|
|
||||||
?.addRealmListField(RoomSummaryEntityFields.CHILDREN.`$`, realm.schema.get("SpaceChildSummaryEntity")!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo11(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 10 -> 11")
|
|
||||||
realm.schema.get("EventEntity")
|
|
||||||
?.addField(EventEntityFields.SEND_STATE_DETAILS, String::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo12(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 11 -> 12")
|
|
||||||
|
|
||||||
val joinRulesContentAdapter = MoshiProvider.providesMoshi().adapter(RoomJoinRulesContent::class.java)
|
|
||||||
realm.schema.get("RoomSummaryEntity")
|
|
||||||
?.addField(RoomSummaryEntityFields.JOIN_RULES_STR, String::class.java)
|
|
||||||
?.transform { obj ->
|
|
||||||
val joinRulesEvent = realm.where("CurrentStateEventEntity")
|
|
||||||
.equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
|
|
||||||
.equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_JOIN_RULES)
|
|
||||||
.findFirst()
|
|
||||||
|
|
||||||
val roomJoinRules = joinRulesEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
|
|
||||||
?.getString(EventEntityFields.CONTENT)?.let {
|
|
||||||
joinRulesContentAdapter.fromJson(it)?.joinRules
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.setString(RoomSummaryEntityFields.JOIN_RULES_STR, roomJoinRules?.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
realm.schema.get("SpaceChildSummaryEntity")
|
|
||||||
?.addField(SpaceChildSummaryEntityFields.SUGGESTED, Boolean::class.java)
|
|
||||||
?.setNullable(SpaceChildSummaryEntityFields.SUGGESTED, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo13(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 12 -> 13")
|
|
||||||
// Fix issue with the nightly build. Eventually play again the migration which has been included in migrateTo12()
|
|
||||||
realm.schema.get("SpaceChildSummaryEntity")
|
|
||||||
?.takeIf { !it.hasField(SpaceChildSummaryEntityFields.SUGGESTED) }
|
|
||||||
?.addField(SpaceChildSummaryEntityFields.SUGGESTED, Boolean::class.java)
|
|
||||||
?.setNullable(SpaceChildSummaryEntityFields.SUGGESTED, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo14(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 13 -> 14")
|
|
||||||
val roomAccountDataSchema = realm.schema.create("RoomAccountDataEntity")
|
|
||||||
.addField(RoomAccountDataEntityFields.CONTENT_STR, String::class.java)
|
|
||||||
.addField(RoomAccountDataEntityFields.TYPE, String::class.java, FieldAttribute.INDEXED)
|
|
||||||
|
|
||||||
realm.schema.get("RoomEntity")
|
|
||||||
?.addRealmListField(RoomEntityFields.ACCOUNT_DATA.`$`, roomAccountDataSchema)
|
|
||||||
|
|
||||||
realm.schema.get("RoomSummaryEntity")
|
|
||||||
?.addField(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, Boolean::class.java, FieldAttribute.INDEXED)
|
|
||||||
?.transform {
|
|
||||||
val isHiddenFromUser = it.getString(RoomSummaryEntityFields.VERSIONING_STATE_STR) == VersioningState.UPGRADED_ROOM_JOINED.name
|
|
||||||
it.setBoolean(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, isHiddenFromUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
roomAccountDataSchema.isEmbedded = true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo15(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 14 -> 15")
|
|
||||||
// fix issue with flattenParentIds on DM that kept growing with duplicate
|
|
||||||
// so we reset it, will be updated next sync
|
|
||||||
realm.where("RoomSummaryEntity")
|
|
||||||
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
|
|
||||||
.equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
|
|
||||||
.findAll()
|
|
||||||
.onEach {
|
|
||||||
it.setString(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo16(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 15 -> 16")
|
|
||||||
realm.schema.get("HomeServerCapabilitiesEntity")
|
|
||||||
?.addField(HomeServerCapabilitiesEntityFields.ROOM_VERSIONS_JSON, String::class.java)
|
|
||||||
?.transform { obj ->
|
|
||||||
// Schedule a refresh of the capabilities
|
|
||||||
obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo17(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 16 -> 17")
|
|
||||||
realm.schema.get("EventInsertEntity")
|
|
||||||
?.addField(EventInsertEntityFields.CAN_BE_PROCESSED, Boolean::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo18(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 17 -> 18")
|
|
||||||
realm.schema.create("UserPresenceEntity")
|
|
||||||
?.addField(UserPresenceEntityFields.USER_ID, String::class.java)
|
|
||||||
?.addPrimaryKey(UserPresenceEntityFields.USER_ID)
|
|
||||||
?.setRequired(UserPresenceEntityFields.USER_ID, true)
|
|
||||||
?.addField(UserPresenceEntityFields.PRESENCE_STR, String::class.java)
|
|
||||||
?.addField(UserPresenceEntityFields.LAST_ACTIVE_AGO, Long::class.java)
|
|
||||||
?.setNullable(UserPresenceEntityFields.LAST_ACTIVE_AGO, true)
|
|
||||||
?.addField(UserPresenceEntityFields.STATUS_MESSAGE, String::class.java)
|
|
||||||
?.addField(UserPresenceEntityFields.IS_CURRENTLY_ACTIVE, Boolean::class.java)
|
|
||||||
?.setNullable(UserPresenceEntityFields.IS_CURRENTLY_ACTIVE, true)
|
|
||||||
?.addField(UserPresenceEntityFields.AVATAR_URL, String::class.java)
|
|
||||||
?.addField(UserPresenceEntityFields.DISPLAY_NAME, String::class.java)
|
|
||||||
|
|
||||||
val userPresenceEntity = realm.schema.get("UserPresenceEntity") ?: return
|
|
||||||
realm.schema.get("RoomSummaryEntity")
|
|
||||||
?.addRealmObjectField(RoomSummaryEntityFields.DIRECT_USER_PRESENCE.`$`, userPresenceEntity)
|
|
||||||
|
|
||||||
realm.schema.get("RoomMemberSummaryEntity")
|
|
||||||
?.addRealmObjectField(RoomMemberSummaryEntityFields.USER_PRESENCE_ENTITY.`$`, userPresenceEntity)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo19(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 18 -> 19")
|
|
||||||
realm.schema.get("RoomSummaryEntity")
|
|
||||||
?.addField(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, String::class.java)
|
|
||||||
?.transform {
|
|
||||||
it.getString(RoomSummaryEntityFields.DISPLAY_NAME)?.let { displayName ->
|
|
||||||
val normalised = normalizer.normalize(displayName)
|
|
||||||
it.set(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, normalised)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo20(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 19 -> 20")
|
|
||||||
|
|
||||||
realm.schema.get("ChunkEntity")?.apply {
|
|
||||||
if (hasField("numberOfTimelineEvents")) {
|
|
||||||
removeField("numberOfTimelineEvents")
|
|
||||||
}
|
|
||||||
var cleanOldChunks = false
|
|
||||||
if (!hasField(ChunkEntityFields.NEXT_CHUNK.`$`)) {
|
|
||||||
cleanOldChunks = true
|
|
||||||
addRealmObjectField(ChunkEntityFields.NEXT_CHUNK.`$`, this)
|
|
||||||
}
|
|
||||||
if (!hasField(ChunkEntityFields.PREV_CHUNK.`$`)) {
|
|
||||||
cleanOldChunks = true
|
|
||||||
addRealmObjectField(ChunkEntityFields.PREV_CHUNK.`$`, this)
|
|
||||||
}
|
|
||||||
if (cleanOldChunks) {
|
|
||||||
val chunkEntities = realm.where("ChunkEntity").equalTo(ChunkEntityFields.IS_LAST_FORWARD, false).findAll()
|
|
||||||
chunkEntities.deleteAllFromRealm()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo21(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 20 -> 21")
|
|
||||||
|
|
||||||
realm.schema.get("RoomSummaryEntity")
|
|
||||||
?.addField(RoomSummaryEntityFields.E2E_ALGORITHM, String::class.java)
|
|
||||||
?.transform { obj ->
|
|
||||||
|
|
||||||
val encryptionContentAdapter = MoshiProvider.providesMoshi().adapter(EncryptionEventContent::class.java)
|
|
||||||
|
|
||||||
val encryptionEvent = realm.where("CurrentStateEventEntity")
|
|
||||||
.equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
|
|
||||||
.equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_ENCRYPTION)
|
|
||||||
.findFirst()
|
|
||||||
|
|
||||||
val encryptionEventRoot = encryptionEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
|
|
||||||
val algorithm = encryptionEventRoot
|
|
||||||
?.getString(EventEntityFields.CONTENT)?.let {
|
|
||||||
encryptionContentAdapter.fromJson(it)?.algorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.setString(RoomSummaryEntityFields.E2E_ALGORITHM, algorithm)
|
|
||||||
obj.setBoolean(RoomSummaryEntityFields.IS_ENCRYPTED, encryptionEvent != null)
|
|
||||||
encryptionEventRoot?.getLong(EventEntityFields.ORIGIN_SERVER_TS)?.let {
|
|
||||||
obj.setLong(RoomSummaryEntityFields.ENCRYPTION_EVENT_TS, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo22(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 21 -> 22")
|
|
||||||
val listJoinedRoomIds = realm.where("RoomEntity")
|
|
||||||
.equalTo(RoomEntityFields.MEMBERSHIP_STR, Membership.JOIN.name).findAll()
|
|
||||||
.map { it.getString(RoomEntityFields.ROOM_ID) }
|
|
||||||
|
|
||||||
val hasMissingStateEvent = realm.where("CurrentStateEventEntity")
|
|
||||||
.`in`(CurrentStateEventEntityFields.ROOM_ID, listJoinedRoomIds.toTypedArray())
|
|
||||||
.isNull(CurrentStateEventEntityFields.ROOT.`$`).findFirst() != null
|
|
||||||
|
|
||||||
if (hasMissingStateEvent) {
|
|
||||||
Timber.v("Has some missing state event, clear session cache")
|
|
||||||
realm.deleteAll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo23(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 22 -> 23")
|
|
||||||
val eventEntity = realm.schema.get("TimelineEventEntity") ?: return
|
|
||||||
|
|
||||||
realm.schema.get("EventEntity")
|
|
||||||
?.addField(EventEntityFields.IS_ROOT_THREAD, Boolean::class.java, FieldAttribute.INDEXED)
|
|
||||||
?.addField(EventEntityFields.ROOT_THREAD_EVENT_ID, String::class.java, FieldAttribute.INDEXED)
|
|
||||||
?.addField(EventEntityFields.NUMBER_OF_THREADS, Int::class.java)
|
|
||||||
?.addField(EventEntityFields.THREAD_NOTIFICATION_STATE_STR, String::class.java)
|
|
||||||
?.transform {
|
|
||||||
it.setString(EventEntityFields.THREAD_NOTIFICATION_STATE_STR, ThreadNotificationState.NO_NEW_MESSAGE.name)
|
|
||||||
}
|
|
||||||
?.addRealmObjectField(EventEntityFields.THREAD_SUMMARY_LATEST_MESSAGE.`$`, eventEntity)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo24(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 23 -> 24")
|
|
||||||
realm.schema.get("PreviewUrlCacheEntity")
|
|
||||||
?.addField(PreviewUrlCacheEntityFields.IMAGE_WIDTH, Int::class.java)
|
|
||||||
?.setNullable(PreviewUrlCacheEntityFields.IMAGE_WIDTH, true)
|
|
||||||
?.addField(PreviewUrlCacheEntityFields.IMAGE_HEIGHT, Int::class.java)
|
|
||||||
?.setNullable(PreviewUrlCacheEntityFields.IMAGE_HEIGHT, true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
|
|||||||
}
|
}
|
||||||
.allowWritesOnUiThread(true)
|
.allowWritesOnUiThread(true)
|
||||||
.modules(SessionRealmModule())
|
.modules(SessionRealmModule())
|
||||||
.schemaVersion(RealmSessionStoreMigration.SESSION_STORE_SCHEMA_VERSION)
|
.schemaVersion(realmSessionStoreMigration.schemaVersion)
|
||||||
.migration(realmSessionStoreMigration)
|
.migration(realmSessionStoreMigration)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo001(realm: DynamicRealm) : RealmMigrator(realm, 1) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
// Add hasFailedSending in RoomSummary and a small warning icon on room list
|
||||||
|
realm.schema.get("RoomSummaryEntity")
|
||||||
|
?.addField(RoomSummaryEntityFields.HAS_FAILED_SENDING, Boolean::class.java)
|
||||||
|
?.transform { obj ->
|
||||||
|
obj.setBoolean(RoomSummaryEntityFields.HAS_FAILED_SENDING, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo002(realm: DynamicRealm) : RealmMigrator(realm, 2) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("HomeServerCapabilitiesEntity")
|
||||||
|
?.addField("adminE2EByDefault", Boolean::class.java)
|
||||||
|
?.transform { obj ->
|
||||||
|
obj.setBoolean("adminE2EByDefault", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo003(realm: DynamicRealm) : RealmMigrator(realm, 3) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("HomeServerCapabilitiesEntity")
|
||||||
|
?.addField("preferredJitsiDomain", String::class.java)
|
||||||
|
?.transform { obj ->
|
||||||
|
// Schedule a refresh of the capabilities
|
||||||
|
obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.create("PendingThreePidEntity")
|
||||||
|
.addField(PendingThreePidEntityFields.CLIENT_SECRET, String::class.java)
|
||||||
|
.setRequired(PendingThreePidEntityFields.CLIENT_SECRET, true)
|
||||||
|
.addField(PendingThreePidEntityFields.EMAIL, String::class.java)
|
||||||
|
.addField(PendingThreePidEntityFields.MSISDN, String::class.java)
|
||||||
|
.addField(PendingThreePidEntityFields.SEND_ATTEMPT, Int::class.java)
|
||||||
|
.addField(PendingThreePidEntityFields.SID, String::class.java)
|
||||||
|
.setRequired(PendingThreePidEntityFields.SID, true)
|
||||||
|
.addField(PendingThreePidEntityFields.SUBMIT_URL, String::class.java)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo005(realm: DynamicRealm) : RealmMigrator(realm, 5) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("HomeServerCapabilitiesEntity")
|
||||||
|
?.removeField("adminE2EByDefault")
|
||||||
|
?.removeField("preferredJitsiDomain")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo006(realm: DynamicRealm) : RealmMigrator(realm, 6) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.create("PreviewUrlCacheEntity")
|
||||||
|
.addField(PreviewUrlCacheEntityFields.URL, String::class.java)
|
||||||
|
.setRequired(PreviewUrlCacheEntityFields.URL, true)
|
||||||
|
.addPrimaryKey(PreviewUrlCacheEntityFields.URL)
|
||||||
|
.addField(PreviewUrlCacheEntityFields.URL_FROM_SERVER, String::class.java)
|
||||||
|
.addField(PreviewUrlCacheEntityFields.SITE_NAME, String::class.java)
|
||||||
|
.addField(PreviewUrlCacheEntityFields.TITLE, String::class.java)
|
||||||
|
.addField(PreviewUrlCacheEntityFields.DESCRIPTION, String::class.java)
|
||||||
|
.addField(PreviewUrlCacheEntityFields.MXC_URL, String::class.java)
|
||||||
|
.addField(PreviewUrlCacheEntityFields.LAST_UPDATED_TIMESTAMP, Long::class.java)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo007(realm: DynamicRealm) : RealmMigrator(realm, 7) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("RoomEntity")
|
||||||
|
?.addField(RoomEntityFields.MEMBERS_LOAD_STATUS_STR, String::class.java)
|
||||||
|
?.transform { obj ->
|
||||||
|
if (obj.getBoolean("areAllMembersLoaded")) {
|
||||||
|
obj.setString("membersLoadStatusStr", RoomMembersLoadStatusType.LOADED.name)
|
||||||
|
} else {
|
||||||
|
obj.setString("membersLoadStatusStr", RoomMembersLoadStatusType.NONE.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?.removeField("areAllMembersLoaded")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EditionOfEventFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo008(realm: DynamicRealm) : RealmMigrator(realm, 8) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
val editionOfEventSchema = realm.schema.create("EditionOfEvent")
|
||||||
|
.addField(EditionOfEventFields.CONTENT, String::class.java)
|
||||||
|
.addField(EditionOfEventFields.EVENT_ID, String::class.java)
|
||||||
|
.setRequired(EditionOfEventFields.EVENT_ID, true)
|
||||||
|
.addField(EditionOfEventFields.SENDER_ID, String::class.java)
|
||||||
|
.setRequired(EditionOfEventFields.SENDER_ID, true)
|
||||||
|
.addField(EditionOfEventFields.TIMESTAMP, Long::class.java)
|
||||||
|
.addField(EditionOfEventFields.IS_LOCAL_ECHO, Boolean::class.java)
|
||||||
|
|
||||||
|
realm.schema.get("EditAggregatedSummaryEntity")
|
||||||
|
?.removeField("aggregatedContent")
|
||||||
|
?.removeField("sourceEvents")
|
||||||
|
?.removeField("lastEditTs")
|
||||||
|
?.removeField("sourceLocalEchoEvents")
|
||||||
|
?.addRealmListField(EditAggregatedSummaryEntityFields.EDITIONS.`$`, editionOfEventSchema)
|
||||||
|
|
||||||
|
// This has to be done once a parent use the model as a child
|
||||||
|
// See https://github.com/realm/realm-java/issues/7402
|
||||||
|
editionOfEventSchema.isEmbedded = true
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import io.realm.FieldAttribute
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomTagEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo009(realm: DynamicRealm) : RealmMigrator(realm, 9) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("RoomSummaryEntity")
|
||||||
|
?.addField(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Long::class.java, FieldAttribute.INDEXED)
|
||||||
|
?.setNullable(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, true)
|
||||||
|
?.addIndex(RoomSummaryEntityFields.MEMBERSHIP_STR)
|
||||||
|
?.addIndex(RoomSummaryEntityFields.IS_DIRECT)
|
||||||
|
?.addIndex(RoomSummaryEntityFields.VERSIONING_STATE_STR)
|
||||||
|
|
||||||
|
?.addField(RoomSummaryEntityFields.IS_FAVOURITE, Boolean::class.java)
|
||||||
|
?.addIndex(RoomSummaryEntityFields.IS_FAVOURITE)
|
||||||
|
?.addField(RoomSummaryEntityFields.IS_LOW_PRIORITY, Boolean::class.java)
|
||||||
|
?.addIndex(RoomSummaryEntityFields.IS_LOW_PRIORITY)
|
||||||
|
?.addField(RoomSummaryEntityFields.IS_SERVER_NOTICE, Boolean::class.java)
|
||||||
|
?.addIndex(RoomSummaryEntityFields.IS_SERVER_NOTICE)
|
||||||
|
|
||||||
|
?.transform { obj ->
|
||||||
|
val isFavorite = obj.getList(RoomSummaryEntityFields.TAGS.`$`).any {
|
||||||
|
it.getString(RoomTagEntityFields.TAG_NAME) == RoomTag.ROOM_TAG_FAVOURITE
|
||||||
|
}
|
||||||
|
obj.setBoolean(RoomSummaryEntityFields.IS_FAVOURITE, isFavorite)
|
||||||
|
|
||||||
|
val isLowPriority = obj.getList(RoomSummaryEntityFields.TAGS.`$`).any {
|
||||||
|
it.getString(RoomTagEntityFields.TAG_NAME) == RoomTag.ROOM_TAG_LOW_PRIORITY
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.setBoolean(RoomSummaryEntityFields.IS_LOW_PRIORITY, isLowPriority)
|
||||||
|
|
||||||
|
// XXX migrate last message origin server ts
|
||||||
|
obj.getObject(RoomSummaryEntityFields.LATEST_PREVIEWABLE_EVENT.`$`)
|
||||||
|
?.getObject(TimelineEventEntityFields.ROOT.`$`)
|
||||||
|
?.getLong(EventEntityFields.ORIGIN_SERVER_TS)?.let {
|
||||||
|
obj.setLong(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||||
|
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.SpaceParentSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo010(realm: DynamicRealm) : RealmMigrator(realm, 10) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.create("SpaceChildSummaryEntity")
|
||||||
|
?.addField(SpaceChildSummaryEntityFields.ORDER, String::class.java)
|
||||||
|
?.addField(SpaceChildSummaryEntityFields.CHILD_ROOM_ID, String::class.java)
|
||||||
|
?.addField(SpaceChildSummaryEntityFields.AUTO_JOIN, Boolean::class.java)
|
||||||
|
?.setNullable(SpaceChildSummaryEntityFields.AUTO_JOIN, true)
|
||||||
|
?.addRealmObjectField(SpaceChildSummaryEntityFields.CHILD_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
|
||||||
|
?.addRealmListField(SpaceChildSummaryEntityFields.VIA_SERVERS.`$`, String::class.java)
|
||||||
|
|
||||||
|
realm.schema.create("SpaceParentSummaryEntity")
|
||||||
|
?.addField(SpaceParentSummaryEntityFields.PARENT_ROOM_ID, String::class.java)
|
||||||
|
?.addField(SpaceParentSummaryEntityFields.CANONICAL, Boolean::class.java)
|
||||||
|
?.setNullable(SpaceParentSummaryEntityFields.CANONICAL, true)
|
||||||
|
?.addRealmObjectField(SpaceParentSummaryEntityFields.PARENT_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
|
||||||
|
?.addRealmListField(SpaceParentSummaryEntityFields.VIA_SERVERS.`$`, String::class.java)
|
||||||
|
|
||||||
|
val creationContentAdapter = MoshiProvider.providesMoshi().adapter(RoomCreateContent::class.java)
|
||||||
|
realm.schema.get("RoomSummaryEntity")
|
||||||
|
?.addField(RoomSummaryEntityFields.ROOM_TYPE, String::class.java)
|
||||||
|
?.addField(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, String::class.java)
|
||||||
|
?.addField(RoomSummaryEntityFields.GROUP_IDS, String::class.java)
|
||||||
|
?.transform { obj ->
|
||||||
|
|
||||||
|
val creationEvent = realm.where("CurrentStateEventEntity")
|
||||||
|
.equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
|
||||||
|
.equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_CREATE)
|
||||||
|
.findFirst()
|
||||||
|
|
||||||
|
val roomType = creationEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
|
||||||
|
?.getString(EventEntityFields.CONTENT)?.let {
|
||||||
|
creationContentAdapter.fromJson(it)?.type
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.setString(RoomSummaryEntityFields.ROOM_TYPE, roomType)
|
||||||
|
}
|
||||||
|
?.addRealmListField(RoomSummaryEntityFields.PARENTS.`$`, realm.schema.get("SpaceParentSummaryEntity")!!)
|
||||||
|
?.addRealmListField(RoomSummaryEntityFields.CHILDREN.`$`, realm.schema.get("SpaceChildSummaryEntity")!!)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo011(realm: DynamicRealm) : RealmMigrator(realm, 11) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("EventEntity")
|
||||||
|
?.addField(EventEntityFields.SEND_STATE_DETAILS, String::class.java)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
|
||||||
|
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo012(realm: DynamicRealm) : RealmMigrator(realm, 12) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
val joinRulesContentAdapter = MoshiProvider.providesMoshi().adapter(RoomJoinRulesContent::class.java)
|
||||||
|
realm.schema.get("RoomSummaryEntity")
|
||||||
|
?.addField(RoomSummaryEntityFields.JOIN_RULES_STR, String::class.java)
|
||||||
|
?.transform { obj ->
|
||||||
|
val joinRulesEvent = realm.where("CurrentStateEventEntity")
|
||||||
|
.equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
|
||||||
|
.equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_JOIN_RULES)
|
||||||
|
.findFirst()
|
||||||
|
|
||||||
|
val roomJoinRules = joinRulesEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
|
||||||
|
?.getString(EventEntityFields.CONTENT)?.let {
|
||||||
|
joinRulesContentAdapter.fromJson(it)?.joinRules
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.setString(RoomSummaryEntityFields.JOIN_RULES_STR, roomJoinRules?.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
realm.schema.get("SpaceChildSummaryEntity")
|
||||||
|
?.addField(SpaceChildSummaryEntityFields.SUGGESTED, Boolean::class.java)
|
||||||
|
?.setNullable(SpaceChildSummaryEntityFields.SUGGESTED, true)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo013(realm: DynamicRealm) : RealmMigrator(realm, 13) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
// Fix issue with the nightly build. Eventually play again the migration which has been included in migrateTo12()
|
||||||
|
realm.schema.get("SpaceChildSummaryEntity")
|
||||||
|
?.takeIf { !it.hasField(SpaceChildSummaryEntityFields.SUGGESTED) }
|
||||||
|
?.addField(SpaceChildSummaryEntityFields.SUGGESTED, Boolean::class.java)
|
||||||
|
?.setNullable(SpaceChildSummaryEntityFields.SUGGESTED, true)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import io.realm.FieldAttribute
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.VersioningState
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomAccountDataEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo014(realm: DynamicRealm) : RealmMigrator(realm, 14) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
val roomAccountDataSchema = realm.schema.create("RoomAccountDataEntity")
|
||||||
|
.addField(RoomAccountDataEntityFields.CONTENT_STR, String::class.java)
|
||||||
|
.addField(RoomAccountDataEntityFields.TYPE, String::class.java, FieldAttribute.INDEXED)
|
||||||
|
|
||||||
|
realm.schema.get("RoomEntity")
|
||||||
|
?.addRealmListField(RoomEntityFields.ACCOUNT_DATA.`$`, roomAccountDataSchema)
|
||||||
|
|
||||||
|
realm.schema.get("RoomSummaryEntity")
|
||||||
|
?.addField(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, Boolean::class.java, FieldAttribute.INDEXED)
|
||||||
|
?.transform {
|
||||||
|
val isHiddenFromUser = it.getString(RoomSummaryEntityFields.VERSIONING_STATE_STR) == VersioningState.UPGRADED_ROOM_JOINED.name
|
||||||
|
it.setBoolean(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, isHiddenFromUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
roomAccountDataSchema.isEmbedded = true
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.query.process
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo015(realm: DynamicRealm) : RealmMigrator(realm, 15) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
// fix issue with flattenParentIds on DM that kept growing with duplicate
|
||||||
|
// so we reset it, will be updated next sync
|
||||||
|
realm.where("RoomSummaryEntity")
|
||||||
|
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
|
||||||
|
.equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
|
||||||
|
.findAll()
|
||||||
|
.onEach {
|
||||||
|
it.setString(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo016(realm: DynamicRealm) : RealmMigrator(realm, 16) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("HomeServerCapabilitiesEntity")
|
||||||
|
?.addField(HomeServerCapabilitiesEntityFields.ROOM_VERSIONS_JSON, String::class.java)
|
||||||
|
?.transform { obj ->
|
||||||
|
// Schedule a refresh of the capabilities
|
||||||
|
obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EventInsertEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo017(realm: DynamicRealm) : RealmMigrator(realm, 17) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("EventInsertEntity")
|
||||||
|
?.addField(EventInsertEntityFields.CAN_BE_PROCESSED, Boolean::class.java)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo018(realm: DynamicRealm) : RealmMigrator(realm, 18) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.create("UserPresenceEntity")
|
||||||
|
?.addField(UserPresenceEntityFields.USER_ID, String::class.java)
|
||||||
|
?.addPrimaryKey(UserPresenceEntityFields.USER_ID)
|
||||||
|
?.setRequired(UserPresenceEntityFields.USER_ID, true)
|
||||||
|
?.addField(UserPresenceEntityFields.PRESENCE_STR, String::class.java)
|
||||||
|
?.addField(UserPresenceEntityFields.LAST_ACTIVE_AGO, Long::class.java)
|
||||||
|
?.setNullable(UserPresenceEntityFields.LAST_ACTIVE_AGO, true)
|
||||||
|
?.addField(UserPresenceEntityFields.STATUS_MESSAGE, String::class.java)
|
||||||
|
?.addField(UserPresenceEntityFields.IS_CURRENTLY_ACTIVE, Boolean::class.java)
|
||||||
|
?.setNullable(UserPresenceEntityFields.IS_CURRENTLY_ACTIVE, true)
|
||||||
|
?.addField(UserPresenceEntityFields.AVATAR_URL, String::class.java)
|
||||||
|
?.addField(UserPresenceEntityFields.DISPLAY_NAME, String::class.java)
|
||||||
|
|
||||||
|
val userPresenceEntity = realm.schema.get("UserPresenceEntity") ?: return
|
||||||
|
realm.schema.get("RoomSummaryEntity")
|
||||||
|
?.addRealmObjectField(RoomSummaryEntityFields.DIRECT_USER_PRESENCE.`$`, userPresenceEntity)
|
||||||
|
|
||||||
|
realm.schema.get("RoomMemberSummaryEntity")
|
||||||
|
?.addRealmObjectField(RoomMemberSummaryEntityFields.USER_PRESENCE_ENTITY.`$`, userPresenceEntity)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.Normalizer
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo019(realm: DynamicRealm,
|
||||||
|
private val normalizer: Normalizer) : RealmMigrator(realm, 19) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("RoomSummaryEntity")
|
||||||
|
?.addField(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, String::class.java)
|
||||||
|
?.transform {
|
||||||
|
it.getString(RoomSummaryEntityFields.DISPLAY_NAME)?.let { displayName ->
|
||||||
|
val normalised = normalizer.normalize(displayName)
|
||||||
|
it.set(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, normalised)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo020(realm: DynamicRealm) : RealmMigrator(realm, 20) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("ChunkEntity")?.apply {
|
||||||
|
if (hasField("numberOfTimelineEvents")) {
|
||||||
|
removeField("numberOfTimelineEvents")
|
||||||
|
}
|
||||||
|
var cleanOldChunks = false
|
||||||
|
if (!hasField(ChunkEntityFields.NEXT_CHUNK.`$`)) {
|
||||||
|
cleanOldChunks = true
|
||||||
|
addRealmObjectField(ChunkEntityFields.NEXT_CHUNK.`$`, this)
|
||||||
|
}
|
||||||
|
if (!hasField(ChunkEntityFields.PREV_CHUNK.`$`)) {
|
||||||
|
cleanOldChunks = true
|
||||||
|
addRealmObjectField(ChunkEntityFields.PREV_CHUNK.`$`, this)
|
||||||
|
}
|
||||||
|
if (cleanOldChunks) {
|
||||||
|
val chunkEntities = realm.where("ChunkEntity").equalTo(ChunkEntityFields.IS_LAST_FORWARD, false).findAll()
|
||||||
|
chunkEntities.deleteAllFromRealm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
|
import org.matrix.android.sdk.internal.crypto.model.event.EncryptionEventContent
|
||||||
|
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo021(realm: DynamicRealm) : RealmMigrator(realm, 21) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("RoomSummaryEntity")
|
||||||
|
?.addField(RoomSummaryEntityFields.E2E_ALGORITHM, String::class.java)
|
||||||
|
?.transform { obj ->
|
||||||
|
|
||||||
|
val encryptionContentAdapter = MoshiProvider.providesMoshi().adapter(EncryptionEventContent::class.java)
|
||||||
|
|
||||||
|
val encryptionEvent = realm.where("CurrentStateEventEntity")
|
||||||
|
.equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
|
||||||
|
.equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_ENCRYPTION)
|
||||||
|
.findFirst()
|
||||||
|
|
||||||
|
val encryptionEventRoot = encryptionEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
|
||||||
|
val algorithm = encryptionEventRoot
|
||||||
|
?.getString(EventEntityFields.CONTENT)?.let {
|
||||||
|
encryptionContentAdapter.fromJson(it)?.algorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.setString(RoomSummaryEntityFields.E2E_ALGORITHM, algorithm)
|
||||||
|
obj.setBoolean(RoomSummaryEntityFields.IS_ENCRYPTED, encryptionEvent != null)
|
||||||
|
encryptionEventRoot?.getLong(EventEntityFields.ORIGIN_SERVER_TS)?.let {
|
||||||
|
obj.setLong(RoomSummaryEntityFields.ENCRYPTION_EVENT_TS, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
|
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class MigrateSessionTo022(realm: DynamicRealm) : RealmMigrator(realm, 22) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
val listJoinedRoomIds = realm.where("RoomEntity")
|
||||||
|
.equalTo(RoomEntityFields.MEMBERSHIP_STR, Membership.JOIN.name).findAll()
|
||||||
|
.map { it.getString(RoomEntityFields.ROOM_ID) }
|
||||||
|
|
||||||
|
val hasMissingStateEvent = realm.where("CurrentStateEventEntity")
|
||||||
|
.`in`(CurrentStateEventEntityFields.ROOM_ID, listJoinedRoomIds.toTypedArray())
|
||||||
|
.isNull(CurrentStateEventEntityFields.ROOT.`$`).findFirst() != null
|
||||||
|
|
||||||
|
if (hasMissingStateEvent) {
|
||||||
|
Timber.v("Has some missing state event, clear session cache")
|
||||||
|
realm.deleteAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import io.realm.FieldAttribute
|
||||||
|
import org.matrix.android.sdk.api.session.threads.ThreadNotificationState
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo023(realm: DynamicRealm) : RealmMigrator(realm, 23) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
val eventEntity = realm.schema.get("TimelineEventEntity") ?: return
|
||||||
|
|
||||||
|
realm.schema.get("EventEntity")
|
||||||
|
?.addField(EventEntityFields.IS_ROOT_THREAD, Boolean::class.java, FieldAttribute.INDEXED)
|
||||||
|
?.addField(EventEntityFields.ROOT_THREAD_EVENT_ID, String::class.java, FieldAttribute.INDEXED)
|
||||||
|
?.addField(EventEntityFields.NUMBER_OF_THREADS, Int::class.java)
|
||||||
|
?.addField(EventEntityFields.THREAD_NOTIFICATION_STATE_STR, String::class.java)
|
||||||
|
?.transform {
|
||||||
|
it.setString(EventEntityFields.THREAD_NOTIFICATION_STATE_STR, ThreadNotificationState.NO_NEW_MESSAGE.name)
|
||||||
|
}
|
||||||
|
?.addRealmObjectField(EventEntityFields.THREAD_SUMMARY_LATEST_MESSAGE.`$`, eventEntity)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateSessionTo024(realm: DynamicRealm) : RealmMigrator(realm, 24) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("PreviewUrlCacheEntity")
|
||||||
|
?.addField(PreviewUrlCacheEntityFields.IMAGE_WIDTH, Int::class.java)
|
||||||
|
?.setNullable(PreviewUrlCacheEntityFields.IMAGE_WIDTH, true)
|
||||||
|
?.addField(PreviewUrlCacheEntityFields.IMAGE_HEIGHT, Int::class.java)
|
||||||
|
?.setNullable(PreviewUrlCacheEntityFields.IMAGE_HEIGHT, true)
|
||||||
|
}
|
||||||
|
}
|
@ -42,7 +42,8 @@ import org.matrix.android.sdk.internal.legacy.riot.HomeServerConnectionConfig as
|
|||||||
internal class DefaultLegacySessionImporter @Inject constructor(
|
internal class DefaultLegacySessionImporter @Inject constructor(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val sessionParamsStore: SessionParamsStore,
|
private val sessionParamsStore: SessionParamsStore,
|
||||||
private val realmKeysUtils: RealmKeysUtils
|
private val realmKeysUtils: RealmKeysUtils,
|
||||||
|
private val realmCryptoStoreMigration: RealmCryptoStoreMigration
|
||||||
) : LegacySessionImporter {
|
) : LegacySessionImporter {
|
||||||
|
|
||||||
private val loginStorage = LoginStorage(context)
|
private val loginStorage = LoginStorage(context)
|
||||||
@ -170,8 +171,8 @@ internal class DefaultLegacySessionImporter @Inject constructor(
|
|||||||
.directory(File(context.filesDir, userMd5))
|
.directory(File(context.filesDir, userMd5))
|
||||||
.name("crypto_store.realm")
|
.name("crypto_store.realm")
|
||||||
.modules(RealmCryptoStoreModule())
|
.modules(RealmCryptoStoreModule())
|
||||||
.schemaVersion(RealmCryptoStoreMigration.CRYPTO_STORE_SCHEMA_VERSION)
|
.schemaVersion(realmCryptoStoreMigration.schemaVersion)
|
||||||
.migration(RealmCryptoStoreMigration)
|
.migration(realmCryptoStoreMigration)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
Timber.d("Migration: copy DB to encrypted DB")
|
Timber.d("Migration: copy DB to encrypted DB")
|
||||||
|
@ -18,24 +18,23 @@ package org.matrix.android.sdk.internal.raw
|
|||||||
|
|
||||||
import io.realm.DynamicRealm
|
import io.realm.DynamicRealm
|
||||||
import io.realm.RealmMigration
|
import io.realm.RealmMigration
|
||||||
import org.matrix.android.sdk.internal.database.model.KnownServerUrlEntityFields
|
import org.matrix.android.sdk.internal.raw.migration.MigrateGlobalTo001
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal object GlobalRealmMigration : RealmMigration {
|
internal class GlobalRealmMigration @Inject constructor() : RealmMigration {
|
||||||
|
/**
|
||||||
|
* Forces all GlobalRealmMigration instances to be equal
|
||||||
|
* Avoids Realm throwing when multiple instances of the migration are set
|
||||||
|
*/
|
||||||
|
override fun equals(other: Any?) = other is GlobalRealmMigration
|
||||||
|
override fun hashCode() = 2000
|
||||||
|
|
||||||
// Current schema version
|
val schemaVersion = 1L
|
||||||
const val SCHEMA_VERSION = 1L
|
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
Timber.d("Migrating Auth Realm from $oldVersion to $newVersion")
|
Timber.d("Migrating Global Realm from $oldVersion to $newVersion")
|
||||||
|
|
||||||
if (oldVersion <= 0) migrateTo1(realm)
|
if (oldVersion < 1) MigrateGlobalTo001(realm).perform()
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo1(realm: DynamicRealm) {
|
|
||||||
realm.schema.create("KnownServerUrlEntity")
|
|
||||||
.addField(KnownServerUrlEntityFields.URL, String::class.java)
|
|
||||||
.addPrimaryKey(KnownServerUrlEntityFields.URL)
|
|
||||||
.setRequired(KnownServerUrlEntityFields.URL, true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,14 +51,15 @@ internal abstract class RawModule {
|
|||||||
@Provides
|
@Provides
|
||||||
@GlobalDatabase
|
@GlobalDatabase
|
||||||
@MatrixScope
|
@MatrixScope
|
||||||
fun providesRealmConfiguration(realmKeysUtils: RealmKeysUtils): RealmConfiguration {
|
fun providesRealmConfiguration(realmKeysUtils: RealmKeysUtils,
|
||||||
|
globalRealmMigration: GlobalRealmMigration): RealmConfiguration {
|
||||||
return RealmConfiguration.Builder()
|
return RealmConfiguration.Builder()
|
||||||
.apply {
|
.apply {
|
||||||
realmKeysUtils.configureEncryption(this, DB_ALIAS)
|
realmKeysUtils.configureEncryption(this, DB_ALIAS)
|
||||||
}
|
}
|
||||||
.name("matrix-sdk-global.realm")
|
.name("matrix-sdk-global.realm")
|
||||||
.schemaVersion(GlobalRealmMigration.SCHEMA_VERSION)
|
.schemaVersion(globalRealmMigration.schemaVersion)
|
||||||
.migration(GlobalRealmMigration)
|
.migration(globalRealmMigration)
|
||||||
.allowWritesOnUiThread(true)
|
.allowWritesOnUiThread(true)
|
||||||
.modules(GlobalRealmModule())
|
.modules(GlobalRealmModule())
|
||||||
.build()
|
.build()
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.raw.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.KnownServerUrlEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
class MigrateGlobalTo001(realm: DynamicRealm) : RealmMigrator(realm, 1) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.create("KnownServerUrlEntity")
|
||||||
|
.addField(KnownServerUrlEntityFields.URL, String::class.java)
|
||||||
|
.addPrimaryKey(KnownServerUrlEntityFields.URL)
|
||||||
|
.setRequired(KnownServerUrlEntityFields.URL, true)
|
||||||
|
}
|
||||||
|
}
|
@ -60,6 +60,7 @@ internal abstract class IdentityModule {
|
|||||||
@IdentityDatabase
|
@IdentityDatabase
|
||||||
@SessionScope
|
@SessionScope
|
||||||
fun providesIdentityRealmConfiguration(realmKeysUtils: RealmKeysUtils,
|
fun providesIdentityRealmConfiguration(realmKeysUtils: RealmKeysUtils,
|
||||||
|
realmIdentityStoreMigration: RealmIdentityStoreMigration,
|
||||||
@SessionFilesDirectory directory: File,
|
@SessionFilesDirectory directory: File,
|
||||||
@UserMd5 userMd5: String): RealmConfiguration {
|
@UserMd5 userMd5: String): RealmConfiguration {
|
||||||
return RealmConfiguration.Builder()
|
return RealmConfiguration.Builder()
|
||||||
@ -68,8 +69,8 @@ internal abstract class IdentityModule {
|
|||||||
.apply {
|
.apply {
|
||||||
realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5))
|
realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5))
|
||||||
}
|
}
|
||||||
.schemaVersion(RealmIdentityStoreMigration.IDENTITY_STORE_SCHEMA_VERSION)
|
.schemaVersion(realmIdentityStoreMigration.schemaVersion)
|
||||||
.migration(RealmIdentityStoreMigration)
|
.migration(realmIdentityStoreMigration)
|
||||||
.allowWritesOnUiThread(true)
|
.allowWritesOnUiThread(true)
|
||||||
.modules(IdentityRealmModule())
|
.modules(IdentityRealmModule())
|
||||||
.build()
|
.build()
|
||||||
|
@ -18,23 +18,23 @@ package org.matrix.android.sdk.internal.session.identity.db
|
|||||||
|
|
||||||
import io.realm.DynamicRealm
|
import io.realm.DynamicRealm
|
||||||
import io.realm.RealmMigration
|
import io.realm.RealmMigration
|
||||||
|
import org.matrix.android.sdk.internal.session.identity.db.migration.MigrateIdentityTo001
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal object RealmIdentityStoreMigration : RealmMigration {
|
internal class RealmIdentityStoreMigration @Inject constructor() : RealmMigration {
|
||||||
|
/**
|
||||||
|
* Forces all RealmIdentityStoreMigration instances to be equal
|
||||||
|
* Avoids Realm throwing when multiple instances of the migration are set
|
||||||
|
*/
|
||||||
|
override fun equals(other: Any?) = other is RealmIdentityStoreMigration
|
||||||
|
override fun hashCode() = 3000
|
||||||
|
|
||||||
const val IDENTITY_STORE_SCHEMA_VERSION = 1L
|
val schemaVersion = 1L
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
Timber.v("Migrating Realm Identity from $oldVersion to $newVersion")
|
Timber.d("Migrating Realm Identity from $oldVersion to $newVersion")
|
||||||
|
|
||||||
if (oldVersion <= 0) migrateTo1(realm)
|
if (oldVersion < 1) MigrateIdentityTo001(realm).perform()
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateTo1(realm: DynamicRealm) {
|
|
||||||
Timber.d("Step 0 -> 1")
|
|
||||||
Timber.d("Add field userConsent (Boolean) and set the value to false")
|
|
||||||
|
|
||||||
realm.schema.get("IdentityDataEntity")
|
|
||||||
?.addField(IdentityDataEntityFields.USER_CONSENT, Boolean::class.java)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.session.identity.db.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.session.identity.db.IdentityDataEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class MigrateIdentityTo001(realm: DynamicRealm) : RealmMigrator(realm, 1) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
Timber.d("Add field userConsent (Boolean) and set the value to false")
|
||||||
|
realm.schema.get("IdentityDataEntity")
|
||||||
|
?.addField(IdentityDataEntityFields.USER_CONSENT, Boolean::class.java)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.database
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import io.realm.RealmObjectSchema
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
abstract class RealmMigrator(private val realm: DynamicRealm,
|
||||||
|
private val targetSchemaVersion: Int) {
|
||||||
|
fun perform() {
|
||||||
|
Timber.d("Migrate ${realm.configuration.realmFileName} to $targetSchemaVersion")
|
||||||
|
doMigrate(realm)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun doMigrate(realm: DynamicRealm)
|
||||||
|
|
||||||
|
protected fun RealmObjectSchema.addFieldIfNotExists(fieldName: String, fieldType: Class<*>): RealmObjectSchema {
|
||||||
|
if (!hasField(fieldName)) {
|
||||||
|
addField(fieldName, fieldType)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun RealmObjectSchema.removeFieldIfExists(fieldName: String): RealmObjectSchema {
|
||||||
|
if (hasField(fieldName)) {
|
||||||
|
removeField(fieldName)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun RealmObjectSchema.setRequiredIfNotAlready(fieldName: String, isRequired: Boolean): RealmObjectSchema {
|
||||||
|
if (isRequired != isRequired(fieldName)) {
|
||||||
|
setRequired(fieldName, isRequired)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user