Compare commits

...

79 Commits

Author SHA1 Message Date
ganfra
fc19bf8e5b Realm-kotlin: add name to timeline coroutine scope 2022-10-21 17:13:22 +02:00
ganfra
e1031fab0f Realm-kotlin: introduce queryFirstMapped so we can map on the same dispatcher 2022-10-21 17:13:13 +02:00
Benoit Marty
b806bd59a1 Small cleanup 2022-10-21 10:10:45 +02:00
Benoit Marty
97d82866b6 Make ./gradlew assembleAndroidTest success. Some tests are not passing though, in particular ensureKeysAreNotSharedIfOptionDisabled() 2022-10-21 10:06:28 +02:00
Benoit Marty
974079ff00 delete all objects. 2022-10-20 17:49:05 +02:00
Benoit Marty
9dca4293a1 Restore previous comment 2022-10-20 17:36:12 +02:00
Benoit Marty
47ca9a07af Use updateCryptoMetadata. 2022-10-20 16:44:07 +02:00
ganfra
7527693a05 Realm-kotlin: implements equals where needed as objects are frozen now 2022-10-20 11:57:13 +02:00
ganfra
ca4ed5c822 Realm-kotlin: makes timelineScope child of sessionScope 2022-10-20 11:56:33 +02:00
ganfra
e6f911a64b Realm-kotlin : dispatch map to coroutineDispatcher 2022-10-20 11:54:12 +02:00
Benoit Marty
e7587a6f47 Fix compilation issue and ensure we update existing data. 2022-10-19 15:42:14 +02:00
Benoit Marty
c43b50b675 Import Sort to avoid using long qualifier. 2022-10-19 15:26:20 +02:00
Benoit Marty
054c61d076 Merge branch 'develop' into feature/fga/realm_kotlin_session 2022-10-19 15:24:47 +02:00
Benoit Marty
1210e8c712 Remove unnecessary TypedRealm by realm 2022-10-19 15:01:11 +02:00
Benoit Marty
f27f9f3ae5 Sort classes following the alphabetical order. 2022-10-19 14:54:25 +02:00
Benoit Marty
a5b6a01691 Realm 1.4.0
Should fix this problem: https://github.com/realm/realm-kotlin/issues/1024#issuecomment-1282192523
2022-10-19 14:49:26 +02:00
Benoit Marty
978294cdc0 Merge remote-tracking branch 'origin/feature/fga/realm_kotlin_session' into feature/fga/realm_kotlin_session 2022-10-19 14:38:51 +02:00
Benoit Marty
18481211df Fix all merge conflict and compilation issue after merging develop to this branch. 2022-10-19 14:38:08 +02:00
ganfra
f7b6ed1963 Realm-kotlin : fix timeline pagination 2022-10-19 11:54:50 +02:00
ganfra
433704191c Realm-kotlin : fix EventInsertLiveObserver 2022-10-19 11:25:28 +02:00
ganfra
ad772222d6 Realm-kotlin: fix pagedlist scope 2022-10-18 19:16:20 +02:00
ganfra
ac14c8cd27 Realm-kotlin: fix breadcrump update 2022-10-18 19:16:12 +02:00
ganfra
0b0b2d5d63 Realm-kotlin: fix room order query 2022-10-18 19:16:04 +02:00
ganfra
14099be861 Realm-kotlin : update to 1.3.0 and use provided deleteAll methods 2022-10-18 19:15:50 +02:00
Benoit Marty
47cf9e58bd Merge branch 'develop' into feature/fga/realm_kotlin_session
Will fix all the conflicts in a dedicated commit.
2022-10-18 14:32:59 +02:00
Benoit Marty
fec9b0d83a Prefer using parametrization 2022-10-18 14:07:17 +02:00
Benoit Marty
2db5f5a5f0 Reuse $0 parameter 2022-10-18 14:07:01 +02:00
Benoit Marty
27bbd18a74 Run ./gradlew ktlintFormat 2022-10-18 12:54:24 +02:00
Benoit Marty
5b58f6cfe5 Remove unused dependency dk.ilios:realmfieldnameshelper 2022-10-18 12:51:35 +02:00
ganfra
ad0af11358 Realm-kotlin: fix crashes on some event processors 2022-10-17 21:18:09 +02:00
ganfra
e20febb4a0 Realm-kotlin : fix issue on low_priority filter 2022-10-17 21:17:55 +02:00
ganfra
f3d36e4d31 Realm-kotlin: fix some issues on rooms and timeline 2022-10-17 21:08:46 +02:00
ganfra
3aba7803dd realm-kotlin : make app compile! 2022-10-14 12:02:25 +02:00
ganfra
6379c199ea Realm-kotlin: handle a bunch of classes on session db (timeline, eventinsertentity and some more tasks) 2022-10-13 12:54:26 +02:00
ganfra
6edea43ab4 Realm-kotlin : continue migrating session db 2022-10-06 19:28:09 +02:00
ganfra
5d73118c8c Realm-kotlin: continue migration of session 2022-10-05 19:42:15 +02:00
ganfra
a93bba88ac Realm-kotlin: continue to migrate session... 2022-10-04 19:24:52 +02:00
ganfra
85969f3d81 Realm kotlin: migrate a bunch of tasks 2022-09-29 20:04:36 +02:00
ganfra
5b0f7b7b7c Realm kotlin: migrate UserAccountDataDataSource 2022-09-29 18:44:36 +02:00
ganfra
981ab5bc87 Realm kotlin: migrate ScalarTokenStore 2022-09-29 18:42:41 +02:00
ganfra
baa854e5f2 Realm kotlin: migrate FilterRepository 2022-09-29 18:39:54 +02:00
ganfra
6b3ce7872e Realm kotlin: migrate localecho 2022-09-29 18:09:19 +02:00
ganfra
87a3362e62 Realm kotlin : continue to migrate session 2022-09-29 17:48:10 +02:00
ganfra
d7e93e8229 Realm session: more queries 2022-09-28 21:08:29 +02:00
ganfra
184edd9398 Realm kotlin session: continue on RoomSummary 2022-09-28 16:50:34 +02:00
ganfra
a4a4bac75b Realm kotlin: continue migrating queries (some are blocked by lack of backlink) 2022-09-16 19:24:23 +02:00
ganfra
aeaf4389a8 Realm kotlin session: loop through entities 2022-08-24 19:56:50 +02:00
ganfra
7ea73d3ad0 Merge branch 'develop' into feature/fga/realm_kotlin 2022-08-24 16:29:34 +02:00
ganfra
4bdc880eb6
Merge pull request #6775 from vector-im/feature/fga/realm_kotlin_crypto
Feature/fga/realm kotlin crypto
2022-08-24 13:20:50 +02:00
ganfra
913d430d1e Realm kotlin : fix warnings 2022-08-24 12:41:08 +02:00
ganfra
81629b81f1 Realm kotlin: format code 2022-08-08 15:31:40 +02:00
ganfra
def2b0067f Coroutine scope: update some coroutine scopes 2022-08-05 20:33:57 +02:00
ganfra
948e24065f Realm: fix realm instance close too soon 2022-08-05 20:33:45 +02:00
ganfra
d0cb078f18 Coroutine: use SessionCoroutineScope and update MatrixCoroutineScope 2022-08-05 19:29:54 +02:00
ganfra
f25764d09a Realm crypto: update test 2022-08-05 19:29:10 +02:00
ganfra
2cdd05072b Realm: fix upsert on other dbs 2022-08-05 19:28:31 +02:00
ganfra
5b91c14e71 Realm crypto: migrate RealmCryptoStore 2022-08-05 19:27:49 +02:00
ganfra
7717637e57 Realm crypto: Update migration classes 2022-08-05 19:23:50 +02:00
ganfra
6cfac4526e Realm: update some methods use on RealmInstance 2022-08-05 19:20:34 +02:00
ganfra
462d1bce68 Realm crypto: migrate entity classes 2022-08-05 19:16:53 +02:00
ganfra
4040593608 Merge branch 'feature/fga/realm_kotlin_content_scanner' into feature/fga/realm_kotlin 2022-07-29 17:59:09 +02:00
ganfra
a60f42fc00 Merge branch 'develop' into feature/fga/realm_kotlin 2022-07-29 17:43:31 +02:00
ganfra
af5bbe12f5 Realm: convert ContentScannerDatabase to realm-kotlin 2022-07-29 17:35:53 +02:00
ganfra
c5883b3e7c RealmQueryBuilder: use TypedRealm instead of Realm 2022-07-29 17:35:29 +02:00
ganfra
7e2f821287 Realm: fix small identity mistakes 2022-07-29 17:35:07 +02:00
ganfra
ed135bc4fc Realm: migrate identity db to realm-kotlin 2022-07-28 12:16:05 +02:00
ganfra
0fe189b3dd Coroutine: use MatrixCoroutineScope as parent for SessionCoroutineScope and inject it 2022-07-28 12:15:37 +02:00
ganfra
4b2043b64a Realm: use '==' instead of '=' on query language. 2022-07-26 19:18:41 +02:00
ganfra
58788e27d5 Merge branch 'develop' into feature/fga/realm_kotlin 2022-07-26 19:09:54 +02:00
ganfra
6fb5d7fc30 Realm : update copyright 2022-07-26 19:09:24 +02:00
ganfra
736bc3064f Realm: use realm-kotlin for GlobalDatabase 2022-07-26 18:58:25 +02:00
ganfra
e8f2ceaed4 Realm: introduce MatrixAutomaticSchemaMigration 2022-07-26 18:58:00 +02:00
ganfra
9bb53da626 Merge branch 'develop' into feature/fga/realm_kotlin 2022-07-25 18:46:44 +02:00
ganfra
1380c60d10 Realm : migrate Auth database to realm-kotlin 2022-07-22 19:49:40 +02:00
ganfra
4a68412777 Add MatrixCoroutineScope (configurable through MatrixConfiguration) 2022-07-22 19:43:36 +02:00
ganfra
dee0b824e9 Realm: use RealmModel instead of RealmObject so we can enable realm-kotlin plugin. 2022-07-22 12:27:29 +02:00
ganfra
186753f691 Realm: add RealmInstance class 2022-07-21 17:07:44 +02:00
ganfra
82180304ef Realm: add PagedList implementation 2022-07-21 17:07:33 +02:00
ganfra
52ebe74302 Realm : add realm-kotlin dependencies 2022-07-21 17:07:19 +02:00
408 changed files with 6896 additions and 9113 deletions

