Compare commits
79 Commits
develop
...
feature/fg
Author | SHA1 | Date | |
---|---|---|---|
|
fc19bf8e5b | ||
|
e1031fab0f | ||
|
b806bd59a1 | ||
|
97d82866b6 | ||
|
974079ff00 | ||
|
9dca4293a1 | ||
|
47ca9a07af | ||
|
7527693a05 | ||
|
ca4ed5c822 | ||
|
e6f911a64b | ||
|
e7587a6f47 | ||
|
c43b50b675 | ||
|
054c61d076 | ||
|
1210e8c712 | ||
|
f27f9f3ae5 | ||
|
a5b6a01691 | ||
|
978294cdc0 | ||
|
18481211df | ||
|
f7b6ed1963 | ||
|
433704191c | ||
|
ad772222d6 | ||
|
ac14c8cd27 | ||
|
0b0b2d5d63 | ||
|
14099be861 | ||
|
47cf9e58bd | ||
|
fec9b0d83a | ||
|
2db5f5a5f0 | ||
|
27bbd18a74 | ||
|
5b58f6cfe5 | ||
|
ad0af11358 | ||
|
e20febb4a0 | ||
|
f3d36e4d31 | ||
|
3aba7803dd | ||
|
6379c199ea | ||
|
6edea43ab4 | ||
|
5d73118c8c | ||
|
a93bba88ac | ||
|
85969f3d81 | ||
|
5b0f7b7b7c | ||
|
981ab5bc87 | ||
|
baa854e5f2 | ||
|
6b3ce7872e | ||
|
87a3362e62 | ||
|
d7e93e8229 | ||
|
184edd9398 | ||
|
a4a4bac75b | ||
|
aeaf4389a8 | ||
|
7ea73d3ad0 | ||
|
4bdc880eb6 | ||
|
913d430d1e | ||
|
81629b81f1 | ||
|
def2b0067f | ||
|
948e24065f | ||
|
d0cb078f18 | ||
|
f25764d09a | ||
|
2cdd05072b | ||
|
5b91c14e71 | ||
|
7717637e57 | ||
|
6cfac4526e | ||
|
462d1bce68 | ||
|
4040593608 | ||
|
a60f42fc00 | ||
|
af5bbe12f5 | ||
|
c5883b3e7c | ||
|
7e2f821287 | ||
|
ed135bc4fc | ||
|
0fe189b3dd | ||
|
4b2043b64a | ||
|
58788e27d5 | ||
|
6fb5d7fc30 | ||
|
736bc3064f | ||
|
e8f2ceaed4 | ||
|
9bb53da626 | ||
|
1380c60d10 | ||
|
4a68412777 | ||
|
dee0b824e9 | ||
|
186753f691 | ||
|
82180304ef | ||
|
52ebe74302 |
@ -163,6 +163,9 @@ ext.libs = [
|
||||
apache : [
|
||||
'commonsImaging' : "org.apache.sanselan:sanselan:0.97-incubator"
|
||||
],
|
||||
realm : [
|
||||
'base' : "io.realm.kotlin:library-base:${realmKotlinVersion}"
|
||||
],
|
||||
sentry: [
|
||||
'sentryAndroid' : "io.sentry:sentry-android:$sentry"
|
||||
],
|
||||
|
@ -150,6 +150,7 @@ ext.groups = [
|
||||
'io.perfmark',
|
||||
'io.reactivex.rxjava2',
|
||||
'io.realm',
|
||||
'io.realm.kotlin',
|
||||
'io.sentry',
|
||||
'it.unimi.dsi',
|
||||
'jakarta.activation',
|
||||
@ -232,8 +233,6 @@ ext.groups = [
|
||||
'com.amulyakhare',
|
||||
'com.otaliastudios',
|
||||
'com.yqritc',
|
||||
// https://github.com/cmelchior/realmfieldnameshelper/issues/42
|
||||
'dk.ilios',
|
||||
'im.dlg',
|
||||
'me.dm7.barcodescanner',
|
||||
'me.gujun.android',
|
||||
|
@ -35,6 +35,9 @@ signing.element.storePassword=Secret
|
||||
signing.element.keyId=Secret
|
||||
signing.element.keyPassword=Secret
|
||||
|
||||
# This belongs here as it's the only way to share the version number between the plugin and the library.
|
||||
realmKotlinVersion = 1.4.0
|
||||
|
||||
# Dummy values for signing secrets / nightly
|
||||
signing.element.nightly.storePassword=Secret
|
||||
signing.element.nightly.keyId=Secret
|
||||
|
@ -1,26 +1,18 @@
|
||||
|
||||
plugins {
|
||||
id("io.realm.kotlin") version "${realmKotlinVersion}"
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
apply plugin: 'realm-android'
|
||||
apply plugin: "org.jetbrains.dokka"
|
||||
|
||||
if (project.hasProperty("coverage")) {
|
||||
apply plugin: 'jacoco'
|
||||
}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
// Do not use `mavenCentral()`, it prevents Dependabot from working properly
|
||||
maven {
|
||||
url 'https://repo1.maven.org/maven2'
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath "io.realm:realm-gradle-plugin:10.11.1"
|
||||
}
|
||||
}
|
||||
|
||||
dokkaHtml {
|
||||
dokkaSourceSets {
|
||||
configureEach {
|
||||
@ -150,6 +142,10 @@ dependencies {
|
||||
// Lifecycle
|
||||
implementation libs.androidx.lifecycleCommon
|
||||
implementation libs.androidx.lifecycleProcess
|
||||
implementation libs.androidx.lifecycleLivedata
|
||||
|
||||
// Paging
|
||||
implementation libs.androidx.pagingRuntimeKtx
|
||||
|
||||
// Network
|
||||
implementation libs.squareup.retrofit
|
||||
@ -174,9 +170,7 @@ dependencies {
|
||||
implementation libs.androidx.exifinterface
|
||||
|
||||
// Database
|
||||
implementation 'com.github.Zhuinden:realm-monarchy:0.7.1'
|
||||
|
||||
kapt 'dk.ilios:realmfieldnameshelper:2.0.0'
|
||||
implementation libs.realm.base
|
||||
|
||||
// Shared Preferences
|
||||
implementation libs.androidx.preferenceKtx
|
||||
|
@ -23,7 +23,6 @@ import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.work.Configuration
|
||||
import androidx.work.impl.WorkManagerImpl
|
||||
import androidx.work.impl.utils.taskexecutor.WorkManagerTaskExecutor
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||
@ -61,7 +60,6 @@ internal class TestMatrix(context: Context, matrixConfiguration: MatrixConfigura
|
||||
|
||||
init {
|
||||
val appContext = context.applicationContext
|
||||
Monarchy.init(appContext)
|
||||
DaggerTestMatrixComponent.factory().create(appContext, matrixConfiguration).inject(this)
|
||||
val configuration = Configuration.Builder()
|
||||
.setExecutor(Executors.newCachedThreadPool())
|
||||
|
@ -16,24 +16,32 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto
|
||||
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.RealmConfiguration
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.CRYPTO_REALM_SCHEMA
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.mapper.MyDeviceLastSeenInfoEntityMapper
|
||||
import org.matrix.android.sdk.internal.database.RealmInstance
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.android.sdk.internal.util.time.DefaultClock
|
||||
import kotlin.random.Random
|
||||
|
||||
internal class CryptoStoreHelper {
|
||||
|
||||
fun createStore(): IMXCryptoStore {
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun createStore(coroutineScope: CoroutineScope): IMXCryptoStore {
|
||||
val realmConfiguration = RealmConfiguration.Builder(CRYPTO_REALM_SCHEMA)
|
||||
.name("test.realm")
|
||||
.deleteRealmIfMigrationNeeded()
|
||||
.build()
|
||||
|
||||
val realmInstance = RealmInstance(coroutineScope, realmConfiguration, UnconfinedTestDispatcher())
|
||||
return RealmCryptoStore(
|
||||
realmConfiguration = RealmConfiguration.Builder()
|
||||
.name("test.realm")
|
||||
.modules(RealmCryptoStoreModule())
|
||||
.build(),
|
||||
realmInstance = realmInstance,
|
||||
crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi()),
|
||||
userId = "userId_" + Random.nextInt(),
|
||||
deviceId = "deviceId_sample",
|
||||
|
@ -17,12 +17,11 @@
|
||||
package org.matrix.android.sdk.internal.crypto
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.realm.Realm
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@ -37,8 +36,8 @@ import org.matrix.olm.OlmSession
|
||||
|
||||
private const val DUMMY_DEVICE_KEY = "DeviceKey"
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@Ignore
|
||||
class CryptoStoreTest : InstrumentedTest {
|
||||
|
||||
@get:Rule val rule = RetryTestRule(3)
|
||||
@ -46,11 +45,6 @@ class CryptoStoreTest : InstrumentedTest {
|
||||
private val cryptoStoreHelper = CryptoStoreHelper()
|
||||
private val clock = DefaultClock()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
Realm.init(context())
|
||||
}
|
||||
|
||||
// @Test
|
||||
// fun test_metadata_realm_ok() {
|
||||
// val cryptoStore: IMXCryptoStore = cryptoStoreHelper.createStore()
|
||||
@ -69,11 +63,11 @@ class CryptoStoreTest : InstrumentedTest {
|
||||
// }
|
||||
|
||||
@Test
|
||||
fun test_lastSessionUsed() {
|
||||
fun test_lastSessionUsed() = runTest {
|
||||
// Ensure Olm is initialized
|
||||
OlmManager()
|
||||
|
||||
val cryptoStore: IMXCryptoStore = cryptoStoreHelper.createStore()
|
||||
val cryptoStore: IMXCryptoStore = cryptoStoreHelper.createStore(this)
|
||||
|
||||
assertNull(cryptoStore.getLastUsedSessionId(DUMMY_DEVICE_KEY))
|
||||
|
||||
|
@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.crypto
|
||||
import android.util.Log
|
||||
import androidx.test.filters.LargeTest
|
||||
import org.amshove.kluent.internal.assertEquals
|
||||
import org.amshove.kluent.shouldBe
|
||||
import org.junit.Assert
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
@ -56,6 +57,7 @@ class E2EShareKeysConfigTest : InstrumentedTest {
|
||||
fun ensureKeysAreNotSharedIfOptionDisabled() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
|
||||
val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
|
||||
aliceSession.cryptoService().enableShareKeyOnInvite(false)
|
||||
aliceSession.cryptoService().isShareKeysOnInviteEnabled() shouldBe false
|
||||
val roomId = aliceSession.roomService().createRoom(CreateRoomParams().apply {
|
||||
historyVisibility = RoomHistoryVisibility.SHARED
|
||||
name = "MyRoom"
|
||||
@ -72,6 +74,13 @@ class E2EShareKeysConfigTest : InstrumentedTest {
|
||||
aliceSession.cryptoService().discardOutboundSession(roomId)
|
||||
val withSession2 = commonTestHelper.sendTextMessage(roomAlice, "World", 1)
|
||||
|
||||
// Check that the session was rotated
|
||||
Assert.assertNotEquals(
|
||||
"Session should have been rotated, because it was discarded",
|
||||
withSession1.first().root.content?.get("session_id")!!,
|
||||
withSession2.first().root.content?.get("session_id")!!
|
||||
)
|
||||
|
||||
// Create bob account
|
||||
val bobSession = commonTestHelper.createAccount(TestConstants.USER_BOB, SessionTestParams(withInitialSync = true))
|
||||
|
||||
@ -92,11 +101,12 @@ class E2EShareKeysConfigTest : InstrumentedTest {
|
||||
|
||||
// Now let's enable history key sharing on alice side
|
||||
aliceSession.cryptoService().enableShareKeyOnInvite(true)
|
||||
aliceSession.cryptoService().isShareKeysOnInviteEnabled() shouldBe true
|
||||
|
||||
// let's add a new message first
|
||||
val afterFlagOn = commonTestHelper.sendTextMessage(roomAlice, "After", 1)
|
||||
|
||||
// Worth nothing to check that the session was rotated
|
||||
// Worth nothing to check that the session was rotated (because Bob's device has left)
|
||||
Assert.assertNotEquals(
|
||||
"Session should have been rotated",
|
||||
withSession2.first().root.content?.get("session_id")!!,
|
||||
|
@ -17,10 +17,11 @@
|
||||
package org.matrix.android.sdk.session.room.timeline
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.MutableRealm
|
||||
import io.realm.kotlin.RealmConfiguration
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@ -28,10 +29,11 @@ import org.junit.runner.RunWith
|
||||
import org.matrix.android.sdk.InstrumentedTest
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.internal.database.RealmInstance
|
||||
import org.matrix.android.sdk.internal.database.helper.addTimelineEvent
|
||||
import org.matrix.android.sdk.internal.database.mapper.toEntity
|
||||
import org.matrix.android.sdk.internal.database.model.ChunkEntity
|
||||
import org.matrix.android.sdk.internal.database.model.SessionRealmModule
|
||||
import org.matrix.android.sdk.internal.database.model.SESSION_REALM_SCHEMA
|
||||
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
|
||||
import org.matrix.android.sdk.internal.util.time.DefaultClock
|
||||
import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeMessageEvent
|
||||
@ -39,29 +41,33 @@ import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeMes
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
internal class ChunkEntityTest : InstrumentedTest {
|
||||
|
||||
private lateinit var monarchy: Monarchy
|
||||
private lateinit var realmInstance: RealmInstance
|
||||
private val clock = DefaultClock()
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Before
|
||||
fun setup() {
|
||||
Realm.init(context())
|
||||
val testConfig = RealmConfiguration.Builder()
|
||||
.inMemory()
|
||||
val testConfig = RealmConfiguration.Builder(SESSION_REALM_SCHEMA)
|
||||
//.inMemory()
|
||||
.name("test-realm")
|
||||
.modules(SessionRealmModule())
|
||||
.build()
|
||||
monarchy = Monarchy.Builder().setRealmConfiguration(testConfig).build()
|
||||
realmInstance = RealmInstance(
|
||||
coroutineScope = TestScope(),
|
||||
realmConfiguration = testConfig,
|
||||
coroutineDispatcher = Main,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun add_shouldAdd_whenNotAlreadyIncluded() {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
val chunk: ChunkEntity = realm.createObject()
|
||||
realmInstance.blockingWrite {
|
||||
val chunk = ChunkEntity()
|
||||
|
||||
val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED, clock.epochMillis()).let {
|
||||
realm.copyToRealm(it)
|
||||
copyToRealm(it)
|
||||
}
|
||||
chunk.addTimelineEvent(
|
||||
realm = this,
|
||||
roomId = ROOM_ID,
|
||||
eventEntity = fakeEvent,
|
||||
direction = PaginationDirection.FORWARDS,
|
||||
@ -73,18 +79,20 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
|
||||
@Test
|
||||
fun add_shouldNotAdd_whenAlreadyIncluded() {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
val chunk: ChunkEntity = realm.createObject()
|
||||
realmInstance.blockingWrite {
|
||||
val chunk = ChunkEntity()
|
||||
val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED, clock.epochMillis()).let {
|
||||
realm.copyToRealm(it)
|
||||
copyToRealm(it)
|
||||
}
|
||||
chunk.addTimelineEvent(
|
||||
realm = this,
|
||||
roomId = ROOM_ID,
|
||||
eventEntity = fakeEvent,
|
||||
direction = PaginationDirection.FORWARDS,
|
||||
roomMemberContentsByUser = emptyMap()
|
||||
)
|
||||
chunk.addTimelineEvent(
|
||||
realm = this,
|
||||
roomId = ROOM_ID,
|
||||
eventEntity = fakeEvent,
|
||||
direction = PaginationDirection.FORWARDS,
|
||||
@ -95,6 +103,7 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
private fun ChunkEntity.addAll(
|
||||
realm: MutableRealm,
|
||||
roomId: String,
|
||||
events: List<Event>,
|
||||
direction: PaginationDirection
|
||||
@ -104,6 +113,7 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
realm.copyToRealm(it)
|
||||
}
|
||||
addTimelineEvent(
|
||||
realm = realm,
|
||||
roomId = roomId,
|
||||
eventEntity = fakeEvent,
|
||||
direction = direction,
|
||||
|
@ -23,7 +23,6 @@ import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.work.Configuration
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkerFactory
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||
import org.matrix.android.sdk.api.auth.HomeServerHistoryService
|
||||
@ -73,7 +72,6 @@ class Matrix(context: Context, matrixConfiguration: MatrixConfiguration) {
|
||||
|
||||
init {
|
||||
val appContext = context.applicationContext
|
||||
Monarchy.init(appContext)
|
||||
DaggerMatrixComponent.factory().create(appContext, matrixConfiguration).inject(this)
|
||||
if (appContext !is Configuration.Provider) {
|
||||
val configuration = Configuration.Builder()
|
||||
|
@ -16,12 +16,15 @@
|
||||
|
||||
package org.matrix.android.sdk.api
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.MainScope
|
||||
import okhttp3.ConnectionSpec
|
||||
import okhttp3.Interceptor
|
||||
import org.matrix.android.sdk.api.crypto.MXCryptoConfig
|
||||
import java.net.Proxy
|
||||
|
||||
data class MatrixConfiguration(
|
||||
val coroutineScope: CoroutineScope = MainScope(),
|
||||
val applicationFlavor: String = "Default-application-flavor",
|
||||
val cryptoConfig: MXCryptoConfig = MXCryptoConfig(),
|
||||
val integrationUIUrl: String = "https://scalar.vector.im/",
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
package org.matrix.android.sdk.api.debug
|
||||
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.RealmConfiguration
|
||||
|
||||
/**
|
||||
* Useful methods to access to some private data managed by the SDK.
|
||||
|
@ -17,7 +17,7 @@
|
||||
package org.matrix.android.sdk.api.session
|
||||
|
||||
import androidx.annotation.MainThread
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.RealmConfiguration
|
||||
import okhttp3.OkHttpClient
|
||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.api.auth.data.SessionParams
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
package org.matrix.android.sdk.api.session.contentscanner
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.matrix.android.sdk.api.session.crypto.attachments.ElementToDecrypt
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
|
||||
@ -24,12 +24,15 @@ interface ContentScannerService {
|
||||
|
||||
val serverPublicKey: String?
|
||||
|
||||
// TODO suspend
|
||||
fun getContentScannerServer(): String?
|
||||
fun setScannerUrl(url: String?)
|
||||
fun enableScanner(enabled: Boolean)
|
||||
suspend fun setScannerUrl(url: String?)
|
||||
suspend fun enableScanner(enabled: Boolean)
|
||||
|
||||
// TODO suspend
|
||||
fun isScannerEnabled(): Boolean
|
||||
fun getLiveStatusForFile(mxcUrl: String, fetchIfNeeded: Boolean = true, fileInfo: ElementToDecrypt? = null): LiveData<Optional<ScanStatusInfo>>
|
||||
fun getCachedScanResultForFile(mxcUrl: String): ScanStatusInfo?
|
||||
fun getLiveStatusForFile(mxcUrl: String, fetchIfNeeded: Boolean = true, fileInfo: ElementToDecrypt? = null): Flow<Optional<ScanStatusInfo>>
|
||||
suspend fun getCachedScanResultForFile(mxcUrl: String): ScanStatusInfo?
|
||||
|
||||
/**
|
||||
* Get the current public curve25519 key that the AV server is advertising.
|
||||
|
@ -32,7 +32,7 @@ interface IdentityService {
|
||||
/**
|
||||
* Return the current identity server URL used by this account. Returns null if no identity server is configured.
|
||||
*/
|
||||
fun getCurrentIdentityServerUrl(): String?
|
||||
suspend fun getCurrentIdentityServerUrl(): String?
|
||||
|
||||
/**
|
||||
* Check if the identity server is valid.
|
||||
@ -105,7 +105,7 @@ interface IdentityService {
|
||||
* @return the value stored using [setUserConsent] or false if [setUserConsent] has never been called, or if the identity server
|
||||
* has been changed
|
||||
*/
|
||||
fun getUserConsent(): Boolean
|
||||
suspend fun getUserConsent(): Boolean
|
||||
|
||||
/**
|
||||
* Set the user consent to the provided value. Application MUST explicitly ask for the user consent to send their private data
|
||||
@ -113,7 +113,7 @@ interface IdentityService {
|
||||
* Please see https://support.google.com/googleplay/android-developer/answer/9888076?hl=en for more details.
|
||||
* @param newValue true if the user explicitly give their consent, false if the user wants to revoke their consent.
|
||||
*/
|
||||
fun setUserConsent(newValue: Boolean)
|
||||
suspend fun setUserConsent(newValue: Boolean)
|
||||
|
||||
/**
|
||||
* Get the status of the current user's threePid.
|
||||
|
@ -20,20 +20,25 @@ import android.content.Context
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.RealmConfiguration
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||
import org.matrix.android.sdk.api.auth.HomeServerHistoryService
|
||||
import org.matrix.android.sdk.api.legacy.LegacySessionImporter
|
||||
import org.matrix.android.sdk.internal.auth.db.AUTH_REALM_SCHEMA
|
||||
import org.matrix.android.sdk.internal.auth.db.AuthRealmMigration
|
||||
import org.matrix.android.sdk.internal.auth.db.AuthRealmModule
|
||||
import org.matrix.android.sdk.internal.auth.db.RealmPendingSessionStore
|
||||
import org.matrix.android.sdk.internal.auth.db.RealmSessionParamsStore
|
||||
import org.matrix.android.sdk.internal.auth.login.DefaultDirectLoginTask
|
||||
import org.matrix.android.sdk.internal.auth.login.DefaultQrLoginTokenTask
|
||||
import org.matrix.android.sdk.internal.auth.login.DirectLoginTask
|
||||
import org.matrix.android.sdk.internal.auth.login.QrLoginTokenTask
|
||||
import org.matrix.android.sdk.internal.database.RealmInstance
|
||||
import org.matrix.android.sdk.internal.database.RealmKeysUtils
|
||||
import org.matrix.android.sdk.internal.di.AuthDatabase
|
||||
import org.matrix.android.sdk.internal.di.MatrixCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.MatrixScope
|
||||
import org.matrix.android.sdk.internal.legacy.DefaultLegacySessionImporter
|
||||
import org.matrix.android.sdk.internal.wellknown.WellknownModule
|
||||
import java.io.File
|
||||
@ -58,16 +63,31 @@ internal abstract class AuthModule {
|
||||
old.renameTo(File(context.filesDir, "matrix-sdk-auth.realm"))
|
||||
}
|
||||
|
||||
return RealmConfiguration.Builder()
|
||||
return RealmConfiguration.Builder(AUTH_REALM_SCHEMA)
|
||||
.apply {
|
||||
realmKeysUtils.configureEncryption(this, DB_ALIAS)
|
||||
}
|
||||
.name("matrix-sdk-auth.realm")
|
||||
.modules(AuthRealmModule())
|
||||
.schemaVersion(authRealmMigration.schemaVersion)
|
||||
.migration(authRealmMigration)
|
||||
.build()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@AuthDatabase
|
||||
@MatrixScope
|
||||
fun providesRealmInstance(
|
||||
@AuthDatabase realmConfiguration: RealmConfiguration,
|
||||
@MatrixCoroutineScope matrixCoroutineScope: CoroutineScope,
|
||||
matrixCoroutineDispatchers: MatrixCoroutineDispatchers
|
||||
): RealmInstance {
|
||||
return RealmInstance(
|
||||
coroutineScope = matrixCoroutineScope,
|
||||
realmConfiguration = realmConfiguration,
|
||||
coroutineDispatcher = matrixCoroutineDispatchers.io
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Binds
|
||||
|
@ -16,35 +16,23 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.auth
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import io.realm.kotlin.where
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.matrix.android.sdk.api.auth.HomeServerHistoryService
|
||||
import org.matrix.android.sdk.internal.database.model.KnownServerUrlEntity
|
||||
import org.matrix.android.sdk.internal.di.GlobalDatabase
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultHomeServerHistoryService @Inject constructor(
|
||||
@GlobalDatabase private val monarchy: Monarchy
|
||||
private val knownServerUrlStore: KnownServerUrlStore
|
||||
) : HomeServerHistoryService {
|
||||
|
||||
override fun getKnownServersUrls(): List<String> {
|
||||
return monarchy.fetchAllMappedSync(
|
||||
{ realm ->
|
||||
realm.where<KnownServerUrlEntity>()
|
||||
},
|
||||
{ it.url }
|
||||
)
|
||||
override fun getKnownServersUrls(): List<String> = runBlocking {
|
||||
knownServerUrlStore.getAll()
|
||||
}
|
||||
|
||||
override fun addHomeServerToHistory(url: String) {
|
||||
monarchy.writeAsync { realm ->
|
||||
KnownServerUrlEntity(url).let {
|
||||
realm.insertOrUpdate(it)
|
||||
}
|
||||
}
|
||||
override fun addHomeServerToHistory(url: String) = runBlocking {
|
||||
knownServerUrlStore.add(url)
|
||||
}
|
||||
|
||||
override fun clearHistory() {
|
||||
monarchy.runTransactionSync { it.where<KnownServerUrlEntity>().findAll().deleteAllFromRealm() }
|
||||
override fun clearHistory() = runBlocking {
|
||||
knownServerUrlStore.deleteAll()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.auth
|
||||
|
||||
import io.realm.kotlin.UpdatePolicy
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.internal.database.RealmInstance
|
||||
import org.matrix.android.sdk.internal.database.await
|
||||
import org.matrix.android.sdk.internal.di.GlobalDatabase
|
||||
import org.matrix.android.sdk.internal.raw.db.model.KnownServerUrlEntity
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class KnownServerUrlStore @Inject constructor(
|
||||
@GlobalDatabase private val realmInstance: RealmInstance,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
) {
|
||||
|
||||
suspend fun getAll(): List<String> = withContext(coroutineDispatchers.io) {
|
||||
val realm = realmInstance.getRealm()
|
||||
realm.query(KnownServerUrlEntity::class)
|
||||
.await()
|
||||
.map { it.url }
|
||||
}
|
||||
|
||||
suspend fun add(url: String) {
|
||||
realmInstance.write {
|
||||
val entity = KnownServerUrlEntity().apply {
|
||||
this.url = url
|
||||
}
|
||||
copyToRealm(entity, updatePolicy = UpdatePolicy.ALL)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun deleteAll() {
|
||||
realmInstance.write {
|
||||
val entities = query(KnownServerUrlEntity::class).find()
|
||||
delete(entities)
|
||||
}
|
||||
}
|
||||
}
|
@ -16,18 +16,18 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.auth.db
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo001
|
||||
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo002
|
||||
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo003
|
||||
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo004
|
||||
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo005
|
||||
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
|
||||
import org.matrix.android.sdk.internal.database.MatrixAutomaticSchemaMigration
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class AuthRealmMigration @Inject constructor() : MatrixRealmMigration(
|
||||
internal class AuthRealmMigration @Inject constructor() : MatrixAutomaticSchemaMigration(
|
||||
dbName = "Auth",
|
||||
schemaVersion = 5L,
|
||||
schemaVersion = 5L
|
||||
) {
|
||||
/**
|
||||
* Forces all AuthRealmMigration instances to be equal.
|
||||
@ -36,11 +36,11 @@ internal class AuthRealmMigration @Inject constructor() : MatrixRealmMigration(
|
||||
override fun equals(other: Any?) = other is AuthRealmMigration
|
||||
override fun hashCode() = 4000
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm, oldVersion: Long) {
|
||||
if (oldVersion < 1) MigrateAuthTo001(realm).perform()
|
||||
if (oldVersion < 2) MigrateAuthTo002(realm).perform()
|
||||
if (oldVersion < 3) MigrateAuthTo003(realm).perform()
|
||||
if (oldVersion < 4) MigrateAuthTo004(realm).perform()
|
||||
if (oldVersion < 5) MigrateAuthTo005(realm).perform()
|
||||
override fun doMigrate(oldVersion: Long, migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
if (oldVersion < 1) MigrateAuthTo001(migrationContext).perform()
|
||||
if (oldVersion < 2) MigrateAuthTo002(migrationContext).perform()
|
||||
if (oldVersion < 3) MigrateAuthTo003(migrationContext).perform()
|
||||
if (oldVersion < 4) MigrateAuthTo004(migrationContext).perform()
|
||||
if (oldVersion < 5) MigrateAuthTo005(migrationContext).perform()
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
* 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.
|
||||
@ -16,16 +16,11 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.auth.db
|
||||
|
||||
import io.realm.annotations.RealmModule
|
||||
|
||||
/**
|
||||
* Realm module for authentication classes.
|
||||
* Please respect the order (alphabetically) to avoid mistake during merge conflict, and avoid duplication.
|
||||
*/
|
||||
@RealmModule(
|
||||
library = true,
|
||||
classes = [
|
||||
SessionParamsEntity::class,
|
||||
PendingSessionEntity::class
|
||||
]
|
||||
internal val AUTH_REALM_SCHEMA = setOf(
|
||||
PendingSessionEntity::class,
|
||||
SessionParamsEntity::class,
|
||||
)
|
||||
internal class AuthRealmModule
|
||||
|
@ -16,14 +16,14 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.auth.db
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
|
||||
internal open class PendingSessionEntity(
|
||||
var homeServerConnectionConfigJson: String = "",
|
||||
var clientSecret: String = "",
|
||||
var sendAttempt: Int = 0,
|
||||
var resetPasswordDataJson: String? = null,
|
||||
var currentSession: String? = null,
|
||||
var isRegistrationStarted: Boolean = false,
|
||||
var currentThreePidDataJson: String? = null
|
||||
) : RealmObject()
|
||||
internal class PendingSessionEntity : RealmObject {
|
||||
var homeServerConnectionConfigJson: String = ""
|
||||
var clientSecret: String = ""
|
||||
var sendAttempt: Int = 0
|
||||
var resetPasswordDataJson: String? = null
|
||||
var currentSession: String? = null
|
||||
var isRegistrationStarted: Boolean = false
|
||||
var currentThreePidDataJson: String? = null
|
||||
}
|
||||
|
@ -57,14 +57,14 @@ internal class PendingSessionMapper @Inject constructor(moshi: Moshi) {
|
||||
val resetPasswordDataJson = resetPasswordDataAdapter.toJson(sessionData.resetPasswordData)
|
||||
val currentThreePidDataJson = threePidDataAdapter.toJson(sessionData.currentThreePidData)
|
||||
|
||||
return PendingSessionEntity(
|
||||
homeServerConnectionConfigJson = homeServerConnectionConfigJson,
|
||||
clientSecret = sessionData.clientSecret,
|
||||
sendAttempt = sessionData.sendAttempt,
|
||||
resetPasswordDataJson = resetPasswordDataJson,
|
||||
currentSession = sessionData.currentSession,
|
||||
isRegistrationStarted = sessionData.isRegistrationStarted,
|
||||
currentThreePidDataJson = currentThreePidDataJson
|
||||
)
|
||||
return PendingSessionEntity().apply {
|
||||
this.homeServerConnectionConfigJson = homeServerConnectionConfigJson
|
||||
this.clientSecret = sessionData.clientSecret
|
||||
this.sendAttempt = sessionData.sendAttempt
|
||||
this.resetPasswordDataJson = resetPasswordDataJson
|
||||
this.currentSession = sessionData.currentSession
|
||||
this.isRegistrationStarted = sessionData.isRegistrationStarted
|
||||
this.currentThreePidDataJson = currentThreePidDataJson
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,47 +16,44 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.auth.db
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.MutableRealm
|
||||
import org.matrix.android.sdk.internal.auth.PendingSessionStore
|
||||
import org.matrix.android.sdk.internal.database.awaitTransaction
|
||||
import org.matrix.android.sdk.internal.database.RealmInstance
|
||||
import org.matrix.android.sdk.internal.di.AuthDatabase
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class RealmPendingSessionStore @Inject constructor(
|
||||
private val mapper: PendingSessionMapper,
|
||||
@AuthDatabase
|
||||
private val realmConfiguration: RealmConfiguration
|
||||
private val realmInstance: RealmInstance,
|
||||
) : PendingSessionStore {
|
||||
|
||||
override suspend fun savePendingSessionData(pendingSessionData: PendingSessionData) {
|
||||
awaitTransaction(realmConfiguration) { realm ->
|
||||
realmInstance.write {
|
||||
val entity = mapper.map(pendingSessionData)
|
||||
if (entity != null) {
|
||||
realm.where(PendingSessionEntity::class.java)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
|
||||
realm.insert(entity)
|
||||
deleteAllPendingSessions()
|
||||
copyToRealm(entity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPendingSessionData(): PendingSessionData? {
|
||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
||||
realm
|
||||
.where(PendingSessionEntity::class.java)
|
||||
.findAll()
|
||||
.map { mapper.map(it) }
|
||||
.firstOrNull()
|
||||
}
|
||||
return realmInstance.getBlockingRealm()
|
||||
.query(PendingSessionEntity::class)
|
||||
.find()
|
||||
.map { mapper.map(it) }
|
||||
.firstOrNull()
|
||||
}
|
||||
|
||||
override suspend fun delete() {
|
||||
awaitTransaction(realmConfiguration) {
|
||||
it.where(PendingSessionEntity::class.java)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
realmInstance.write {
|
||||
deleteAllPendingSessions()
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableRealm.deleteAllPendingSessions() {
|
||||
val pendingSessionEntities = query(PendingSessionEntity::class).find()
|
||||
delete(pendingSessionEntities)
|
||||
}
|
||||
}
|
||||
|
@ -16,14 +16,12 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.auth.db
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.exceptions.RealmPrimaryKeyConstraintException
|
||||
import io.realm.kotlin.UpdatePolicy
|
||||
import org.matrix.android.sdk.api.auth.data.Credentials
|
||||
import org.matrix.android.sdk.api.auth.data.SessionParams
|
||||
import org.matrix.android.sdk.api.auth.data.sessionId
|
||||
import org.matrix.android.sdk.internal.auth.SessionParamsStore
|
||||
import org.matrix.android.sdk.internal.database.awaitTransaction
|
||||
import org.matrix.android.sdk.internal.database.RealmInstance
|
||||
import org.matrix.android.sdk.internal.di.AuthDatabase
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
@ -31,60 +29,49 @@ import javax.inject.Inject
|
||||
internal class RealmSessionParamsStore @Inject constructor(
|
||||
private val mapper: SessionParamsMapper,
|
||||
@AuthDatabase
|
||||
private val realmConfiguration: RealmConfiguration
|
||||
private val realmInstance: RealmInstance
|
||||
) : SessionParamsStore {
|
||||
|
||||
override fun getLast(): SessionParams? {
|
||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
||||
realm
|
||||
.where(SessionParamsEntity::class.java)
|
||||
.findAll()
|
||||
.map { mapper.map(it) }
|
||||
.lastOrNull()
|
||||
}
|
||||
return realmInstance.getBlockingRealm()
|
||||
.query(SessionParamsEntity::class)
|
||||
.find()
|
||||
.map { mapper.map(it) }
|
||||
.lastOrNull()
|
||||
}
|
||||
|
||||
override fun get(sessionId: String): SessionParams? {
|
||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
||||
realm
|
||||
.where(SessionParamsEntity::class.java)
|
||||
.equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
|
||||
.findAll()
|
||||
.map { mapper.map(it) }
|
||||
.firstOrNull()
|
||||
}
|
||||
return realmInstance.getBlockingRealm()
|
||||
.query(SessionParamsEntity::class)
|
||||
.query("sessionId == $0", sessionId)
|
||||
.first()
|
||||
.find()
|
||||
?.let { mapper.map(it) }
|
||||
}
|
||||
|
||||
override fun getAll(): List<SessionParams> {
|
||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
||||
realm
|
||||
.where(SessionParamsEntity::class.java)
|
||||
.findAll()
|
||||
.mapNotNull { mapper.map(it) }
|
||||
}
|
||||
return realmInstance.getBlockingRealm()
|
||||
.query(SessionParamsEntity::class)
|
||||
.find()
|
||||
.mapNotNull { mapper.map(it) }
|
||||
}
|
||||
|
||||
override suspend fun save(sessionParams: SessionParams) {
|
||||
awaitTransaction(realmConfiguration) {
|
||||
realmInstance.write {
|
||||
val entity = mapper.map(sessionParams)
|
||||
if (entity != null) {
|
||||
try {
|
||||
it.insert(entity)
|
||||
} catch (e: RealmPrimaryKeyConstraintException) {
|
||||
Timber.e(e, "Something wrong happened during previous session creation. Override with new credentials")
|
||||
it.insertOrUpdate(entity)
|
||||
}
|
||||
copyToRealm(entity, updatePolicy = UpdatePolicy.ALL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setTokenInvalid(sessionId: String) {
|
||||
awaitTransaction(realmConfiguration) { realm ->
|
||||
val currentSessionParams = realm
|
||||
.where(SessionParamsEntity::class.java)
|
||||
.equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
|
||||
.findAll()
|
||||
.firstOrNull()
|
||||
realmInstance.write {
|
||||
val currentSessionParams =
|
||||
query(SessionParamsEntity::class)
|
||||
.query("sessionId == $0", sessionId)
|
||||
.first()
|
||||
.find()
|
||||
|
||||
if (currentSessionParams == null) {
|
||||
// Should not happen
|
||||
@ -98,13 +85,12 @@ internal class RealmSessionParamsStore @Inject constructor(
|
||||
}
|
||||
|
||||
override suspend fun updateCredentials(newCredentials: Credentials) {
|
||||
awaitTransaction(realmConfiguration) { realm ->
|
||||
val currentSessionParams = realm
|
||||
.where(SessionParamsEntity::class.java)
|
||||
.equalTo(SessionParamsEntityFields.SESSION_ID, newCredentials.sessionId())
|
||||
.findAll()
|
||||
.map { mapper.map(it) }
|
||||
.firstOrNull()
|
||||
realmInstance.write {
|
||||
val currentSessionParams = query(SessionParamsEntity::class)
|
||||
.query("sessionId == $0", newCredentials.sessionId())
|
||||
.first()
|
||||
.find()
|
||||
?.let { mapper.map(it) }
|
||||
|
||||
if (currentSessionParams == null) {
|
||||
// Should not happen
|
||||
@ -119,26 +105,25 @@ internal class RealmSessionParamsStore @Inject constructor(
|
||||
|
||||
val entity = mapper.map(newSessionParams)
|
||||
if (entity != null) {
|
||||
realm.insertOrUpdate(entity)
|
||||
copyToRealm(entity, updatePolicy = UpdatePolicy.ALL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun delete(sessionId: String) {
|
||||
awaitTransaction(realmConfiguration) {
|
||||
it.where(SessionParamsEntity::class.java)
|
||||
.equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
realmInstance.write {
|
||||
val sessionParam = query(SessionParamsEntity::class)
|
||||
.query("sessionId == $0", sessionId)
|
||||
.find()
|
||||
delete(sessionParam)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteAll() {
|
||||
awaitTransaction(realmConfiguration) {
|
||||
it.where(SessionParamsEntity::class.java)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
realmInstance.write {
|
||||
val sessionParam = query(SessionParamsEntity::class).find()
|
||||
delete(sessionParam)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,16 +16,17 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.auth.db
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
|
||||
internal open class SessionParamsEntity(
|
||||
@PrimaryKey var sessionId: String = "",
|
||||
var userId: String = "",
|
||||
var credentialsJson: String = "",
|
||||
var homeServerConnectionConfigJson: String = "",
|
||||
// Set to false when the token is invalid and the user has been soft logged out
|
||||
// In case of hard logout, this object is deleted from DB
|
||||
var isTokenValid: Boolean = true,
|
||||
var loginType: String = "",
|
||||
) : RealmObject()
|
||||
internal class SessionParamsEntity : RealmObject {
|
||||
@PrimaryKey var sessionId: String = ""
|
||||
var userId: String = ""
|
||||
var credentialsJson: String = ""
|
||||
var homeServerConnectionConfigJson: String = ""
|
||||
|
||||
// Set to false when the token is invalid and the user has been soft logged out
|
||||
// In case of hard logout, this object is deleted from DB
|
||||
var isTokenValid: Boolean = true
|
||||
var loginType: String = ""
|
||||
}
|
||||
|
@ -50,13 +50,13 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
|
||||
if (credentialsJson == null || homeServerConnectionConfigJson == null) {
|
||||
return null
|
||||
}
|
||||
return SessionParamsEntity(
|
||||
sessionParams.credentials.sessionId(),
|
||||
sessionParams.userId,
|
||||
credentialsJson,
|
||||
homeServerConnectionConfigJson,
|
||||
sessionParams.isTokenValid,
|
||||
sessionParams.loginType.name,
|
||||
)
|
||||
return SessionParamsEntity().apply {
|
||||
this.sessionId = sessionParams.credentials.sessionId()
|
||||
this.userId = sessionParams.userId
|
||||
this.credentialsJson = credentialsJson
|
||||
this.homeServerConnectionConfigJson = homeServerConnectionConfigJson
|
||||
this.isTokenValid = sessionParams.isTokenValid
|
||||
this.loginType = sessionParams.loginType.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,26 +16,13 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.auth.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.auth.db.PendingSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateAuthTo001(realm: DynamicRealm) : RealmMigrator(realm, 1) {
|
||||
internal class MigrateAuthTo001(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, targetSchemaVersion = 1) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Create PendingSessionEntity")
|
||||
|
||||
realm.schema.create("PendingSessionEntity")
|
||||
.addField(PendingSessionEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, String::class.java)
|
||||
.setRequired(PendingSessionEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, true)
|
||||
.addField(PendingSessionEntityFields.CLIENT_SECRET, String::class.java)
|
||||
.setRequired(PendingSessionEntityFields.CLIENT_SECRET, true)
|
||||
.addField(PendingSessionEntityFields.SEND_ATTEMPT, Integer::class.java)
|
||||
.setRequired(PendingSessionEntityFields.SEND_ATTEMPT, true)
|
||||
.addField(PendingSessionEntityFields.RESET_PASSWORD_DATA_JSON, String::class.java)
|
||||
.addField(PendingSessionEntityFields.CURRENT_SESSION, String::class.java)
|
||||
.addField(PendingSessionEntityFields.IS_REGISTRATION_STARTED, Boolean::class.java)
|
||||
.addField(PendingSessionEntityFields.CURRENT_THREE_PID_DATA_JSON, String::class.java)
|
||||
}
|
||||
}
|
||||
|
@ -16,18 +16,13 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.auth.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateAuthTo002(realm: DynamicRealm) : RealmMigrator(realm, 2) {
|
||||
internal class MigrateAuthTo002(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, targetSchemaVersion = 2) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Add boolean isTokenValid in SessionParamsEntity, with value true")
|
||||
|
||||
realm.schema.get("SessionParamsEntity")
|
||||
?.addField(SessionParamsEntityFields.IS_TOKEN_VALID, Boolean::class.java)
|
||||
?.transform { it.set(SessionParamsEntityFields.IS_TOKEN_VALID, true) }
|
||||
}
|
||||
}
|
||||
|
@ -16,32 +16,24 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.auth.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.api.auth.data.Credentials
|
||||
import org.matrix.android.sdk.api.auth.data.sessionId
|
||||
import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateAuthTo003(realm: DynamicRealm) : RealmMigrator(realm, 3) {
|
||||
internal class MigrateAuthTo003(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, targetSchemaVersion = 3) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Update SessionParamsEntity primary key, to allow several sessions with the same userId")
|
||||
|
||||
realm.schema.get("SessionParamsEntity")
|
||||
?.removePrimaryKey()
|
||||
?.addField(SessionParamsEntityFields.SESSION_ID, String::class.java)
|
||||
?.setRequired(SessionParamsEntityFields.SESSION_ID, true)
|
||||
?.transform {
|
||||
val credentialsJson = it.getString(SessionParamsEntityFields.CREDENTIALS_JSON)
|
||||
|
||||
val credentials = MoshiProvider.providesMoshi()
|
||||
.adapter(Credentials::class.java)
|
||||
.fromJson(credentialsJson)
|
||||
|
||||
it.set(SessionParamsEntityFields.SESSION_ID, credentials!!.sessionId())
|
||||
}
|
||||
?.addPrimaryKey(SessionParamsEntityFields.SESSION_ID)
|
||||
val credentialsAdapter = MoshiProvider.providesMoshi()
|
||||
.adapter(Credentials::class.java)
|
||||
migrationContext.enumerate("SessionParamsEntity") { oldObject, newObject ->
|
||||
val credentialsJson = oldObject.getValue("credentialsJson", String::class)
|
||||
val credentials = credentialsAdapter.fromJson(credentialsJson)
|
||||
newObject?.set("sessionId", credentials!!.sessionId())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,41 +17,38 @@
|
||||
package org.matrix.android.sdk.internal.auth.db.migration
|
||||
|
||||
import android.net.Uri
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||
import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateAuthTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) {
|
||||
internal class MigrateAuthTo004(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, targetSchemaVersion = 4) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Update SessionParamsEntity to add HomeServerConnectionConfig.homeServerUriBase value")
|
||||
|
||||
val adapter = MoshiProvider.providesMoshi()
|
||||
.adapter(HomeServerConnectionConfig::class.java)
|
||||
|
||||
realm.schema.get("SessionParamsEntity")
|
||||
?.transform {
|
||||
val homeserverConnectionConfigJson = it.getString(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON)
|
||||
migrationContext.enumerate("SessionParamsEntity") { oldObj, newObj ->
|
||||
val homeserverConnectionConfigJson = oldObj.getValue("homeServerConnectionConfigJson", String::class)
|
||||
val homeserverConnectionConfig = adapter
|
||||
.fromJson(homeserverConnectionConfigJson)
|
||||
val homeserverUrl = homeserverConnectionConfig?.homeServerUri?.toString()
|
||||
|
||||
val homeserverConnectionConfig = adapter
|
||||
.fromJson(homeserverConnectionConfigJson)
|
||||
|
||||
val homeserverUrl = homeserverConnectionConfig?.homeServerUri?.toString()
|
||||
// Special case for matrix.org. Old session may use "https://matrix.org", newer one may use
|
||||
// "https://matrix-client.matrix.org". So fix that here
|
||||
val alteredHomeserverConnectionConfig =
|
||||
if (homeserverUrl == "https://matrix.org" || homeserverUrl == "https://matrix-client.matrix.org") {
|
||||
homeserverConnectionConfig.copy(
|
||||
homeServerUri = Uri.parse("https://matrix.org"),
|
||||
homeServerUriBase = Uri.parse("https://matrix-client.matrix.org")
|
||||
)
|
||||
} else {
|
||||
homeserverConnectionConfig
|
||||
}
|
||||
it.set(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, adapter.toJson(alteredHomeserverConnectionConfig))
|
||||
}
|
||||
// Special case for matrix.org. Old session may use "https://matrix.org", newer one may use
|
||||
// "https://matrix-client.matrix.org". So fix that here
|
||||
val alteredHomeserverConnectionConfig =
|
||||
if (homeserverUrl == "https://matrix.org" || homeserverUrl == "https://matrix-client.matrix.org") {
|
||||
homeserverConnectionConfig.copy(
|
||||
homeServerUri = Uri.parse("https://matrix.org"),
|
||||
homeServerUriBase = Uri.parse("https://matrix-client.matrix.org")
|
||||
)
|
||||
} else {
|
||||
homeserverConnectionConfig
|
||||
}
|
||||
newObj?.set("homeServerConnectionConfigJson", adapter.toJson(alteredHomeserverConnectionConfig))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,20 +16,17 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.auth.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.api.auth.LoginType
|
||||
import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateAuthTo005(realm: DynamicRealm) : RealmMigrator(realm, 5) {
|
||||
internal class MigrateAuthTo005(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, targetSchemaVersion = 5) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Update SessionParamsEntity to add LoginType")
|
||||
|
||||
realm.schema.get("SessionParamsEntity")
|
||||
?.addField(SessionParamsEntityFields.LOGIN_TYPE, String::class.java)
|
||||
?.setRequired(SessionParamsEntityFields.LOGIN_TYPE, true)
|
||||
?.transform { it.set(SessionParamsEntityFields.LOGIN_TYPE, LoginType.UNKNOWN.name) }
|
||||
migrationContext.enumerate("SessionParamsEntity") { _, newObj ->
|
||||
newObj?.set("loginType", LoginType.UNKNOWN.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,9 @@ package org.matrix.android.sdk.internal.crypto
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.RealmConfiguration
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.api.session.crypto.CryptoService
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
|
||||
import org.matrix.android.sdk.internal.crypto.api.CryptoApi
|
||||
@ -58,9 +58,9 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreRoomSessions
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.CRYPTO_REALM_SCHEMA
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore
|
||||
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.tasks.ClaimOneTimeKeysForUsersDeviceTask
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.DefaultClaimOneTimeKeysForUsersDevice
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.DefaultDeleteDeviceTask
|
||||
@ -89,13 +89,15 @@ import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.UploadSignaturesTask
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.UploadSigningKeysTask
|
||||
import org.matrix.android.sdk.internal.database.RealmInstance
|
||||
import org.matrix.android.sdk.internal.database.RealmKeysUtils
|
||||
import org.matrix.android.sdk.internal.di.CryptoDatabase
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.SessionFilesDirectory
|
||||
import org.matrix.android.sdk.internal.di.UserMd5
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.session.cache.ClearCacheTask
|
||||
import org.matrix.android.sdk.internal.session.cache.RealmClearCacheTask
|
||||
import org.matrix.android.sdk.internal.session.cache.RealmKotlinClearCacheTask
|
||||
import retrofit2.Retrofit
|
||||
import java.io.File
|
||||
|
||||
@ -109,21 +111,18 @@ internal abstract class CryptoModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@CryptoDatabase
|
||||
@SessionScope
|
||||
fun providesRealmConfiguration(
|
||||
fun providesKotlinRealmConfiguration(
|
||||
@SessionFilesDirectory directory: File,
|
||||
@UserMd5 userMd5: String,
|
||||
realmKeysUtils: RealmKeysUtils,
|
||||
realmCryptoStoreMigration: RealmCryptoStoreMigration
|
||||
): RealmConfiguration {
|
||||
return RealmConfiguration.Builder()
|
||||
.directory(directory)
|
||||
return RealmConfiguration.Builder(CRYPTO_REALM_SCHEMA)
|
||||
.directory(directory.path)
|
||||
.apply {
|
||||
realmKeysUtils.configureEncryption(this, getKeyAlias(userMd5))
|
||||
}
|
||||
.name("crypto_store.realm")
|
||||
.modules(RealmCryptoStoreModule())
|
||||
.allowWritesOnUiThread(true)
|
||||
.schemaVersion(realmCryptoStoreMigration.schemaVersion)
|
||||
.migration(realmCryptoStoreMigration)
|
||||
.build()
|
||||
@ -131,16 +130,25 @@ internal abstract class CryptoModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@CryptoDatabase
|
||||
@SessionScope
|
||||
fun providesCryptoCoroutineScope(): CoroutineScope {
|
||||
return CoroutineScope(SupervisorJob())
|
||||
fun providesRealmInstance(
|
||||
@CryptoDatabase realmConfiguration: RealmConfiguration,
|
||||
@SessionCoroutineScope coroutineScope: CoroutineScope,
|
||||
matrixCoroutineDispatchers: MatrixCoroutineDispatchers
|
||||
): RealmInstance {
|
||||
return RealmInstance(
|
||||
coroutineScope = coroutineScope,
|
||||
realmConfiguration = realmConfiguration,
|
||||
coroutineDispatcher = matrixCoroutineDispatchers.io
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@CryptoDatabase
|
||||
fun providesClearCacheTask(@CryptoDatabase realmConfiguration: RealmConfiguration): ClearCacheTask {
|
||||
return RealmClearCacheTask(realmConfiguration)
|
||||
fun providesClearCacheTask(@CryptoDatabase realmInstance: RealmInstance): ClearCacheTask {
|
||||
return RealmKotlinClearCacheTask(realmInstance)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -16,14 +16,12 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.internal.database.RealmInstance
|
||||
import org.matrix.android.sdk.internal.database.model.EventEntity
|
||||
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
||||
import org.matrix.android.sdk.internal.database.query.whereType
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
|
||||
import org.matrix.android.sdk.internal.util.fetchCopied
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
@ -31,18 +29,17 @@ import javax.inject.Inject
|
||||
* in the session DB, this class encapsulate this functionality.
|
||||
*/
|
||||
internal class CryptoSessionInfoProvider @Inject constructor(
|
||||
@SessionDatabase private val monarchy: Monarchy
|
||||
@SessionDatabase private val realmInstance: RealmInstance,
|
||||
) {
|
||||
|
||||
fun isRoomEncrypted(roomId: String): Boolean {
|
||||
// We look at the presence at any m.room.encryption state event no matter if it's
|
||||
// the latest one or if it is well formed
|
||||
val encryptionEvent = monarchy.fetchCopied { realm ->
|
||||
EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION)
|
||||
.isEmpty(EventEntityFields.STATE_KEY)
|
||||
.findFirst()
|
||||
}
|
||||
return encryptionEvent != null
|
||||
val realm = realmInstance.getBlockingRealm()
|
||||
return EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION)
|
||||
.query("stateKey == ''")
|
||||
.first()
|
||||
.find() != null
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,14 +47,11 @@ internal class CryptoSessionInfoProvider @Inject constructor(
|
||||
* @param allActive if true return joined as well as invited, if false, only joined
|
||||
*/
|
||||
fun getRoomUserIds(roomId: String, allActive: Boolean): List<String> {
|
||||
var userIds: List<String> = emptyList()
|
||||
monarchy.doWithRealm { realm ->
|
||||
userIds = if (allActive) {
|
||||
RoomMemberHelper(realm, roomId).getActiveRoomMemberIds()
|
||||
} else {
|
||||
RoomMemberHelper(realm, roomId).getJoinedRoomMemberIds()
|
||||
}
|
||||
val realm = realmInstance.getBlockingRealm()
|
||||
return if (allActive) {
|
||||
RoomMemberHelper(realm, roomId).getActiveRoomMemberIds()
|
||||
} else {
|
||||
RoomMemberHelper(realm, roomId).getJoinedRoomMemberIds()
|
||||
}
|
||||
return userIds
|
||||
}
|
||||
}
|
||||
|
@ -22,9 +22,7 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.paging.PagedList
|
||||
import com.squareup.moshi.Types
|
||||
import dagger.Lazy
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.cancelChildren
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -98,6 +96,7 @@ import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationSe
|
||||
import org.matrix.android.sdk.internal.crypto.verification.VerificationMessageProcessor
|
||||
import org.matrix.android.sdk.internal.di.DeviceId
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.extensions.foldToCallback
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
@ -182,7 +181,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
private val cryptoSessionInfoProvider: CryptoSessionInfoProvider,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val cryptoCoroutineScope: CoroutineScope,
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||
private val eventDecryptor: EventDecryptor,
|
||||
private val verificationMessageProcessor: VerificationMessageProcessor,
|
||||
private val liveEventManager: Lazy<StreamEventsManager>,
|
||||
@ -213,7 +212,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
// handle verification
|
||||
if (!isInitialSync) {
|
||||
if (event.type != null && verificationMessageProcessor.shouldProcess(event.type)) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.dmVerif) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.dmVerif) {
|
||||
verificationMessageProcessor.process(event)
|
||||
}
|
||||
}
|
||||
@ -329,19 +328,19 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
*
|
||||
*/
|
||||
fun start() {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
internalStart()
|
||||
}
|
||||
// Just update
|
||||
fetchDevicesList(NoOpMatrixCallback())
|
||||
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
cryptoStore.tidyUpDataBase()
|
||||
}
|
||||
}
|
||||
|
||||
fun ensureDevice() {
|
||||
cryptoCoroutineScope.launchToCallback(coroutineDispatchers.crypto, NoOpMatrixCallback()) {
|
||||
sessionCoroutineScope.launchToCallback(coroutineDispatchers.crypto, NoOpMatrixCallback()) {
|
||||
// Open the store
|
||||
cryptoStore.open()
|
||||
|
||||
@ -364,7 +363,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
}
|
||||
|
||||
fun onSyncWillProcess(isInitialSync: Boolean) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
if (isInitialSync) {
|
||||
try {
|
||||
// On initial sync, we start all our tracking from
|
||||
@ -399,7 +398,6 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
* Close the crypto.
|
||||
*/
|
||||
fun close() = runBlocking(coroutineDispatchers.crypto) {
|
||||
cryptoCoroutineScope.coroutineContext.cancelChildren(CancellationException("Closing crypto module"))
|
||||
incomingKeyRequestManager.close()
|
||||
outgoingKeyRequestManager.close()
|
||||
unrequestedForwardManager.close()
|
||||
@ -428,7 +426,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
* @param syncResponse the syncResponse
|
||||
*/
|
||||
fun onSyncCompleted(syncResponse: SyncResponse) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
runCatching {
|
||||
if (syncResponse.deviceLists != null) {
|
||||
deviceListManager.handleDeviceListsChanges(syncResponse.deviceLists.changed, syncResponse.deviceLists.left)
|
||||
@ -491,7 +489,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
}
|
||||
|
||||
unrequestedForwardManager.postSyncProcessParkedKeysIfNeeded(clock.epochMillis()) { events ->
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
events.forEach {
|
||||
onRoomKeyEvent(it, true)
|
||||
}
|
||||
@ -723,7 +721,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
callback: MatrixCallback<MXEncryptEventContentResult>
|
||||
) {
|
||||
// moved to crypto scope to have uptodate values
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
val userIds = getRoomUserIds(roomId)
|
||||
var alg = roomEncryptorsStore.get(roomId)
|
||||
if (alg == null) {
|
||||
@ -756,7 +754,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
}
|
||||
|
||||
override fun discardOutboundSession(roomId: String) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
val roomEncryptor = roomEncryptorsStore.get(roomId)
|
||||
if (roomEncryptor is IMXGroupEncryption) {
|
||||
roomEncryptor.discardSessionKey()
|
||||
@ -817,7 +815,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
*/
|
||||
fun onToDeviceEvent(event: Event) {
|
||||
// event have already been decrypted
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
when (event.getClearType()) {
|
||||
EventType.ROOM_KEY, EventType.FORWARDED_ROOM_KEY -> {
|
||||
// Keys are imported directly, not waiting for end of sync
|
||||
@ -945,7 +943,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
Timber.tag(loggerTag.value).w("Invalid encryption event")
|
||||
return
|
||||
}
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
val userIds = getRoomUserIds(roomId)
|
||||
setEncryptionInRoom(roomId, event.content?.get("algorithm")?.toString(), true, userIds)
|
||||
}
|
||||
@ -1119,7 +1117,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
*/
|
||||
fun checkUnknownDevices(userIds: List<String>, callback: MatrixCallback<Unit>) {
|
||||
// force the refresh to ensure that the devices list is up-to-date
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
runCatching {
|
||||
val keys = deviceListManager.downloadKeys(userIds, true)
|
||||
val unknownDevices = getUnknownDevices(keys)
|
||||
@ -1265,7 +1263,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
}
|
||||
|
||||
override fun downloadKeys(userIds: List<String>, forceDownload: Boolean, callback: MatrixCallback<MXUsersDevicesMap<CryptoDeviceInfo>>) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
runCatching {
|
||||
deviceListManager.downloadKeys(userIds, forceDownload)
|
||||
}.foldToCallback(callback)
|
||||
@ -1334,7 +1332,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
}
|
||||
|
||||
override fun prepareToEncrypt(roomId: String, callback: MatrixCallback<Unit>) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
Timber.tag(loggerTag.value).d("prepareToEncrypt() roomId:$roomId Check room members up to date")
|
||||
// Ensure to load all room members
|
||||
try {
|
||||
|
@ -37,6 +37,7 @@ import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevice
|
||||
import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.extensions.foldToCallback
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
@ -49,7 +50,7 @@ private val loggerTag = LoggerTag("EventDecryptor", LoggerTag.CRYPTO)
|
||||
|
||||
@SessionScope
|
||||
internal class EventDecryptor @Inject constructor(
|
||||
private val cryptoCoroutineScope: CoroutineScope,
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val clock: Clock,
|
||||
private val roomDecryptorProvider: RoomDecryptorProvider,
|
||||
@ -94,7 +95,7 @@ internal class EventDecryptor @Inject constructor(
|
||||
*/
|
||||
fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult>) {
|
||||
// is it needed to do that on the crypto scope??
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
runCatching {
|
||||
internalDecryptEvent(event, timeline)
|
||||
}.foldToCallback(callback)
|
||||
|
@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -40,7 +41,7 @@ private val loggerTag = LoggerTag("InboundGroupSessionStore", LoggerTag.CRYPTO)
|
||||
*/
|
||||
internal class InboundGroupSessionStore @Inject constructor(
|
||||
private val store: IMXCryptoStore,
|
||||
private val cryptoCoroutineScope: CoroutineScope,
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers
|
||||
) {
|
||||
|
||||
@ -52,7 +53,7 @@ internal class InboundGroupSessionStore @Inject constructor(
|
||||
private val sessionCache = object : LruCache<CacheKey, InboundGroupSessionHolder>(100) {
|
||||
override fun entryRemoved(evicted: Boolean, key: CacheKey?, oldValue: InboundGroupSessionHolder?, newValue: InboundGroupSessionHolder?) {
|
||||
if (oldValue != null) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
Timber.tag(loggerTag.value).v("## Inbound: entryRemoved ${oldValue.wrapper.roomId}-${oldValue.wrapper.senderKey}")
|
||||
// store.storeInboundGroupSessions(listOf(oldValue).map { it.wrapper })
|
||||
oldValue.wrapper.session.releaseSession()
|
||||
@ -119,7 +120,7 @@ internal class InboundGroupSessionStore @Inject constructor(
|
||||
// If it's already known, no need to update cache it's already there
|
||||
sessionCache.put(CacheKey(sessionId, senderKey), holder)
|
||||
}
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
store.storeInboundGroupSessions(listOf(holder.wrapper))
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,7 @@
|
||||
package org.matrix.android.sdk.internal.crypto
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -42,6 +40,7 @@ import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevice
|
||||
import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.task.SemaphoreCoroutineSequencer
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
@ -63,10 +62,11 @@ internal class IncomingKeyRequestManager @Inject constructor(
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val sendToDeviceTask: SendToDeviceTask,
|
||||
private val clock: Clock,
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||
) {
|
||||
|
||||
private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
|
||||
private val outgoingRequestScope = CoroutineScope(SupervisorJob() + dispatcher)
|
||||
private val outgoingRequestScope = CoroutineScope(sessionCoroutineScope.coroutineContext + dispatcher)
|
||||
val sequencer = SemaphoreCoroutineSequencer()
|
||||
|
||||
private val incomingRequestBuffer = mutableListOf<ValidMegolmRequestBody>()
|
||||
@ -456,7 +456,6 @@ internal class IncomingKeyRequestManager @Inject constructor(
|
||||
|
||||
fun close() {
|
||||
try {
|
||||
outgoingRequestScope.cancel("User Terminate")
|
||||
incomingRequestBuffer.clear()
|
||||
} catch (failure: Throwable) {
|
||||
Timber.tag(loggerTag.value).w("Failed to shutDown request manager")
|
||||
|
@ -17,9 +17,7 @@
|
||||
package org.matrix.android.sdk.internal.crypto
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -42,6 +40,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.util.fromBase64
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.SessionId
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
@ -71,11 +70,12 @@ internal class OutgoingKeyRequestManager @Inject constructor(
|
||||
private val inboundGroupSessionStore: InboundGroupSessionStore,
|
||||
private val sendToDeviceTask: SendToDeviceTask,
|
||||
private val deviceListManager: DeviceListManager,
|
||||
private val perSessionBackupQueryRateLimiter: PerSessionBackupQueryRateLimiter
|
||||
private val perSessionBackupQueryRateLimiter: PerSessionBackupQueryRateLimiter,
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||
) {
|
||||
|
||||
private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
|
||||
private val outgoingRequestScope = CoroutineScope(SupervisorJob() + dispatcher)
|
||||
private val outgoingRequestScope = CoroutineScope(sessionCoroutineScope.coroutineContext + dispatcher)
|
||||
private val sequencer = SemaphoreCoroutineSequencer()
|
||||
|
||||
// We only have one active key request per session, so we don't request if it's already requested
|
||||
@ -330,7 +330,6 @@ internal class OutgoingKeyRequestManager @Inject constructor(
|
||||
|
||||
fun close() {
|
||||
try {
|
||||
outgoingRequestScope.cancel("User Terminate")
|
||||
requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup.clear()
|
||||
} catch (failure: Throwable) {
|
||||
Timber.tag(loggerTag.value).w("Failed to shutDown request manager")
|
||||
|
@ -42,6 +42,7 @@ import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.createUniqueTxnId
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
import timber.log.Timber
|
||||
@ -53,7 +54,7 @@ private val loggerTag = LoggerTag("SecretShareManager", LoggerTag.CRYPTO)
|
||||
internal class SecretShareManager @Inject constructor(
|
||||
private val credentials: Credentials,
|
||||
private val cryptoStore: IMXCryptoStore,
|
||||
private val cryptoCoroutineScope: CoroutineScope,
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||
private val messageEncrypter: MessageEncrypter,
|
||||
private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
|
||||
private val sendToDeviceTask: SendToDeviceTask,
|
||||
@ -100,7 +101,7 @@ internal class SecretShareManager @Inject constructor(
|
||||
*/
|
||||
fun onVerificationCompleteForDevice(deviceId: String) {
|
||||
// For now we just keep an in memory cache
|
||||
cryptoCoroutineScope.launch {
|
||||
sessionCoroutineScope.launch {
|
||||
verifMutex.withLock {
|
||||
recentlyVerifiedDevices[deviceId] = clock.epochMillis()
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ import org.matrix.android.sdk.internal.crypto.model.toDebugString
|
||||
import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.util.JsonCanonicalizer
|
||||
import org.matrix.android.sdk.internal.util.convertToUTF8
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
@ -67,7 +68,7 @@ internal class MXMegolmEncryption(
|
||||
private val messageEncrypter: MessageEncrypter,
|
||||
private val warnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val cryptoCoroutineScope: CoroutineScope,
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||
private val clock: Clock,
|
||||
) : IMXEncrypting, IMXGroupEncryption {
|
||||
|
||||
@ -127,7 +128,7 @@ internal class MXMegolmEncryption(
|
||||
|
||||
private fun notifyWithheldForSession(devices: MXUsersDevicesMap<WithHeldCode>, outboundSession: MXOutboundSessionInfo) {
|
||||
// offload to computation thread
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.computation) {
|
||||
mutableListOf<Pair<UserDevice, WithHeldCode>>().apply {
|
||||
devices.forEach { userId, deviceId, withheldCode ->
|
||||
this.add(UserDevice(userId, deviceId) to withheldCode)
|
||||
|
@ -27,6 +27,7 @@ import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepo
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
|
||||
import org.matrix.android.sdk.internal.di.DeviceId
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
import javax.inject.Inject
|
||||
@ -43,7 +44,7 @@ internal class MXMegolmEncryptionFactory @Inject constructor(
|
||||
private val messageEncrypter: MessageEncrypter,
|
||||
private val warnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val cryptoCoroutineScope: CoroutineScope,
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||
private val clock: Clock,
|
||||
) {
|
||||
|
||||
@ -61,7 +62,7 @@ internal class MXMegolmEncryptionFactory @Inject constructor(
|
||||
messageEncrypter = messageEncrypter,
|
||||
warnOnUnknownDevicesRepository = warnOnUnknownDevicesRepository,
|
||||
coroutineDispatchers = coroutineDispatchers,
|
||||
cryptoCoroutineScope = cryptoCoroutineScope,
|
||||
sessionCoroutineScope = sessionCoroutineScope,
|
||||
clock = clock,
|
||||
)
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ import org.matrix.android.sdk.internal.crypto.model.rest.UploadSignatureQueryBui
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.InitializeCrossSigningTask
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.UploadSignaturesTask
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.SessionId
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.di.WorkManagerProvider
|
||||
@ -68,7 +69,7 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
private val uploadSignaturesTask: UploadSignaturesTask,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val cryptoCoroutineScope: CoroutineScope,
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||
private val workManagerProvider: WorkManagerProvider,
|
||||
private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
|
||||
private val crossSigningOlm: CrossSigningOlm,
|
||||
@ -556,7 +557,7 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
}
|
||||
|
||||
override fun trustUser(otherUserId: String, callback: MatrixCallback<Unit>) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
Timber.d("## CrossSigning - Mark user $otherUserId as trusted ")
|
||||
// We should have this user keys
|
||||
val otherMasterKeys = getUserCrossSigningKeys(otherUserId)?.masterKey()
|
||||
@ -608,7 +609,7 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
}
|
||||
|
||||
override fun markMyMasterKeyAsTrusted() {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
cryptoStore.markMyMasterKeyAsLocallyTrusted(true)
|
||||
checkSelfTrust()
|
||||
// re-verify all trusts
|
||||
@ -617,7 +618,7 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
}
|
||||
|
||||
override fun trustDevice(deviceId: String, callback: MatrixCallback<Unit>) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
// This device should be yours
|
||||
val device = cryptoStore.getUserDevice(myUserId, deviceId)
|
||||
if (device == null) {
|
||||
|
@ -19,9 +19,8 @@ package org.matrix.android.sdk.internal.crypto.crosssigning
|
||||
import android.content.Context
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.where
|
||||
import io.realm.kotlin.MutableRealm
|
||||
import io.realm.kotlin.TypedRealm
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.UserTrustResult
|
||||
@ -32,17 +31,16 @@ import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
|
||||
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.database.awaitTransaction
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.query.crossSigningInfoEntityQueries
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.query.userEntityQueries
|
||||
import org.matrix.android.sdk.internal.database.RealmInstance
|
||||
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
|
||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||
import org.matrix.android.sdk.internal.database.query.where
|
||||
import org.matrix.android.sdk.internal.database.queryIn
|
||||
import org.matrix.android.sdk.internal.di.CryptoDatabase
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
@ -72,10 +70,10 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
|
||||
// It breaks the crypto store contract, but we need to batch things :/
|
||||
@CryptoDatabase
|
||||
@Inject lateinit var cryptoRealmConfiguration: RealmConfiguration
|
||||
@Inject lateinit var cryptoRealmInstance: RealmInstance
|
||||
|
||||
@SessionDatabase
|
||||
@Inject lateinit var sessionRealmConfiguration: RealmConfiguration
|
||||
@Inject lateinit var sessionRealmInstance: RealmInstance
|
||||
|
||||
@UserId
|
||||
@Inject lateinit var myUserId: String
|
||||
@ -113,11 +111,10 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
|
||||
// First we check that the users MSK are trusted by mine
|
||||
// After that we check the trust chain for each devices of each users
|
||||
awaitTransaction(cryptoRealmConfiguration) { cryptoRealm ->
|
||||
cryptoRealmInstance.write {
|
||||
// By mapping here to model, this object is not live
|
||||
// I should update it if needed
|
||||
myCrossSigningInfo = getCrossSigningInfo(cryptoRealm, myUserId)
|
||||
|
||||
myCrossSigningInfo = getCrossSigningInfo(myUserId)
|
||||
var myTrustResult: UserTrustResult? = null
|
||||
|
||||
if (userList.contains(myUserId)) {
|
||||
@ -125,25 +122,25 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
// i am in the list.. but i don't know exactly the delta of change :/
|
||||
// If it's my cross signing keys we should refresh all trust
|
||||
// do it anyway ?
|
||||
userList = cryptoRealm.where(CrossSigningInfoEntity::class.java)
|
||||
.findAll()
|
||||
userList = query(CrossSigningInfoEntity::class)
|
||||
.find()
|
||||
.mapNotNull { it.userId }
|
||||
|
||||
// check right now my keys and mark it as trusted as other trust depends on it
|
||||
val myDevices = cryptoRealm.where<UserEntity>()
|
||||
.equalTo(UserEntityFields.USER_ID, myUserId)
|
||||
.findFirst()
|
||||
val myDevices = query(UserEntity::class, "userId == $0", myUserId)
|
||||
.first()
|
||||
.find()
|
||||
?.devices
|
||||
?.map { CryptoMapper.mapToModel(it) }
|
||||
|
||||
myTrustResult = crossSigningService.checkSelfTrust(myCrossSigningInfo, myDevices)
|
||||
updateCrossSigningKeysTrust(cryptoRealm, myUserId, myTrustResult.isVerified())
|
||||
updateCrossSigningKeysTrust(myUserId, myTrustResult.isVerified())
|
||||
// update model reference
|
||||
myCrossSigningInfo = getCrossSigningInfo(cryptoRealm, myUserId)
|
||||
myCrossSigningInfo = getCrossSigningInfo(myUserId)
|
||||
}
|
||||
|
||||
val otherInfos = userList.associateWith { userId ->
|
||||
getCrossSigningInfo(cryptoRealm, userId)
|
||||
getCrossSigningInfo(userId)
|
||||
}
|
||||
|
||||
val trusts = otherInfos.mapValues { entry ->
|
||||
@ -162,20 +159,20 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
trusts.forEach {
|
||||
val verified = it.value?.isVerified() == true
|
||||
Timber.v("[$myUserId] ## CrossSigning - Updating user trust: ${it.key} to $verified")
|
||||
updateCrossSigningKeysTrust(cryptoRealm, it.key, verified)
|
||||
updateCrossSigningKeysTrust(it.key, verified)
|
||||
}
|
||||
|
||||
// Ok so now we have to check device trust for all these users..
|
||||
Timber.v("## CrossSigning - Updating devices cross trust users: ${trusts.keys.logLimit()}")
|
||||
trusts.keys.forEach { userId ->
|
||||
val devicesEntities = cryptoRealm.where<UserEntity>()
|
||||
.equalTo(UserEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
val devicesEntities = query(UserEntity::class, "userId == $0", userId)
|
||||
.first()
|
||||
.find()
|
||||
?.devices
|
||||
|
||||
val trustMap = devicesEntities?.associateWith { device ->
|
||||
// get up to date from DB has could have been updated
|
||||
val otherInfo = getCrossSigningInfo(cryptoRealm, userId)
|
||||
val otherInfo = getCrossSigningInfo(userId)
|
||||
crossSigningService.checkDeviceTrust(myCrossSigningInfo, otherInfo, CryptoMapper.mapToModel(device))
|
||||
}
|
||||
|
||||
@ -188,7 +185,7 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
// need to save
|
||||
val trustEntity = device.trustLevelEntity
|
||||
if (trustEntity == null) {
|
||||
device.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also {
|
||||
device.trustLevelEntity = TrustLevelEntity().also {
|
||||
it.locallyVerified = false
|
||||
it.crossSignedVerified = crossSignedVerified
|
||||
}
|
||||
@ -199,7 +196,6 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// So Cross Signing keys trust is updated, device trust is updated
|
||||
// We can now update room shields? in the session DB?
|
||||
updateTrustStep2(userList, myCrossSigningInfo)
|
||||
@ -207,48 +203,50 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
|
||||
private suspend fun updateTrustStep2(userList: List<String>, myCrossSigningInfo: MXCrossSigningInfo?) {
|
||||
Timber.d("## CrossSigning - Updating shields for impacted rooms...")
|
||||
awaitTransaction(sessionRealmConfiguration) { sessionRealm ->
|
||||
sessionRealmInstance.write {
|
||||
Timber.d("## CrossSigning - Updating shields for impacted rooms - in transaction")
|
||||
Realm.getInstance(cryptoRealmConfiguration).use { cryptoRealm ->
|
||||
sessionRealm.where(RoomMemberSummaryEntity::class.java)
|
||||
.`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray())
|
||||
.distinct(RoomMemberSummaryEntityFields.ROOM_ID)
|
||||
.findAll()
|
||||
.map { it.roomId }
|
||||
.also { Timber.d("## CrossSigning - ... impacted rooms ${it.logLimit()}") }
|
||||
.forEach { roomId ->
|
||||
RoomSummaryEntity.where(sessionRealm, roomId)
|
||||
.equalTo(RoomSummaryEntityFields.IS_ENCRYPTED, true)
|
||||
.findFirst()
|
||||
?.let { roomSummary ->
|
||||
Timber.v("## CrossSigning - Check shield state for room $roomId")
|
||||
val allActiveRoomMembers = RoomMemberHelper(sessionRealm, roomId).getActiveRoomMemberIds()
|
||||
try {
|
||||
val updatedTrust = computeRoomShield(
|
||||
myCrossSigningInfo,
|
||||
cryptoRealm,
|
||||
allActiveRoomMembers,
|
||||
roomSummary
|
||||
)
|
||||
if (roomSummary.roomEncryptionTrustLevel != updatedTrust) {
|
||||
Timber.d("## CrossSigning - Shield change detected for $roomId -> $updatedTrust")
|
||||
roomSummary.roomEncryptionTrustLevel = updatedTrust
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure)
|
||||
val cryptoRealm = cryptoRealmInstance.getBlockingRealm()
|
||||
query(RoomMemberSummaryEntity::class)
|
||||
.queryIn("userId", userList)
|
||||
.distinct("roomId")
|
||||
.find()
|
||||
.map { it.roomId }
|
||||
.also { Timber.d("## CrossSigning - ... impacted rooms ${it.logLimit()}") }
|
||||
.forEach { roomId ->
|
||||
RoomSummaryEntity.where(this, roomId)
|
||||
.query("isEncrypted == true")
|
||||
.first()
|
||||
.find()
|
||||
?.let { roomSummary ->
|
||||
Timber.v("## CrossSigning - Check shield state for room $roomId")
|
||||
val allActiveRoomMembers = RoomMemberHelper(this, roomId).getActiveRoomMemberIds()
|
||||
try {
|
||||
val updatedTrust = computeRoomShield(
|
||||
myCrossSigningInfo,
|
||||
cryptoRealm,
|
||||
allActiveRoomMembers,
|
||||
roomSummary
|
||||
)
|
||||
if (roomSummary.roomEncryptionTrustLevel != updatedTrust) {
|
||||
Timber.d("## CrossSigning - Shield change detected for $roomId -> $updatedTrust")
|
||||
roomSummary.roomEncryptionTrustLevel = updatedTrust
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Timber.d("## CrossSigning - Updating shields for impacted rooms - END")
|
||||
}
|
||||
|
||||
private fun getCrossSigningInfo(cryptoRealm: Realm, userId: String): MXCrossSigningInfo? {
|
||||
return cryptoRealm.where(CrossSigningInfoEntity::class.java)
|
||||
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
?.let { mapCrossSigningInfoEntity(it) }
|
||||
private fun TypedRealm.getCrossSigningInfo(userId: String): MXCrossSigningInfo? {
|
||||
return crossSigningInfoEntityQueries()
|
||||
.firstUserId(userId)
|
||||
.find()
|
||||
?.let {
|
||||
mapCrossSigningInfoEntity(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanup(params: Params) {
|
||||
@ -256,10 +254,10 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
?.let { updateTrustWorkerDataRepository.delete(it) }
|
||||
}
|
||||
|
||||
private fun updateCrossSigningKeysTrust(cryptoRealm: Realm, userId: String, verified: Boolean) {
|
||||
cryptoRealm.where(CrossSigningInfoEntity::class.java)
|
||||
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
private fun MutableRealm.updateCrossSigningKeysTrust(userId: String, verified: Boolean) {
|
||||
crossSigningInfoEntityQueries()
|
||||
.firstUserId(userId)
|
||||
.find()
|
||||
?.let { userKeyInfo ->
|
||||
userKeyInfo
|
||||
.crossSigningKeys
|
||||
@ -269,7 +267,7 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
Timber.d("## CrossSigning - Trust change for $userId : $verified")
|
||||
val level = key.trustLevelEntity
|
||||
if (level == null) {
|
||||
key.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also {
|
||||
key.trustLevelEntity = TrustLevelEntity().also {
|
||||
it.locallyVerified = verified
|
||||
it.crossSignedVerified = verified
|
||||
}
|
||||
@ -287,7 +285,7 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
|
||||
private fun computeRoomShield(
|
||||
myCrossSigningInfo: MXCrossSigningInfo?,
|
||||
cryptoRealm: Realm,
|
||||
cryptoRealm: TypedRealm,
|
||||
activeMemberUserIds: List<String>,
|
||||
roomSummaryEntity: RoomSummaryEntity
|
||||
): RoomEncryptionTrustLevel {
|
||||
@ -303,12 +301,12 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
|
||||
val allTrustedUserIds = listToCheck
|
||||
.filter { userId ->
|
||||
getCrossSigningInfo(cryptoRealm, userId)?.isTrusted() == true
|
||||
cryptoRealm.getCrossSigningInfo(userId)?.isTrusted() == true
|
||||
}
|
||||
|
||||
val resetTrust = listToCheck
|
||||
.filter { userId ->
|
||||
val crossSigningInfo = getCrossSigningInfo(cryptoRealm, userId)
|
||||
val crossSigningInfo = cryptoRealm.getCrossSigningInfo(userId)
|
||||
crossSigningInfo?.isTrusted() != true && crossSigningInfo?.wasTrustedOnce == true
|
||||
}
|
||||
|
||||
@ -324,9 +322,9 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||
// else -> black
|
||||
allTrustedUserIds
|
||||
.mapNotNull { userId ->
|
||||
cryptoRealm.where<UserEntity>()
|
||||
.equalTo(UserEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
cryptoRealm.userEntityQueries()
|
||||
.firstUserId(userId)
|
||||
.find()
|
||||
?.devices
|
||||
?.map { CryptoMapper.mapToModel(it) }
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrappe
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.extensions.foldToCallback
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
@ -124,7 +125,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
private val matrixConfiguration: MatrixConfiguration,
|
||||
private val inboundGroupSessionStore: InboundGroupSessionStore,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val cryptoCoroutineScope: CoroutineScope
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope
|
||||
) : KeysBackupService {
|
||||
|
||||
private val uiHandler = Handler(Looper.getMainLooper())
|
||||
@ -161,7 +162,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
progressListener: ProgressListener?,
|
||||
callback: MatrixCallback<MegolmBackupCreationInfo>
|
||||
) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
try {
|
||||
val olmPkDecryption = OlmPkDecryption()
|
||||
val signalableMegolmBackupAuthData = if (password != null) {
|
||||
@ -251,7 +252,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
this.callback = object : MatrixCallback<KeysVersion> {
|
||||
override fun onSuccess(data: KeysVersion) {
|
||||
// Reset backup markers.
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
// move tx out of UI thread
|
||||
cryptoStore.resetBackupMarkers()
|
||||
}
|
||||
@ -280,7 +281,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
}
|
||||
|
||||
override fun deleteBackup(version: String, callback: MatrixCallback<Unit>?) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
// If we're currently backing up to this backup... stop.
|
||||
// (We start using it automatically in createKeysBackupVersion so this is symmetrical).
|
||||
if (keysBackupVersion != null && version == keysBackupVersion?.version) {
|
||||
@ -528,7 +529,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
callback.onFailure(IllegalArgumentException("Missing element"))
|
||||
}
|
||||
} else {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
val updateKeysBackupVersionBody = withContext(coroutineDispatchers.crypto) {
|
||||
// Get current signatures, or create an empty set
|
||||
val myUserSignatures = authData.signatures?.get(userId).orEmpty().toMutableMap()
|
||||
@ -605,7 +606,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
) {
|
||||
Timber.v("trustKeysBackupVersionWithRecoveryKey: version ${keysBackupVersion.version}")
|
||||
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
val isValid = isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)
|
||||
|
||||
if (!isValid) {
|
||||
@ -626,7 +627,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
) {
|
||||
Timber.v("trustKeysBackupVersionWithPassphrase: version ${keysBackupVersion.version}")
|
||||
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
val recoveryKey = recoveryKeyFromPassword(password, keysBackupVersion, null)
|
||||
|
||||
if (recoveryKey == null) {
|
||||
@ -644,7 +645,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
fun onSecretKeyGossip(secret: String) {
|
||||
Timber.i("## CrossSigning - onSecretKeyGossip")
|
||||
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
try {
|
||||
val keysBackupVersion = getKeysBackupLastVersionTask.execute(Unit).toKeysVersionResult()
|
||||
?: return@launch Unit.also {
|
||||
@ -723,7 +724,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
) {
|
||||
Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}")
|
||||
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
runCatching {
|
||||
val decryption = withContext(coroutineDispatchers.computation) {
|
||||
// Check if the recovery is valid before going any further
|
||||
@ -824,7 +825,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
) {
|
||||
Timber.v("[MXKeyBackup] restoreKeyBackup with password: From backup version: ${keysBackupVersion.version}")
|
||||
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.io) {
|
||||
runCatching {
|
||||
val progressListener = if (stepProgressListener != null) {
|
||||
object : ProgressListener {
|
||||
@ -940,7 +941,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
// new key is sent
|
||||
val delayInMs = Random.nextLong(KEY_BACKUP_WAITING_TIME_TO_SEND_KEY_BACKUP_MILLIS)
|
||||
|
||||
cryptoCoroutineScope.launch {
|
||||
sessionCoroutineScope.launch {
|
||||
delay(delayInMs)
|
||||
uiHandler.post { backupKeys() }
|
||||
}
|
||||
@ -1186,7 +1187,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
override fun isValidRecoveryKeyForCurrentVersion(recoveryKey: String, callback: MatrixCallback<Boolean>) {
|
||||
val safeKeysBackupVersion = keysBackupVersion ?: return Unit.also { callback.onSuccess(false) }
|
||||
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.main) {
|
||||
isValidRecoveryKeyForKeysBackupVersion(recoveryKey, safeKeysBackupVersion).let {
|
||||
callback.onSuccess(it)
|
||||
}
|
||||
@ -1213,7 +1214,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
|
||||
if (retrievedMegolmBackupAuthData != null) {
|
||||
keysBackupVersion = keysVersionResult
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
cryptoStore.setKeyBackupVersion(keysVersionResult.version)
|
||||
}
|
||||
|
||||
@ -1304,7 +1305,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
|
||||
keysBackupStateManager.state = KeysBackupState.BackingUp
|
||||
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.main) {
|
||||
withContext(coroutineDispatchers.crypto) {
|
||||
Timber.v("backupKeys: 2 - Encrypting keys")
|
||||
|
||||
|
@ -45,6 +45,7 @@ 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.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.olm.OlmPkMessage
|
||||
import java.security.SecureRandom
|
||||
@ -60,7 +61,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
|
||||
private val accountDataService: SessionAccountDataService,
|
||||
private val secretShareManager: SecretShareManager,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val cryptoCoroutineScope: CoroutineScope
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope
|
||||
) : SharedSecretStorageService {
|
||||
|
||||
override suspend fun generateKey(
|
||||
@ -69,7 +70,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
|
||||
keyName: String,
|
||||
keySigner: KeySigner?
|
||||
): SsssKeyCreationInfo {
|
||||
return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
|
||||
return withContext(sessionCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
|
||||
val bytes = (key as? RawBytesKeySpec)?.privateKey
|
||||
?: ByteArray(32).also {
|
||||
SecureRandom().nextBytes(it)
|
||||
@ -104,7 +105,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
|
||||
keySigner: KeySigner,
|
||||
progressListener: ProgressListener?
|
||||
): SsssKeyCreationInfo {
|
||||
return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
|
||||
return withContext(sessionCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
|
||||
val privatePart = generatePrivateKeyWithPassword(passphrase, progressListener)
|
||||
|
||||
val storageKeyContent = SecretStorageKeyContent(
|
||||
@ -163,7 +164,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
|
||||
}
|
||||
|
||||
override suspend fun storeSecret(name: String, secretBase64: String, keys: List<KeyRef>) {
|
||||
withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
|
||||
withContext(sessionCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
|
||||
val encryptedContents = HashMap<String, EncryptedSecretContent>()
|
||||
keys.forEach {
|
||||
val keyId = it.keyId
|
||||
@ -323,7 +324,7 @@ 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
|
||||
return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
|
||||
return withContext(sessionCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
|
||||
// decrypt from recovery key
|
||||
withOlmDecryption { olmPkDecryption ->
|
||||
olmPkDecryption.setPrivateKey(keySpec.privateKey)
|
||||
@ -338,7 +339,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
|
||||
}
|
||||
} else if (SSSS_ALGORITHM_AES_HMAC_SHA2 == algorithm.algorithm) {
|
||||
val keySpec = secretKey as? RawBytesKeySpec ?: throw SharedSecretStorageError.BadKeyFormat
|
||||
return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
|
||||
return withContext(sessionCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
|
||||
decryptAesHmacSha2(keySpec, name, secretContent)
|
||||
}
|
||||
} else {
|
||||
|
@ -17,56 +17,11 @@
|
||||
package org.matrix.android.sdk.internal.crypto.store.db
|
||||
|
||||
import android.util.Base64
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.RealmObject
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.ObjectOutputStream
|
||||
import java.util.zip.GZIPInputStream
|
||||
import java.util.zip.GZIPOutputStream
|
||||
|
||||
/**
|
||||
* Get realm, invoke the action, close realm, and return the result of the action.
|
||||
*/
|
||||
internal fun <T> doWithRealm(realmConfiguration: RealmConfiguration, action: (Realm) -> T): T {
|
||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
||||
action.invoke(realm)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get realm, do the query, copy from realm, close realm, and return the copied result.
|
||||
*/
|
||||
internal fun <T : RealmObject> doRealmQueryAndCopy(realmConfiguration: RealmConfiguration, action: (Realm) -> T?): T? {
|
||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
||||
action.invoke(realm)?.let { realm.copyFromRealm(it) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get realm, do the list query, copy from realm, close realm, and return the copied result.
|
||||
*/
|
||||
internal fun <T : RealmObject> doRealmQueryAndCopyList(realmConfiguration: RealmConfiguration, action: (Realm) -> Iterable<T>): Iterable<T> {
|
||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
||||
action.invoke(realm).let { realm.copyFromRealm(it) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get realm instance, invoke the action in a transaction and close realm.
|
||||
*/
|
||||
internal fun doRealmTransaction(realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) {
|
||||
Realm.getInstance(realmConfiguration).use { realm ->
|
||||
realm.executeTransaction { action.invoke(it) }
|
||||
}
|
||||
}
|
||||
|
||||
internal fun doRealmTransactionAsync(realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) {
|
||||
Realm.getInstance(realmConfiguration).use { realm ->
|
||||
realm.executeTransactionAsync { action.invoke(it) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize any Serializable object, zip it and convert to Base64 String.
|
||||
*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,7 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo001Legacy
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo002Legacy
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo003RiotX
|
||||
@ -37,7 +37,8 @@ import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo
|
||||
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.util.database.MatrixRealmMigration
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo021
|
||||
import org.matrix.android.sdk.internal.database.MatrixAutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -49,37 +50,39 @@ import javax.inject.Inject
|
||||
*/
|
||||
internal class RealmCryptoStoreMigration @Inject constructor(
|
||||
private val clock: Clock,
|
||||
) : MatrixRealmMigration(
|
||||
) : MatrixAutomaticSchemaMigration(
|
||||
dbName = "Crypto",
|
||||
schemaVersion = 20L,
|
||||
schemaVersion = 21L,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Forces all RealmCryptoStoreMigration instances to be equal.
|
||||
* Avoids Realm throwing when multiple instances of the migration are set.
|
||||
* Avoids migrationContext throwing when multiple instances of the migration are set.
|
||||
*/
|
||||
override fun equals(other: Any?) = other is RealmCryptoStoreMigration
|
||||
override fun hashCode() = 5000
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm, oldVersion: Long) {
|
||||
if (oldVersion < 1) MigrateCryptoTo001Legacy(realm).perform()
|
||||
if (oldVersion < 2) MigrateCryptoTo002Legacy(realm).perform()
|
||||
if (oldVersion < 3) MigrateCryptoTo003RiotX(realm).perform()
|
||||
if (oldVersion < 4) MigrateCryptoTo004(realm).perform()
|
||||
if (oldVersion < 5) MigrateCryptoTo005(realm).perform()
|
||||
if (oldVersion < 6) MigrateCryptoTo006(realm).perform()
|
||||
if (oldVersion < 7) MigrateCryptoTo007(realm).perform()
|
||||
if (oldVersion < 8) MigrateCryptoTo008(realm, clock).perform()
|
||||
if (oldVersion < 9) MigrateCryptoTo009(realm).perform()
|
||||
if (oldVersion < 10) MigrateCryptoTo010(realm).perform()
|
||||
if (oldVersion < 11) MigrateCryptoTo011(realm).perform()
|
||||
if (oldVersion < 12) MigrateCryptoTo012(realm).perform()
|
||||
if (oldVersion < 13) MigrateCryptoTo013(realm).perform()
|
||||
if (oldVersion < 14) MigrateCryptoTo014(realm).perform()
|
||||
if (oldVersion < 15) MigrateCryptoTo015(realm).perform()
|
||||
if (oldVersion < 16) MigrateCryptoTo016(realm).perform()
|
||||
if (oldVersion < 17) MigrateCryptoTo017(realm).perform()
|
||||
if (oldVersion < 18) MigrateCryptoTo018(realm).perform()
|
||||
if (oldVersion < 19) MigrateCryptoTo019(realm).perform()
|
||||
if (oldVersion < 20) MigrateCryptoTo020(realm).perform()
|
||||
override fun doMigrate(oldVersion: Long, migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
if (oldVersion < 1) MigrateCryptoTo001Legacy(migrationContext).perform()
|
||||
if (oldVersion < 2) MigrateCryptoTo002Legacy(migrationContext).perform()
|
||||
if (oldVersion < 3) MigrateCryptoTo003RiotX(migrationContext).perform()
|
||||
if (oldVersion < 4) MigrateCryptoTo004(migrationContext).perform()
|
||||
if (oldVersion < 5) MigrateCryptoTo005(migrationContext).perform()
|
||||
if (oldVersion < 6) MigrateCryptoTo006(migrationContext).perform()
|
||||
if (oldVersion < 7) MigrateCryptoTo007(migrationContext).perform()
|
||||
if (oldVersion < 8) MigrateCryptoTo008(migrationContext, clock).perform()
|
||||
if (oldVersion < 9) MigrateCryptoTo009(migrationContext).perform()
|
||||
if (oldVersion < 10) MigrateCryptoTo010(migrationContext).perform()
|
||||
if (oldVersion < 11) MigrateCryptoTo011(migrationContext).perform()
|
||||
if (oldVersion < 12) MigrateCryptoTo012(migrationContext).perform()
|
||||
if (oldVersion < 13) MigrateCryptoTo013(migrationContext).perform()
|
||||
if (oldVersion < 14) MigrateCryptoTo014(migrationContext).perform()
|
||||
if (oldVersion < 15) MigrateCryptoTo015(migrationContext).perform()
|
||||
if (oldVersion < 16) MigrateCryptoTo016(migrationContext).perform()
|
||||
if (oldVersion < 17) MigrateCryptoTo017(migrationContext).perform()
|
||||
if (oldVersion < 18) MigrateCryptoTo018(migrationContext).perform()
|
||||
if (oldVersion < 19) MigrateCryptoTo019(migrationContext).perform()
|
||||
if (oldVersion < 20) MigrateCryptoTo020(migrationContext).perform()
|
||||
if (oldVersion < 21) MigrateCryptoTo021(migrationContext).perform()
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db
|
||||
|
||||
import io.realm.annotations.RealmModule
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity
|
||||
@ -37,27 +36,24 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEnti
|
||||
|
||||
/**
|
||||
* Realm module for Crypto store classes.
|
||||
* Please respect the order (alphabetically) to avoid mistake during merge conflict, and avoid duplication.
|
||||
*/
|
||||
@RealmModule(
|
||||
library = true,
|
||||
classes = [
|
||||
CryptoMetadataEntity::class,
|
||||
CryptoRoomEntity::class,
|
||||
DeviceInfoEntity::class,
|
||||
KeysBackupDataEntity::class,
|
||||
OlmInboundGroupSessionEntity::class,
|
||||
OlmSessionEntity::class,
|
||||
UserEntity::class,
|
||||
KeyInfoEntity::class,
|
||||
CrossSigningInfoEntity::class,
|
||||
TrustLevelEntity::class,
|
||||
AuditTrailEntity::class,
|
||||
OutgoingKeyRequestEntity::class,
|
||||
KeyRequestReplyEntity::class,
|
||||
MyDeviceLastSeenInfoEntity::class,
|
||||
WithHeldSessionEntity::class,
|
||||
SharedSessionEntity::class,
|
||||
OutboundGroupSessionInfoEntity::class
|
||||
]
|
||||
internal val CRYPTO_REALM_SCHEMA = setOf(
|
||||
AuditTrailEntity::class,
|
||||
CrossSigningInfoEntity::class,
|
||||
CryptoMetadataEntity::class,
|
||||
CryptoRoomEntity::class,
|
||||
DeviceInfoEntity::class,
|
||||
KeyInfoEntity::class,
|
||||
KeyRequestReplyEntity::class,
|
||||
KeysBackupDataEntity::class,
|
||||
MyDeviceLastSeenInfoEntity::class,
|
||||
OlmInboundGroupSessionEntity::class,
|
||||
OlmSessionEntity::class,
|
||||
OutboundGroupSessionInfoEntity::class,
|
||||
OutgoingKeyRequestEntity::class,
|
||||
SharedSessionEntity::class,
|
||||
TrustLevelEntity::class,
|
||||
UserEntity::class,
|
||||
WithHeldSessionEntity::class,
|
||||
)
|
||||
internal class RealmCryptoStoreModule
|
||||
|
@ -18,7 +18,7 @@ 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 io.realm.kotlin.ext.realmListOf
|
||||
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
|
||||
@ -37,9 +37,10 @@ internal class CrossSigningKeysMapper @Inject constructor(moshi: Moshi) {
|
||||
|
||||
fun update(keyInfo: KeyInfoEntity, cryptoCrossSigningKey: CryptoCrossSigningKey) {
|
||||
// update signatures?
|
||||
val usages = cryptoCrossSigningKey.usages ?: emptyList()
|
||||
keyInfo.signatures = serializeSignatures(cryptoCrossSigningKey.signatures)
|
||||
keyInfo.usages = cryptoCrossSigningKey.usages?.toTypedArray()?.let { RealmList(*it) }
|
||||
?: RealmList()
|
||||
keyInfo.usages = realmListOf()
|
||||
keyInfo.usages.addAll(usages)
|
||||
}
|
||||
|
||||
fun map(userId: String?, keyInfo: KeyInfoEntity?): CryptoCrossSigningKey? {
|
||||
@ -59,13 +60,15 @@ internal class CrossSigningKeysMapper @Inject constructor(moshi: Moshi) {
|
||||
}
|
||||
|
||||
fun map(keyInfo: CryptoCrossSigningKey): KeyInfoEntity {
|
||||
val usages = keyInfo.usages ?: emptyList()
|
||||
return KeyInfoEntity().apply {
|
||||
publicKeyBase64 = keyInfo.unpaddedBase64PublicKey
|
||||
usages = keyInfo.usages?.let { RealmList(*it.toTypedArray()) } ?: RealmList()
|
||||
signatures = serializeSignatures(keyInfo.signatures)
|
||||
this.publicKeyBase64 = keyInfo.unpaddedBase64PublicKey
|
||||
this.usages = realmListOf()
|
||||
this.usages.addAll(usages)
|
||||
this.signatures = serializeSignatures(keyInfo.signatures)
|
||||
// TODO how to handle better, check if same keys?
|
||||
// reset trust
|
||||
trustLevelEntity = null
|
||||
this.trustLevelEntity = null
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,12 +33,12 @@ internal class MyDeviceLastSeenInfoEntityMapper @Inject constructor() {
|
||||
}
|
||||
|
||||
fun map(deviceInfo: DeviceInfo): MyDeviceLastSeenInfoEntity {
|
||||
return MyDeviceLastSeenInfoEntity(
|
||||
deviceId = deviceInfo.deviceId,
|
||||
lastSeenIp = deviceInfo.lastSeenIp,
|
||||
lastSeenTs = deviceInfo.lastSeenTs,
|
||||
displayName = deviceInfo.displayName,
|
||||
lastSeenUserAgent = deviceInfo.getBestLastSeenUserAgent(),
|
||||
)
|
||||
return MyDeviceLastSeenInfoEntity().apply {
|
||||
deviceId = deviceInfo.deviceId
|
||||
lastSeenIp = deviceInfo.lastSeenIp
|
||||
lastSeenTs = deviceInfo.lastSeenTs
|
||||
displayName = deviceInfo.displayName
|
||||
lastSeenUserAgent = deviceInfo.getBestLastSeenUserAgent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,20 +16,13 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateCryptoTo001Legacy(realm: DynamicRealm) : RealmMigrator(realm, 1) {
|
||||
internal class MigrateCryptoTo001Legacy(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 1) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Add field lastReceivedMessageTs (Long) and set the value to 0")
|
||||
|
||||
realm.schema.get("OlmSessionEntity")
|
||||
?.addField(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, Long::class.java)
|
||||
?.transform {
|
||||
it.setLong(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,71 +16,15 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateCryptoTo002Legacy(realm: DynamicRealm) : RealmMigrator(realm, 2) {
|
||||
internal class MigrateCryptoTo002Legacy(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 2) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Update IncomingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields")
|
||||
realm.schema.get("IncomingRoomKeyRequestEntity")
|
||||
?.addFieldIfNotExists("requestBodyAlgorithm", String::class.java)
|
||||
?.addFieldIfNotExists("requestBodyRoomId", String::class.java)
|
||||
?.addFieldIfNotExists("requestBodySenderKey", String::class.java)
|
||||
?.addFieldIfNotExists("requestBodySessionId", String::class.java)
|
||||
?.transform { dynamicObject ->
|
||||
try {
|
||||
val requestBodyString = dynamicObject.getString("requestBodyString")
|
||||
// It was a map before
|
||||
val map: Map<String, String>? = deserializeFromRealm(requestBodyString)
|
||||
|
||||
map?.let {
|
||||
dynamicObject.setString("requestBodyAlgorithm", it["algorithm"])
|
||||
dynamicObject.setString("requestBodyRoomId", it["room_id"])
|
||||
dynamicObject.setString("requestBodySenderKey", it["sender_key"])
|
||||
dynamicObject.setString("requestBodySessionId", it["session_id"])
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error")
|
||||
}
|
||||
}
|
||||
?.removeFieldIfExists("requestBodyString")
|
||||
|
||||
Timber.d("Update IncomingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields")
|
||||
realm.schema.get("OutgoingRoomKeyRequestEntity")
|
||||
?.addFieldIfNotExists("requestBodyAlgorithm", String::class.java)
|
||||
?.addFieldIfNotExists("requestBodyRoomId", String::class.java)
|
||||
?.addFieldIfNotExists("requestBodySenderKey", String::class.java)
|
||||
?.addFieldIfNotExists("requestBodySessionId", String::class.java)
|
||||
?.transform { dynamicObject ->
|
||||
try {
|
||||
val requestBodyString = dynamicObject.getString("requestBodyString")
|
||||
// It was a map before
|
||||
val map: Map<String, String>? = deserializeFromRealm(requestBodyString)
|
||||
|
||||
map?.let {
|
||||
dynamicObject.setString("requestBodyAlgorithm", it["algorithm"])
|
||||
dynamicObject.setString("requestBodyRoomId", it["room_id"])
|
||||
dynamicObject.setString("requestBodySenderKey", it["sender_key"])
|
||||
dynamicObject.setString("requestBodySessionId", it["session_id"])
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error")
|
||||
}
|
||||
}
|
||||
?.removeFieldIfExists("requestBodyString")
|
||||
|
||||
Timber.d("Update OutgoingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields")
|
||||
Timber.d("Create KeysBackupDataEntity")
|
||||
if (!realm.schema.contains("KeysBackupDataEntity")) {
|
||||
realm.schema.create("KeysBackupDataEntity")
|
||||
.addField(KeysBackupDataEntityFields.PRIMARY_KEY, Integer::class.java)
|
||||
.addPrimaryKey(KeysBackupDataEntityFields.PRIMARY_KEY)
|
||||
.setRequired(KeysBackupDataEntityFields.PRIMARY_KEY, true)
|
||||
.addField(KeysBackupDataEntityFields.BACKUP_LAST_SERVER_HASH, String::class.java)
|
||||
.addField(KeysBackupDataEntityFields.BACKUP_LAST_SERVER_NUMBER_OF_KEYS, Integer::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,68 +16,61 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import org.matrix.android.sdk.internal.database.safeEnumerate
|
||||
import org.matrix.androidsdk.crypto.data.MXDeviceInfo
|
||||
import org.matrix.androidsdk.crypto.data.MXOlmInboundGroupSession2
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateCryptoTo003RiotX(realm: DynamicRealm) : RealmMigrator(realm, 3) {
|
||||
internal class MigrateCryptoTo003RiotX(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 3) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Migrate to RiotX model")
|
||||
realm.schema.get("CryptoRoomEntity")
|
||||
?.addFieldIfNotExists(CryptoRoomEntityFields.SHOULD_ENCRYPT_FOR_INVITED_MEMBERS, Boolean::class.java)
|
||||
?.setRequiredIfNotAlready(CryptoRoomEntityFields.SHOULD_ENCRYPT_FOR_INVITED_MEMBERS, false)
|
||||
|
||||
// Convert format of MXDeviceInfo, package has to be the same.
|
||||
realm.schema.get("DeviceInfoEntity")
|
||||
?.transform { obj ->
|
||||
try {
|
||||
val oldSerializedData = obj.getString("deviceInfoData")
|
||||
deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { legacyMxDeviceInfo ->
|
||||
val newMxDeviceInfo = org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo(
|
||||
deviceId = legacyMxDeviceInfo.deviceId,
|
||||
userId = legacyMxDeviceInfo.userId,
|
||||
algorithms = legacyMxDeviceInfo.algorithms,
|
||||
keys = legacyMxDeviceInfo.keys,
|
||||
signatures = legacyMxDeviceInfo.signatures,
|
||||
unsigned = legacyMxDeviceInfo.unsigned,
|
||||
verified = legacyMxDeviceInfo.mVerified
|
||||
)
|
||||
|
||||
obj.setString("deviceInfoData", serializeForRealm(newMxDeviceInfo))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error")
|
||||
}
|
||||
migrationContext.safeEnumerate("DeviceInfoEntity") { oldObject, newObject ->
|
||||
try {
|
||||
val oldSerializedData = oldObject.getNullableValue("deviceInfoData", String::class)
|
||||
deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { legacyMxDeviceInfo ->
|
||||
val newMxDeviceInfo = org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo(
|
||||
deviceId = legacyMxDeviceInfo.deviceId,
|
||||
userId = legacyMxDeviceInfo.userId,
|
||||
algorithms = legacyMxDeviceInfo.algorithms,
|
||||
keys = legacyMxDeviceInfo.keys,
|
||||
signatures = legacyMxDeviceInfo.signatures,
|
||||
unsigned = legacyMxDeviceInfo.unsigned,
|
||||
verified = legacyMxDeviceInfo.mVerified
|
||||
)
|
||||
newObject?.set("deviceInfoData", serializeForRealm(newMxDeviceInfo))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error")
|
||||
}
|
||||
}
|
||||
|
||||
// Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper
|
||||
realm.schema.get("OlmInboundGroupSessionEntity")
|
||||
?.transform { obj ->
|
||||
try {
|
||||
val oldSerializedData = obj.getString("olmInboundGroupSessionData")
|
||||
deserializeFromRealm<MXOlmInboundGroupSession2>(oldSerializedData)?.let { mxOlmInboundGroupSession2 ->
|
||||
val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier()
|
||||
val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false)
|
||||
.apply {
|
||||
olmInboundGroupSession = mxOlmInboundGroupSession2.mSession
|
||||
roomId = mxOlmInboundGroupSession2.mRoomId
|
||||
senderKey = mxOlmInboundGroupSession2.mSenderKey
|
||||
keysClaimed = mxOlmInboundGroupSession2.mKeysClaimed
|
||||
forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain
|
||||
}
|
||||
migrationContext.enumerate("OlmInboundGroupSessionEntity") { oldObject, newObject ->
|
||||
try {
|
||||
val oldSerializedData = oldObject.getNullableValue("olmInboundGroupSessionData", String::class)
|
||||
deserializeFromRealm<MXOlmInboundGroupSession2>(oldSerializedData)?.let { mxOlmInboundGroupSession2 ->
|
||||
val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier()
|
||||
val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false)
|
||||
.apply {
|
||||
olmInboundGroupSession = mxOlmInboundGroupSession2.mSession
|
||||
roomId = mxOlmInboundGroupSession2.mRoomId
|
||||
senderKey = mxOlmInboundGroupSession2.mSenderKey
|
||||
keysClaimed = mxOlmInboundGroupSession2.mKeysClaimed
|
||||
forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain
|
||||
}
|
||||
|
||||
obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error")
|
||||
}
|
||||
newObject?.set("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,58 +18,28 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import org.matrix.android.sdk.internal.database.safeEnumerate
|
||||
import org.matrix.android.sdk.internal.di.SerializeNulls
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
// Version 4L added Cross Signing info persistence
|
||||
internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) {
|
||||
internal class MigrateCryptoTo004(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 4) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
if (realm.schema.contains("TrustLevelEntity")) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
if (migrationContext.oldRealm.schema()["TrustLevelEntity"] != null) {
|
||||
Timber.d("Skipping Step 3 -> 4 because entities already exist")
|
||||
return
|
||||
}
|
||||
|
||||
Timber.d("Create KeyInfoEntity")
|
||||
val trustLevelEntityEntitySchema = realm.schema.create("TrustLevelEntity")
|
||||
.addField(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, Boolean::class.java)
|
||||
.setNullable(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, true)
|
||||
.addField(TrustLevelEntityFields.LOCALLY_VERIFIED, Boolean::class.java)
|
||||
.setNullable(TrustLevelEntityFields.LOCALLY_VERIFIED, true)
|
||||
|
||||
val keyInfoEntitySchema = realm.schema.create("KeyInfoEntity")
|
||||
.addField(KeyInfoEntityFields.PUBLIC_KEY_BASE64, String::class.java)
|
||||
.addField(KeyInfoEntityFields.SIGNATURES, String::class.java)
|
||||
.addRealmListField(KeyInfoEntityFields.USAGES.`$`, String::class.java)
|
||||
.addRealmObjectField(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelEntityEntitySchema)
|
||||
|
||||
Timber.d("Create CrossSigningInfoEntity")
|
||||
|
||||
val crossSigningInfoSchema = realm.schema.create("CrossSigningInfoEntity")
|
||||
.addField(CrossSigningInfoEntityFields.USER_ID, String::class.java)
|
||||
.addPrimaryKey(CrossSigningInfoEntityFields.USER_ID)
|
||||
.addRealmListField(CrossSigningInfoEntityFields.CROSS_SIGNING_KEYS.`$`, keyInfoEntitySchema)
|
||||
|
||||
Timber.d("Updating UserEntity table")
|
||||
realm.schema.get("UserEntity")
|
||||
?.addRealmObjectField(UserEntityFields.CROSS_SIGNING_INFO_ENTITY.`$`, crossSigningInfoSchema)
|
||||
|
||||
Timber.d("Updating CryptoMetadataEntity table")
|
||||
realm.schema.get("CryptoMetadataEntity")
|
||||
?.addField(CryptoMetadataEntityFields.X_SIGN_MASTER_PRIVATE_KEY, String::class.java)
|
||||
?.addField(CryptoMetadataEntityFields.X_SIGN_USER_PRIVATE_KEY, String::class.java)
|
||||
?.addField(CryptoMetadataEntityFields.X_SIGN_SELF_SIGNED_PRIVATE_KEY, String::class.java)
|
||||
|
||||
val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build()
|
||||
val listMigrationAdapter = moshi.adapter<List<String>>(
|
||||
@ -87,57 +57,45 @@ internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4)
|
||||
)
|
||||
)
|
||||
|
||||
realm.schema.get("DeviceInfoEntity")
|
||||
?.addField(DeviceInfoEntityFields.USER_ID, String::class.java)
|
||||
?.addField(DeviceInfoEntityFields.ALGORITHM_LIST_JSON, String::class.java)
|
||||
?.addField(DeviceInfoEntityFields.KEYS_MAP_JSON, String::class.java)
|
||||
?.addField(DeviceInfoEntityFields.SIGNATURE_MAP_JSON, String::class.java)
|
||||
?.addField(DeviceInfoEntityFields.UNSIGNED_MAP_JSON, String::class.java)
|
||||
?.addField(DeviceInfoEntityFields.IS_BLOCKED, Boolean::class.java)
|
||||
?.setNullable(DeviceInfoEntityFields.IS_BLOCKED, true)
|
||||
?.addRealmObjectField(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelEntityEntitySchema)
|
||||
?.transform { obj ->
|
||||
|
||||
try {
|
||||
val oldSerializedData = obj.getString("deviceInfoData")
|
||||
deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { oldDevice ->
|
||||
|
||||
val trustLevel = realm.createObject("TrustLevelEntity")
|
||||
when (oldDevice.verified) {
|
||||
MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> {
|
||||
obj.setNull(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`)
|
||||
}
|
||||
MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> {
|
||||
trustLevel.setNull(TrustLevelEntityFields.LOCALLY_VERIFIED)
|
||||
trustLevel.setNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED)
|
||||
obj.setBoolean(DeviceInfoEntityFields.IS_BLOCKED, oldDevice.isBlocked)
|
||||
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
|
||||
}
|
||||
MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED -> {
|
||||
trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, false)
|
||||
trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false)
|
||||
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
|
||||
}
|
||||
MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> {
|
||||
trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, true)
|
||||
trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false)
|
||||
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
|
||||
}
|
||||
}
|
||||
|
||||
obj.setString(DeviceInfoEntityFields.USER_ID, oldDevice.userId)
|
||||
obj.setString(DeviceInfoEntityFields.IDENTITY_KEY, oldDevice.identityKey())
|
||||
obj.setString(DeviceInfoEntityFields.ALGORITHM_LIST_JSON, listMigrationAdapter.toJson(oldDevice.algorithms))
|
||||
obj.setString(DeviceInfoEntityFields.KEYS_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.keys))
|
||||
obj.setString(DeviceInfoEntityFields.SIGNATURE_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.signatures))
|
||||
obj.setString(DeviceInfoEntityFields.UNSIGNED_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.unsigned))
|
||||
migrationContext.safeEnumerate("DeviceInfoEntity") { oldObject, newObject ->
|
||||
if (newObject == null) return@safeEnumerate
|
||||
try {
|
||||
val oldSerializedData = oldObject.getNullableValue("deviceInfoData", String::class)
|
||||
deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { oldDevice ->
|
||||
val trustLevel = TrustLevelEntity()
|
||||
when (oldDevice.verified) {
|
||||
MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> {
|
||||
newObject.set("trustLevelEntity", null)
|
||||
}
|
||||
MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> {
|
||||
trustLevel.locallyVerified = null
|
||||
trustLevel.crossSignedVerified = null
|
||||
newObject.set("isBlocked", oldDevice.isBlocked)
|
||||
newObject.set("trustLevelEntity", trustLevel)
|
||||
}
|
||||
MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED -> {
|
||||
trustLevel.locallyVerified = false
|
||||
trustLevel.crossSignedVerified = false
|
||||
newObject.set("trustLevelEntity", trustLevel)
|
||||
}
|
||||
MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> {
|
||||
trustLevel.locallyVerified = true
|
||||
trustLevel.crossSignedVerified = false
|
||||
newObject.set("trustLevelEntity", trustLevel)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
Timber.w(failure, "Crypto Data base migration error")
|
||||
// an unfortunate refactor did modify that class, making deserialization failing
|
||||
// so we just skip and ignore..
|
||||
}
|
||||
newObject.set("userId", oldDevice.userId)
|
||||
newObject.set("identityKey", oldDevice.identityKey())
|
||||
newObject.set("algorithmListJson", listMigrationAdapter.toJson(oldDevice.algorithms))
|
||||
newObject.set("keysMapJson", mapMigrationAdapter.toJson(oldDevice.keys))
|
||||
newObject.set("signatureMapJson", mapMigrationAdapter.toJson(oldDevice.signatures))
|
||||
newObject.set("unsignedMapJson", mapMigrationAdapter.toJson(oldDevice.unsigned))
|
||||
}
|
||||
?.removeField("deviceInfoData")
|
||||
} catch (failure: Throwable) {
|
||||
Timber.w(failure, "Crypto Data base migration error")
|
||||
// an unfortunate refactor did modify that class, making deserialization failing
|
||||
// so we just skip and ignore..
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,47 +16,17 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateCryptoTo005(realm: DynamicRealm) : RealmMigrator(realm, 5) {
|
||||
internal class MigrateCryptoTo005(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 5) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.remove("OutgoingRoomKeyRequestEntity")
|
||||
realm.schema.remove("IncomingRoomKeyRequestEntity")
|
||||
|
||||
// Not need to migrate existing request, just start fresh?
|
||||
realm.schema.create("GossipingEventEntity")
|
||||
.addField("type", String::class.java)
|
||||
.addIndex("type")
|
||||
.addField("content", String::class.java)
|
||||
.addField("sender", String::class.java)
|
||||
.addIndex("sender")
|
||||
.addField("decryptionResultJson", String::class.java)
|
||||
.addField("decryptionErrorCode", String::class.java)
|
||||
.addField("ageLocalTs", Long::class.java)
|
||||
.setNullable("ageLocalTs", true)
|
||||
.addField("sendStateStr", String::class.java)
|
||||
|
||||
realm.schema.create("IncomingGossipingRequestEntity")
|
||||
.addField("requestId", String::class.java)
|
||||
.addIndex("requestId")
|
||||
.addField("typeStr", String::class.java)
|
||||
.addIndex("typeStr")
|
||||
.addField("otherUserId", String::class.java)
|
||||
.addField("requestedInfoStr", String::class.java)
|
||||
.addField("otherDeviceId", String::class.java)
|
||||
.addField("requestStateStr", String::class.java)
|
||||
.addField("localCreationTimestamp", Long::class.java)
|
||||
.setNullable("localCreationTimestamp", true)
|
||||
|
||||
realm.schema.create("OutgoingGossipingRequestEntity")
|
||||
.addField("requestId", String::class.java)
|
||||
.addIndex("requestId")
|
||||
.addField("recipientsData", String::class.java)
|
||||
.addField("requestedInfoStr", String::class.java)
|
||||
.addField("typeStr", String::class.java)
|
||||
.addIndex("typeStr")
|
||||
.addField("requestStateStr", String::class.java)
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Remove OutgoingRoomKeyRequestEntity")
|
||||
Timber.d("Remove IncomingRoomKeyRequestEntity")
|
||||
Timber.d("Create GossipingEventEntity")
|
||||
Timber.d("Create IncomingGossipingRequestEntity")
|
||||
Timber.d("Create OutgoingGossipingRequestEntity")
|
||||
}
|
||||
}
|
||||
|
@ -16,17 +16,13 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateCryptoTo006(realm: DynamicRealm) : RealmMigrator(realm, 6) {
|
||||
internal class MigrateCryptoTo006(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 6) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Updating CryptoMetadataEntity table")
|
||||
realm.schema.get("CryptoMetadataEntity")
|
||||
?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY, String::class.java)
|
||||
?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY_VERSION, String::class.java)
|
||||
}
|
||||
}
|
||||
|
@ -16,45 +16,43 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.dynamic.getNullableValue
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper
|
||||
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateCryptoTo007(realm: DynamicRealm) : RealmMigrator(realm, 7) {
|
||||
internal class MigrateCryptoTo007(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 7) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Updating KeyInfoEntity table")
|
||||
val crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi())
|
||||
|
||||
val keyInfoEntities = realm.where("KeyInfoEntity").findAll()
|
||||
val keyInfoEntities = migrationContext.newRealm.query("KeyInfoEntity").find()
|
||||
try {
|
||||
keyInfoEntities.forEach {
|
||||
val stringSignatures = it.getString(KeyInfoEntityFields.SIGNATURES)
|
||||
val stringSignatures: String? = it.getNullableValue("signatures")
|
||||
val objectSignatures: Map<String, Map<String, String>>? = deserializeFromRealm(stringSignatures)
|
||||
val jsonSignatures = crossSigningKeysMapper.serializeSignatures(objectSignatures)
|
||||
it.setString(KeyInfoEntityFields.SIGNATURES, jsonSignatures)
|
||||
it.set("signatures", jsonSignatures)
|
||||
}
|
||||
} catch (ignore: Throwable) {
|
||||
}
|
||||
|
||||
// Migrate frozen classes
|
||||
val inboundGroupSessions = realm.where("OlmInboundGroupSessionEntity").findAll()
|
||||
val inboundGroupSessions = migrationContext.newRealm.query("OlmInboundGroupSessionEntity").find()
|
||||
inboundGroupSessions.forEach { dynamicObject ->
|
||||
dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { serializedObject ->
|
||||
dynamicObject.getNullableValue("olmInboundGroupSessionData", String::class)?.let { serializedObject ->
|
||||
try {
|
||||
deserializeFromRealm<OlmInboundGroupSessionWrapper?>(serializedObject)?.let { oldFormat ->
|
||||
val newFormat = oldFormat.exportKeys()?.let {
|
||||
OlmInboundGroupSessionWrapper2(it)
|
||||
}
|
||||
dynamicObject.setString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA, serializeForRealm(newFormat))
|
||||
dynamicObject.set("olmInboundGroupSessionData", serializeForRealm(newFormat))
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "## OlmInboundGroupSessionEntity migration failed")
|
||||
|
@ -16,35 +16,20 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import org.matrix.android.sdk.internal.database.safeEnumerate
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateCryptoTo008(
|
||||
realm: DynamicRealm,
|
||||
private val clock: Clock,
|
||||
) : RealmMigrator(realm, 8) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.create("MyDeviceLastSeenInfoEntity")
|
||||
.addField(MyDeviceLastSeenInfoEntityFields.DEVICE_ID, String::class.java)
|
||||
.addPrimaryKey(MyDeviceLastSeenInfoEntityFields.DEVICE_ID)
|
||||
.addField(MyDeviceLastSeenInfoEntityFields.DISPLAY_NAME, String::class.java)
|
||||
.addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_IP, String::class.java)
|
||||
.addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_TS, Long::class.java)
|
||||
.setNullable(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_TS, true)
|
||||
internal class MigrateCryptoTo008(context: AutomaticSchemaMigration.MigrationContext, private val clock: Clock) : KotlinRealmMigrator(context, 8) {
|
||||
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Create MyDeviceLastSeenInfoEntity")
|
||||
Timber.d("Update DeviceInfoEntity")
|
||||
val now = clock.epochMillis()
|
||||
realm.schema.get("DeviceInfoEntity")
|
||||
?.addField(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, Long::class.java)
|
||||
?.setNullable(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, true)
|
||||
?.transform { deviceInfoEntity ->
|
||||
tryOrNull {
|
||||
deviceInfoEntity.setLong(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, now)
|
||||
}
|
||||
}
|
||||
migrationContext.safeEnumerate("DeviceInfoEntity") { _, newObject ->
|
||||
newObject?.set("firstTimeSeenLocalTs", now)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,22 +16,20 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
// Fixes duplicate devices in UserEntity#devices
|
||||
internal class MigrateCryptoTo009(realm: DynamicRealm) : RealmMigrator(realm, 9) {
|
||||
internal class MigrateCryptoTo009(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 9) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
val userEntities = realm.where("UserEntity").findAll()
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Fixes duplicate devices in UserEntity#devices")
|
||||
val userEntities = migrationContext.newRealm.query("UserEntity").find()
|
||||
userEntities.forEach {
|
||||
try {
|
||||
val deviceList = it.getList(UserEntityFields.DEVICES.`$`)
|
||||
?: return@forEach
|
||||
val distinct = deviceList.distinctBy { it.getString(DeviceInfoEntityFields.DEVICE_ID) }
|
||||
val deviceList = it.getValueList("devices", DeviceInfoEntity::class)
|
||||
val distinct = deviceList.distinctBy { it.deviceId }
|
||||
if (distinct.size != deviceList.size) {
|
||||
deviceList.clear()
|
||||
deviceList.addAll(distinct)
|
||||
|
@ -16,35 +16,15 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
// Version 10L added WithHeld Keys Info (MSC2399)
|
||||
internal class MigrateCryptoTo010(realm: DynamicRealm) : RealmMigrator(realm, 10) {
|
||||
internal class MigrateCryptoTo010(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 10) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.create("WithHeldSessionEntity")
|
||||
.addField(WithHeldSessionEntityFields.ROOM_ID, String::class.java)
|
||||
.addField(WithHeldSessionEntityFields.ALGORITHM, String::class.java)
|
||||
.addField(WithHeldSessionEntityFields.SESSION_ID, String::class.java)
|
||||
.addIndex(WithHeldSessionEntityFields.SESSION_ID)
|
||||
.addField(WithHeldSessionEntityFields.SENDER_KEY, String::class.java)
|
||||
.addIndex(WithHeldSessionEntityFields.SENDER_KEY)
|
||||
.addField(WithHeldSessionEntityFields.CODE_STRING, String::class.java)
|
||||
.addField(WithHeldSessionEntityFields.REASON, String::class.java)
|
||||
|
||||
realm.schema.create("SharedSessionEntity")
|
||||
.addField(SharedSessionEntityFields.ROOM_ID, String::class.java)
|
||||
.addField(SharedSessionEntityFields.ALGORITHM, String::class.java)
|
||||
.addField(SharedSessionEntityFields.SESSION_ID, String::class.java)
|
||||
.addIndex(SharedSessionEntityFields.SESSION_ID)
|
||||
.addField(SharedSessionEntityFields.USER_ID, String::class.java)
|
||||
.addIndex(SharedSessionEntityFields.USER_ID)
|
||||
.addField(SharedSessionEntityFields.DEVICE_ID, String::class.java)
|
||||
.addIndex(SharedSessionEntityFields.DEVICE_ID)
|
||||
.addField(SharedSessionEntityFields.CHAIN_INDEX, Long::class.java)
|
||||
.setNullable(SharedSessionEntityFields.CHAIN_INDEX, true)
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Create WithHeldSessionEntity")
|
||||
Timber.d("Create SharedSessionEntity")
|
||||
}
|
||||
}
|
||||
|
@ -16,15 +16,14 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
// Version 11L added deviceKeysSentToServer boolean to CryptoMetadataEntity
|
||||
internal class MigrateCryptoTo011(realm: DynamicRealm) : RealmMigrator(realm, 11) {
|
||||
internal class MigrateCryptoTo011(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 11) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("CryptoMetadataEntity")
|
||||
?.addField(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER, Boolean::class.java)
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Update CryptoMetadataEntity")
|
||||
}
|
||||
}
|
||||
|
@ -16,21 +16,15 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
// Version 12L added outbound group session persistence
|
||||
internal class MigrateCryptoTo012(realm: DynamicRealm) : RealmMigrator(realm, 12) {
|
||||
internal class MigrateCryptoTo012(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 12) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
val outboundEntitySchema = realm.schema.create("OutboundGroupSessionInfoEntity")
|
||||
.addField(OutboundGroupSessionInfoEntityFields.SERIALIZED_OUTBOUND_SESSION_DATA, String::class.java)
|
||||
.addField(OutboundGroupSessionInfoEntityFields.CREATION_TIME, Long::class.java)
|
||||
.setNullable(OutboundGroupSessionInfoEntityFields.CREATION_TIME, true)
|
||||
|
||||
realm.schema.get("CryptoRoomEntity")
|
||||
?.addRealmObjectField(CryptoRoomEntityFields.OUTBOUND_SESSION_INFO.`$`, outboundEntitySchema)
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Create OutboundGroupSessionInfoEntity")
|
||||
Timber.d("Update CryptoRoomEntity")
|
||||
}
|
||||
}
|
||||
|
@ -16,63 +16,26 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import timber.log.Timber
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
|
||||
// Version 13L delete unreferenced TrustLevelEntity
|
||||
internal class MigrateCryptoTo013(realm: DynamicRealm) : RealmMigrator(realm, 13) {
|
||||
internal class MigrateCryptoTo013(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 13) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
// Use a trick to do that... Ref: https://stackoverflow.com/questions/55221366
|
||||
val trustLevelEntitySchema = realm.schema.get("TrustLevelEntity")
|
||||
|
||||
/*
|
||||
Creating a new temp field called isLinked which is set to true for those which are
|
||||
references by other objects. Rest of them are set to false. Then removing all
|
||||
those which are false and hence duplicate and unnecessary. Then removing the temp field
|
||||
isLinked
|
||||
*/
|
||||
var mainCounter = 0
|
||||
var deviceInfoCounter = 0
|
||||
var keyInfoCounter = 0
|
||||
val deleteCounter: Int
|
||||
|
||||
trustLevelEntitySchema
|
||||
?.addField("isLinked", Boolean::class.java)
|
||||
?.transform { obj ->
|
||||
// Setting to false for all by default
|
||||
obj.set("isLinked", false)
|
||||
mainCounter++
|
||||
}
|
||||
|
||||
realm.schema.get("DeviceInfoEntity")?.transform { obj ->
|
||||
// Setting to true for those which are referenced in DeviceInfoEntity
|
||||
deviceInfoCounter++
|
||||
obj.getObject("trustLevelEntity")?.set("isLinked", true)
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
val trustLevelEntities = migrationContext.newRealm.query("TrustLevelEntity").find()
|
||||
val linkedTrustLevelEntities = mutableSetOf<TrustLevelEntity>()
|
||||
val deviceInfoEntities = migrationContext.newRealm.query("DeviceInfoEntity").find()
|
||||
deviceInfoEntities.forEach {
|
||||
val trustLevelEntity = it.getNullableValue("trustLevelEntity", TrustLevelEntity::class)
|
||||
if (trustLevelEntity != null) {
|
||||
linkedTrustLevelEntities.add(trustLevelEntity)
|
||||
}
|
||||
}
|
||||
|
||||
realm.schema.get("KeyInfoEntity")?.transform { obj ->
|
||||
// Setting to true for those which are referenced in KeyInfoEntity
|
||||
keyInfoCounter++
|
||||
obj.getObject("trustLevelEntity")?.set("isLinked", true)
|
||||
}
|
||||
|
||||
// Removing all those which are set as false
|
||||
realm.where("TrustLevelEntity")
|
||||
.equalTo("isLinked", false)
|
||||
.findAll()
|
||||
.also { deleteCounter = it.size }
|
||||
.deleteAllFromRealm()
|
||||
|
||||
trustLevelEntitySchema?.removeField("isLinked")
|
||||
|
||||
Timber.w("TrustLevelEntity cleanup: $mainCounter entities")
|
||||
Timber.w("TrustLevelEntity cleanup: $deviceInfoCounter entities referenced in DeviceInfoEntities")
|
||||
Timber.w("TrustLevelEntity cleanup: $keyInfoCounter entities referenced in KeyInfoEntity")
|
||||
Timber.w("TrustLevelEntity cleanup: $deleteCounter entities deleted!")
|
||||
if (mainCounter != deviceInfoCounter + keyInfoCounter + deleteCounter) {
|
||||
Timber.e("TrustLevelEntity cleanup: Something is not correct...")
|
||||
val unreferencedTrustLevelEntities = trustLevelEntities.subtract(linkedTrustLevelEntities)
|
||||
unreferencedTrustLevelEntities.forEach {
|
||||
migrationContext.newRealm.delete(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,26 +16,28 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import org.matrix.android.sdk.internal.database.safeEnumerate
|
||||
import timber.log.Timber
|
||||
|
||||
// Version 14L Update the way we remember key sharing
|
||||
internal class MigrateCryptoTo014(realm: DynamicRealm) : RealmMigrator(realm, 14) {
|
||||
internal class MigrateCryptoTo014(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 14) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("SharedSessionEntity")
|
||||
?.addField(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, String::class.java)
|
||||
?.addIndex(SharedSessionEntityFields.DEVICE_IDENTITY_KEY)
|
||||
?.transform {
|
||||
val sharedUserId = it.getString(SharedSessionEntityFields.USER_ID)
|
||||
val sharedDeviceId = it.getString(SharedSessionEntityFields.DEVICE_ID)
|
||||
val knownDevice = realm.where("DeviceInfoEntity")
|
||||
.equalTo(DeviceInfoEntityFields.USER_ID, sharedUserId)
|
||||
.equalTo(DeviceInfoEntityFields.DEVICE_ID, sharedDeviceId)
|
||||
.findFirst()
|
||||
it.setString(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, knownDevice?.getString(DeviceInfoEntityFields.IDENTITY_KEY))
|
||||
}
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Update SharedSessionEntity")
|
||||
migrationContext.safeEnumerate("SharedSessionEntity") { oldObject, newObject ->
|
||||
if (newObject == null) return@safeEnumerate
|
||||
val sharedUserId = oldObject.getNullableValue("userId", String::class)
|
||||
val sharedDeviceId = oldObject.getNullableValue("deviceId", String::class)
|
||||
val knownDevice = migrationContext.newRealm.query("DeviceInfoEntity")
|
||||
.query("userId == $0", sharedUserId)
|
||||
.query("deviceId == $0", sharedDeviceId)
|
||||
.first()
|
||||
.find()
|
||||
|
||||
val deviceIdentityKey = knownDevice?.getNullableValue("identityKey", String::class)
|
||||
newObject.set("deviceIdentityKey", deviceIdentityKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,21 +16,21 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import org.matrix.android.sdk.internal.database.safeEnumerate
|
||||
import timber.log.Timber
|
||||
|
||||
// Version 15L adds wasEncryptedOnce field to CryptoRoomEntity
|
||||
internal class MigrateCryptoTo015(realm: DynamicRealm) : RealmMigrator(realm, 15) {
|
||||
internal class MigrateCryptoTo015(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 15) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("CryptoRoomEntity")
|
||||
?.addField(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, Boolean::class.java)
|
||||
?.setNullable(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, true)
|
||||
?.transform {
|
||||
val currentAlgorithm = it.getString(CryptoRoomEntityFields.ALGORITHM)
|
||||
it.set(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, currentAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
}
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Update CryptoRoomEntity")
|
||||
migrationContext.safeEnumerate("CryptoRoomEntity") { oldObject, newObject ->
|
||||
if (newObject == null) return@safeEnumerate
|
||||
val currentAlgorithm = oldObject.getNullableValue("algorithm", String::class)
|
||||
newObject.set("wasEncryptedOnce", currentAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,55 +16,21 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyRequestReplyEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateCryptoTo016(realm: DynamicRealm) : RealmMigrator(realm, 16) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.remove("OutgoingGossipingRequestEntity")
|
||||
realm.schema.remove("IncomingGossipingRequestEntity")
|
||||
realm.schema.remove("GossipingEventEntity")
|
||||
internal class MigrateCryptoTo016(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 16) {
|
||||
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Remove OutgoingGossipingRequestEntity")
|
||||
Timber.d("Remove IncomingGossipingRequestEntity")
|
||||
Timber.d("Remove GossipingEventEntity")
|
||||
// No need to migrate existing request, just start fresh
|
||||
Timber.d("Create GossipingEventEntity")
|
||||
Timber.d("Create GossipingEventEntity")
|
||||
Timber.d("Create GossipingEventEntity")
|
||||
|
||||
val replySchema = realm.schema.create("KeyRequestReplyEntity")
|
||||
.addField(KeyRequestReplyEntityFields.SENDER_ID, String::class.java)
|
||||
.addField(KeyRequestReplyEntityFields.FROM_DEVICE, String::class.java)
|
||||
.addField(KeyRequestReplyEntityFields.EVENT_JSON, String::class.java)
|
||||
|
||||
realm.schema.create("OutgoingKeyRequestEntity")
|
||||
.addField(OutgoingKeyRequestEntityFields.REQUEST_ID, String::class.java)
|
||||
.addIndex(OutgoingKeyRequestEntityFields.REQUEST_ID)
|
||||
.addField(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, String::class.java)
|
||||
.addIndex(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID)
|
||||
.addRealmListField(OutgoingKeyRequestEntityFields.REPLIES.`$`, replySchema)
|
||||
.addField(OutgoingKeyRequestEntityFields.RECIPIENTS_DATA, String::class.java)
|
||||
.addField(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, String::class.java)
|
||||
.addIndex(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR)
|
||||
.addField(OutgoingKeyRequestEntityFields.REQUESTED_INFO_STR, String::class.java)
|
||||
.addField(OutgoingKeyRequestEntityFields.ROOM_ID, String::class.java)
|
||||
.addIndex(OutgoingKeyRequestEntityFields.ROOM_ID)
|
||||
.addField(OutgoingKeyRequestEntityFields.REQUESTED_INDEX, Integer::class.java)
|
||||
.addField(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, Long::class.java)
|
||||
.setNullable(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, true)
|
||||
|
||||
realm.schema.create("AuditTrailEntity")
|
||||
.addField(AuditTrailEntityFields.AGE_LOCAL_TS, Long::class.java)
|
||||
.setNullable(AuditTrailEntityFields.AGE_LOCAL_TS, true)
|
||||
.addField(AuditTrailEntityFields.CONTENT_JSON, String::class.java)
|
||||
.addField(AuditTrailEntityFields.TYPE, String::class.java)
|
||||
.addIndex(AuditTrailEntityFields.TYPE)
|
||||
|
||||
realm.schema.get("CryptoMetadataEntity")
|
||||
?.addField(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, Boolean::class.java)
|
||||
?.transform {
|
||||
// set the default value to true
|
||||
it.setBoolean(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, true)
|
||||
}
|
||||
Timber.d("Update CryptoMetadataEntity")
|
||||
}
|
||||
}
|
||||
|
@ -16,86 +16,60 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import org.matrix.android.sdk.internal.database.safeEnumerate
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Version 17L enhance OlmInboundGroupSessionEntity to support shared history for MSC3061.
|
||||
* Also migrates how megolm session are stored to avoid additional serialized frozen class.
|
||||
*/
|
||||
internal class MigrateCryptoTo017(realm: DynamicRealm) : RealmMigrator(realm, 17) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("CryptoRoomEntity")
|
||||
?.addField(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform {
|
||||
// We don't have access to the session database to check for the state here and set the good value.
|
||||
// But for now as it's behind a lab flag, will set to false and force initial sync when enabled
|
||||
it.setBoolean(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, false)
|
||||
}
|
||||
|
||||
realm.schema.get("OutboundGroupSessionInfoEntity")
|
||||
?.addField(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform {
|
||||
// We don't have access to the session database to check for the state here and set the good value.
|
||||
// But for now as it's behind a lab flag, will set to false and force initial sync when enabled
|
||||
it.setBoolean(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, false)
|
||||
}
|
||||
|
||||
realm.schema.get("CryptoMetadataEntity")
|
||||
?.addField(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, Boolean::class.java)
|
||||
?.transform { obj ->
|
||||
// default to false
|
||||
obj.setBoolean(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, false)
|
||||
}
|
||||
internal class MigrateCryptoTo017(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 17) {
|
||||
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Update CryptoRoomEntity")
|
||||
Timber.d("Update OutboundGroupSessionInfoEntity")
|
||||
Timber.d("Update CryptoMetadataEntity")
|
||||
Timber.d("Update OlmInboundGroupSessionEntity")
|
||||
val moshiAdapter = MoshiProvider.providesMoshi().adapter(InboundGroupSessionData::class.java)
|
||||
|
||||
realm.schema.get("OlmInboundGroupSessionEntity")
|
||||
?.addField(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, Boolean::class.java)
|
||||
?.addField(OlmInboundGroupSessionEntityFields.ROOM_ID, String::class.java)
|
||||
?.addField(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, String::class.java)
|
||||
?.addField(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, String::class.java)
|
||||
?.transform { dynamicObject ->
|
||||
try {
|
||||
// we want to convert the old wrapper frozen class into a
|
||||
// map of sessionData & the pickled session herself
|
||||
dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { oldData ->
|
||||
val oldWrapper = tryOrNull("Failed to convert megolm inbound group data") {
|
||||
@Suppress("DEPRECATION")
|
||||
deserializeFromRealm<org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2?>(oldData)
|
||||
}
|
||||
val groupSession = oldWrapper?.olmInboundGroupSession
|
||||
?: return@transform Unit.also {
|
||||
Timber.w("Failed to migrate megolm session, no olmInboundGroupSession")
|
||||
}
|
||||
// now convert to new data
|
||||
val data = InboundGroupSessionData(
|
||||
senderKey = oldWrapper.senderKey,
|
||||
roomId = oldWrapper.roomId,
|
||||
keysClaimed = oldWrapper.keysClaimed,
|
||||
forwardingCurve25519KeyChain = oldWrapper.forwardingCurve25519KeyChain,
|
||||
sharedHistory = false,
|
||||
)
|
||||
|
||||
dynamicObject.setString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, moshiAdapter.toJson(data))
|
||||
dynamicObject.setString(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, serializeForRealm(groupSession))
|
||||
|
||||
// denormalized fields
|
||||
dynamicObject.setString(OlmInboundGroupSessionEntityFields.ROOM_ID, oldWrapper.roomId)
|
||||
dynamicObject.setBoolean(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, false)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "Failed to migrate megolm session")
|
||||
migrationContext.safeEnumerate("OlmInboundGroupSessionEntity") { oldObject, newObject ->
|
||||
if (newObject == null) return@safeEnumerate
|
||||
try {
|
||||
// we want to convert the old wrapper frozen class into a
|
||||
// map of sessionData & the pickled session herself
|
||||
oldObject.getNullableValue("olmInboundGroupSessionData", String::class)?.let { oldData ->
|
||||
val oldWrapper = tryOrNull("Failed to convert megolm inbound group data") {
|
||||
@Suppress("DEPRECATION")
|
||||
deserializeFromRealm<org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2?>(oldData)
|
||||
}
|
||||
val groupSession = oldWrapper?.olmInboundGroupSession
|
||||
?: return@safeEnumerate Unit.also {
|
||||
Timber.w("Failed to migrate megolm session, no olmInboundGroupSession")
|
||||
}
|
||||
// now convert to new data
|
||||
val data = InboundGroupSessionData(
|
||||
senderKey = oldWrapper.senderKey,
|
||||
roomId = oldWrapper.roomId,
|
||||
keysClaimed = oldWrapper.keysClaimed,
|
||||
forwardingCurve25519KeyChain = oldWrapper.forwardingCurve25519KeyChain,
|
||||
sharedHistory = false,
|
||||
)
|
||||
|
||||
newObject.set("inboundGroupSessionDataJson", moshiAdapter.toJson(data))
|
||||
newObject.set("serializedOlmInboundGroupSession", serializeForRealm(groupSession))
|
||||
|
||||
// denormalized fields
|
||||
newObject.set("roomId", oldWrapper.roomId)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "Failed to migrate megolm session")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,12 +16,11 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import org.matrix.android.sdk.internal.database.safeEnumerate
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* This migration is adding support for trusted flags on megolm sessions.
|
||||
@ -29,24 +28,20 @@ import timber.log.Timber
|
||||
* mark existing keys as safe.
|
||||
* This migration can take long depending on the account
|
||||
*/
|
||||
internal class MigrateCryptoTo018(realm: DynamicRealm) : RealmMigrator(realm, 18) {
|
||||
internal class MigrateCryptoTo018(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 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")
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
migrationContext.safeEnumerate("OlmInboundGroupSessionEntity") { oldObject, newObject ->
|
||||
if (newObject == null) return@safeEnumerate
|
||||
oldObject.getNullableValue("inboundGroupSessionDataJson", String::class)?.let { oldData ->
|
||||
moshiAdapter.fromJson(oldData)?.let { dataToMigrate ->
|
||||
dataToMigrate.copy(trusted = true).let {
|
||||
newObject.set("inboundGroupSessionDataJson", moshiAdapter.toJson(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,13 +16,12 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.DynamicRealmObject
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
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
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import org.matrix.android.sdk.internal.database.safeEnumerate
|
||||
|
||||
/**
|
||||
* This migration is adding support for trusted flags on megolm sessions.
|
||||
@ -30,30 +29,30 @@ import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
* mark existing keys as safe.
|
||||
* This migration can take long depending on the account
|
||||
*/
|
||||
internal class MigrateCryptoTo019(realm: DynamicRealm) : RealmMigrator(realm, 19) {
|
||||
internal class MigrateCryptoTo019(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 19) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("CrossSigningInfoEntity")
|
||||
?.addField(CrossSigningInfoEntityFields.WAS_USER_VERIFIED_ONCE, Boolean::class.java)
|
||||
?.transform { dynamicObject ->
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
migrationContext.safeEnumerate("CrossSigningInfoEntity") { oldObject, newObject ->
|
||||
if (newObject == null) return@safeEnumerate
|
||||
|
||||
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.`$`))
|
||||
// Will be a list of `KeyInfoEntity`
|
||||
val knowKeys = oldObject.getValueList("crossSigningKeys", KeyInfoEntity::class)
|
||||
val msk = knowKeys.firstOrNull {
|
||||
it.usages.contains(KeyUsage.MASTER.value)
|
||||
}
|
||||
val ssk = knowKeys.firstOrNull {
|
||||
it.usages.contains(KeyUsage.SELF_SIGNING.value)
|
||||
}
|
||||
val isTrusted = isDynamicKeyInfoTrusted(msk?.trustLevelEntity) &&
|
||||
isDynamicKeyInfoTrusted(ssk?.trustLevelEntity)
|
||||
|
||||
dynamicObject.setBoolean(CrossSigningInfoEntityFields.WAS_USER_VERIFIED_ONCE, isTrusted)
|
||||
}
|
||||
newObject.set("wasUserVerifiedOnce", isTrusted)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isDynamicKeyInfoTrusted(keyInfo: DynamicRealmObject?): Boolean {
|
||||
private fun isDynamicKeyInfoTrusted(keyInfo: TrustLevelEntity?): 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)
|
||||
return keyInfo.crossSignedVerified == true &&
|
||||
keyInfo.locallyVerified == true
|
||||
}
|
||||
}
|
||||
|
@ -16,17 +16,15 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
|
||||
/**
|
||||
* This migration adds a new field into MyDeviceLastSeenInfoEntity corresponding to the last seen user agent.
|
||||
*/
|
||||
internal class MigrateCryptoTo020(realm: DynamicRealm) : RealmMigrator(realm, 20) {
|
||||
internal class MigrateCryptoTo020(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 20) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("MyDeviceLastSeenInfoEntity")
|
||||
?.addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_USER_AGENT, String::class.java)
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
// Nothing to do, this is an automatic migration now.
|
||||
}
|
||||
}
|
||||
|
@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.database.migration
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateSessionTo032(realm: DynamicRealm) : RealmMigrator(realm, 32) {
|
||||
internal class MigrateCryptoTo021(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 21) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("RoomSummaryEntity")
|
||||
?.removeField("groupIds")
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Migrate to realm-kotlin")
|
||||
}
|
||||
}
|
@ -16,13 +16,13 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Index
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.Index
|
||||
|
||||
internal class AuditTrailEntity : RealmObject {
|
||||
var ageLocalTs: Long? = null
|
||||
@Index var type: String? = null
|
||||
var contentJson: String? = null
|
||||
|
||||
internal open class AuditTrailEntity(
|
||||
var ageLocalTs: Long? = null,
|
||||
@Index var type: String? = null,
|
||||
var contentJson: String? = null
|
||||
) : RealmObject() {
|
||||
companion object
|
||||
}
|
||||
|
@ -16,18 +16,17 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.kotlin.ext.realmListOf
|
||||
import io.realm.kotlin.types.RealmList
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.KeyUsage
|
||||
import org.matrix.android.sdk.internal.extensions.clearWith
|
||||
|
||||
internal open class CrossSigningInfoEntity(
|
||||
@PrimaryKey
|
||||
var userId: String? = null,
|
||||
var wasUserVerifiedOnce: Boolean = false,
|
||||
var crossSigningKeys: RealmList<KeyInfoEntity> = RealmList()
|
||||
) : RealmObject() {
|
||||
internal class CrossSigningInfoEntity : RealmObject {
|
||||
@PrimaryKey
|
||||
var userId: String? = null
|
||||
var wasUserVerifiedOnce: Boolean = false
|
||||
var crossSigningKeys: RealmList<KeyInfoEntity> = realmListOf()
|
||||
|
||||
companion object
|
||||
|
||||
@ -59,7 +58,10 @@ internal open class CrossSigningInfoEntity(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
internal fun CrossSigningInfoEntity.deleteOnCascade() {
|
||||
crossSigningKeys.clearWith { it.deleteOnCascade() }
|
||||
deleteFromRealm()
|
||||
}
|
||||
|
||||
*/
|
||||
|
@ -50,8 +50,10 @@ internal object CryptoMapper {
|
||||
)
|
||||
|
||||
internal fun mapToEntity(deviceInfo: CryptoDeviceInfo): DeviceInfoEntity {
|
||||
return DeviceInfoEntity(primaryKey = DeviceInfoEntity.createPrimaryKey(deviceInfo.userId, deviceInfo.deviceId))
|
||||
.also { updateDeviceInfoEntity(it, deviceInfo) }
|
||||
return DeviceInfoEntity().apply {
|
||||
primaryKey = DeviceInfoEntity.createPrimaryKey(deviceInfo.userId, deviceInfo.deviceId)
|
||||
updateDeviceInfoEntity(this, deviceInfo)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun updateDeviceInfoEntity(entity: DeviceInfoEntity, deviceInfo: CryptoDeviceInfo) {
|
||||
@ -62,17 +64,14 @@ internal object CryptoMapper {
|
||||
entity.signatureMapJson = mapMigrationAdapter.toJson(deviceInfo.signatures)
|
||||
entity.isBlocked = deviceInfo.isBlocked
|
||||
val deviceInfoTrustLevel = deviceInfo.trustLevel
|
||||
// deletion of the trustLevelEntity has to be handled before
|
||||
if (deviceInfoTrustLevel == null) {
|
||||
entity.trustLevelEntity?.deleteFromRealm()
|
||||
entity.trustLevelEntity = null
|
||||
} else {
|
||||
if (entity.trustLevelEntity == null) {
|
||||
// Create a new TrustLevelEntity object
|
||||
entity.trustLevelEntity = TrustLevelEntity()
|
||||
entity.trustLevelEntity = TrustLevelEntity().apply {
|
||||
this.crossSignedVerified = deviceInfoTrustLevel.crossSigningVerified
|
||||
this.locallyVerified = deviceInfoTrustLevel.locallyVerified
|
||||
}
|
||||
// Update the existing TrustLevelEntity object
|
||||
entity.trustLevelEntity?.crossSignedVerified = deviceInfoTrustLevel.crossSigningVerified
|
||||
entity.trustLevelEntity?.locallyVerified = deviceInfoTrustLevel.locallyVerified
|
||||
}
|
||||
// We store the device name if present now
|
||||
entity.unsignedMapJson = deviceInfo.unsigned?.deviceDisplayName
|
||||
|
@ -16,44 +16,48 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.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.
|
||||
@PrimaryKey var userId: String? = null,
|
||||
// The current device id.
|
||||
var deviceId: String? = null,
|
||||
// Serialized OlmAccount
|
||||
var olmAccountData: String? = null,
|
||||
// The sync token corresponding to the device list. // TODO?
|
||||
var deviceSyncToken: String? = null,
|
||||
// Settings for blacklisting unverified devices.
|
||||
var globalBlacklistUnverifiedDevices: Boolean = false,
|
||||
// setting to enable or disable key gossiping
|
||||
var globalEnableKeyGossiping: Boolean = true,
|
||||
internal class CryptoMetadataEntity : RealmObject {
|
||||
// The current user id.
|
||||
@PrimaryKey var userId: String? = null
|
||||
|
||||
// MSC3061: Sharing room keys for past messages
|
||||
// If set to true key history will be shared to invited users with respect to room setting
|
||||
var enableKeyForwardingOnInvite: Boolean = false,
|
||||
// The current device id.
|
||||
var deviceId: String? = null
|
||||
|
||||
// The keys backup version currently used. Null means no backup.
|
||||
var backupVersion: String? = null,
|
||||
// Serialized OlmAccount
|
||||
var olmAccountData: String? = null
|
||||
|
||||
// The device keys has been sent to the homeserver
|
||||
var deviceKeysSentToServer: Boolean = false,
|
||||
// The sync token corresponding to the device list. // TODO?
|
||||
var deviceSyncToken: String? = null
|
||||
|
||||
var xSignMasterPrivateKey: String? = null,
|
||||
var xSignUserPrivateKey: String? = null,
|
||||
var xSignSelfSignedPrivateKey: String? = null,
|
||||
var keyBackupRecoveryKey: String? = null,
|
||||
var keyBackupRecoveryKeyVersion: String? = null
|
||||
// Settings for blacklisting unverified devices.
|
||||
var globalBlacklistUnverifiedDevices: Boolean = false
|
||||
|
||||
// setting to enable or disable key gossiping
|
||||
var globalEnableKeyGossiping: Boolean = true
|
||||
|
||||
// MSC3061: Sharing room keys for past messages
|
||||
// If set to true key history will be shared to invited users with respect to room setting
|
||||
var enableKeyForwardingOnInvite: Boolean = false
|
||||
|
||||
// The keys backup version currently used. Null means no backup.
|
||||
var backupVersion: String? = null
|
||||
|
||||
// The device keys has been sent to the homeserver
|
||||
var deviceKeysSentToServer: Boolean = false
|
||||
|
||||
var xSignMasterPrivateKey: String? = null
|
||||
var xSignUserPrivateKey: String? = null
|
||||
var xSignSelfSignedPrivateKey: String? = null
|
||||
var keyBackupRecoveryKey: String? = null
|
||||
var keyBackupRecoveryKeyVersion: String? = null
|
||||
|
||||
// var crossSigningInfoEntity: CrossSigningInfoEntity? = null
|
||||
) : RealmObject() {
|
||||
|
||||
// Deserialize data
|
||||
fun getOlmAccount(): OlmAccount? {
|
||||
|
@ -16,25 +16,26 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
|
||||
internal open class CryptoRoomEntity(
|
||||
@PrimaryKey var roomId: String? = null,
|
||||
var algorithm: String? = null,
|
||||
var shouldEncryptForInvitedMembers: Boolean? = null,
|
||||
var blacklistUnverifiedDevices: Boolean = false,
|
||||
// Determines whether or not room history should be shared on new member invites
|
||||
var shouldShareHistory: Boolean = false,
|
||||
// Store the current outbound session for this room,
|
||||
// to avoid re-create and re-share at each startup (if rotation not needed..)
|
||||
// This is specific to megolm but not sure how to model it better
|
||||
var outboundSessionInfo: OutboundGroupSessionInfoEntity? = null,
|
||||
// a security to ensure that a room will never revert to not encrypted
|
||||
// even if a new state event with empty encryption, or state is reset somehow
|
||||
var wasEncryptedOnce: Boolean? = false
|
||||
) :
|
||||
RealmObject() {
|
||||
internal class CryptoRoomEntity : RealmObject {
|
||||
@PrimaryKey var roomId: String? = null
|
||||
var algorithm: String? = null
|
||||
var shouldEncryptForInvitedMembers: Boolean? = null
|
||||
var blacklistUnverifiedDevices: Boolean = false
|
||||
|
||||
// Determines whether or not room history should be shared on new member invites
|
||||
var shouldShareHistory: Boolean = false
|
||||
|
||||
// Store the current outbound session for this room,
|
||||
// to avoid re-create and re-share at each startup (if rotation not needed..)
|
||||
// This is specific to megolm but not sure how to model it better
|
||||
var outboundSessionInfo: OutboundGroupSessionInfoEntity? = null
|
||||
|
||||
// a security to ensure that a room will never revert to not encrypted
|
||||
// even if a new state event with empty encryption, or state is reset somehow
|
||||
var wasEncryptedOnce: Boolean? = false
|
||||
|
||||
companion object
|
||||
}
|
||||
|
@ -16,39 +16,38 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.RealmResults
|
||||
import io.realm.annotations.LinkingObjects
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
|
||||
internal fun DeviceInfoEntity.Companion.createPrimaryKey(userId: String, deviceId: String) = "$userId|$deviceId"
|
||||
|
||||
internal open class DeviceInfoEntity(
|
||||
@PrimaryKey var primaryKey: String = "",
|
||||
var deviceId: String? = null,
|
||||
var identityKey: String? = null,
|
||||
var userId: String? = null,
|
||||
var isBlocked: Boolean? = null,
|
||||
var algorithmListJson: String? = null,
|
||||
var keysMapJson: String? = null,
|
||||
var signatureMapJson: String? = null,
|
||||
// Will contain the device name from unsigned data if present
|
||||
var unsignedMapJson: String? = null,
|
||||
var trustLevelEntity: TrustLevelEntity? = null,
|
||||
/**
|
||||
* We use that to make distinction between old devices (there before mine)
|
||||
* and new ones. Used for example to detect new unverified login
|
||||
*/
|
||||
var firstTimeSeenLocalTs: Long? = null
|
||||
) : RealmObject() {
|
||||
internal class DeviceInfoEntity : RealmObject {
|
||||
@PrimaryKey var primaryKey: String = ""
|
||||
var deviceId: String? = null
|
||||
var identityKey: String? = null
|
||||
var userId: String? = null
|
||||
var isBlocked: Boolean? = null
|
||||
var algorithmListJson: String? = null
|
||||
var keysMapJson: String? = null
|
||||
var signatureMapJson: String? = null
|
||||
|
||||
@LinkingObjects("devices")
|
||||
val users: RealmResults<UserEntity>? = null
|
||||
// Will contain the device name from unsigned data if present
|
||||
var unsignedMapJson: String? = null
|
||||
var trustLevelEntity: TrustLevelEntity? = null
|
||||
|
||||
/**
|
||||
* We use that to make distinction between old devices (there before mine)
|
||||
* and new ones. Used for example to detect new unverified login
|
||||
*/
|
||||
var firstTimeSeenLocalTs: Long? = null
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
/*
|
||||
internal fun DeviceInfoEntity.deleteOnCascade() {
|
||||
trustLevelEntity?.deleteFromRealm()
|
||||
deleteFromRealm()
|
||||
}
|
||||
|
||||
*/
|
||||
|
@ -16,22 +16,28 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.kotlin.ext.realmListOf
|
||||
import io.realm.kotlin.types.RealmList
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
|
||||
internal open class KeyInfoEntity(
|
||||
var publicKeyBase64: String? = null,
|
||||
// var isTrusted: Boolean = false,
|
||||
var usages: RealmList<String> = RealmList(),
|
||||
/**
|
||||
* The signature of this MXDeviceInfo.
|
||||
* A map from "<userId>" to a map from "<key type>:<Publickey>" to "<signature>"
|
||||
*/
|
||||
var signatures: String? = null,
|
||||
var trustLevelEntity: TrustLevelEntity? = null
|
||||
) : RealmObject()
|
||||
internal class KeyInfoEntity : RealmObject {
|
||||
var publicKeyBase64: String? = null
|
||||
|
||||
// var isTrusted: Boolean = false,
|
||||
var usages: RealmList<String> = realmListOf()
|
||||
|
||||
/**
|
||||
* The signature of this MXDeviceInfo.
|
||||
* A map from "<userId>" to a map from "<key type>:<Publickey>" to "<signature>"
|
||||
*/
|
||||
var signatures: String? = null
|
||||
var trustLevelEntity: TrustLevelEntity? = null
|
||||
}
|
||||
|
||||
/*
|
||||
internal fun KeyInfoEntity.deleteOnCascade() {
|
||||
trustLevelEntity?.deleteFromRealm()
|
||||
deleteFromRealm()
|
||||
}
|
||||
|
||||
*/
|
||||
|
@ -16,15 +16,15 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
|
||||
internal open class KeyRequestReplyEntity(
|
||||
var senderId: String? = null,
|
||||
var fromDevice: String? = null,
|
||||
var eventJson: String? = null
|
||||
) : RealmObject() {
|
||||
internal class KeyRequestReplyEntity : RealmObject {
|
||||
var senderId: String? = null
|
||||
var fromDevice: String? = null
|
||||
var eventJson: String? = null
|
||||
|
||||
companion object
|
||||
|
||||
fun getEvent(): Event? {
|
||||
|
@ -16,15 +16,17 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
|
||||
internal open class KeysBackupDataEntity(
|
||||
// Primary key to update this object. There is only one object, so it's a constant, please do not set it
|
||||
@PrimaryKey
|
||||
var primaryKey: Int = 0,
|
||||
// The last known hash of the backed up keys on the server
|
||||
var backupLastServerHash: String? = null,
|
||||
// The last known number of backed up keys on the server
|
||||
var backupLastServerNumberOfKeys: Int? = null
|
||||
) : RealmObject()
|
||||
internal class KeysBackupDataEntity : RealmObject {
|
||||
// Primary key to update this object. There is only one object, so it's a constant, please do not set it
|
||||
@PrimaryKey
|
||||
var primaryKey: Int = 0
|
||||
|
||||
// The last known hash of the backed up keys on the server
|
||||
var backupLastServerHash: String? = null
|
||||
|
||||
// The last known number of backed up keys on the server
|
||||
var backupLastServerNumberOfKeys: Int? = null
|
||||
}
|
||||
|
@ -16,21 +16,24 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
|
||||
internal open class MyDeviceLastSeenInfoEntity(
|
||||
/** The device id. */
|
||||
@PrimaryKey var deviceId: String? = null,
|
||||
/** The device display name. */
|
||||
var displayName: String? = null,
|
||||
/** The last time this device has been seen. */
|
||||
var lastSeenTs: Long? = null,
|
||||
/** The last ip address. */
|
||||
var lastSeenIp: String? = null,
|
||||
/** The last user agent. */
|
||||
var lastSeenUserAgent: String? = null,
|
||||
) : RealmObject() {
|
||||
internal class MyDeviceLastSeenInfoEntity : RealmObject {
|
||||
/** The device id. */
|
||||
@PrimaryKey var deviceId: String? = null
|
||||
|
||||
/** The device display name. */
|
||||
var displayName: String? = null
|
||||
|
||||
/** The last time this device has been seen. */
|
||||
var lastSeenTs: Long? = null
|
||||
|
||||
/** The last ip address. */
|
||||
var lastSeenIp: String? = null
|
||||
|
||||
/** The last user agent. */
|
||||
var lastSeenUserAgent: String? = null
|
||||
|
||||
companion object
|
||||
}
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.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
|
||||
@ -28,33 +28,32 @@ import timber.log.Timber
|
||||
|
||||
internal fun OlmInboundGroupSessionEntity.Companion.createPrimaryKey(sessionId: String?, senderKey: String?) = "$sessionId|$senderKey"
|
||||
|
||||
internal open class OlmInboundGroupSessionEntity(
|
||||
// Combined value to build a primary key
|
||||
@PrimaryKey var primaryKey: String? = null,
|
||||
internal class OlmInboundGroupSessionEntity : RealmObject {
|
||||
// Combined value to build a primary key
|
||||
@PrimaryKey var primaryKey: String? = null
|
||||
|
||||
// denormalization for faster querying (these fields are in the inboundGroupSessionDataJson)
|
||||
var sessionId: String? = null,
|
||||
var senderKey: String? = null,
|
||||
var roomId: String? = null,
|
||||
// denormalization for faster querying (these fields are in the inboundGroupSessionDataJson)
|
||||
var sessionId: String? = null
|
||||
var senderKey: String? = null
|
||||
var roomId: String? = null
|
||||
|
||||
// Deprecated, used for migration / olmInboundGroupSessionData contains Json
|
||||
// keep it in case of problem to have a chance to recover
|
||||
var olmInboundGroupSessionData: String? = null,
|
||||
// Deprecated, used for migration / olmInboundGroupSessionData contains Json
|
||||
// keep it in case of problem to have a chance to recover
|
||||
var olmInboundGroupSessionData: String? = null
|
||||
|
||||
// Stores the session data in an extensible format
|
||||
// to allow to store data not yet supported for later use
|
||||
var inboundGroupSessionDataJson: String? = null,
|
||||
// Stores the session data in an extensible format
|
||||
// to allow to store data not yet supported for later use
|
||||
var inboundGroupSessionDataJson: String? = null
|
||||
|
||||
// The pickled session
|
||||
var serializedOlmInboundGroupSession: String? = null,
|
||||
// The pickled session
|
||||
var serializedOlmInboundGroupSession: String? = null
|
||||
|
||||
// Flag that indicates whether or not the current inboundSession will be shared to
|
||||
// invited users to decrypt past messages
|
||||
var sharedHistory: Boolean = false,
|
||||
// Indicate if the key has been backed up to the homeserver
|
||||
var backedUp: Boolean = false
|
||||
) :
|
||||
RealmObject() {
|
||||
// Flag that indicates whether or not the current inboundSession will be shared to
|
||||
// invited users to decrypt past messages
|
||||
var sharedHistory: Boolean = false
|
||||
|
||||
// Indicate if the key has been backed up to the homeserver
|
||||
var backedUp: Boolean = false
|
||||
|
||||
fun store(wrapper: MXInboundMegolmSessionWrapper) {
|
||||
this.serializedOlmInboundGroupSession = serializeForRealm(wrapper.session)
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.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
|
||||
@ -25,14 +25,12 @@ import org.matrix.olm.OlmSession
|
||||
internal fun OlmSessionEntity.Companion.createPrimaryKey(sessionId: String, deviceKey: String) = "$sessionId|$deviceKey"
|
||||
|
||||
// olmSessionData is a serialized OlmSession
|
||||
internal open class OlmSessionEntity(
|
||||
@PrimaryKey var primaryKey: String = "",
|
||||
var sessionId: String? = null,
|
||||
var deviceKey: String? = null,
|
||||
var olmSessionData: String? = null,
|
||||
var lastReceivedMessageTs: Long = 0
|
||||
) :
|
||||
RealmObject() {
|
||||
internal class OlmSessionEntity : RealmObject {
|
||||
@PrimaryKey var primaryKey: String = ""
|
||||
var sessionId: String? = null
|
||||
var deviceKey: String? = null
|
||||
var olmSessionData: String? = null
|
||||
var lastReceivedMessageTs: Long = 0
|
||||
|
||||
fun getOlmSession(): OlmSession? {
|
||||
return deserializeFromRealm(olmSessionData)
|
||||
|
@ -16,17 +16,16 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.kotlin.types.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,
|
||||
var creationTime: Long? = null,
|
||||
var shouldShareHistory: Boolean = false
|
||||
) : RealmObject() {
|
||||
internal class OutboundGroupSessionInfoEntity : RealmObject {
|
||||
var serializedOutboundSessionData: String? = null
|
||||
var creationTime: Long? = null
|
||||
var shouldShareHistory: Boolean = false
|
||||
|
||||
fun getOutboundGroupSession(): OlmOutboundGroupSession? {
|
||||
return try {
|
||||
|
@ -18,9 +18,10 @@ package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.Types
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Index
|
||||
import io.realm.kotlin.ext.realmListOf
|
||||
import io.realm.kotlin.types.RealmList
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.Index
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest
|
||||
import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
|
||||
@ -33,18 +34,17 @@ import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldCo
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
|
||||
internal open class OutgoingKeyRequestEntity(
|
||||
@Index var requestId: String? = null,
|
||||
var requestedIndex: Int? = null,
|
||||
var recipientsData: String? = null,
|
||||
var requestedInfoStr: String? = null,
|
||||
var creationTimeStamp: Long? = null,
|
||||
// de-normalization for better query (if not have to query all and parse json)
|
||||
@Index var roomId: String? = null,
|
||||
@Index var megolmSessionId: String? = null,
|
||||
internal class OutgoingKeyRequestEntity : RealmObject {
|
||||
@Index var requestId: String? = null
|
||||
var requestedIndex: Int? = null
|
||||
var recipientsData: String? = null
|
||||
var requestedInfoStr: String? = null
|
||||
var creationTimeStamp: Long? = null
|
||||
|
||||
var replies: RealmList<KeyRequestReplyEntity> = RealmList()
|
||||
) : RealmObject() {
|
||||
// de-normalization for better query (if not have to query all and parse json)
|
||||
@Index var roomId: String? = null
|
||||
@Index var megolmSessionId: String? = null
|
||||
var replies: RealmList<KeyRequestReplyEntity> = realmListOf()
|
||||
|
||||
@Index private var requestStateStr: String = OutgoingRoomKeyRequestState.UNSENT.name
|
||||
|
||||
@ -84,11 +84,11 @@ internal open class OutgoingKeyRequestEntity(
|
||||
}
|
||||
|
||||
fun addReply(userId: String, fromDevice: String?, event: Event) {
|
||||
val newReply = KeyRequestReplyEntity(
|
||||
senderId = userId,
|
||||
fromDevice = fromDevice,
|
||||
eventJson = MoshiProvider.providesMoshi().adapter(Event::class.java).toJson(event)
|
||||
)
|
||||
val newReply = KeyRequestReplyEntity().apply {
|
||||
this.senderId = userId
|
||||
this.fromDevice = fromDevice
|
||||
this.eventJson = MoshiProvider.providesMoshi().adapter(Event::class.java).toJson(event)
|
||||
}
|
||||
replies.add(newReply)
|
||||
}
|
||||
|
||||
@ -130,7 +130,10 @@ internal open class OutgoingKeyRequestEntity(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
internal fun OutgoingKeyRequestEntity.deleteOnCascade() {
|
||||
replies.deleteAllFromRealm()
|
||||
deleteFromRealm()
|
||||
}
|
||||
|
||||
*/
|
||||
|
@ -16,23 +16,22 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Index
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.Index
|
||||
|
||||
/**
|
||||
* Keep a record of to whom (user/device) a given session should have been shared.
|
||||
* It will be used to reply to keyshare requests from other users, in order to see if
|
||||
* this session was originaly shared with a given user
|
||||
*/
|
||||
internal open class SharedSessionEntity(
|
||||
var roomId: String? = null,
|
||||
var algorithm: String? = null,
|
||||
@Index var sessionId: String? = null,
|
||||
@Index var userId: String? = null,
|
||||
@Index var deviceId: String? = null,
|
||||
@Index var deviceIdentityKey: String? = null,
|
||||
var chainIndex: Int? = null
|
||||
) : RealmObject() {
|
||||
internal class SharedSessionEntity : RealmObject {
|
||||
var roomId: String? = null
|
||||
var algorithm: String? = null
|
||||
@Index var sessionId: String? = null
|
||||
@Index var userId: String? = null
|
||||
@Index var deviceId: String? = null
|
||||
@Index var deviceIdentityKey: String? = null
|
||||
var chainIndex: Int? = null
|
||||
|
||||
companion object
|
||||
}
|
||||
|
@ -16,12 +16,11 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
|
||||
internal open class TrustLevelEntity(
|
||||
var crossSignedVerified: Boolean? = null,
|
||||
var locallyVerified: Boolean? = null
|
||||
) : RealmObject() {
|
||||
internal class TrustLevelEntity : RealmObject {
|
||||
var crossSignedVerified: Boolean? = null
|
||||
var locallyVerified: Boolean? = null
|
||||
|
||||
companion object
|
||||
|
||||
|
@ -16,23 +16,25 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import org.matrix.android.sdk.internal.extensions.clearWith
|
||||
import io.realm.kotlin.ext.realmListOf
|
||||
import io.realm.kotlin.types.RealmList
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
|
||||
internal open class UserEntity(
|
||||
@PrimaryKey var userId: String? = null,
|
||||
var devices: RealmList<DeviceInfoEntity> = RealmList(),
|
||||
var crossSigningInfoEntity: CrossSigningInfoEntity? = null,
|
||||
var deviceTrackingStatus: Int = 0
|
||||
) : RealmObject() {
|
||||
internal class UserEntity : RealmObject {
|
||||
@PrimaryKey var userId: String? = null
|
||||
var devices: RealmList<DeviceInfoEntity> = realmListOf()
|
||||
var crossSigningInfoEntity: CrossSigningInfoEntity? = null
|
||||
var deviceTrackingStatus: Int = 0
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
/*
|
||||
internal fun UserEntity.deleteOnCascade() {
|
||||
devices.clearWith { it.deleteOnCascade() }
|
||||
crossSigningInfoEntity?.deleteOnCascade()
|
||||
deleteFromRealm()
|
||||
}
|
||||
|
||||
*/
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Index
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.Index
|
||||
import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
|
||||
|
||||
/**
|
||||
@ -27,14 +27,13 @@ import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
|
||||
* For example, the sender may have blacklisted certain devices or users,
|
||||
* or may be choosing to not send the megolm key to devices that they have not verified yet.
|
||||
*/
|
||||
internal open class WithHeldSessionEntity(
|
||||
var roomId: String? = null,
|
||||
var algorithm: String? = null,
|
||||
@Index var sessionId: String? = null,
|
||||
@Index var senderKey: String? = null,
|
||||
var codeString: String? = null,
|
||||
var reason: String? = null
|
||||
) : RealmObject() {
|
||||
internal class WithHeldSessionEntity : RealmObject {
|
||||
var roomId: String? = null
|
||||
var algorithm: String? = null
|
||||
@Index var sessionId: String? = null
|
||||
@Index var senderKey: String? = null
|
||||
var codeString: String? = null
|
||||
var reason: String? = null
|
||||
|
||||
var code: WithHeldCode?
|
||||
get() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
* 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.
|
||||
@ -16,21 +16,15 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
import io.realm.kotlin.TypedRealm
|
||||
import io.realm.kotlin.query.RealmSingleQuery
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
|
||||
|
||||
internal fun CrossSigningInfoEntity.Companion.getOrCreate(realm: Realm, userId: String): CrossSigningInfoEntity {
|
||||
return realm.where<CrossSigningInfoEntity>()
|
||||
.equalTo(UserEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
?: realm.createObject(userId)
|
||||
internal class CrossSigningInfoEntityQueries(realm: TypedRealm) : TypedRealm by realm {
|
||||
|
||||
fun firstUserId(userId: String): RealmSingleQuery<CrossSigningInfoEntity> {
|
||||
return query(CrossSigningInfoEntity::class, "userId == $0", userId).first()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun CrossSigningInfoEntity.Companion.get(realm: Realm, userId: String): CrossSigningInfoEntity? {
|
||||
return realm.where<CrossSigningInfoEntity>()
|
||||
.equalTo(UserEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
}
|
||||
internal fun TypedRealm.crossSigningInfoEntityQueries() = CrossSigningInfoEntityQueries(this)
|
||||
|
@ -1,39 +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.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||
|
||||
/**
|
||||
* Get or create a room.
|
||||
*/
|
||||
internal fun CryptoRoomEntity.Companion.getOrCreate(realm: Realm, roomId: String): CryptoRoomEntity {
|
||||
return getById(realm, roomId) ?: realm.createObject(roomId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a room.
|
||||
*/
|
||||
internal fun CryptoRoomEntity.Companion.getById(realm: Realm, roomId: String): CryptoRoomEntity? {
|
||||
return realm.where<CryptoRoomEntity>()
|
||||
.equalTo(CryptoRoomEntityFields.ROOM_ID, roomId)
|
||||
.findFirst()
|
||||
}
|
@ -1,39 +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.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.createPrimaryKey
|
||||
|
||||
/**
|
||||
* Get or create a device info.
|
||||
*/
|
||||
internal fun DeviceInfoEntity.Companion.getOrCreate(realm: Realm, userId: String, deviceId: String): DeviceInfoEntity {
|
||||
val key = DeviceInfoEntity.createPrimaryKey(userId, deviceId)
|
||||
|
||||
return realm.where<DeviceInfoEntity>()
|
||||
.equalTo(DeviceInfoEntityFields.PRIMARY_KEY, key)
|
||||
.findFirst()
|
||||
?: realm.createObject<DeviceInfoEntity>(key)
|
||||
.apply {
|
||||
this.deviceId = deviceId
|
||||
}
|
||||
}
|
@ -1,71 +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.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmResults
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields
|
||||
|
||||
internal fun SharedSessionEntity.Companion.get(
|
||||
realm: Realm,
|
||||
roomId: String?,
|
||||
sessionId: String,
|
||||
userId: String,
|
||||
deviceId: String,
|
||||
deviceIdentityKey: String?
|
||||
): SharedSessionEntity? {
|
||||
return realm.where<SharedSessionEntity>()
|
||||
.equalTo(SharedSessionEntityFields.ROOM_ID, roomId)
|
||||
.equalTo(SharedSessionEntityFields.SESSION_ID, sessionId)
|
||||
.equalTo(SharedSessionEntityFields.ALGORITHM, MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
.equalTo(SharedSessionEntityFields.USER_ID, userId)
|
||||
.equalTo(SharedSessionEntityFields.DEVICE_ID, deviceId)
|
||||
.equalTo(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, deviceIdentityKey)
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
internal fun SharedSessionEntity.Companion.get(realm: Realm, roomId: String?, sessionId: String): RealmResults<SharedSessionEntity> {
|
||||
return realm.where<SharedSessionEntity>()
|
||||
.equalTo(SharedSessionEntityFields.ROOM_ID, roomId)
|
||||
.equalTo(SharedSessionEntityFields.SESSION_ID, sessionId)
|
||||
.equalTo(SharedSessionEntityFields.ALGORITHM, MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
.findAll()
|
||||
}
|
||||
|
||||
internal fun SharedSessionEntity.Companion.create(
|
||||
realm: Realm,
|
||||
roomId: String?,
|
||||
sessionId: String,
|
||||
userId: String,
|
||||
deviceId: String,
|
||||
deviceIdentityKey: String,
|
||||
chainIndex: Int
|
||||
): SharedSessionEntity {
|
||||
return realm.createObject<SharedSessionEntity>().apply {
|
||||
this.roomId = roomId
|
||||
this.algorithm = MXCRYPTO_ALGORITHM_MEGOLM
|
||||
this.sessionId = sessionId
|
||||
this.userId = userId
|
||||
this.deviceId = deviceId
|
||||
this.deviceIdentityKey = deviceIdentityKey
|
||||
this.chainIndex = chainIndex
|
||||
}
|
||||
}
|
@ -1,44 +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.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
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.crypto.store.db.model.deleteOnCascade
|
||||
|
||||
/**
|
||||
* Get or create a user.
|
||||
*/
|
||||
internal fun UserEntity.Companion.getOrCreate(realm: Realm, userId: String): UserEntity {
|
||||
return realm.where<UserEntity>()
|
||||
.equalTo(UserEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
?: realm.createObject(userId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a user.
|
||||
*/
|
||||
internal fun UserEntity.Companion.delete(realm: Realm, userId: String) {
|
||||
realm.where<UserEntity>()
|
||||
.equalTo(UserEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
?.deleteOnCascade()
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.db.query
|
||||
|
||||
import io.realm.kotlin.TypedRealm
|
||||
import io.realm.kotlin.query.RealmQuery
|
||||
import io.realm.kotlin.query.RealmSingleQuery
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
|
||||
import org.matrix.android.sdk.internal.database.queryIn
|
||||
|
||||
internal class UserEntityQueries(
|
||||
private val realm: TypedRealm,
|
||||
) {
|
||||
|
||||
fun all(): RealmQuery<UserEntity> {
|
||||
return realm.query(UserEntity::class)
|
||||
}
|
||||
|
||||
fun byUserId(userId: String): RealmQuery<UserEntity> {
|
||||
return all().query("userId == $0", userId)
|
||||
}
|
||||
|
||||
fun firstUserId(userId: String): RealmSingleQuery<UserEntity> {
|
||||
return byUserId(userId).first()
|
||||
}
|
||||
|
||||
fun byUserIds(userIds: List<String>): RealmQuery<UserEntity> {
|
||||
return all().queryIn("userId", userIds)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun TypedRealm.userEntityQueries() = UserEntityQueries(this)
|
@ -1,41 +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.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntityFields
|
||||
|
||||
internal fun WithHeldSessionEntity.Companion.get(realm: Realm, roomId: String, sessionId: String): WithHeldSessionEntity? {
|
||||
return realm.where<WithHeldSessionEntity>()
|
||||
.equalTo(WithHeldSessionEntityFields.ROOM_ID, roomId)
|
||||
.equalTo(WithHeldSessionEntityFields.SESSION_ID, sessionId)
|
||||
.equalTo(WithHeldSessionEntityFields.ALGORITHM, MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
internal fun WithHeldSessionEntity.Companion.getOrCreate(realm: Realm, roomId: String, sessionId: String): WithHeldSessionEntity? {
|
||||
return get(realm, roomId, sessionId)
|
||||
?: realm.createObject<WithHeldSessionEntity>().apply {
|
||||
this.roomId = roomId
|
||||
this.algorithm = MXCRYPTO_ALGORITHM_MEGOLM
|
||||
this.sessionId = sessionId
|
||||
}
|
||||
}
|
@ -81,6 +81,7 @@ import org.matrix.android.sdk.internal.crypto.verification.qrcode.DefaultQrCodeV
|
||||
import org.matrix.android.sdk.internal.crypto.verification.qrcode.QrCodeData
|
||||
import org.matrix.android.sdk.internal.crypto.verification.qrcode.generateSharedSecretV2
|
||||
import org.matrix.android.sdk.internal.di.DeviceId
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.task.TaskExecutor
|
||||
@ -104,7 +105,7 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
private val verificationTransportRoomMessageFactory: VerificationTransportRoomMessageFactory,
|
||||
private val verificationTransportToDeviceFactory: VerificationTransportToDeviceFactory,
|
||||
private val crossSigningService: CrossSigningService,
|
||||
private val cryptoCoroutineScope: CoroutineScope,
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val clock: Clock,
|
||||
) : DefaultVerificationTransaction.Listener, VerificationService {
|
||||
@ -127,7 +128,7 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
// Event received from the sync
|
||||
fun onToDeviceEvent(event: Event) {
|
||||
Timber.d("## SAS onToDeviceEvent ${event.getClearType()}")
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.dmVerif) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.dmVerif) {
|
||||
when (event.getClearType()) {
|
||||
EventType.KEY_VERIFICATION_START -> {
|
||||
onStartRequestReceived(event)
|
||||
@ -161,7 +162,7 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
}
|
||||
|
||||
fun onRoomEvent(event: Event) {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.dmVerif) {
|
||||
sessionCoroutineScope.launch(coroutineDispatchers.dmVerif) {
|
||||
when (event.getClearType()) {
|
||||
EventType.KEY_VERIFICATION_START -> {
|
||||
onRoomStartRequestReceived(event)
|
||||
@ -306,7 +307,7 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
|
||||
Timber.v("## SAS onRequestReceived from $senderId and device $otherDeviceId, txId:${validRequestInfo.transactionId}")
|
||||
|
||||
cryptoCoroutineScope.launch {
|
||||
sessionCoroutineScope.launch {
|
||||
if (checkKeysAreDownloaded(senderId, otherDeviceId) == null) {
|
||||
Timber.e("## Verification device $otherDeviceId is not known")
|
||||
}
|
||||
@ -827,7 +828,7 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
?.let { vt ->
|
||||
val otherDeviceId = vt.otherDeviceId ?: return@let
|
||||
if (!crossSigningService.canCrossSign()) {
|
||||
cryptoCoroutineScope.launch {
|
||||
sessionCoroutineScope.launch {
|
||||
secretShareManager.requestSecretTo(otherDeviceId, MASTER_KEY_SSSS_NAME)
|
||||
secretShareManager.requestSecretTo(otherDeviceId, SELF_SIGNING_KEY_SSSS_NAME)
|
||||
secretShareManager.requestSecretTo(otherDeviceId, USER_SIGNING_KEY_SSSS_NAME)
|
||||
|
@ -53,12 +53,12 @@ internal class VerificationTransportRoomMessage(
|
||||
private val roomId: String,
|
||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||
private val tx: DefaultVerificationTransaction?,
|
||||
cryptoCoroutineScope: CoroutineScope,
|
||||
sessionCoroutineScope: CoroutineScope,
|
||||
private val clock: Clock,
|
||||
) : VerificationTransport {
|
||||
|
||||
private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
|
||||
private val verificationSenderScope = CoroutineScope(cryptoCoroutineScope.coroutineContext + dispatcher)
|
||||
private val verificationSenderScope = CoroutineScope(sessionCoroutineScope.coroutineContext + dispatcher)
|
||||
private val sequencer = SemaphoreCoroutineSequencer()
|
||||
|
||||
override fun <T> sendToOther(
|
||||
|
@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.crypto.verification
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.SendVerificationMessageTask
|
||||
import org.matrix.android.sdk.internal.di.DeviceId
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
@ -31,7 +32,7 @@ internal class VerificationTransportRoomMessageFactory @Inject constructor(
|
||||
@DeviceId
|
||||
private val deviceId: String?,
|
||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||
private val cryptoCoroutineScope: CoroutineScope,
|
||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||
private val clock: Clock,
|
||||
) {
|
||||
|
||||
@ -43,7 +44,7 @@ internal class VerificationTransportRoomMessageFactory @Inject constructor(
|
||||
roomId = roomId,
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
tx = tx,
|
||||
cryptoCoroutineScope = cryptoCoroutineScope,
|
||||
sessionCoroutineScope = sessionCoroutineScope,
|
||||
clock = clock,
|
||||
)
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user