mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-21 17:05:39 +03:00
Remove dependency on libolm - WIP
This commit is contained in:
parent
6a8e978204
commit
5908cd54f0
64 changed files with 51 additions and 3290 deletions
|
@ -205,9 +205,6 @@ dependencies {
|
|||
// Work
|
||||
implementation libs.androidx.work
|
||||
|
||||
// olm lib is now hosted in MavenCentral
|
||||
implementation 'org.matrix.android:olm-sdk:3.2.12'
|
||||
|
||||
// DI
|
||||
implementation libs.dagger.dagger
|
||||
kapt libs.dagger.daggerCompiler
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a7acd69f37612bab0a1ab7f456656712d7ba19dbb679f81b97b58ef44e239f42
|
||||
size 8523776
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:59b4957aa2f9cdc17b14ec8546e144537fac9dee050c6eb173f56fa8602c2736
|
||||
size 2097152
|
|
@ -36,7 +36,6 @@ import org.matrix.android.sdk.internal.network.ApiInterceptor
|
|||
import org.matrix.android.sdk.internal.network.UserAgentHolder
|
||||
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
|
||||
import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
|
||||
import org.matrix.olm.OlmManager
|
||||
import java.util.concurrent.Executors
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -49,7 +48,6 @@ internal class TestMatrix(context: Context, matrixConfiguration: MatrixConfigura
|
|||
@Inject internal lateinit var rawService: RawService
|
||||
@Inject internal lateinit var userAgentHolder: UserAgentHolder
|
||||
@Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver
|
||||
@Inject internal lateinit var olmManager: OlmManager
|
||||
@Inject internal lateinit var sessionManager: SessionManager
|
||||
@Inject internal lateinit var homeServerHistoryService: HomeServerHistoryService
|
||||
@Inject internal lateinit var apiInterceptor: ApiInterceptor
|
||||
|
|
|
@ -20,7 +20,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
|||
import org.junit.Assert.assertArrayEquals
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
|
@ -29,19 +28,12 @@ import org.junit.runners.MethodSorters
|
|||
import org.matrix.android.sdk.InstrumentedTest
|
||||
import org.matrix.android.sdk.api.listeners.ProgressListener
|
||||
import org.matrix.android.sdk.common.assertByteArrayNotEqual
|
||||
import org.matrix.olm.OlmManager
|
||||
import org.matrix.olm.OlmPkDecryption
|
||||
|
||||
@Ignore("Ignored in order to speed up test run time")
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class KeysBackupPasswordTest : InstrumentedTest {
|
||||
|
||||
@Before
|
||||
fun ensureLibLoaded() {
|
||||
OlmManager()
|
||||
}
|
||||
|
||||
/**
|
||||
* Check KeysBackupPassword utilities
|
||||
*/
|
||||
|
@ -51,7 +43,7 @@ class KeysBackupPasswordTest : InstrumentedTest {
|
|||
|
||||
assertEquals(32, generatePrivateKeyResult.salt.length)
|
||||
assertEquals(500_000, generatePrivateKeyResult.iterations)
|
||||
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
|
||||
assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, generatePrivateKeyResult.privateKey.size)
|
||||
|
||||
// Reverse operation
|
||||
val retrievedPrivateKey = retrievePrivateKeyWithPassword(
|
||||
|
@ -60,7 +52,7 @@ class KeysBackupPasswordTest : InstrumentedTest {
|
|||
generatePrivateKeyResult.iterations
|
||||
)
|
||||
|
||||
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
|
||||
assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, retrievedPrivateKey.size)
|
||||
assertArrayEquals(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
|
||||
}
|
||||
|
||||
|
@ -101,7 +93,7 @@ class KeysBackupPasswordTest : InstrumentedTest {
|
|||
|
||||
assertEquals(32, generatePrivateKeyResult.salt.length)
|
||||
assertEquals(500_000, generatePrivateKeyResult.iterations)
|
||||
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
|
||||
assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, generatePrivateKeyResult.privateKey.size)
|
||||
|
||||
// Reverse operation, with bad password
|
||||
val retrievedPrivateKey = retrievePrivateKeyWithPassword(
|
||||
|
@ -110,7 +102,7 @@ class KeysBackupPasswordTest : InstrumentedTest {
|
|||
generatePrivateKeyResult.iterations
|
||||
)
|
||||
|
||||
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
|
||||
assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, retrievedPrivateKey.size)
|
||||
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
|
||||
}
|
||||
|
||||
|
@ -123,7 +115,7 @@ class KeysBackupPasswordTest : InstrumentedTest {
|
|||
|
||||
assertEquals(32, generatePrivateKeyResult.salt.length)
|
||||
assertEquals(500_000, generatePrivateKeyResult.iterations)
|
||||
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
|
||||
assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, generatePrivateKeyResult.privateKey.size)
|
||||
|
||||
// Reverse operation, with bad iteration
|
||||
val retrievedPrivateKey = retrievePrivateKeyWithPassword(
|
||||
|
@ -132,7 +124,7 @@ class KeysBackupPasswordTest : InstrumentedTest {
|
|||
500_001
|
||||
)
|
||||
|
||||
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
|
||||
assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, retrievedPrivateKey.size)
|
||||
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
|
||||
}
|
||||
|
||||
|
@ -145,7 +137,7 @@ class KeysBackupPasswordTest : InstrumentedTest {
|
|||
|
||||
assertEquals(32, generatePrivateKeyResult.salt.length)
|
||||
assertEquals(500_000, generatePrivateKeyResult.iterations)
|
||||
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
|
||||
assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, generatePrivateKeyResult.privateKey.size)
|
||||
|
||||
// Reverse operation, with bad iteration
|
||||
val retrievedPrivateKey = retrievePrivateKeyWithPassword(
|
||||
|
@ -154,7 +146,7 @@ class KeysBackupPasswordTest : InstrumentedTest {
|
|||
generatePrivateKeyResult.iterations
|
||||
)
|
||||
|
||||
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
|
||||
assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, retrievedPrivateKey.size)
|
||||
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
|
||||
}
|
||||
|
||||
|
@ -169,7 +161,7 @@ class KeysBackupPasswordTest : InstrumentedTest {
|
|||
|
||||
val retrievedPrivateKey = retrievePrivateKeyWithPassword(password, salt, iteration)
|
||||
|
||||
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
|
||||
assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, retrievedPrivateKey.size)
|
||||
|
||||
// Data from RiotWeb
|
||||
val privateKeyBytes = byteArrayOf(
|
||||
|
@ -187,5 +179,7 @@ class KeysBackupPasswordTest : InstrumentedTest {
|
|||
private const val BAD_PASSWORD = "passw0rd"
|
||||
|
||||
private const val BAD_SALT = "AA0lxhQ9aYgGfMsclVWPIAublg8h9Nlu"
|
||||
|
||||
private const val EXPECTED_PRIVATE_KEY_LENGTH = 32
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
* Copyright 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.migration
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import io.mockk.spyk
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.where
|
||||
import org.amshove.kluent.internal.assertEquals
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.matrix.android.sdk.TestBuildVersionSdkIntProvider
|
||||
import org.matrix.android.sdk.api.securestorage.SecretStoringUtils
|
||||
import org.matrix.android.sdk.internal.crypto.RustEncryptionConfiguration
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreMigration
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.RustMigrationInfoProvider
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity
|
||||
import org.matrix.android.sdk.internal.database.RealmKeysUtils
|
||||
import org.matrix.android.sdk.internal.database.TestRealmConfigurationFactory
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
import org.matrix.android.sdk.test.shared.createTimberTestRule
|
||||
import org.matrix.olm.OlmAccount
|
||||
import org.matrix.olm.OlmManager
|
||||
import org.matrix.rustcomponents.sdk.crypto.OlmMachine
|
||||
import java.io.File
|
||||
import java.security.KeyStore
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class DynamicElementAndroidToElementRMigrationTest {
|
||||
|
||||
@get:Rule val configurationFactory = TestRealmConfigurationFactory()
|
||||
|
||||
@Rule
|
||||
fun timberTestRule() = createTimberTestRule()
|
||||
|
||||
var context: Context = InstrumentationRegistry.getInstrumentation().context
|
||||
var realm: Realm? = null
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
// Ensure Olm is initialized
|
||||
OlmManager()
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
realm?.close()
|
||||
}
|
||||
|
||||
private val keyStore = spyk(KeyStore.getInstance("AndroidKeyStore")).also { it.load(null) }
|
||||
|
||||
private val rustEncryptionConfiguration = RustEncryptionConfiguration(
|
||||
"foo",
|
||||
RealmKeysUtils(
|
||||
context,
|
||||
SecretStoringUtils(context, keyStore, TestBuildVersionSdkIntProvider(), false)
|
||||
)
|
||||
)
|
||||
|
||||
private val fakeClock = object : Clock {
|
||||
override fun epochMillis() = 0L
|
||||
}
|
||||
|
||||
@Test
|
||||
fun given_a_valid_crypto_store_realm_file_then_migration_should_be_successful() {
|
||||
testMigrate(false)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("We don't migrate group sessions for now, and it's making this test suite unstable")
|
||||
fun given_a_valid_crypto_store_realm_file_no_lazy_then_migration_should_be_successful() {
|
||||
testMigrate(true)
|
||||
}
|
||||
|
||||
private fun testMigrate(migrateGroupSessions: Boolean) {
|
||||
val targetFile = File(configurationFactory.root, "rust-sdk")
|
||||
|
||||
val realmName = "crypto_store_migration_16.realm"
|
||||
val infoProvider = RustMigrationInfoProvider(
|
||||
targetFile,
|
||||
rustEncryptionConfiguration
|
||||
).apply {
|
||||
migrateMegolmGroupSessions = migrateGroupSessions
|
||||
}
|
||||
val migration = RealmCryptoStoreMigration(fakeClock, infoProvider)
|
||||
|
||||
val realmConfiguration = configurationFactory.createConfiguration(
|
||||
realmName,
|
||||
null,
|
||||
RealmCryptoStoreModule(),
|
||||
migration.schemaVersion,
|
||||
migration
|
||||
)
|
||||
configurationFactory.copyRealmFromAssets(context, realmName, realmName)
|
||||
|
||||
realm = Realm.getInstance(realmConfiguration)
|
||||
val metaData = realm!!.where<CryptoMetadataEntity>().findFirst()!!
|
||||
val userId = metaData.userId!!
|
||||
val deviceId = metaData.deviceId!!
|
||||
val olmAccount = metaData.getOlmAccount()!!
|
||||
|
||||
val machine = OlmMachine(userId, deviceId, targetFile.path, rustEncryptionConfiguration.getDatabasePassphrase())
|
||||
|
||||
assertEquals(olmAccount.identityKeys()[OlmAccount.JSON_KEY_FINGER_PRINT_KEY], machine.identityKeys()["ed25519"])
|
||||
assertNotNull(machine.getBackupKeys())
|
||||
val crossSigningStatus = machine.crossSigningStatus()
|
||||
assertTrue(crossSigningStatus.hasMaster)
|
||||
assertTrue(crossSigningStatus.hasSelfSigning)
|
||||
assertTrue(crossSigningStatus.hasUserSigning)
|
||||
|
||||
if (migrateGroupSessions) {
|
||||
assertTrue("Some outbound sessions should be migrated", machine.roomKeyCounts().total.toInt() > 0)
|
||||
assertTrue("There are some backed-up sessions", machine.roomKeyCounts().backedUp.toInt() > 0)
|
||||
} else {
|
||||
assertTrue(machine.roomKeyCounts().total.toInt() == 0)
|
||||
assertTrue(machine.roomKeyCounts().backedUp.toInt() == 0)
|
||||
}
|
||||
|
||||
// legacy olm sessions should have been deleted
|
||||
val remainingOlmSessions = realm!!.where<OlmSessionEntity>().findAll().size
|
||||
assertEquals("legacy olm sessions should have been removed from store", 0, remainingOlmSessions)
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023 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
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import io.mockk.spyk
|
||||
import io.realm.Realm
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.TestBuildVersionSdkIntProvider
|
||||
import org.matrix.android.sdk.api.securestorage.SecretStoringUtils
|
||||
import org.matrix.android.sdk.internal.crypto.RustEncryptionConfiguration
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreMigration
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.RustMigrationInfoProvider
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
import org.matrix.olm.OlmManager
|
||||
import java.io.File
|
||||
import java.security.KeyStore
|
||||
|
||||
class CryptoSanityMigrationTest {
|
||||
@get:Rule val configurationFactory = TestRealmConfigurationFactory()
|
||||
|
||||
lateinit var context: Context
|
||||
var realm: Realm? = null
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
// Ensure Olm is initialized
|
||||
OlmManager()
|
||||
context = InstrumentationRegistry.getInstrumentation().context
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
realm?.close()
|
||||
}
|
||||
|
||||
private val keyStore = spyk(KeyStore.getInstance("AndroidKeyStore")).also { it.load(null) }
|
||||
|
||||
@Test
|
||||
fun cryptoDatabaseShouldMigrateGracefully() {
|
||||
val realmName = "crypto_store_20.realm"
|
||||
|
||||
val rustMigrationInfo = RustMigrationInfoProvider(
|
||||
File(configurationFactory.root, "test_rust"),
|
||||
RustEncryptionConfiguration(
|
||||
"foo",
|
||||
RealmKeysUtils(
|
||||
context,
|
||||
SecretStoringUtils(context, keyStore, TestBuildVersionSdkIntProvider(), false)
|
||||
)
|
||||
),
|
||||
)
|
||||
val migration = RealmCryptoStoreMigration(
|
||||
object : Clock {
|
||||
override fun epochMillis(): Long {
|
||||
return 0L
|
||||
}
|
||||
},
|
||||
rustMigrationInfo
|
||||
)
|
||||
|
||||
val realmConfiguration = configurationFactory.createConfiguration(
|
||||
realmName,
|
||||
"7b9a21a8a311e85d75b069a343c23fc952fc3fec5e0c83ecfa13f24b787479c487c3ed587db3dd1f5805d52041fc0ac246516e94b27ffa699ff928622e621aca",
|
||||
RealmCryptoStoreModule(),
|
||||
migration.schemaVersion,
|
||||
migration
|
||||
)
|
||||
configurationFactory.copyRealmFromAssets(context, realmName, realmName)
|
||||
|
||||
realm = Realm.getInstance(realmConfiguration)
|
||||
}
|
||||
}
|
|
@ -39,7 +39,6 @@ import org.matrix.android.sdk.internal.network.ApiInterceptor
|
|||
import org.matrix.android.sdk.internal.network.UserAgentHolder
|
||||
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
|
||||
import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
|
||||
import org.matrix.olm.OlmManager
|
||||
import java.util.concurrent.Executors
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -59,7 +58,6 @@ class Matrix(context: Context, matrixConfiguration: MatrixConfiguration) {
|
|||
@Inject internal lateinit var debugService: DebugService
|
||||
@Inject internal lateinit var userAgentHolder: UserAgentHolder
|
||||
@Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver
|
||||
@Inject internal lateinit var olmManager: OlmManager
|
||||
@Inject internal lateinit var sessionManager: SessionManager
|
||||
@Inject internal lateinit var homeServerHistoryService: HomeServerHistoryService
|
||||
@Inject internal lateinit var apiInterceptor: ApiInterceptor
|
||||
|
|
|
@ -18,7 +18,6 @@ package org.matrix.android.sdk.api.session.crypto
|
|||
|
||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
|
||||
import org.matrix.olm.OlmException
|
||||
|
||||
/**
|
||||
* Represents a crypto error response.
|
||||
|
@ -34,8 +33,6 @@ sealed class MXCryptoError : Throwable() {
|
|||
val detailedErrorDescription: String? = null
|
||||
) : MXCryptoError()
|
||||
|
||||
data class OlmError(val olmException: OlmException) : MXCryptoError()
|
||||
|
||||
data class UnknownDevice(val deviceList: MXUsersDevicesMap<CryptoDeviceInfo>) : MXCryptoError()
|
||||
|
||||
enum class ErrorType {
|
||||
|
|
|
@ -53,7 +53,6 @@ import org.matrix.android.sdk.api.util.toOptional
|
|||
import org.matrix.android.sdk.internal.coroutines.builder.safeInvokeOnClose
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.DefaultKeysAlgorithmAndData
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysAlgorithmAndData
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
|
||||
import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
||||
import org.matrix.android.sdk.internal.crypto.verification.SasVerification
|
||||
import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest
|
||||
|
@ -318,22 +317,6 @@ internal class OlmMachine @Inject constructor(
|
|||
inner.receiveVerificationEvent(serializedEvent, roomId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for lazy migration of inboundGroupSession from EA to ER.
|
||||
*/
|
||||
suspend fun importRoomKey(inbound: MXInboundMegolmSessionWrapper): Result<Unit> {
|
||||
Timber.v("Migration:: Tentative lazy migration")
|
||||
return withContext(coroutineDispatchers.io) {
|
||||
val export = inbound.exportKeys()
|
||||
?: return@withContext Result.failure(Exception("Failed to export key"))
|
||||
val result = importDecryptedKeys(listOf(export), null).also {
|
||||
Timber.v("Migration:: Tentative lazy migration result: ${it.totalNumberOfKeys}")
|
||||
}
|
||||
if (result.totalNumberOfKeys == 1) return@withContext Result.success(Unit)
|
||||
return@withContext Result.failure(Exception("Import failed"))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the given list of users to be tracked, triggering a key query request for them.
|
||||
*
|
||||
|
|
|
@ -504,17 +504,10 @@ internal class RustCryptoService @Inject constructor(
|
|||
val content = event.content?.toModel<EncryptedEventContent>() ?: throw mxCryptoError
|
||||
val roomId = event.roomId
|
||||
val sessionId = content.sessionId
|
||||
val senderKey = content.senderKey
|
||||
if (roomId != null && sessionId != null) {
|
||||
// try to perform a lazy migration from legacy store
|
||||
val legacy = tryOrNull("Failed to access legacy crypto store") {
|
||||
cryptoStore.getInboundGroupSession(sessionId, senderKey.orEmpty())
|
||||
}
|
||||
if (legacy == null || olmMachine.importRoomKey(legacy).isFailure) {
|
||||
perSessionBackupQueryRateLimiter.tryFromBackupIfPossible(sessionId, roomId)
|
||||
}
|
||||
}
|
||||
}
|
||||
throw mxCryptoError
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,6 @@ import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
|||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.util.JsonCanonicalizer
|
||||
import org.matrix.olm.OlmException
|
||||
import org.matrix.rustcomponents.sdk.crypto.Request
|
||||
import org.matrix.rustcomponents.sdk.crypto.RequestType
|
||||
import org.matrix.rustcomponents.sdk.crypto.SignatureVerification
|
||||
|
@ -840,8 +839,8 @@ internal class RustKeyBackupService @Inject constructor(
|
|||
try {
|
||||
olmMachine.enableBackupV1(retrievedMegolmBackupAuthData.publicKey, keysVersionResult.version)
|
||||
keysBackupVersion = keysVersionResult
|
||||
} catch (e: OlmException) {
|
||||
Timber.e(e, "OlmException")
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Exception")
|
||||
keysBackupStateManager.state = KeysBackupState.Disabled
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* Copyright 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.model
|
||||
|
||||
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.internal.crypto.MegolmSessionData
|
||||
import org.matrix.olm.OlmInboundGroupSession
|
||||
import timber.log.Timber
|
||||
|
||||
data class MXInboundMegolmSessionWrapper(
|
||||
// olm object
|
||||
val session: OlmInboundGroupSession,
|
||||
// data about the session
|
||||
val sessionData: InboundGroupSessionData
|
||||
) {
|
||||
// shortcut
|
||||
val roomId = sessionData.roomId
|
||||
val senderKey = sessionData.senderKey
|
||||
val safeSessionId = tryOrNull("Fail to get megolm session Id") { session.sessionIdentifier() }
|
||||
|
||||
/**
|
||||
* Export the inbound group session keys.
|
||||
* @param index the index to export. If null, the first known index will be used
|
||||
* @return the inbound group session as MegolmSessionData if the operation succeeds
|
||||
*/
|
||||
internal fun exportKeys(index: Long? = null): MegolmSessionData? {
|
||||
return try {
|
||||
val keysClaimed = sessionData.keysClaimed ?: return null
|
||||
val wantedIndex = index ?: session.firstKnownIndex
|
||||
|
||||
MegolmSessionData(
|
||||
senderClaimedEd25519Key = sessionData.keysClaimed?.get("ed25519"),
|
||||
forwardingCurve25519KeyChain = sessionData.forwardingCurve25519KeyChain?.toList().orEmpty(),
|
||||
sessionKey = session.export(wantedIndex),
|
||||
senderClaimedKeys = keysClaimed,
|
||||
roomId = sessionData.roomId,
|
||||
sessionId = session.sessionIdentifier(),
|
||||
senderKey = senderKey,
|
||||
algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
|
||||
sharedHistory = sessionData.sharedHistory
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## Failed to export megolm : sessionID ${tryOrNull { session.sessionIdentifier() }} failed")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* @exportFormat true if the megolm keys are in export format
|
||||
* (ie, they lack an ed25519 signature)
|
||||
*/
|
||||
@Throws
|
||||
internal fun newFromMegolmData(megolmSessionData: MegolmSessionData, exportFormat: Boolean): MXInboundMegolmSessionWrapper {
|
||||
val exportedKey = megolmSessionData.sessionKey ?: throw IllegalArgumentException("key data not found")
|
||||
val inboundSession = if (exportFormat) {
|
||||
OlmInboundGroupSession.importSession(exportedKey)
|
||||
} else {
|
||||
OlmInboundGroupSession(exportedKey)
|
||||
}
|
||||
.also {
|
||||
if (it.sessionIdentifier() != megolmSessionData.sessionId) {
|
||||
it.releaseSession()
|
||||
throw IllegalStateException("Mismatched group session Id")
|
||||
}
|
||||
}
|
||||
val data = InboundGroupSessionData(
|
||||
roomId = megolmSessionData.roomId,
|
||||
senderKey = megolmSessionData.senderKey,
|
||||
keysClaimed = megolmSessionData.senderClaimedKeys,
|
||||
forwardingCurve25519KeyChain = megolmSessionData.forwardingCurve25519KeyChain,
|
||||
sharedHistory = megolmSessionData.sharedHistory,
|
||||
trusted = false
|
||||
)
|
||||
|
||||
return MXInboundMegolmSessionWrapper(
|
||||
inboundSession,
|
||||
data
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.model
|
||||
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import timber.log.Timber
|
||||
|
||||
internal data class MXKey(
|
||||
/**
|
||||
* The type of the key (in the example: "signed_curve25519").
|
||||
*/
|
||||
val type: String,
|
||||
|
||||
/**
|
||||
* The id of the key (in the example: "AAAAFw").
|
||||
*/
|
||||
private val keyId: String,
|
||||
|
||||
/**
|
||||
* The key (in the example: "IjwIcskng7YjYcn0tS8TUOT2OHHtBSfMpcfIczCgXj4").
|
||||
*/
|
||||
val value: String,
|
||||
|
||||
/**
|
||||
* signature user Id to [deviceid][signature].
|
||||
*/
|
||||
private val signatures: Map<String, Map<String, String>>,
|
||||
|
||||
/**
|
||||
* We have to store the original json because it can contain other fields
|
||||
* that we don't support yet but they would be needed to check signatures.
|
||||
*/
|
||||
private val rawMap: JsonDict
|
||||
) {
|
||||
|
||||
/**
|
||||
* @return the signed data map
|
||||
*/
|
||||
fun signalableJSONDictionary(): Map<String, Any> {
|
||||
return rawMap.filter {
|
||||
it.key != "signatures" && it.key != "unsigned"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a signature for an user Id and a signkey.
|
||||
*
|
||||
* @param userId the user id
|
||||
* @param signkey the sign key
|
||||
* @return the signature
|
||||
*/
|
||||
fun signatureForUserId(userId: String, signkey: String): String? {
|
||||
// sanity checks
|
||||
if (userId.isNotBlank() && signkey.isNotBlank()) {
|
||||
return signatures[userId]?.get(signkey)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Key types.
|
||||
*/
|
||||
const val KEY_CURVE_25519_TYPE = "curve25519"
|
||||
const val KEY_SIGNED_CURVE_25519_TYPE = "signed_curve25519"
|
||||
// const val KEY_ED_25519_TYPE = "ed25519"
|
||||
|
||||
/**
|
||||
* Convert a map to a MXKey.
|
||||
*
|
||||
* @param map the map to convert
|
||||
*
|
||||
* Json Example:
|
||||
*
|
||||
* <pre>
|
||||
* "signed_curve25519:AAAAFw": {
|
||||
* "key": "IjwIcskng7YjYcn0tS8TUOT2OHHtBSfMpcfIczCgXj4",
|
||||
* "fallback" : true|false
|
||||
* "signatures": {
|
||||
* "@userId:matrix.org": {
|
||||
* "ed25519:GMJRREOASV": "EUjp6pXzK9u3SDFR\/qLbzpOi3bEREeI6qMnKzXu992HsfuDDZftfJfiUXv9b\/Hqq1og4qM\/vCQJGTHAWMmgkCg"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* into several val members
|
||||
*/
|
||||
fun from(map: Map<String, JsonDict>?): MXKey? {
|
||||
if (map?.isNotEmpty() == true) {
|
||||
val firstKey = map.keys.first()
|
||||
|
||||
val components = firstKey.split(":").dropLastWhile { it.isEmpty() }
|
||||
|
||||
if (components.size == 2) {
|
||||
val params = map[firstKey]
|
||||
if (params != null) {
|
||||
if (params["key"] is String) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return MXKey(
|
||||
type = components[0],
|
||||
keyId = components[1],
|
||||
value = params["key"] as String,
|
||||
signatures = params["signatures"] as Map<String, Map<String, String>>,
|
||||
rawMap = params
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error case
|
||||
Timber.e("## Unable to parse map")
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.model
|
||||
|
||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||
import java.io.Serializable
|
||||
|
||||
internal data class MXOlmSessionResult(
|
||||
/**
|
||||
* the device.
|
||||
*/
|
||||
val deviceInfo: CryptoDeviceInfo,
|
||||
/**
|
||||
* Base64 olm session id.
|
||||
* null if no session could be established.
|
||||
*/
|
||||
var sessionId: String?
|
||||
) : Serializable
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.model
|
||||
|
||||
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
|
||||
|
||||
internal fun <T> MXUsersDevicesMap<T>.toDebugString() =
|
||||
map.entries.joinToString { "${it.key} [${it.value.keys.joinToString { it }}]" }
|
||||
|
||||
internal fun <T> MXUsersDevicesMap<T>.toDebugCount() =
|
||||
map.entries.fold(0) { acc, new ->
|
||||
acc + new.value.keys.size
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.model
|
||||
|
||||
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.MegolmSessionData
|
||||
import org.matrix.olm.OlmInboundGroupSession
|
||||
import timber.log.Timber
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* This class adds more context to a OlmInboundGroupSession object.
|
||||
* This allows additional checks. The class implements Serializable so that the context can be stored.
|
||||
*/
|
||||
internal class OlmInboundGroupSessionWrapper : Serializable {
|
||||
|
||||
// The associated olm inbound group session.
|
||||
var olmInboundGroupSession: OlmInboundGroupSession? = null
|
||||
|
||||
// The room in which this session is used.
|
||||
var roomId: String? = null
|
||||
|
||||
// The base64-encoded curve25519 key of the sender.
|
||||
var senderKey: String? = null
|
||||
|
||||
// Other keys the sender claims.
|
||||
var keysClaimed: Map<String, String>? = null
|
||||
|
||||
// Devices which forwarded this session to us (normally empty).
|
||||
var forwardingCurve25519KeyChain: List<String>? = ArrayList()
|
||||
|
||||
/**
|
||||
* @return the first known message index
|
||||
*/
|
||||
val firstKnownIndex: Long?
|
||||
get() {
|
||||
if (null != olmInboundGroupSession) {
|
||||
try {
|
||||
return olmInboundGroupSession!!.firstKnownIndex
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed")
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param sessionKey the session key
|
||||
* @param isImported true if it is an imported session key
|
||||
*/
|
||||
constructor(sessionKey: String, isImported: Boolean) {
|
||||
try {
|
||||
if (!isImported) {
|
||||
olmInboundGroupSession = OlmInboundGroupSession(sessionKey)
|
||||
} else {
|
||||
olmInboundGroupSession = OlmInboundGroupSession.importSession(sessionKey)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Cannot create")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance from the provided keys map.
|
||||
*
|
||||
* @param megolmSessionData the megolm session data
|
||||
* @throws Exception if the data are invalid
|
||||
*/
|
||||
@Throws(Exception::class)
|
||||
constructor(megolmSessionData: MegolmSessionData) {
|
||||
try {
|
||||
olmInboundGroupSession = OlmInboundGroupSession.importSession(megolmSessionData.sessionKey!!)
|
||||
|
||||
if (olmInboundGroupSession!!.sessionIdentifier() != megolmSessionData.sessionId) {
|
||||
throw Exception("Mismatched group session Id")
|
||||
}
|
||||
|
||||
senderKey = megolmSessionData.senderKey
|
||||
keysClaimed = megolmSessionData.senderClaimedKeys
|
||||
roomId = megolmSessionData.roomId
|
||||
} catch (e: Exception) {
|
||||
throw Exception(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the inbound group session keys.
|
||||
*
|
||||
* @return the inbound group session as MegolmSessionData if the operation succeeds
|
||||
*/
|
||||
fun exportKeys(): MegolmSessionData? {
|
||||
return try {
|
||||
if (null == forwardingCurve25519KeyChain) {
|
||||
forwardingCurve25519KeyChain = ArrayList()
|
||||
}
|
||||
|
||||
if (keysClaimed == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
MegolmSessionData(
|
||||
senderClaimedEd25519Key = keysClaimed?.get("ed25519"),
|
||||
forwardingCurve25519KeyChain = ArrayList(forwardingCurve25519KeyChain!!),
|
||||
senderKey = senderKey,
|
||||
senderClaimedKeys = keysClaimed,
|
||||
roomId = roomId,
|
||||
sessionId = olmInboundGroupSession!!.sessionIdentifier(),
|
||||
sessionKey = olmInboundGroupSession!!.export(olmInboundGroupSession!!.firstKnownIndex),
|
||||
algorithm = MXCRYPTO_ALGORITHM_MEGOLM
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## export() : senderKey $senderKey failed")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the session for a message index.
|
||||
*
|
||||
* @param messageIndex the message index
|
||||
* @return the exported data
|
||||
*/
|
||||
fun exportSession(messageIndex: Long): String? {
|
||||
if (null != olmInboundGroupSession) {
|
||||
try {
|
||||
return olmInboundGroupSession!!.export(messageIndex)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## exportSession() : export failed")
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -1,158 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.model
|
||||
|
||||
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.MegolmSessionData
|
||||
import org.matrix.olm.OlmInboundGroupSession
|
||||
import timber.log.Timber
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* This class adds more context to a OlmInboundGroupSession object.
|
||||
* This allows additional checks. The class implements Serializable so that the context can be stored.
|
||||
*/
|
||||
// Note used anymore, just for database migration
|
||||
// Deprecated("Use MXInboundMegolmSessionWrapper")
|
||||
internal class OlmInboundGroupSessionWrapper2 : Serializable {
|
||||
|
||||
// The associated olm inbound group session.
|
||||
var olmInboundGroupSession: OlmInboundGroupSession? = null
|
||||
|
||||
// The room in which this session is used.
|
||||
var roomId: String? = null
|
||||
|
||||
// The base64-encoded curve25519 key of the sender.
|
||||
var senderKey: String? = null
|
||||
|
||||
// Other keys the sender claims.
|
||||
var keysClaimed: Map<String, String>? = null
|
||||
|
||||
// Devices which forwarded this session to us (normally empty).
|
||||
var forwardingCurve25519KeyChain: List<String>? = ArrayList()
|
||||
|
||||
/**
|
||||
* @return the first known message index
|
||||
*/
|
||||
val firstKnownIndex: Long?
|
||||
get() {
|
||||
return try {
|
||||
olmInboundGroupSession?.firstKnownIndex
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param sessionKey the session key
|
||||
* @param isImported true if it is an imported session key
|
||||
*/
|
||||
constructor(sessionKey: String, isImported: Boolean) {
|
||||
try {
|
||||
if (!isImported) {
|
||||
olmInboundGroupSession = OlmInboundGroupSession(sessionKey)
|
||||
} else {
|
||||
olmInboundGroupSession = OlmInboundGroupSession.importSession(sessionKey)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Cannot create")
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance from the provided keys map.
|
||||
*
|
||||
* @param megolmSessionData the megolm session data
|
||||
* @throws Exception if the data are invalid
|
||||
*/
|
||||
@Throws(Exception::class)
|
||||
constructor(megolmSessionData: MegolmSessionData) {
|
||||
try {
|
||||
val safeSessionKey = megolmSessionData.sessionKey ?: throw Exception("invalid data")
|
||||
olmInboundGroupSession = OlmInboundGroupSession.importSession(safeSessionKey)
|
||||
.also {
|
||||
if (it.sessionIdentifier() != megolmSessionData.sessionId) {
|
||||
throw Exception("Mismatched group session Id")
|
||||
}
|
||||
}
|
||||
|
||||
senderKey = megolmSessionData.senderKey
|
||||
keysClaimed = megolmSessionData.senderClaimedKeys
|
||||
roomId = megolmSessionData.roomId
|
||||
} catch (e: Exception) {
|
||||
throw Exception(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the inbound group session keys.
|
||||
* @param index the index to export. If null, the first known index will be used
|
||||
*
|
||||
* @return the inbound group session as MegolmSessionData if the operation succeeds
|
||||
*/
|
||||
fun exportKeys(index: Long? = null): MegolmSessionData? {
|
||||
return try {
|
||||
if (null == forwardingCurve25519KeyChain) {
|
||||
forwardingCurve25519KeyChain = ArrayList()
|
||||
}
|
||||
|
||||
if (keysClaimed == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val safeOlmInboundGroupSession = olmInboundGroupSession ?: return null
|
||||
|
||||
val wantedIndex = index ?: safeOlmInboundGroupSession.firstKnownIndex
|
||||
|
||||
MegolmSessionData(
|
||||
senderClaimedEd25519Key = keysClaimed?.get("ed25519"),
|
||||
forwardingCurve25519KeyChain = forwardingCurve25519KeyChain?.toList().orEmpty(),
|
||||
senderKey = senderKey,
|
||||
senderClaimedKeys = keysClaimed,
|
||||
roomId = roomId,
|
||||
sessionId = safeOlmInboundGroupSession.sessionIdentifier(),
|
||||
sessionKey = safeOlmInboundGroupSession.export(wantedIndex),
|
||||
algorithm = MXCRYPTO_ALGORITHM_MEGOLM
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## export() : senderKey $senderKey failed")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the session for a message index.
|
||||
*
|
||||
* @param messageIndex the message index
|
||||
* @return the exported data
|
||||
*/
|
||||
fun exportSession(messageIndex: Long): String? {
|
||||
return try {
|
||||
return olmInboundGroupSession?.export(messageIndex)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## exportSession() : export failed")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.model
|
||||
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import org.matrix.olm.OlmSession
|
||||
|
||||
/**
|
||||
* Encapsulate a OlmSession and a last received message Timestamp.
|
||||
*/
|
||||
internal data class OlmSessionWrapper(
|
||||
// The associated olm session.
|
||||
val olmSession: OlmSession,
|
||||
// Timestamp at which the session last received a message.
|
||||
var lastReceivedMessageTs: Long = 0,
|
||||
|
||||
val mutex: Mutex = Mutex()
|
||||
) {
|
||||
|
||||
/**
|
||||
* Notify that a message has been received on this olm session so that it updates `lastReceivedMessageTs`.
|
||||
*/
|
||||
fun onMessageReceived(currentTimeMillis: Long) {
|
||||
lastReceivedMessageTs = currentTimeMillis
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.model
|
||||
|
||||
import org.matrix.olm.OlmOutboundGroupSession
|
||||
|
||||
internal data class OutboundGroupSessionWrapper(
|
||||
val outboundGroupSession: OlmOutboundGroupSession,
|
||||
val creationTime: Long,
|
||||
/**
|
||||
* As per MSC 3061, declares if this key could be shared when inviting a new user to the room.
|
||||
*/
|
||||
val sharedHistory: Boolean = false
|
||||
)
|
|
@ -44,9 +44,7 @@ import org.matrix.android.sdk.api.util.toBase64NoPadding
|
|||
import org.matrix.android.sdk.internal.crypto.SecretShareManager
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.generatePrivateKeyWithPassword
|
||||
import org.matrix.android.sdk.internal.crypto.tools.HkdfSha256
|
||||
import org.matrix.android.sdk.internal.crypto.tools.withOlmDecryption
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.olm.OlmPkMessage
|
||||
import java.security.SecureRandom
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.Mac
|
||||
|
@ -322,9 +320,13 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
|
|||
|
||||
val algorithm = key.keyInfo.content
|
||||
if (SSSS_ALGORITHM_CURVE25519_AES_SHA2 == algorithm.algorithm) {
|
||||
val keySpec = secretKey as? RawBytesKeySpec ?: throw SharedSecretStorageError.BadKeyFormat
|
||||
// TODO BMA
|
||||
// val keySpec = secretKey as? RawBytesKeySpec ?: throw SharedSecretStorageError.BadKeyFormat
|
||||
return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
|
||||
// decrypt from recovery key
|
||||
"TODO"
|
||||
// TODO BMA
|
||||
/*
|
||||
withOlmDecryption { olmPkDecryption ->
|
||||
olmPkDecryption.setPrivateKey(keySpec.privateKey)
|
||||
olmPkDecryption.decrypt(OlmPkMessage()
|
||||
|
@ -335,6 +337,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
|
|||
}
|
||||
)
|
||||
}
|
||||
*/
|
||||
}
|
||||
} else if (SSSS_ALGORITHM_AES_HMAC_SHA2 == algorithm.algorithm) {
|
||||
val keySpec = secretKey as? RawBytesKeySpec ?: throw SharedSecretStorageError.BadKeyFormat
|
||||
|
|
|
@ -23,7 +23,6 @@ import org.matrix.android.sdk.api.session.crypto.model.CryptoRoomInfo
|
|||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
|
||||
|
||||
/**
|
||||
|
@ -143,14 +142,4 @@ interface IMXCommonCryptoStore {
|
|||
* @return the device or null if not found
|
||||
*/
|
||||
fun deviceWithIdentityKey(userId: String, identityKey: String): CryptoDeviceInfo?
|
||||
|
||||
/**
|
||||
* Retrieve an inbound group session.
|
||||
* Used in rust for lazy migration
|
||||
*
|
||||
* @param sessionId the session identifier.
|
||||
* @param senderKey the base64-encoded curve25519 key of the sender.
|
||||
* @return an inbound group session.
|
||||
*/
|
||||
fun getInboundGroupSession(sessionId: String, senderKey: String): MXInboundMegolmSessionWrapper?
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventCo
|
|||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.api.util.toOptional
|
||||
import org.matrix.android.sdk.internal.crypto.OlmMachine
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.doRealmTransaction
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.doRealmTransactionAsync
|
||||
|
@ -49,11 +48,8 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity
|
|||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.createPrimaryKey
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.query.getById
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.query.getOrCreate
|
||||
import org.matrix.android.sdk.internal.di.CryptoDatabase
|
||||
|
@ -70,7 +66,7 @@ private val loggerTag = LoggerTag("RealmCryptoStore", LoggerTag.CRYPTO)
|
|||
|
||||
/**
|
||||
* In the transition phase, the rust SDK is still using parts to the realm crypto store,
|
||||
* this should be removed after full migration.
|
||||
* this should be removed after full migration. TODO BMA
|
||||
*/
|
||||
@SessionScope
|
||||
internal class RustCryptoStore @Inject constructor(
|
||||
|
@ -86,6 +82,7 @@ internal class RustCryptoStore @Inject constructor(
|
|||
// still needed on rust due to the global crypto settings
|
||||
init {
|
||||
// Ensure CryptoMetadataEntity is inserted in DB
|
||||
// TODO BMA
|
||||
doRealmTransaction("init", realmConfiguration) { realm ->
|
||||
var currentMetadata = realm.where<CryptoMetadataEntity>().findFirst()
|
||||
|
||||
|
@ -134,20 +131,6 @@ internal class RustCryptoStore @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Needed for lazy migration of sessions from the legacy store.
|
||||
*/
|
||||
override fun getInboundGroupSession(sessionId: String, senderKey: String): MXInboundMegolmSessionWrapper? {
|
||||
val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionId, senderKey)
|
||||
|
||||
return doWithRealm(realmConfiguration) { realm ->
|
||||
realm.where<OlmInboundGroupSessionEntity>()
|
||||
.equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
|
||||
.findFirst()
|
||||
?.toModel()
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================
|
||||
// Things that should be migrated to another store than realm
|
||||
// ================================================
|
||||
|
|
|
@ -17,31 +17,7 @@
|
|||
package org.matrix.android.sdk.internal.crypto.store.db
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo001Legacy
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo002Legacy
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo003RiotX
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo004
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo005
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo006
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo007
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo008
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo009
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo010
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo011
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo012
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo013
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo014
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo015
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo016
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo017
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo018
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo019
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo020
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo021
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo022
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo023
|
||||
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
@ -51,11 +27,9 @@ import javax.inject.Inject
|
|||
* 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6).
|
||||
*/
|
||||
internal class RealmCryptoStoreMigration @Inject constructor(
|
||||
private val clock: Clock,
|
||||
private val rustMigrationInfoProvider: RustMigrationInfoProvider,
|
||||
) : MatrixRealmMigration(
|
||||
dbName = "Crypto",
|
||||
schemaVersion = 23L,
|
||||
schemaVersion = 24L,
|
||||
) {
|
||||
/**
|
||||
* Forces all RealmCryptoStoreMigration instances to be equal.
|
||||
|
@ -65,33 +39,8 @@ internal class RealmCryptoStoreMigration @Inject constructor(
|
|||
override fun hashCode() = 5000
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm, oldVersion: Long) {
|
||||
if (oldVersion < 1) MigrateCryptoTo001Legacy(realm).perform()
|
||||
if (oldVersion < 2) MigrateCryptoTo002Legacy(realm).perform()
|
||||
if (oldVersion < 3) MigrateCryptoTo003RiotX(realm).perform()
|
||||
if (oldVersion < 4) MigrateCryptoTo004(realm).perform()
|
||||
if (oldVersion < 5) MigrateCryptoTo005(realm).perform()
|
||||
if (oldVersion < 6) MigrateCryptoTo006(realm).perform()
|
||||
if (oldVersion < 7) MigrateCryptoTo007(realm).perform()
|
||||
if (oldVersion < 8) MigrateCryptoTo008(realm, clock).perform()
|
||||
if (oldVersion < 9) MigrateCryptoTo009(realm).perform()
|
||||
if (oldVersion < 10) MigrateCryptoTo010(realm).perform()
|
||||
if (oldVersion < 11) MigrateCryptoTo011(realm).perform()
|
||||
if (oldVersion < 12) MigrateCryptoTo012(realm).perform()
|
||||
if (oldVersion < 13) MigrateCryptoTo013(realm).perform()
|
||||
if (oldVersion < 14) MigrateCryptoTo014(realm).perform()
|
||||
if (oldVersion < 15) MigrateCryptoTo015(realm).perform()
|
||||
if (oldVersion < 16) MigrateCryptoTo016(realm).perform()
|
||||
if (oldVersion < 17) MigrateCryptoTo017(realm).perform()
|
||||
if (oldVersion < 18) MigrateCryptoTo018(realm).perform()
|
||||
if (oldVersion < 19) MigrateCryptoTo019(realm).perform()
|
||||
if (oldVersion < 20) MigrateCryptoTo020(realm).perform()
|
||||
if (oldVersion < 21) MigrateCryptoTo021(realm).perform()
|
||||
if (oldVersion < 22) MigrateCryptoTo022(
|
||||
realm,
|
||||
rustMigrationInfoProvider.rustDirectory,
|
||||
rustMigrationInfoProvider.rustEncryptionConfiguration,
|
||||
rustMigrationInfoProvider.migrateMegolmGroupSessions
|
||||
).perform()
|
||||
if (oldVersion < 23) MigrateCryptoTo023(realm).perform()
|
||||
// Delete the whole DB
|
||||
// TODO BMA
|
||||
realm.deleteAll()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023 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
|
||||
|
||||
import org.matrix.android.sdk.internal.crypto.RustEncryptionConfiguration
|
||||
import org.matrix.android.sdk.internal.di.SessionRustFilesDirectory
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class RustMigrationInfoProvider @Inject constructor(
|
||||
@SessionRustFilesDirectory
|
||||
val rustDirectory: File,
|
||||
val rustEncryptionConfiguration: RustEncryptionConfiguration
|
||||
) {
|
||||
|
||||
var migrateMegolmGroupSessions: Boolean = false
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.mapper
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import io.realm.RealmList
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntity
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class CrossSigningKeysMapper @Inject constructor(moshi: Moshi) {
|
||||
|
||||
private val signaturesAdapter = moshi.adapter<Map<String, Map<String, String>>>(
|
||||
Types.newParameterizedType(
|
||||
Map::class.java,
|
||||
String::class.java,
|
||||
Any::class.java
|
||||
)
|
||||
)
|
||||
|
||||
fun update(keyInfo: KeyInfoEntity, cryptoCrossSigningKey: CryptoCrossSigningKey) {
|
||||
// update signatures?
|
||||
keyInfo.signatures = serializeSignatures(cryptoCrossSigningKey.signatures)
|
||||
keyInfo.usages = cryptoCrossSigningKey.usages?.toTypedArray()?.let { RealmList(*it) }
|
||||
?: RealmList()
|
||||
}
|
||||
|
||||
fun map(userId: String?, keyInfo: KeyInfoEntity?): CryptoCrossSigningKey? {
|
||||
val pubKey = keyInfo?.publicKeyBase64 ?: return null
|
||||
return CryptoCrossSigningKey(
|
||||
userId = userId ?: "",
|
||||
keys = mapOf("ed25519:$pubKey" to pubKey),
|
||||
usages = keyInfo.usages.toList(),
|
||||
signatures = deserializeSignatures(keyInfo.signatures),
|
||||
trustLevel = keyInfo.trustLevelEntity?.let {
|
||||
DeviceTrustLevel(
|
||||
crossSigningVerified = it.crossSignedVerified ?: false,
|
||||
locallyVerified = it.locallyVerified ?: false
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun map(keyInfo: CryptoCrossSigningKey): KeyInfoEntity {
|
||||
return KeyInfoEntity().apply {
|
||||
publicKeyBase64 = keyInfo.unpaddedBase64PublicKey
|
||||
usages = keyInfo.usages?.let { RealmList(*it.toTypedArray()) } ?: RealmList()
|
||||
signatures = serializeSignatures(keyInfo.signatures)
|
||||
// TODO how to handle better, check if same keys?
|
||||
// reset trust
|
||||
trustLevelEntity = null
|
||||
}
|
||||
}
|
||||
|
||||
fun serializeSignatures(signatures: Map<String, Map<String, String>>?): String {
|
||||
return signaturesAdapter.toJson(signatures)
|
||||
}
|
||||
|
||||
fun deserializeSignatures(signatures: String?): Map<String, Map<String, String>>? {
|
||||
if (signatures == null) {
|
||||
return null
|
||||
}
|
||||
return try {
|
||||
signaturesAdapter.fromJson(signatures)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
internal 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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
internal 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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
internal 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.api.session.crypto.model.MXDeviceInfo(
|
||||
deviceId = legacyMxDeviceInfo.deviceId,
|
||||
userId = legacyMxDeviceInfo.userId,
|
||||
algorithms = legacyMxDeviceInfo.algorithms,
|
||||
keys = legacyMxDeviceInfo.keys,
|
||||
signatures = legacyMxDeviceInfo.signatures,
|
||||
unsigned = legacyMxDeviceInfo.unsigned,
|
||||
verified = legacyMxDeviceInfo.mVerified
|
||||
)
|
||||
|
||||
obj.setString("deviceInfoData", serializeForRealm(newMxDeviceInfo))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error")
|
||||
}
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* 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.session.crypto.model.MXDeviceInfo
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
|
||||
import org.matrix.android.sdk.internal.di.SerializeNulls
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
// Version 4L added Cross Signing info persistence
|
||||
internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) {
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
internal 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("type", String::class.java)
|
||||
.addIndex("type")
|
||||
.addField("content", String::class.java)
|
||||
.addField("sender", String::class.java)
|
||||
.addIndex("sender")
|
||||
.addField("decryptionResultJson", String::class.java)
|
||||
.addField("decryptionErrorCode", String::class.java)
|
||||
.addField("ageLocalTs", Long::class.java)
|
||||
.setNullable("ageLocalTs", true)
|
||||
.addField("sendStateStr", String::class.java)
|
||||
|
||||
realm.schema.create("IncomingGossipingRequestEntity")
|
||||
.addField("requestId", String::class.java)
|
||||
.addIndex("requestId")
|
||||
.addField("typeStr", String::class.java)
|
||||
.addIndex("typeStr")
|
||||
.addField("otherUserId", String::class.java)
|
||||
.addField("requestedInfoStr", String::class.java)
|
||||
.addField("otherDeviceId", String::class.java)
|
||||
.addField("requestStateStr", String::class.java)
|
||||
.addField("localCreationTimestamp", Long::class.java)
|
||||
.setNullable("localCreationTimestamp", true)
|
||||
|
||||
realm.schema.create("OutgoingGossipingRequestEntity")
|
||||
.addField("requestId", String::class.java)
|
||||
.addIndex("requestId")
|
||||
.addField("recipientsData", String::class.java)
|
||||
.addField("requestedInfoStr", String::class.java)
|
||||
.addField("typeStr", String::class.java)
|
||||
.addIndex("typeStr")
|
||||
.addField("requestStateStr", String::class.java)
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
internal 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)
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
internal 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 (ignore: 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
|
||||
internal class MigrateCryptoTo008(
|
||||
realm: DynamicRealm,
|
||||
private val clock: Clock,
|
||||
) : RealmMigrator(realm, 8) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.create("MyDeviceLastSeenInfoEntity")
|
||||
.addField(MyDeviceLastSeenInfoEntityFields.DEVICE_ID, String::class.java)
|
||||
.addPrimaryKey(MyDeviceLastSeenInfoEntityFields.DEVICE_ID)
|
||||
.addField(MyDeviceLastSeenInfoEntityFields.DISPLAY_NAME, String::class.java)
|
||||
.addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_IP, String::class.java)
|
||||
.addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_TS, Long::class.java)
|
||||
.setNullable(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_TS, true)
|
||||
|
||||
val now = clock.epochMillis()
|
||||
realm.schema.get("DeviceInfoEntity")
|
||||
?.addField(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, Long::class.java)
|
||||
?.setNullable(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, true)
|
||||
?.transform { deviceInfoEntity ->
|
||||
tryOrNull {
|
||||
deviceInfoEntity.setLong(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, now)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
internal 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* 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)
|
||||
internal 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)
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
internal 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)
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
internal 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)
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
internal 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...")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
internal 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))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
// Version 15L adds wasEncryptedOnce field to CryptoRoomEntity
|
||||
internal class MigrateCryptoTo015(realm: DynamicRealm) : RealmMigrator(realm, 15) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("CryptoRoomEntity")
|
||||
?.addField(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, Boolean::class.java)
|
||||
?.setNullable(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, true)
|
||||
?.transform {
|
||||
val currentAlgorithm = it.getString(CryptoRoomEntityFields.ALGORITHM)
|
||||
it.set(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, currentAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* 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.AuditTrailEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyRequestReplyEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
internal class MigrateCryptoTo016(realm: DynamicRealm) : RealmMigrator(realm, 16) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.remove("OutgoingGossipingRequestEntity")
|
||||
realm.schema.remove("IncomingGossipingRequestEntity")
|
||||
realm.schema.remove("GossipingEventEntity")
|
||||
|
||||
// No need to migrate existing request, just start fresh
|
||||
|
||||
val replySchema = realm.schema.create("KeyRequestReplyEntity")
|
||||
.addField(KeyRequestReplyEntityFields.SENDER_ID, String::class.java)
|
||||
.addField(KeyRequestReplyEntityFields.FROM_DEVICE, String::class.java)
|
||||
.addField(KeyRequestReplyEntityFields.EVENT_JSON, String::class.java)
|
||||
|
||||
realm.schema.create("OutgoingKeyRequestEntity")
|
||||
.addField(OutgoingKeyRequestEntityFields.REQUEST_ID, String::class.java)
|
||||
.addIndex(OutgoingKeyRequestEntityFields.REQUEST_ID)
|
||||
.addField(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, String::class.java)
|
||||
.addIndex(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID)
|
||||
.addRealmListField(OutgoingKeyRequestEntityFields.REPLIES.`$`, replySchema)
|
||||
.addField(OutgoingKeyRequestEntityFields.RECIPIENTS_DATA, String::class.java)
|
||||
.addField(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, String::class.java)
|
||||
.addIndex(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR)
|
||||
.addField(OutgoingKeyRequestEntityFields.REQUESTED_INFO_STR, String::class.java)
|
||||
.addField(OutgoingKeyRequestEntityFields.ROOM_ID, String::class.java)
|
||||
.addIndex(OutgoingKeyRequestEntityFields.ROOM_ID)
|
||||
.addField(OutgoingKeyRequestEntityFields.REQUESTED_INDEX, Integer::class.java)
|
||||
.addField(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, Long::class.java)
|
||||
.setNullable(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, true)
|
||||
|
||||
realm.schema.create("AuditTrailEntity")
|
||||
.addField(AuditTrailEntityFields.AGE_LOCAL_TS, Long::class.java)
|
||||
.setNullable(AuditTrailEntityFields.AGE_LOCAL_TS, true)
|
||||
.addField(AuditTrailEntityFields.CONTENT_JSON, String::class.java)
|
||||
.addField(AuditTrailEntityFields.TYPE, String::class.java)
|
||||
.addIndex(AuditTrailEntityFields.TYPE)
|
||||
|
||||
realm.schema.get("CryptoMetadataEntity")
|
||||
?.addField(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, Boolean::class.java)
|
||||
?.transform {
|
||||
// set the default value to true
|
||||
it.setBoolean(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, true)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* 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.model.InboundGroupSessionData
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Version 17L enhance OlmInboundGroupSessionEntity to support shared history for MSC3061.
|
||||
* Also migrates how megolm session are stored to avoid additional serialized frozen class.
|
||||
*/
|
||||
internal class MigrateCryptoTo017(realm: DynamicRealm) : RealmMigrator(realm, 17) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("CryptoRoomEntity")
|
||||
?.addField(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform {
|
||||
// We don't have access to the session database to check for the state here and set the good value.
|
||||
// But for now as it's behind a lab flag, will set to false and force initial sync when enabled
|
||||
it.setBoolean(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, false)
|
||||
}
|
||||
|
||||
realm.schema.get("OutboundGroupSessionInfoEntity")
|
||||
?.addField(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform {
|
||||
// We don't have access to the session database to check for the state here and set the good value.
|
||||
// But for now as it's behind a lab flag, will set to false and force initial sync when enabled
|
||||
it.setBoolean(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, false)
|
||||
}
|
||||
|
||||
realm.schema.get("CryptoMetadataEntity")
|
||||
?.addField(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, Boolean::class.java)
|
||||
?.transform { obj ->
|
||||
// default to false
|
||||
obj.setBoolean(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, false)
|
||||
}
|
||||
|
||||
val moshiAdapter = MoshiProvider.providesMoshi().adapter(InboundGroupSessionData::class.java)
|
||||
|
||||
realm.schema.get("OlmInboundGroupSessionEntity")
|
||||
?.addField(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, Boolean::class.java)
|
||||
?.addField(OlmInboundGroupSessionEntityFields.ROOM_ID, String::class.java)
|
||||
?.addField(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, String::class.java)
|
||||
?.addField(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, String::class.java)
|
||||
?.transform { dynamicObject ->
|
||||
try {
|
||||
// we want to convert the old wrapper frozen class into a
|
||||
// map of sessionData & the pickled session herself
|
||||
dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { oldData ->
|
||||
val oldWrapper = tryOrNull("Failed to convert megolm inbound group data") {
|
||||
@Suppress("DEPRECATION")
|
||||
deserializeFromRealm<org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2?>(oldData)
|
||||
}
|
||||
val groupSession = oldWrapper?.olmInboundGroupSession
|
||||
?: return@transform Unit.also {
|
||||
Timber.w("Failed to migrate megolm session, no olmInboundGroupSession")
|
||||
}
|
||||
// now convert to new data
|
||||
val data = InboundGroupSessionData(
|
||||
senderKey = oldWrapper.senderKey,
|
||||
roomId = oldWrapper.roomId,
|
||||
keysClaimed = oldWrapper.keysClaimed,
|
||||
forwardingCurve25519KeyChain = oldWrapper.forwardingCurve25519KeyChain,
|
||||
sharedHistory = false,
|
||||
)
|
||||
|
||||
dynamicObject.setString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, moshiAdapter.toJson(data))
|
||||
dynamicObject.setString(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, serializeForRealm(groupSession))
|
||||
|
||||
// denormalized fields
|
||||
dynamicObject.setString(OlmInboundGroupSessionEntityFields.ROOM_ID, oldWrapper.roomId)
|
||||
dynamicObject.setBoolean(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, false)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "Failed to migrate megolm session")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* 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.InboundGroupSessionData
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* This migration is adding support for trusted flags on megolm sessions.
|
||||
* We can't really assert the trust of existing keys, so for the sake of simplicity we are going to
|
||||
* mark existing keys as safe.
|
||||
* This migration can take long depending on the account
|
||||
*/
|
||||
internal class MigrateCryptoTo018(realm: DynamicRealm) : RealmMigrator(realm, 18) {
|
||||
|
||||
private val moshiAdapter = MoshiProvider.providesMoshi().adapter(InboundGroupSessionData::class.java)
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("OlmInboundGroupSessionEntity")
|
||||
?.transform { dynamicObject ->
|
||||
try {
|
||||
dynamicObject.getString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON)?.let { oldData ->
|
||||
moshiAdapter.fromJson(oldData)?.let { dataToMigrate ->
|
||||
dataToMigrate.copy(trusted = true).let {
|
||||
dynamicObject.setString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, moshiAdapter.toJson(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "Failed to migrate megolm session")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* 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 io.realm.DynamicRealmObject
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.KeyUsage
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields
|
||||
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.util.database.RealmMigrator
|
||||
|
||||
/**
|
||||
* This migration is adding support for trusted flags on megolm sessions.
|
||||
* We can't really assert the trust of existing keys, so for the sake of simplicity we are going to
|
||||
* mark existing keys as safe.
|
||||
* This migration can take long depending on the account
|
||||
*/
|
||||
internal class MigrateCryptoTo019(realm: DynamicRealm) : RealmMigrator(realm, 19) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("CrossSigningInfoEntity")
|
||||
?.addField(CrossSigningInfoEntityFields.WAS_USER_VERIFIED_ONCE, Boolean::class.java)
|
||||
?.transform { dynamicObject ->
|
||||
|
||||
val knowKeys = dynamicObject.getList(CrossSigningInfoEntityFields.CROSS_SIGNING_KEYS.`$`)
|
||||
val msk = knowKeys.firstOrNull {
|
||||
it.getList(KeyInfoEntityFields.USAGES.`$`, String::class.java).orEmpty().contains(KeyUsage.MASTER.value)
|
||||
}
|
||||
val ssk = knowKeys.firstOrNull {
|
||||
it.getList(KeyInfoEntityFields.USAGES.`$`, String::class.java).orEmpty().contains(KeyUsage.SELF_SIGNING.value)
|
||||
}
|
||||
val isTrusted = isDynamicKeyInfoTrusted(msk?.get<DynamicRealmObject>(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`)) &&
|
||||
isDynamicKeyInfoTrusted(ssk?.get<DynamicRealmObject>(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`))
|
||||
|
||||
dynamicObject.setBoolean(CrossSigningInfoEntityFields.WAS_USER_VERIFIED_ONCE, isTrusted)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isDynamicKeyInfoTrusted(keyInfo: DynamicRealmObject?): Boolean {
|
||||
if (keyInfo == null) return false
|
||||
return !keyInfo.isNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED) && keyInfo.getBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED) &&
|
||||
!keyInfo.isNull(TrustLevelEntityFields.LOCALLY_VERIFIED) && keyInfo.getBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED)
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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.MyDeviceLastSeenInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
/**
|
||||
* This migration adds a new field into MyDeviceLastSeenInfoEntity corresponding to the last seen user agent.
|
||||
*/
|
||||
internal class MigrateCryptoTo020(realm: DynamicRealm) : RealmMigrator(realm, 20) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("MyDeviceLastSeenInfoEntity")
|
||||
?.addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_USER_AGENT, String::class.java)
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 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.crypto.MEGOLM_DEFAULT_ROTATION_MSGS
|
||||
import org.matrix.android.sdk.api.crypto.MEGOLM_DEFAULT_ROTATION_PERIOD_MS
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
/**
|
||||
* This migration stores the rotation parameters for megolm oubound sessions.
|
||||
*/
|
||||
internal class MigrateCryptoTo021(realm: DynamicRealm) : RealmMigrator(realm, 21) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("CryptoRoomEntity")
|
||||
?.addField(CryptoRoomEntityFields.ROTATION_PERIOD_MS, Long::class.java)
|
||||
?.setNullable(CryptoRoomEntityFields.ROTATION_PERIOD_MS, true)
|
||||
?.addField(CryptoRoomEntityFields.ROTATION_PERIOD_MSGS, Long::class.java)
|
||||
?.setNullable(CryptoRoomEntityFields.ROTATION_PERIOD_MSGS, true)
|
||||
?.transform {
|
||||
// As a migration we set the default (will be on par with existing code)
|
||||
// A clear cache will have the correct values.
|
||||
it.setLong(CryptoRoomEntityFields.ROTATION_PERIOD_MS, MEGOLM_DEFAULT_ROTATION_PERIOD_MS)
|
||||
it.setLong(CryptoRoomEntityFields.ROTATION_PERIOD_MSGS, MEGOLM_DEFAULT_ROTATION_MSGS)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023 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.RustEncryptionConfiguration
|
||||
import org.matrix.android.sdk.internal.session.MigrateEAtoEROperation
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* This migration creates the rust database and migrates from legacy crypto.
|
||||
*/
|
||||
internal class MigrateCryptoTo022(
|
||||
realm: DynamicRealm,
|
||||
private val rustDirectory: File,
|
||||
private val rustEncryptionConfiguration: RustEncryptionConfiguration,
|
||||
private val migrateMegolmGroupSessions: Boolean = false
|
||||
) : RealmMigrator(
|
||||
realm,
|
||||
22
|
||||
) {
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
// Migrate to rust!
|
||||
val migrateOperation = MigrateEAtoEROperation(migrateMegolmGroupSessions)
|
||||
migrateOperation.dynamicExecute(realm, rustDirectory, rustEncryptionConfiguration.getDatabasePassphrase())
|
||||
|
||||
// wa can't delete all for now, but we can do some cleaning
|
||||
realm.schema.get("OlmSessionEntity")?.transform {
|
||||
it.deleteFromRealm()
|
||||
}
|
||||
|
||||
// a future migration will clean the rest
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2024 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.OutgoingKeyRequestEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
// Some fields are now required due to upgrade of Kotlin version.
|
||||
// See https://github.com/realm/realm-java/issues/7810 for more details.
|
||||
internal class MigrateCryptoTo023(realm: DynamicRealm) : RealmMigrator(realm, 23) {
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("OutgoingKeyRequestEntity")
|
||||
?.setRequired(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, true)
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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.rust
|
||||
|
||||
data class ExtractMigrationDataFailure(override val cause: Throwable) :
|
||||
java.lang.RuntimeException("Can't proceed with migration, crypto store is empty or some necessary data is missing.", cause)
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* 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.rust
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity
|
||||
import org.matrix.olm.OlmUtility
|
||||
import org.matrix.rustcomponents.sdk.crypto.MigrationData
|
||||
import timber.log.Timber
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
internal class ExtractMigrationDataUseCase(private val migrateGroupSessions: Boolean = false) {
|
||||
|
||||
fun extractData(realm: RealmToMigrate, importPartial: ((MigrationData) -> Unit)) {
|
||||
return try {
|
||||
extract(realm, importPartial)
|
||||
} catch (failure: Throwable) {
|
||||
throw ExtractMigrationDataFailure(failure)
|
||||
}
|
||||
}
|
||||
|
||||
fun hasExistingData(realmConfiguration: RealmConfiguration): Boolean {
|
||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
||||
!realm.isEmpty &&
|
||||
// Check if there is a MetaData object
|
||||
realm.where<CryptoMetadataEntity>().count() > 0 &&
|
||||
realm.where<CryptoMetadataEntity>().findFirst()?.olmAccountData != null
|
||||
}
|
||||
}
|
||||
|
||||
private fun extract(realm: RealmToMigrate, importPartial: ((MigrationData) -> Unit)) {
|
||||
val pickleKey = OlmUtility.getRandomKey()
|
||||
|
||||
val baseExtract = realm.getPickledAccount(pickleKey)
|
||||
// import the account asap
|
||||
importPartial(baseExtract)
|
||||
|
||||
val chunkSize = 500
|
||||
realm.trackedUsersChunk(500) {
|
||||
importPartial(
|
||||
baseExtract.copy(trackedUsers = it)
|
||||
)
|
||||
}
|
||||
|
||||
var migratedOlmSessionCount = 0
|
||||
var writeTime = 0L
|
||||
measureTimeMillis {
|
||||
realm.pickledOlmSessions(pickleKey, chunkSize) { pickledSessions ->
|
||||
migratedOlmSessionCount += pickledSessions.size
|
||||
measureTimeMillis {
|
||||
importPartial(
|
||||
baseExtract.copy(sessions = pickledSessions)
|
||||
)
|
||||
}.also { writeTime += it }
|
||||
}
|
||||
}.also {
|
||||
Timber.i("Migration: took $it ms to migrate $migratedOlmSessionCount olm sessions")
|
||||
Timber.i("Migration: rust import time $writeTime")
|
||||
}
|
||||
|
||||
// We don't migrate outbound session by default directly after migration
|
||||
// We are going to do it lazyly when decryption fails
|
||||
if (migrateGroupSessions) {
|
||||
var migratedInboundGroupSessionCount = 0
|
||||
measureTimeMillis {
|
||||
realm.pickledOlmGroupSessions(pickleKey, chunkSize) { pickledSessions ->
|
||||
migratedInboundGroupSessionCount += pickledSessions.size
|
||||
measureTimeMillis {
|
||||
importPartial(
|
||||
baseExtract.copy(inboundGroupSessions = pickledSessions)
|
||||
)
|
||||
}.also { writeTime += it }
|
||||
}
|
||||
}.also {
|
||||
Timber.i("Migration: took $it ms to migrate $migratedInboundGroupSessionCount group sessions")
|
||||
Timber.i("Migration: rust import time $writeTime")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,336 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 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.rust
|
||||
|
||||
import io.realm.kotlin.where
|
||||
import okhttp3.internal.toImmutableList
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.olm.OlmAccount
|
||||
import org.matrix.olm.OlmInboundGroupSession
|
||||
import org.matrix.olm.OlmSession
|
||||
import org.matrix.rustcomponents.sdk.crypto.CrossSigningKeyExport
|
||||
import org.matrix.rustcomponents.sdk.crypto.MigrationData
|
||||
import org.matrix.rustcomponents.sdk.crypto.PickledAccount
|
||||
import org.matrix.rustcomponents.sdk.crypto.PickledInboundGroupSession
|
||||
import org.matrix.rustcomponents.sdk.crypto.PickledSession
|
||||
import timber.log.Timber
|
||||
import java.nio.charset.Charset
|
||||
|
||||
sealed class RealmToMigrate {
|
||||
data class DynamicRealm(val realm: io.realm.DynamicRealm) : RealmToMigrate()
|
||||
data class ClassicRealm(val realm: io.realm.Realm) : RealmToMigrate()
|
||||
}
|
||||
|
||||
fun RealmToMigrate.hasExistingData(): Boolean {
|
||||
return when (this) {
|
||||
is RealmToMigrate.ClassicRealm -> {
|
||||
!this.realm.isEmpty &&
|
||||
// Check if there is a MetaData object
|
||||
this.realm.where<CryptoMetadataEntity>().count() > 0 &&
|
||||
this.realm.where<CryptoMetadataEntity>().findFirst()?.olmAccountData != null
|
||||
}
|
||||
is RealmToMigrate.DynamicRealm -> {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws
|
||||
fun RealmToMigrate.getPickledAccount(pickleKey: ByteArray): MigrationData {
|
||||
return when (this) {
|
||||
is RealmToMigrate.ClassicRealm -> {
|
||||
val metadataEntity = realm.where<CryptoMetadataEntity>().findFirst()
|
||||
?: throw java.lang.IllegalArgumentException("Rust db migration: No existing metadataEntity")
|
||||
|
||||
val masterKey = metadataEntity.xSignMasterPrivateKey
|
||||
val userKey = metadataEntity.xSignUserPrivateKey
|
||||
val selfSignedKey = metadataEntity.xSignSelfSignedPrivateKey
|
||||
|
||||
Timber.i("## Migration: has private MSK ${masterKey.isNullOrBlank().not()}")
|
||||
Timber.i("## Migration: has private USK ${userKey.isNullOrBlank().not()}")
|
||||
Timber.i("## Migration: has private SSK ${selfSignedKey.isNullOrBlank().not()}")
|
||||
|
||||
val userId = metadataEntity.userId
|
||||
?: throw java.lang.IllegalArgumentException("Rust db migration: userId is null")
|
||||
val deviceId = metadataEntity.deviceId
|
||||
?: throw java.lang.IllegalArgumentException("Rust db migration: deviceID is null")
|
||||
|
||||
val backupVersion = metadataEntity.backupVersion
|
||||
val backupRecoveryKey = metadataEntity.keyBackupRecoveryKey
|
||||
|
||||
Timber.i("## Migration: has private backup key ${backupRecoveryKey != null} for version $backupVersion")
|
||||
|
||||
val isOlmAccountShared = metadataEntity.deviceKeysSentToServer
|
||||
|
||||
val olmAccount = metadataEntity.getOlmAccount()
|
||||
?: throw java.lang.IllegalArgumentException("Rust db migration: No existing account")
|
||||
val pickledOlmAccount = olmAccount.pickle(pickleKey, StringBuffer()).asString()
|
||||
|
||||
val pickledAccount = PickledAccount(
|
||||
userId = userId,
|
||||
deviceId = deviceId,
|
||||
pickle = pickledOlmAccount,
|
||||
shared = isOlmAccountShared,
|
||||
uploadedSignedKeyCount = 50
|
||||
)
|
||||
MigrationData(
|
||||
account = pickledAccount,
|
||||
pickleKey = pickleKey,
|
||||
crossSigning = CrossSigningKeyExport(
|
||||
masterKey = masterKey,
|
||||
selfSigningKey = selfSignedKey,
|
||||
userSigningKey = userKey
|
||||
),
|
||||
sessions = emptyList(),
|
||||
backupRecoveryKey = backupRecoveryKey,
|
||||
trackedUsers = emptyList(),
|
||||
inboundGroupSessions = emptyList(),
|
||||
backupVersion = backupVersion,
|
||||
// TODO import room settings from legacy DB
|
||||
roomSettings = emptyMap()
|
||||
)
|
||||
}
|
||||
is RealmToMigrate.DynamicRealm -> {
|
||||
val cryptoMetadataEntitySchema = realm.schema.get("CryptoMetadataEntity")
|
||||
?: throw java.lang.IllegalStateException("Missing Metadata entity")
|
||||
|
||||
var migrationData: MigrationData? = null
|
||||
cryptoMetadataEntitySchema.transform { dynMetaData ->
|
||||
|
||||
val serializedOlmAccount = dynMetaData.getString(CryptoMetadataEntityFields.OLM_ACCOUNT_DATA)
|
||||
|
||||
val masterKey = dynMetaData.getString(CryptoMetadataEntityFields.X_SIGN_MASTER_PRIVATE_KEY)
|
||||
val userKey = dynMetaData.getString(CryptoMetadataEntityFields.X_SIGN_USER_PRIVATE_KEY)
|
||||
val selfSignedKey = dynMetaData.getString(CryptoMetadataEntityFields.X_SIGN_SELF_SIGNED_PRIVATE_KEY)
|
||||
|
||||
val userId = dynMetaData.getString(CryptoMetadataEntityFields.USER_ID)
|
||||
?: throw java.lang.IllegalArgumentException("Rust db migration: userId is null")
|
||||
val deviceId = dynMetaData.getString(CryptoMetadataEntityFields.DEVICE_ID)
|
||||
?: throw java.lang.IllegalArgumentException("Rust db migration: deviceID is null")
|
||||
|
||||
val backupVersion = dynMetaData.getString(CryptoMetadataEntityFields.BACKUP_VERSION)
|
||||
val backupRecoveryKey = dynMetaData.getString(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY)
|
||||
|
||||
val isOlmAccountShared = dynMetaData.getBoolean(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER)
|
||||
|
||||
val olmAccount = deserializeFromRealm<OlmAccount>(serializedOlmAccount)
|
||||
?: throw java.lang.IllegalArgumentException("Rust db migration: No existing account")
|
||||
|
||||
val pickledOlmAccount = olmAccount.pickle(pickleKey, StringBuffer()).asString()
|
||||
|
||||
val pickledAccount = PickledAccount(
|
||||
userId = userId,
|
||||
deviceId = deviceId,
|
||||
pickle = pickledOlmAccount,
|
||||
shared = isOlmAccountShared,
|
||||
uploadedSignedKeyCount = 50
|
||||
)
|
||||
|
||||
migrationData = MigrationData(
|
||||
account = pickledAccount,
|
||||
pickleKey = pickleKey,
|
||||
crossSigning = CrossSigningKeyExport(
|
||||
masterKey = masterKey,
|
||||
selfSigningKey = selfSignedKey,
|
||||
userSigningKey = userKey
|
||||
),
|
||||
sessions = emptyList(),
|
||||
backupRecoveryKey = backupRecoveryKey,
|
||||
trackedUsers = emptyList(),
|
||||
inboundGroupSessions = emptyList(),
|
||||
backupVersion = backupVersion,
|
||||
// TODO import room settings from legacy DB
|
||||
roomSettings = emptyMap()
|
||||
)
|
||||
}
|
||||
migrationData!!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun RealmToMigrate.trackedUsersChunk(chunkSize: Int, onChunk: ((List<String>) -> Unit)) {
|
||||
when (this) {
|
||||
is RealmToMigrate.ClassicRealm -> {
|
||||
realm.where<UserEntity>()
|
||||
.findAll()
|
||||
.chunked(chunkSize)
|
||||
.onEach {
|
||||
onChunk(it.mapNotNull { it.userId })
|
||||
}
|
||||
}
|
||||
is RealmToMigrate.DynamicRealm -> {
|
||||
val userList = mutableListOf<String>()
|
||||
realm.schema.get("UserEntity")?.transform {
|
||||
val userId = it.getString(UserEntityFields.USER_ID)
|
||||
// should we check the tracking status?
|
||||
userList.add(userId)
|
||||
if (userList.size > chunkSize) {
|
||||
onChunk(userList.toImmutableList())
|
||||
userList.clear()
|
||||
}
|
||||
}
|
||||
if (userList.isNotEmpty()) {
|
||||
onChunk(userList)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun RealmToMigrate.pickledOlmSessions(pickleKey: ByteArray, chunkSize: Int, onChunk: ((List<PickledSession>) -> Unit)) {
|
||||
when (this) {
|
||||
is RealmToMigrate.ClassicRealm -> {
|
||||
realm.where<OlmSessionEntity>().findAll()
|
||||
.chunked(chunkSize) { chunk ->
|
||||
val export = chunk.map { it.toPickledSession(pickleKey) }
|
||||
onChunk(export)
|
||||
}
|
||||
}
|
||||
is RealmToMigrate.DynamicRealm -> {
|
||||
val pickledSessions = mutableListOf<PickledSession>()
|
||||
realm.schema.get("OlmSessionEntity")?.transform {
|
||||
val sessionData = it.getString(OlmSessionEntityFields.OLM_SESSION_DATA)
|
||||
val deviceKey = it.getString(OlmSessionEntityFields.DEVICE_KEY)
|
||||
val lastReceivedMessageTs = it.getLong(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS)
|
||||
val olmSession = deserializeFromRealm<OlmSession>(sessionData)!!
|
||||
val pickle = olmSession.pickle(pickleKey, StringBuffer()).asString()
|
||||
val pickledSession = PickledSession(
|
||||
pickle = pickle,
|
||||
senderKey = deviceKey,
|
||||
createdUsingFallbackKey = false,
|
||||
// / Unix timestamp (in seconds) when the session was created.
|
||||
creationTime = (lastReceivedMessageTs / 1000).toULong(),
|
||||
// / Unix timestamp (in seconds) when the session was last used.
|
||||
lastUseTime = (lastReceivedMessageTs / 1000).toULong(),
|
||||
)
|
||||
// should we check the tracking status?
|
||||
pickledSessions.add(pickledSession)
|
||||
if (pickledSessions.size > chunkSize) {
|
||||
onChunk(pickledSessions.toImmutableList())
|
||||
pickledSessions.clear()
|
||||
}
|
||||
}
|
||||
if (pickledSessions.isNotEmpty()) {
|
||||
onChunk(pickledSessions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val sessionDataAdapter = MoshiProvider.providesMoshi()
|
||||
.adapter(InboundGroupSessionData::class.java)
|
||||
fun RealmToMigrate.pickledOlmGroupSessions(pickleKey: ByteArray, chunkSize: Int, onChunk: ((List<PickledInboundGroupSession>) -> Unit)) {
|
||||
when (this) {
|
||||
is RealmToMigrate.ClassicRealm -> {
|
||||
realm.where<OlmInboundGroupSessionEntity>()
|
||||
.findAll()
|
||||
.chunked(chunkSize) { chunk ->
|
||||
val export = chunk.mapNotNull { it.toPickledInboundGroupSession(pickleKey) }
|
||||
onChunk(export)
|
||||
}
|
||||
}
|
||||
is RealmToMigrate.DynamicRealm -> {
|
||||
val pickledSessions = mutableListOf<PickledInboundGroupSession>()
|
||||
realm.schema.get("OlmInboundGroupSessionEntity")?.transform {
|
||||
val senderKey = it.getString(OlmInboundGroupSessionEntityFields.SENDER_KEY)
|
||||
val roomId = it.getString(OlmInboundGroupSessionEntityFields.ROOM_ID)
|
||||
val backedUp = it.getBoolean(OlmInboundGroupSessionEntityFields.BACKED_UP)
|
||||
val serializedOlmInboundGroupSession = it.getString(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION)
|
||||
val inboundSession = deserializeFromRealm<OlmInboundGroupSession>(serializedOlmInboundGroupSession) ?: return@transform Unit.also {
|
||||
Timber.w("Rust db migration: Failed to migrated group session, no meta data")
|
||||
}
|
||||
val sessionData = it.getString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON).let { json ->
|
||||
sessionDataAdapter.fromJson(json)
|
||||
} ?: return@transform Unit.also {
|
||||
Timber.w("Rust db migration: Failed to migrated group session, no meta data")
|
||||
}
|
||||
val pickle = inboundSession.pickle(pickleKey, StringBuffer()).asString()
|
||||
val pickledSession = PickledInboundGroupSession(
|
||||
pickle = pickle,
|
||||
senderKey = senderKey,
|
||||
signingKey = sessionData.keysClaimed.orEmpty(),
|
||||
roomId = roomId,
|
||||
forwardingChains = sessionData.forwardingCurve25519KeyChain.orEmpty(),
|
||||
imported = sessionData.trusted.orFalse().not(),
|
||||
backedUp = backedUp
|
||||
)
|
||||
// should we check the tracking status?
|
||||
pickledSessions.add(pickledSession)
|
||||
if (pickledSessions.size > chunkSize) {
|
||||
onChunk(pickledSessions.toImmutableList())
|
||||
pickledSessions.clear()
|
||||
}
|
||||
}
|
||||
if (pickledSessions.isNotEmpty()) {
|
||||
onChunk(pickledSessions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun OlmInboundGroupSessionEntity.toPickledInboundGroupSession(pickleKey: ByteArray): PickledInboundGroupSession? {
|
||||
val senderKey = this.senderKey ?: return null
|
||||
val backedUp = this.backedUp
|
||||
val olmInboundGroupSession = this.getOlmGroupSession() ?: return null.also {
|
||||
Timber.w("Rust db migration: Failed to migrated group session $sessionId")
|
||||
}
|
||||
val data = this.getData() ?: return null.also {
|
||||
Timber.w("Rust db migration: Failed to migrated group session $sessionId, no meta data")
|
||||
}
|
||||
val roomId = data.roomId ?: return null.also {
|
||||
Timber.w("Rust db migration: Failed to migrated group session $sessionId, no roomId")
|
||||
}
|
||||
val pickledInboundGroupSession = olmInboundGroupSession.pickle(pickleKey, StringBuffer()).asString()
|
||||
return PickledInboundGroupSession(
|
||||
pickle = pickledInboundGroupSession,
|
||||
senderKey = senderKey,
|
||||
signingKey = data.keysClaimed.orEmpty(),
|
||||
roomId = roomId,
|
||||
forwardingChains = data.forwardingCurve25519KeyChain.orEmpty(),
|
||||
imported = data.trusted.orFalse().not(),
|
||||
backedUp = backedUp
|
||||
)
|
||||
}
|
||||
private fun OlmSessionEntity.toPickledSession(pickleKey: ByteArray): PickledSession {
|
||||
val deviceKey = this.deviceKey ?: ""
|
||||
val lastReceivedMessageTs = this.lastReceivedMessageTs
|
||||
val olmSessionStr = this.olmSessionData
|
||||
val olmSession = deserializeFromRealm<OlmSession>(olmSessionStr)!!
|
||||
val pickledOlmSession = olmSession.pickle(pickleKey, StringBuffer()).asString()
|
||||
return PickledSession(
|
||||
pickle = pickledOlmSession,
|
||||
senderKey = deviceKey,
|
||||
createdUsingFallbackKey = false,
|
||||
// Rust expect in seconds
|
||||
creationTime = (lastReceivedMessageTs / 1000).toULong(),
|
||||
// Rust expect in seconds
|
||||
lastUseTime = (lastReceivedMessageTs / 1000).toULong(),
|
||||
)
|
||||
}
|
||||
|
||||
private val charset = Charset.forName("UTF-8")
|
||||
private fun ByteArray.asString() = String(this, charset)
|
|
@ -18,9 +18,6 @@ package org.matrix.android.sdk.internal.crypto.store.db.model
|
|||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
|
||||
import org.matrix.olm.OlmAccount
|
||||
|
||||
internal open class CryptoMetadataEntity(
|
||||
// The current user id.
|
||||
|
@ -53,15 +50,4 @@ internal open class CryptoMetadataEntity(
|
|||
var keyBackupRecoveryKeyVersion: String? = null
|
||||
|
||||
// var crossSigningInfoEntity: CrossSigningInfoEntity? = null
|
||||
) : RealmObject() {
|
||||
|
||||
// Deserialize data
|
||||
fun getOlmAccount(): OlmAccount? {
|
||||
return deserializeFromRealm(olmAccountData)
|
||||
}
|
||||
|
||||
// Serialize data
|
||||
fun putOlmAccount(olmAccount: OlmAccount?) {
|
||||
olmAccountData = serializeForRealm(olmAccount)
|
||||
}
|
||||
}
|
||||
) : RealmObject()
|
||||
|
|
|
@ -19,12 +19,7 @@ package org.matrix.android.sdk.internal.crypto.store.db.model
|
|||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.olm.OlmInboundGroupSession
|
||||
import timber.log.Timber
|
||||
|
||||
internal fun OlmInboundGroupSessionEntity.Companion.createPrimaryKey(sessionId: String?, senderKey: String?) = "$sessionId|$senderKey"
|
||||
|
||||
|
@ -56,14 +51,6 @@ internal open class OlmInboundGroupSessionEntity(
|
|||
) :
|
||||
RealmObject() {
|
||||
|
||||
fun store(wrapper: MXInboundMegolmSessionWrapper) {
|
||||
this.serializedOlmInboundGroupSession = serializeForRealm(wrapper.session)
|
||||
this.inboundGroupSessionDataJson = adapter.toJson(wrapper.sessionData)
|
||||
this.roomId = wrapper.sessionData.roomId
|
||||
this.senderKey = wrapper.sessionData.senderKey
|
||||
this.sessionId = wrapper.session.sessionIdentifier()
|
||||
this.sharedHistory = wrapper.sessionData.sharedHistory
|
||||
}
|
||||
// fun getInboundGroupSession(): OlmInboundGroupSessionWrapper2? {
|
||||
// return try {
|
||||
// deserializeFromRealm<OlmInboundGroupSessionWrapper2?>(olmInboundGroupSessionData)
|
||||
|
@ -77,35 +64,6 @@ internal open class OlmInboundGroupSessionEntity(
|
|||
// olmInboundGroupSessionData = serializeForRealm(olmInboundGroupSessionWrapper)
|
||||
// }
|
||||
|
||||
fun getOlmGroupSession(): OlmInboundGroupSession? {
|
||||
return try {
|
||||
deserializeFromRealm(serializedOlmInboundGroupSession)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "## Deserialization failure")
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun getData(): InboundGroupSessionData? {
|
||||
return try {
|
||||
inboundGroupSessionDataJson?.let {
|
||||
adapter.fromJson(it)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "## Deserialization failure")
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun toModel(): MXInboundMegolmSessionWrapper? {
|
||||
val data = getData() ?: return null
|
||||
val session = getOlmGroupSession() ?: return null
|
||||
return MXInboundMegolmSessionWrapper(
|
||||
session = session,
|
||||
sessionData = data
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val adapter = MoshiProvider.providesMoshi()
|
||||
.adapter(InboundGroupSessionData::class.java)
|
||||
|
|
|
@ -18,9 +18,6 @@ package org.matrix.android.sdk.internal.crypto.store.db.model
|
|||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
|
||||
import org.matrix.olm.OlmSession
|
||||
|
||||
internal fun OlmSessionEntity.Companion.createPrimaryKey(sessionId: String, deviceKey: String) = "$sessionId|$deviceKey"
|
||||
|
||||
|
@ -34,13 +31,5 @@ internal open class OlmSessionEntity(
|
|||
) :
|
||||
RealmObject() {
|
||||
|
||||
fun getOlmSession(): OlmSession? {
|
||||
return deserializeFromRealm(olmSessionData)
|
||||
}
|
||||
|
||||
fun putOlmSession(olmSession: OlmSession?) {
|
||||
olmSessionData = serializeForRealm(olmSession)
|
||||
}
|
||||
|
||||
companion object
|
||||
}
|
||||
|
|
|
@ -17,10 +17,6 @@
|
|||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
|
||||
import org.matrix.olm.OlmOutboundGroupSession
|
||||
import timber.log.Timber
|
||||
|
||||
internal open class OutboundGroupSessionInfoEntity(
|
||||
var serializedOutboundSessionData: String? = null,
|
||||
|
@ -28,18 +24,5 @@ internal open class OutboundGroupSessionInfoEntity(
|
|||
var shouldShareHistory: Boolean = false
|
||||
) : RealmObject() {
|
||||
|
||||
fun getOutboundGroupSession(): OlmOutboundGroupSession? {
|
||||
return try {
|
||||
deserializeFromRealm(serializedOutboundSessionData)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "## getOutboundGroupSession() Deserialization failure")
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun putOutboundGroupSession(olmOutboundGroupSession: OlmOutboundGroupSession?) {
|
||||
serializedOutboundSessionData = serializeForRealm(olmOutboundGroupSession)
|
||||
}
|
||||
|
||||
companion object
|
||||
}
|
||||
|
|
|
@ -16,43 +16,10 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.crypto.tools
|
||||
|
||||
import org.matrix.olm.OlmPkDecryption
|
||||
import org.matrix.olm.OlmPkEncryption
|
||||
import org.matrix.olm.OlmPkSigning
|
||||
import org.matrix.olm.OlmUtility
|
||||
// TODO BMA
|
||||
data object OlmPkEncryption
|
||||
|
||||
internal fun <T> withOlmEncryption(block: (OlmPkEncryption) -> T): T {
|
||||
val olmPkEncryption = OlmPkEncryption()
|
||||
try {
|
||||
val olmPkEncryption = OlmPkEncryption
|
||||
return block(olmPkEncryption)
|
||||
} finally {
|
||||
olmPkEncryption.releaseEncryption()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> withOlmDecryption(block: (OlmPkDecryption) -> T): T {
|
||||
val olmPkDecryption = OlmPkDecryption()
|
||||
try {
|
||||
return block(olmPkDecryption)
|
||||
} finally {
|
||||
olmPkDecryption.releaseDecryption()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> withOlmSigning(block: (OlmPkSigning) -> T): T {
|
||||
val olmPkSigning = OlmPkSigning()
|
||||
try {
|
||||
return block(olmPkSigning)
|
||||
} finally {
|
||||
olmPkSigning.releaseSigning()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> withOlmUtility(block: (OlmUtility) -> T): T {
|
||||
val olmUtility = OlmUtility()
|
||||
try {
|
||||
return block(olmUtility)
|
||||
} finally {
|
||||
olmUtility.releaseUtility()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ import org.matrix.android.sdk.internal.task.TaskExecutor
|
|||
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
|
||||
import org.matrix.android.sdk.internal.util.system.SystemModule
|
||||
import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
|
||||
import org.matrix.olm.OlmManager
|
||||
import java.io.File
|
||||
|
||||
@Component(
|
||||
|
@ -89,8 +88,6 @@ internal interface MatrixComponent {
|
|||
@CacheDirectory
|
||||
fun cacheDir(): File
|
||||
|
||||
fun olmManager(): OlmManager
|
||||
|
||||
fun taskExecutor(): TaskExecutor
|
||||
|
||||
fun sessionParamsStore(): SessionParamsStore
|
||||
|
|
|
@ -25,7 +25,6 @@ import kotlinx.coroutines.android.asCoroutineDispatcher
|
|||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.internal.util.createBackgroundHandler
|
||||
import org.matrix.olm.OlmManager
|
||||
import java.io.File
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
|
@ -57,11 +56,4 @@ internal object MatrixModule {
|
|||
fun providesCacheDir(context: Context): File {
|
||||
return context.cacheDir
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@MatrixScope
|
||||
fun providesOlmManager(): OlmManager {
|
||||
return OlmManager()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.rust.ExtractMigrationDataUseCase
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.rust.RealmToMigrate
|
||||
import org.matrix.rustcomponents.sdk.crypto.ProgressListener
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
|
||||
class MigrateEAtoEROperation(private val migrateGroupSessions: Boolean = false) {
|
||||
|
||||
fun execute(cryptoRealm: RealmConfiguration, rustFilesDir: File, passphrase: String?): File {
|
||||
// Temporary code for migration
|
||||
if (!rustFilesDir.exists()) {
|
||||
rustFilesDir.mkdir()
|
||||
// perform a migration?
|
||||
val extractMigrationData = ExtractMigrationDataUseCase(migrateGroupSessions)
|
||||
val hasExitingData = extractMigrationData.hasExistingData(cryptoRealm)
|
||||
if (!hasExitingData) return rustFilesDir
|
||||
|
||||
try {
|
||||
val progressListener = object : ProgressListener {
|
||||
override fun onProgress(progress: Int, total: Int) {
|
||||
Timber.v("OnProgress: $progress/$total")
|
||||
}
|
||||
}
|
||||
Realm.getInstance(cryptoRealm).use { realm ->
|
||||
extractMigrationData.extractData(RealmToMigrate.ClassicRealm(realm)) {
|
||||
org.matrix.rustcomponents.sdk.crypto.migrate(it, rustFilesDir.path, passphrase, progressListener)
|
||||
}
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "Failure while calling rust migration method")
|
||||
throw failure
|
||||
}
|
||||
}
|
||||
return rustFilesDir
|
||||
}
|
||||
|
||||
fun dynamicExecute(dynamicRealm: DynamicRealm, rustFilesDir: File, passphrase: String?) {
|
||||
if (!rustFilesDir.exists()) {
|
||||
rustFilesDir.mkdir()
|
||||
}
|
||||
val extractMigrationData = ExtractMigrationDataUseCase(migrateGroupSessions)
|
||||
|
||||
try {
|
||||
val progressListener = object : ProgressListener {
|
||||
override fun onProgress(progress: Int, total: Int) {
|
||||
Timber.v("OnProgress: $progress/$total")
|
||||
}
|
||||
}
|
||||
extractMigrationData.extractData(RealmToMigrate.DynamicRealm(dynamicRealm)) {
|
||||
org.matrix.rustcomponents.sdk.crypto.migrate(it, rustFilesDir.path, passphrase, progressListener)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "Failure while calling rust migration method")
|
||||
throw failure
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,9 +44,11 @@ internal object ScanEncryptorUtils {
|
|||
)
|
||||
return if (publicServerKey != null) {
|
||||
// We should encrypt
|
||||
withOlmEncryption { olm ->
|
||||
withOlmEncryption { //olm ->
|
||||
// TODO BMA
|
||||
error("Not supported anymore")
|
||||
/*
|
||||
olm.setRecipientKey(publicServerKey)
|
||||
|
||||
val olmResult = olm.encrypt(DownloadBody(encryptedInfo).toCanonicalJson())
|
||||
DownloadBody(
|
||||
encryptedBody = EncryptedBody(
|
||||
|
@ -55,6 +57,7 @@ internal object ScanEncryptorUtils {
|
|||
mac = olmResult.mMac
|
||||
)
|
||||
)
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
DownloadBody(encryptedInfo)
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.matrix.android.sdk.api.session.identity.FoundThreePid
|
|||
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.api.session.identity.toMedium
|
||||
import org.matrix.android.sdk.internal.crypto.tools.withOlmUtility
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
import org.matrix.android.sdk.internal.session.identity.data.IdentityStore
|
||||
|
@ -31,6 +30,7 @@ import org.matrix.android.sdk.internal.session.identity.model.IdentityLookUpPara
|
|||
import org.matrix.android.sdk.internal.session.identity.model.IdentityLookUpResponse
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import org.matrix.android.sdk.internal.util.base64ToBase64Url
|
||||
import java.security.MessageDigest
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -118,15 +118,10 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
|
|||
}
|
||||
|
||||
private fun getHashedAddresses(threePids: List<ThreePid>, pepper: String): List<String> {
|
||||
return withOlmUtility { olmUtility ->
|
||||
threePids.map { threePid ->
|
||||
return threePids.map { threePid ->
|
||||
base64ToBase64Url(
|
||||
olmUtility.sha256(
|
||||
threePid.value.lowercase(Locale.ROOT) +
|
||||
" " + threePid.toMedium() + " " + pepper
|
||||
(threePid.value.lowercase(Locale.ROOT) + " " + threePid.toMedium() + " " + pepper).toSha256()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,4 +139,11 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val sha256 by lazy { MessageDigest.getInstance("SHA-256") }
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private fun String.toSha256(): String {
|
||||
return sha256.digest(toByteArray()).toHexString()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.androidsdk.crypto.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <b>IMPORTANT:</b> This class is imported from Riot-Android to be able to perform a migration. Do not use it for any other purpose
|
||||
*/
|
||||
public class MXDeviceInfo implements Serializable {
|
||||
private static final long serialVersionUID = 20129670646382964L;
|
||||
|
||||
// This device is a new device and the user was not warned it has been added.
|
||||
public static final int DEVICE_VERIFICATION_UNKNOWN = -1;
|
||||
|
||||
// The user has not yet verified this device.
|
||||
public static final int DEVICE_VERIFICATION_UNVERIFIED = 0;
|
||||
|
||||
// The user has verified this device.
|
||||
public static final int DEVICE_VERIFICATION_VERIFIED = 1;
|
||||
|
||||
// The user has blocked this device.
|
||||
public static final int DEVICE_VERIFICATION_BLOCKED = 2;
|
||||
|
||||
/**
|
||||
* The id of this device.
|
||||
*/
|
||||
public String deviceId;
|
||||
|
||||
/**
|
||||
* the user id
|
||||
*/
|
||||
public String userId;
|
||||
|
||||
/**
|
||||
* The list of algorithms supported by this device.
|
||||
*/
|
||||
public List<String> algorithms;
|
||||
|
||||
/**
|
||||
* A map from <key type>:<id> to <base64-encoded key>>.
|
||||
*/
|
||||
public Map<String, String> keys;
|
||||
|
||||
/**
|
||||
* The signature of this MXDeviceInfo.
|
||||
* A map from <key type>:<device_id> to <base64-encoded key>>.
|
||||
*/
|
||||
public Map<String, Map<String, String>> signatures;
|
||||
|
||||
/*
|
||||
* Additional data from the homeserver.
|
||||
*/
|
||||
public Map<String, Object> unsigned;
|
||||
|
||||
/**
|
||||
* Verification state of this device.
|
||||
*/
|
||||
public int mVerified;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public MXDeviceInfo() {
|
||||
mVerified = DEVICE_VERIFICATION_UNKNOWN;
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.androidsdk.crypto.data;
|
||||
|
||||
import org.matrix.olm.OlmInboundGroupSession;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <b>IMPORTANT:</b> This class is imported from Riot-Android to be able to perform a migration. Do not use it for any other purpose
|
||||
*
|
||||
* This class adds more context to a OLMInboundGroupSession object.
|
||||
* This allows additional checks. The class implements NSCoding so that the context can be stored.
|
||||
*/
|
||||
public class MXOlmInboundGroupSession2 implements Serializable {
|
||||
// define a serialVersionUID to avoid having to redefine the class after updates
|
||||
private static final long serialVersionUID = 201702011617L;
|
||||
|
||||
// The associated olm inbound group session.
|
||||
public OlmInboundGroupSession mSession;
|
||||
|
||||
// The room in which this session is used.
|
||||
public String mRoomId;
|
||||
|
||||
// The base64-encoded curve25519 key of the sender.
|
||||
public String mSenderKey;
|
||||
|
||||
// Other keys the sender claims.
|
||||
public Map<String, String> mKeysClaimed;
|
||||
|
||||
// Devices which forwarded this session to us (normally empty).
|
||||
public List<String> mForwardingCurve25519KeyChain = new ArrayList<>();
|
||||
}
|
Loading…
Reference in a new issue