View File

@ -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"
],

View File

@ -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',

View File

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

View File

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

View File

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

View File

@ -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",

View File

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

View File

@ -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")!!,

View File

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

View File

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

View File

@ -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/",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.
*/

View File

@ -16,7 +16,7 @@
package org.matrix.android.sdk.internal.crypto.store.db
import io.realm.DynamicRealm
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo001Legacy
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo002Legacy
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo003RiotX
@ -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()
}
}

View File

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

View File

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

View File

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

View File

@ -16,20 +16,13 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import timber.log.Timber
internal class MigrateCryptoTo001Legacy(realm: DynamicRealm) : RealmMigrator(realm, 1) {
internal class MigrateCryptoTo001Legacy(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 1) {
override fun doMigrate(realm: DynamicRealm) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Add field lastReceivedMessageTs (Long) and set the value to 0")
realm.schema.get("OlmSessionEntity")
?.addField(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, Long::class.java)
?.transform {
it.setLong(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, 0)
}
}
}

View File

@ -16,71 +16,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)
}
}
}

View File

@ -16,68 +16,61 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.database.safeEnumerate
import org.matrix.androidsdk.crypto.data.MXDeviceInfo
import org.matrix.androidsdk.crypto.data.MXOlmInboundGroupSession2
import timber.log.Timber
internal class MigrateCryptoTo003RiotX(realm: DynamicRealm) : RealmMigrator(realm, 3) {
internal class MigrateCryptoTo003RiotX(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 3) {
override fun doMigrate(realm: DynamicRealm) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Migrate to RiotX model")
realm.schema.get("CryptoRoomEntity")
?.addFieldIfNotExists(CryptoRoomEntityFields.SHOULD_ENCRYPT_FOR_INVITED_MEMBERS, Boolean::class.java)
?.setRequiredIfNotAlready(CryptoRoomEntityFields.SHOULD_ENCRYPT_FOR_INVITED_MEMBERS, false)
// Convert format of MXDeviceInfo, package has to be the same.
realm.schema.get("DeviceInfoEntity")
?.transform { obj ->
try {
val oldSerializedData = obj.getString("deviceInfoData")
deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { legacyMxDeviceInfo ->
val newMxDeviceInfo = org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo(
deviceId = legacyMxDeviceInfo.deviceId,
userId = legacyMxDeviceInfo.userId,
algorithms = legacyMxDeviceInfo.algorithms,
keys = legacyMxDeviceInfo.keys,
signatures = legacyMxDeviceInfo.signatures,
unsigned = legacyMxDeviceInfo.unsigned,
verified = legacyMxDeviceInfo.mVerified
)
obj.setString("deviceInfoData", serializeForRealm(newMxDeviceInfo))
}
} catch (e: Exception) {
Timber.e(e, "Error")
}
migrationContext.safeEnumerate("DeviceInfoEntity") { oldObject, newObject ->
try {
val oldSerializedData = oldObject.getNullableValue("deviceInfoData", String::class)
deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { legacyMxDeviceInfo ->
val newMxDeviceInfo = org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo(
deviceId = legacyMxDeviceInfo.deviceId,
userId = legacyMxDeviceInfo.userId,
algorithms = legacyMxDeviceInfo.algorithms,
keys = legacyMxDeviceInfo.keys,
signatures = legacyMxDeviceInfo.signatures,
unsigned = legacyMxDeviceInfo.unsigned,
verified = legacyMxDeviceInfo.mVerified
)
newObject?.set("deviceInfoData", serializeForRealm(newMxDeviceInfo))
}
} catch (e: Exception) {
Timber.e(e, "Error")
}
}
// Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper
realm.schema.get("OlmInboundGroupSessionEntity")
?.transform { obj ->
try {
val oldSerializedData = obj.getString("olmInboundGroupSessionData")
deserializeFromRealm<MXOlmInboundGroupSession2>(oldSerializedData)?.let { mxOlmInboundGroupSession2 ->
val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier()
val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false)
.apply {
olmInboundGroupSession = mxOlmInboundGroupSession2.mSession
roomId = mxOlmInboundGroupSession2.mRoomId
senderKey = mxOlmInboundGroupSession2.mSenderKey
keysClaimed = mxOlmInboundGroupSession2.mKeysClaimed
forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain
}
migrationContext.enumerate("OlmInboundGroupSessionEntity") { oldObject, newObject ->
try {
val oldSerializedData = oldObject.getNullableValue("olmInboundGroupSessionData", String::class)
deserializeFromRealm<MXOlmInboundGroupSession2>(oldSerializedData)?.let { mxOlmInboundGroupSession2 ->
val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier()
val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false)
.apply {
olmInboundGroupSession = mxOlmInboundGroupSession2.mSession
roomId = mxOlmInboundGroupSession2.mRoomId
senderKey = mxOlmInboundGroupSession2.mSenderKey
keysClaimed = mxOlmInboundGroupSession2.mKeysClaimed
forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain
}
obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper))
}
} catch (e: Exception) {
Timber.e(e, "Error")
}
newObject?.set("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper))
}
} catch (e: Exception) {
Timber.e(e, "Error")
}
}
}
}

View File

@ -18,58 +18,28 @@ package org.matrix.android.sdk.internal.crypto.store.db.migration
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import io.realm.DynamicRealm
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.database.safeEnumerate
import org.matrix.android.sdk.internal.di.SerializeNulls
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber
// Version 4L added Cross Signing info persistence
internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) {
internal class MigrateCryptoTo004(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 4) {
override fun doMigrate(realm: DynamicRealm) {
if (realm.schema.contains("TrustLevelEntity")) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
if (migrationContext.oldRealm.schema()["TrustLevelEntity"] != null) {
Timber.d("Skipping Step 3 -> 4 because entities already exist")
return
}
Timber.d("Create KeyInfoEntity")
val trustLevelEntityEntitySchema = realm.schema.create("TrustLevelEntity")
.addField(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, Boolean::class.java)
.setNullable(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, true)
.addField(TrustLevelEntityFields.LOCALLY_VERIFIED, Boolean::class.java)
.setNullable(TrustLevelEntityFields.LOCALLY_VERIFIED, true)
val keyInfoEntitySchema = realm.schema.create("KeyInfoEntity")
.addField(KeyInfoEntityFields.PUBLIC_KEY_BASE64, String::class.java)
.addField(KeyInfoEntityFields.SIGNATURES, String::class.java)
.addRealmListField(KeyInfoEntityFields.USAGES.`$`, String::class.java)
.addRealmObjectField(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelEntityEntitySchema)
Timber.d("Create CrossSigningInfoEntity")
val crossSigningInfoSchema = realm.schema.create("CrossSigningInfoEntity")
.addField(CrossSigningInfoEntityFields.USER_ID, String::class.java)
.addPrimaryKey(CrossSigningInfoEntityFields.USER_ID)
.addRealmListField(CrossSigningInfoEntityFields.CROSS_SIGNING_KEYS.`$`, keyInfoEntitySchema)
Timber.d("Updating UserEntity table")
realm.schema.get("UserEntity")
?.addRealmObjectField(UserEntityFields.CROSS_SIGNING_INFO_ENTITY.`$`, crossSigningInfoSchema)
Timber.d("Updating CryptoMetadataEntity table")
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.X_SIGN_MASTER_PRIVATE_KEY, String::class.java)
?.addField(CryptoMetadataEntityFields.X_SIGN_USER_PRIVATE_KEY, String::class.java)
?.addField(CryptoMetadataEntityFields.X_SIGN_SELF_SIGNED_PRIVATE_KEY, String::class.java)
val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build()
val listMigrationAdapter = moshi.adapter<List<String>>(
@ -87,57 +57,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..
}
}
}
}

View File

@ -16,47 +16,17 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import timber.log.Timber
internal class MigrateCryptoTo005(realm: DynamicRealm) : RealmMigrator(realm, 5) {
internal class MigrateCryptoTo005(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 5) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.remove("OutgoingRoomKeyRequestEntity")
realm.schema.remove("IncomingRoomKeyRequestEntity")
// Not need to migrate existing request, just start fresh?
realm.schema.create("GossipingEventEntity")
.addField("type", String::class.java)
.addIndex("type")
.addField("content", String::class.java)
.addField("sender", String::class.java)
.addIndex("sender")
.addField("decryptionResultJson", String::class.java)
.addField("decryptionErrorCode", String::class.java)
.addField("ageLocalTs", Long::class.java)
.setNullable("ageLocalTs", true)
.addField("sendStateStr", String::class.java)
realm.schema.create("IncomingGossipingRequestEntity")
.addField("requestId", String::class.java)
.addIndex("requestId")
.addField("typeStr", String::class.java)
.addIndex("typeStr")
.addField("otherUserId", String::class.java)
.addField("requestedInfoStr", String::class.java)
.addField("otherDeviceId", String::class.java)
.addField("requestStateStr", String::class.java)
.addField("localCreationTimestamp", Long::class.java)
.setNullable("localCreationTimestamp", true)
realm.schema.create("OutgoingGossipingRequestEntity")
.addField("requestId", String::class.java)
.addIndex("requestId")
.addField("recipientsData", String::class.java)
.addField("requestedInfoStr", String::class.java)
.addField("typeStr", String::class.java)
.addIndex("typeStr")
.addField("requestStateStr", String::class.java)
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Remove OutgoingRoomKeyRequestEntity")
Timber.d("Remove IncomingRoomKeyRequestEntity")
Timber.d("Create GossipingEventEntity")
Timber.d("Create IncomingGossipingRequestEntity")
Timber.d("Create OutgoingGossipingRequestEntity")
}
}

View File

@ -16,17 +16,13 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import timber.log.Timber
internal class MigrateCryptoTo006(realm: DynamicRealm) : RealmMigrator(realm, 6) {
internal class MigrateCryptoTo006(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 6) {
override fun doMigrate(realm: DynamicRealm) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Updating CryptoMetadataEntity table")
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY, String::class.java)
?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY_VERSION, String::class.java)
}
}

View File

@ -16,45 +16,43 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import io.realm.kotlin.dynamic.getNullableValue
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber
internal class MigrateCryptoTo007(realm: DynamicRealm) : RealmMigrator(realm, 7) {
internal class MigrateCryptoTo007(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 7) {
override fun doMigrate(realm: DynamicRealm) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Updating KeyInfoEntity table")
val crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi())
val keyInfoEntities = realm.where("KeyInfoEntity").findAll()
val keyInfoEntities = migrationContext.newRealm.query("KeyInfoEntity").find()
try {
keyInfoEntities.forEach {
val stringSignatures = it.getString(KeyInfoEntityFields.SIGNATURES)
val stringSignatures: String? = it.getNullableValue("signatures")
val objectSignatures: Map<String, Map<String, String>>? = deserializeFromRealm(stringSignatures)
val jsonSignatures = crossSigningKeysMapper.serializeSignatures(objectSignatures)
it.setString(KeyInfoEntityFields.SIGNATURES, jsonSignatures)
it.set("signatures", jsonSignatures)
}
} catch (ignore: Throwable) {
}
// Migrate frozen classes
val inboundGroupSessions = realm.where("OlmInboundGroupSessionEntity").findAll()
val inboundGroupSessions = migrationContext.newRealm.query("OlmInboundGroupSessionEntity").find()
inboundGroupSessions.forEach { dynamicObject ->
dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { serializedObject ->
dynamicObject.getNullableValue("olmInboundGroupSessionData", String::class)?.let { serializedObject ->
try {
deserializeFromRealm<OlmInboundGroupSessionWrapper?>(serializedObject)?.let { oldFormat ->
val newFormat = oldFormat.exportKeys()?.let {
OlmInboundGroupSessionWrapper2(it)
}
dynamicObject.setString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA, serializeForRealm(newFormat))
dynamicObject.set("olmInboundGroupSessionData", serializeForRealm(newFormat))
}
} catch (failure: Throwable) {
Timber.e(failure, "## OlmInboundGroupSessionEntity migration failed")

View File

@ -16,35 +16,20 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.database.safeEnumerate
import org.matrix.android.sdk.internal.util.time.Clock
import timber.log.Timber
internal class MigrateCryptoTo008(
realm: DynamicRealm,
private val clock: Clock,
) : RealmMigrator(realm, 8) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.create("MyDeviceLastSeenInfoEntity")
.addField(MyDeviceLastSeenInfoEntityFields.DEVICE_ID, String::class.java)
.addPrimaryKey(MyDeviceLastSeenInfoEntityFields.DEVICE_ID)
.addField(MyDeviceLastSeenInfoEntityFields.DISPLAY_NAME, String::class.java)
.addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_IP, String::class.java)
.addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_TS, Long::class.java)
.setNullable(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_TS, true)
internal class MigrateCryptoTo008(context: AutomaticSchemaMigration.MigrationContext, private val clock: Clock) : KotlinRealmMigrator(context, 8) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Create MyDeviceLastSeenInfoEntity")
Timber.d("Update DeviceInfoEntity")
val now = clock.epochMillis()
realm.schema.get("DeviceInfoEntity")
?.addField(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, Long::class.java)
?.setNullable(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, true)
?.transform { deviceInfoEntity ->
tryOrNull {
deviceInfoEntity.setLong(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, now)
}
}
migrationContext.safeEnumerate("DeviceInfoEntity") { _, newObject ->
newObject?.set("firstTimeSeenLocalTs", now)
}
}
}

View File

@ -16,22 +16,20 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import timber.log.Timber
// Fixes duplicate devices in UserEntity#devices
internal class MigrateCryptoTo009(realm: DynamicRealm) : RealmMigrator(realm, 9) {
internal class MigrateCryptoTo009(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 9) {
override fun doMigrate(realm: DynamicRealm) {
val userEntities = realm.where("UserEntity").findAll()
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Fixes duplicate devices in UserEntity#devices")
val userEntities = migrationContext.newRealm.query("UserEntity").find()
userEntities.forEach {
try {
val deviceList = it.getList(UserEntityFields.DEVICES.`$`)
?: return@forEach
val distinct = deviceList.distinctBy { it.getString(DeviceInfoEntityFields.DEVICE_ID) }
val deviceList = it.getValueList("devices", DeviceInfoEntity::class)
val distinct = deviceList.distinctBy { it.deviceId }
if (distinct.size != deviceList.size) {
deviceList.clear()
deviceList.addAll(distinct)

View File

@ -16,35 +16,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")
}
}

View File

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

View File

@ -16,21 +16,15 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import timber.log.Timber
// Version 12L added outbound group session persistence
internal class MigrateCryptoTo012(realm: DynamicRealm) : RealmMigrator(realm, 12) {
internal class MigrateCryptoTo012(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 12) {
override fun doMigrate(realm: DynamicRealm) {
val outboundEntitySchema = realm.schema.create("OutboundGroupSessionInfoEntity")
.addField(OutboundGroupSessionInfoEntityFields.SERIALIZED_OUTBOUND_SESSION_DATA, String::class.java)
.addField(OutboundGroupSessionInfoEntityFields.CREATION_TIME, Long::class.java)
.setNullable(OutboundGroupSessionInfoEntityFields.CREATION_TIME, true)
realm.schema.get("CryptoRoomEntity")
?.addRealmObjectField(CryptoRoomEntityFields.OUTBOUND_SESSION_INFO.`$`, outboundEntitySchema)
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Create OutboundGroupSessionInfoEntity")
Timber.d("Update CryptoRoomEntity")
}
}

View File

@ -16,63 +16,26 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
// Version 13L delete unreferenced TrustLevelEntity
internal class MigrateCryptoTo013(realm: DynamicRealm) : RealmMigrator(realm, 13) {
internal class MigrateCryptoTo013(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 13) {
override fun doMigrate(realm: DynamicRealm) {
// Use a trick to do that... Ref: https://stackoverflow.com/questions/55221366
val trustLevelEntitySchema = realm.schema.get("TrustLevelEntity")
/*
Creating a new temp field called isLinked which is set to true for those which are
references by other objects. Rest of them are set to false. Then removing all
those which are false and hence duplicate and unnecessary. Then removing the temp field
isLinked
*/
var mainCounter = 0
var deviceInfoCounter = 0
var keyInfoCounter = 0
val deleteCounter: Int
trustLevelEntitySchema
?.addField("isLinked", Boolean::class.java)
?.transform { obj ->
// Setting to false for all by default
obj.set("isLinked", false)
mainCounter++
}
realm.schema.get("DeviceInfoEntity")?.transform { obj ->
// Setting to true for those which are referenced in DeviceInfoEntity
deviceInfoCounter++
obj.getObject("trustLevelEntity")?.set("isLinked", true)
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
val trustLevelEntities = migrationContext.newRealm.query("TrustLevelEntity").find()
val linkedTrustLevelEntities = mutableSetOf<TrustLevelEntity>()
val deviceInfoEntities = migrationContext.newRealm.query("DeviceInfoEntity").find()
deviceInfoEntities.forEach {
val trustLevelEntity = it.getNullableValue("trustLevelEntity", TrustLevelEntity::class)
if (trustLevelEntity != null) {
linkedTrustLevelEntities.add(trustLevelEntity)
}
}
realm.schema.get("KeyInfoEntity")?.transform { obj ->
// Setting to true for those which are referenced in KeyInfoEntity
keyInfoCounter++
obj.getObject("trustLevelEntity")?.set("isLinked", true)
}
// Removing all those which are set as false
realm.where("TrustLevelEntity")
.equalTo("isLinked", false)
.findAll()
.also { deleteCounter = it.size }
.deleteAllFromRealm()
trustLevelEntitySchema?.removeField("isLinked")
Timber.w("TrustLevelEntity cleanup: $mainCounter entities")
Timber.w("TrustLevelEntity cleanup: $deviceInfoCounter entities referenced in DeviceInfoEntities")
Timber.w("TrustLevelEntity cleanup: $keyInfoCounter entities referenced in KeyInfoEntity")
Timber.w("TrustLevelEntity cleanup: $deleteCounter entities deleted!")
if (mainCounter != deviceInfoCounter + keyInfoCounter + deleteCounter) {
Timber.e("TrustLevelEntity cleanup: Something is not correct...")
val unreferencedTrustLevelEntities = trustLevelEntities.subtract(linkedTrustLevelEntities)
unreferencedTrustLevelEntities.forEach {
migrationContext.newRealm.delete(it)
}
}
}

View File

@ -16,26 +16,28 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.database.safeEnumerate
import timber.log.Timber
// Version 14L Update the way we remember key sharing
internal class MigrateCryptoTo014(realm: DynamicRealm) : RealmMigrator(realm, 14) {
internal class MigrateCryptoTo014(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 14) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("SharedSessionEntity")
?.addField(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, String::class.java)
?.addIndex(SharedSessionEntityFields.DEVICE_IDENTITY_KEY)
?.transform {
val sharedUserId = it.getString(SharedSessionEntityFields.USER_ID)
val sharedDeviceId = it.getString(SharedSessionEntityFields.DEVICE_ID)
val knownDevice = realm.where("DeviceInfoEntity")
.equalTo(DeviceInfoEntityFields.USER_ID, sharedUserId)
.equalTo(DeviceInfoEntityFields.DEVICE_ID, sharedDeviceId)
.findFirst()
it.setString(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, knownDevice?.getString(DeviceInfoEntityFields.IDENTITY_KEY))
}
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Update SharedSessionEntity")
migrationContext.safeEnumerate("SharedSessionEntity") { oldObject, newObject ->
if (newObject == null) return@safeEnumerate
val sharedUserId = oldObject.getNullableValue("userId", String::class)
val sharedDeviceId = oldObject.getNullableValue("deviceId", String::class)
val knownDevice = migrationContext.newRealm.query("DeviceInfoEntity")
.query("userId == $0", sharedUserId)
.query("deviceId == $0", sharedDeviceId)
.first()
.find()
val deviceIdentityKey = knownDevice?.getNullableValue("identityKey", String::class)
newObject.set("deviceIdentityKey", deviceIdentityKey)
}
}
}

View File

@ -16,21 +16,21 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.database.safeEnumerate
import timber.log.Timber
// Version 15L adds wasEncryptedOnce field to CryptoRoomEntity
internal class MigrateCryptoTo015(realm: DynamicRealm) : RealmMigrator(realm, 15) {
internal class MigrateCryptoTo015(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 15) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("CryptoRoomEntity")
?.addField(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, Boolean::class.java)
?.setNullable(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, true)
?.transform {
val currentAlgorithm = it.getString(CryptoRoomEntityFields.ALGORITHM)
it.set(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, currentAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM)
}
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Update CryptoRoomEntity")
migrationContext.safeEnumerate("CryptoRoomEntity") { oldObject, newObject ->
if (newObject == null) return@safeEnumerate
val currentAlgorithm = oldObject.getNullableValue("algorithm", String::class)
newObject.set("wasEncryptedOnce", currentAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM)
}
}
}

View File

@ -16,55 +16,21 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyRequestReplyEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import timber.log.Timber
internal class MigrateCryptoTo016(realm: DynamicRealm) : RealmMigrator(realm, 16) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.remove("OutgoingGossipingRequestEntity")
realm.schema.remove("IncomingGossipingRequestEntity")
realm.schema.remove("GossipingEventEntity")
internal class MigrateCryptoTo016(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 16) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Remove OutgoingGossipingRequestEntity")
Timber.d("Remove IncomingGossipingRequestEntity")
Timber.d("Remove GossipingEventEntity")
// No need to migrate existing request, just start fresh
Timber.d("Create GossipingEventEntity")
Timber.d("Create GossipingEventEntity")
Timber.d("Create GossipingEventEntity")
val replySchema = realm.schema.create("KeyRequestReplyEntity")
.addField(KeyRequestReplyEntityFields.SENDER_ID, String::class.java)
.addField(KeyRequestReplyEntityFields.FROM_DEVICE, String::class.java)
.addField(KeyRequestReplyEntityFields.EVENT_JSON, String::class.java)
realm.schema.create("OutgoingKeyRequestEntity")
.addField(OutgoingKeyRequestEntityFields.REQUEST_ID, String::class.java)
.addIndex(OutgoingKeyRequestEntityFields.REQUEST_ID)
.addField(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, String::class.java)
.addIndex(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID)
.addRealmListField(OutgoingKeyRequestEntityFields.REPLIES.`$`, replySchema)
.addField(OutgoingKeyRequestEntityFields.RECIPIENTS_DATA, String::class.java)
.addField(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, String::class.java)
.addIndex(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR)
.addField(OutgoingKeyRequestEntityFields.REQUESTED_INFO_STR, String::class.java)
.addField(OutgoingKeyRequestEntityFields.ROOM_ID, String::class.java)
.addIndex(OutgoingKeyRequestEntityFields.ROOM_ID)
.addField(OutgoingKeyRequestEntityFields.REQUESTED_INDEX, Integer::class.java)
.addField(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, Long::class.java)
.setNullable(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, true)
realm.schema.create("AuditTrailEntity")
.addField(AuditTrailEntityFields.AGE_LOCAL_TS, Long::class.java)
.setNullable(AuditTrailEntityFields.AGE_LOCAL_TS, true)
.addField(AuditTrailEntityFields.CONTENT_JSON, String::class.java)
.addField(AuditTrailEntityFields.TYPE, String::class.java)
.addIndex(AuditTrailEntityFields.TYPE)
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, Boolean::class.java)
?.transform {
// set the default value to true
it.setBoolean(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, true)
}
Timber.d("Update CryptoMetadataEntity")
}
}

View File

@ -16,86 +16,60 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.database.safeEnumerate
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber
/**
* Version 17L enhance OlmInboundGroupSessionEntity to support shared history for MSC3061.
* Also migrates how megolm session are stored to avoid additional serialized frozen class.
*/
internal class MigrateCryptoTo017(realm: DynamicRealm) : RealmMigrator(realm, 17) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("CryptoRoomEntity")
?.addField(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform {
// We don't have access to the session database to check for the state here and set the good value.
// But for now as it's behind a lab flag, will set to false and force initial sync when enabled
it.setBoolean(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, false)
}
realm.schema.get("OutboundGroupSessionInfoEntity")
?.addField(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform {
// We don't have access to the session database to check for the state here and set the good value.
// But for now as it's behind a lab flag, will set to false and force initial sync when enabled
it.setBoolean(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, false)
}
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, Boolean::class.java)
?.transform { obj ->
// default to false
obj.setBoolean(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, false)
}
internal class MigrateCryptoTo017(context: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(context, 17) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Update CryptoRoomEntity")
Timber.d("Update OutboundGroupSessionInfoEntity")
Timber.d("Update CryptoMetadataEntity")
Timber.d("Update OlmInboundGroupSessionEntity")
val moshiAdapter = MoshiProvider.providesMoshi().adapter(InboundGroupSessionData::class.java)
realm.schema.get("OlmInboundGroupSessionEntity")
?.addField(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, Boolean::class.java)
?.addField(OlmInboundGroupSessionEntityFields.ROOM_ID, String::class.java)
?.addField(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, String::class.java)
?.addField(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, String::class.java)
?.transform { dynamicObject ->
try {
// we want to convert the old wrapper frozen class into a
// map of sessionData & the pickled session herself
dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { oldData ->
val oldWrapper = tryOrNull("Failed to convert megolm inbound group data") {
@Suppress("DEPRECATION")
deserializeFromRealm<org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2?>(oldData)
}
val groupSession = oldWrapper?.olmInboundGroupSession
?: return@transform Unit.also {
Timber.w("Failed to migrate megolm session, no olmInboundGroupSession")
}
// now convert to new data
val data = InboundGroupSessionData(
senderKey = oldWrapper.senderKey,
roomId = oldWrapper.roomId,
keysClaimed = oldWrapper.keysClaimed,
forwardingCurve25519KeyChain = oldWrapper.forwardingCurve25519KeyChain,
sharedHistory = false,
)
dynamicObject.setString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, moshiAdapter.toJson(data))
dynamicObject.setString(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, serializeForRealm(groupSession))
// denormalized fields
dynamicObject.setString(OlmInboundGroupSessionEntityFields.ROOM_ID, oldWrapper.roomId)
dynamicObject.setBoolean(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, false)
}
} catch (failure: Throwable) {
Timber.e(failure, "Failed to migrate megolm session")
migrationContext.safeEnumerate("OlmInboundGroupSessionEntity") { oldObject, newObject ->
if (newObject == null) return@safeEnumerate
try {
// we want to convert the old wrapper frozen class into a
// map of sessionData & the pickled session herself
oldObject.getNullableValue("olmInboundGroupSessionData", String::class)?.let { oldData ->
val oldWrapper = tryOrNull("Failed to convert megolm inbound group data") {
@Suppress("DEPRECATION")
deserializeFromRealm<org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2?>(oldData)
}
val groupSession = oldWrapper?.olmInboundGroupSession
?: return@safeEnumerate Unit.also {
Timber.w("Failed to migrate megolm session, no olmInboundGroupSession")
}
// now convert to new data
val data = InboundGroupSessionData(
senderKey = oldWrapper.senderKey,
roomId = oldWrapper.roomId,
keysClaimed = oldWrapper.keysClaimed,
forwardingCurve25519KeyChain = oldWrapper.forwardingCurve25519KeyChain,
sharedHistory = false,
)
newObject.set("inboundGroupSessionDataJson", moshiAdapter.toJson(data))
newObject.set("serializedOlmInboundGroupSession", serializeForRealm(groupSession))
// denormalized fields
newObject.set("roomId", oldWrapper.roomId)
}
} catch (failure: Throwable) {
Timber.e(failure, "Failed to migrate megolm session")
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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? {

View File

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

View File

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

View File

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

View File

@ -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? {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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