Better cleanup of the Crypto database.
This commit is contained in:
parent
5908cd54f0
commit
15c86f3fe3
|
@ -41,15 +41,11 @@ import org.matrix.android.sdk.internal.crypto.store.db.doRealmTransactionAsync
|
|||
import org.matrix.android.sdk.internal.crypto.store.db.doWithRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CryptoRoomInfoMapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.mapper.MyDeviceLastSeenInfoEntityMapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.query.getById
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.query.getOrCreate
|
||||
import org.matrix.android.sdk.internal.di.CryptoDatabase
|
||||
|
@ -82,7 +78,6 @@ internal class RustCryptoStore @Inject constructor(
|
|||
// still needed on rust due to the global crypto settings
|
||||
init {
|
||||
// Ensure CryptoMetadataEntity is inserted in DB
|
||||
// TODO BMA
|
||||
doRealmTransaction("init", realmConfiguration) { realm ->
|
||||
var currentMetadata = realm.where<CryptoMetadataEntity>().findFirst()
|
||||
|
||||
|
@ -146,30 +141,7 @@ internal class RustCryptoStore @Inject constructor(
|
|||
// nop
|
||||
}
|
||||
|
||||
override fun tidyUpDataBase() {
|
||||
// These entities are not used in rust actually, but as they are not yet cleaned up, this will do it with time
|
||||
val prevWeekTs = clock.epochMillis() - 7 * 24 * 60 * 60 * 1_000
|
||||
doRealmTransaction("tidyUpDataBase", realmConfiguration) { realm ->
|
||||
|
||||
// Clean the old ones?
|
||||
realm.where<OutgoingKeyRequestEntity>()
|
||||
.lessThan(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, prevWeekTs)
|
||||
.findAll()
|
||||
.also { Timber.i("## Crypto Clean up ${it.size} OutgoingKeyRequestEntity") }
|
||||
.deleteAllFromRealm()
|
||||
|
||||
// Only keep one month history
|
||||
|
||||
val prevMonthTs = clock.epochMillis() - 4 * 7 * 24 * 60 * 60 * 1_000L
|
||||
realm.where<AuditTrailEntity>()
|
||||
.lessThan(AuditTrailEntityFields.AGE_LOCAL_TS, prevMonthTs)
|
||||
.findAll()
|
||||
.also { Timber.i("## Crypto Clean up ${it.size} AuditTrailEntity") }
|
||||
.deleteAllFromRealm()
|
||||
|
||||
// Can we do something for WithHeldSessionEntity?
|
||||
}
|
||||
}
|
||||
override fun tidyUpDataBase() = Unit
|
||||
|
||||
override fun close() {
|
||||
val tasks = monarchyWriteAsyncExecutor.shutdownNow()
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store
|
||||
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.UserIdentity
|
||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||
|
||||
internal data class UserDataToStore(
|
||||
/**
|
||||
* Map of userId -> (Map of deviceId -> [CryptoDeviceInfo]).
|
||||
*/
|
||||
val userDevices: MutableMap<String, Map<String, CryptoDeviceInfo>> = mutableMapOf(),
|
||||
/**
|
||||
* Map of userId -> [UserIdentity].
|
||||
*/
|
||||
val userIdentities: MutableMap<String, UserIdentity> = mutableMapOf(),
|
||||
)
|
|
@ -16,15 +16,9 @@
|
|||
|
||||
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 timber.log.Timber
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.ObjectOutputStream
|
||||
import java.util.zip.GZIPInputStream
|
||||
import java.util.zip.GZIPOutputStream
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
/**
|
||||
|
@ -36,24 +30,6 @@ internal fun <T> doWithRealm(realmConfiguration: RealmConfiguration, action: (Re
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -70,38 +46,3 @@ internal fun doRealmTransactionAsync(realmConfiguration: RealmConfiguration, act
|
|||
realm.executeTransactionAsync { action.invoke(it) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize any Serializable object, zip it and convert to Base64 String.
|
||||
*/
|
||||
internal fun serializeForRealm(o: Any?): String? {
|
||||
if (o == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val baos = ByteArrayOutputStream()
|
||||
val gzis = GZIPOutputStream(baos)
|
||||
val out = ObjectOutputStream(gzis)
|
||||
out.use {
|
||||
it.writeObject(o)
|
||||
}
|
||||
return Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT)
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the opposite of serializeForRealm.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal fun <T> deserializeFromRealm(string: String?): T? {
|
||||
if (string == null) {
|
||||
return null
|
||||
}
|
||||
val decodedB64 = Base64.decode(string.toByteArray(), Base64.DEFAULT)
|
||||
|
||||
val bais = decodedB64.inputStream()
|
||||
val gzis = GZIPInputStream(bais)
|
||||
val ois = SafeObjectInputStream(gzis)
|
||||
return ois.use {
|
||||
it.readObject() as T
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.matrix.android.sdk.internal.crypto.store.db
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo024
|
||||
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -25,6 +26,7 @@ import javax.inject.Inject
|
|||
* 0, 1, 2: legacy Riot-Android;
|
||||
* 3: migrate to RiotX schema;
|
||||
* 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6).
|
||||
* 24: Delete nearly all the crypto DB
|
||||
*/
|
||||
internal class RealmCryptoStoreMigration @Inject constructor(
|
||||
) : MatrixRealmMigration(
|
||||
|
@ -39,8 +41,6 @@ internal class RealmCryptoStoreMigration @Inject constructor(
|
|||
override fun hashCode() = 5000
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm, oldVersion: Long) {
|
||||
// Delete the whole DB
|
||||
// TODO BMA
|
||||
realm.deleteAll()
|
||||
if (oldVersion < 24) MigrateCryptoTo024(realm).perform()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,23 +17,9 @@
|
|||
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
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyRequestReplyEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity
|
||||
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.WithHeldSessionEntity
|
||||
|
||||
/**
|
||||
* Realm module for Crypto store classes.
|
||||
|
@ -43,21 +29,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEnti
|
|||
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 class RealmCryptoStoreModule
|
||||
|
|
|
@ -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
|
||||
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.ObjectInputStream
|
||||
import java.io.ObjectStreamClass
|
||||
|
||||
/**
|
||||
* Package has been renamed from `im.vector.matrix.android` to `org.matrix.android.sdk`
|
||||
* so ensure deserialization of previously stored objects still works
|
||||
*
|
||||
* Ref: https://stackoverflow.com/questions/3884492/how-can-i-change-package-for-a-bunch-of-java-serializable-classes
|
||||
*/
|
||||
internal class SafeObjectInputStream(inputStream: InputStream) : ObjectInputStream(inputStream) {
|
||||
|
||||
init {
|
||||
enableResolveObject(true)
|
||||
}
|
||||
|
||||
@Throws(IOException::class, ClassNotFoundException::class)
|
||||
override fun readClassDescriptor(): ObjectStreamClass {
|
||||
val read = super.readClassDescriptor()
|
||||
if (read.name.startsWith("im.vector.matrix.android.")) {
|
||||
return ObjectStreamClass.lookup(Class.forName(read.name.replace("im.vector.matrix.android.", "org.matrix.android.sdk.")))
|
||||
}
|
||||
return read
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
internal class MigrateCryptoTo024(realm: DynamicRealm) : RealmMigrator(realm, 24) {
|
||||
/**
|
||||
* Delete the whole DB, except tables that are still used to store data:
|
||||
* - CryptoMetadataEntity
|
||||
* - MyDeviceLastSeenInfoEntity
|
||||
* - CryptoRoomEntity (but remove unused member 'outboundSessionInfo: OutboundGroupSessionInfoEntity')
|
||||
*/
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
with(realm.schema) {
|
||||
get("CryptoRoomEntity")?.removeField("outboundSessionInfo")
|
||||
|
||||
// Warning: order is important, first remove classes that depends on others.
|
||||
remove("UserEntity")
|
||||
remove("DeviceInfoEntity")
|
||||
remove("CrossSigningInfoEntity")
|
||||
remove("KeyInfoEntity")
|
||||
remove("TrustLevelEntity")
|
||||
remove("KeysBackupDataEntity")
|
||||
remove("OlmInboundGroupSessionEntity")
|
||||
remove("OlmSessionEntity")
|
||||
remove("AuditTrailEntity")
|
||||
remove("OutgoingKeyRequestEntity")
|
||||
remove("KeyRequestReplyEntity")
|
||||
remove("WithHeldSessionEntity")
|
||||
remove("SharedSessionEntity")
|
||||
remove("OutboundGroupSessionInfoEntity")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Index
|
||||
|
||||
internal open class AuditTrailEntity(
|
||||
var ageLocalTs: Long? = null,
|
||||
@Index var type: String? = null,
|
||||
var contentJson: String? = null
|
||||
) : RealmObject() {
|
||||
companion object
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
|
||||
import org.matrix.android.sdk.api.session.crypto.model.ForwardInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.IncomingKeyRequestInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.TrailType
|
||||
import org.matrix.android.sdk.api.session.crypto.model.UnknownInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.WithheldInfo
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
|
||||
internal object AuditTrailMapper {
|
||||
|
||||
fun map(entity: AuditTrailEntity): AuditTrail? {
|
||||
val contentJson = entity.contentJson ?: return null
|
||||
return when (entity.type) {
|
||||
TrailType.OutgoingKeyForward.name -> {
|
||||
val info = tryOrNull {
|
||||
MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson)
|
||||
} ?: return null
|
||||
AuditTrail(
|
||||
ageLocalTs = entity.ageLocalTs ?: 0,
|
||||
type = TrailType.OutgoingKeyForward,
|
||||
info = info
|
||||
)
|
||||
}
|
||||
TrailType.OutgoingKeyWithheld.name -> {
|
||||
val info = tryOrNull {
|
||||
MoshiProvider.providesMoshi().adapter(WithheldInfo::class.java).fromJson(contentJson)
|
||||
} ?: return null
|
||||
AuditTrail(
|
||||
ageLocalTs = entity.ageLocalTs ?: 0,
|
||||
type = TrailType.OutgoingKeyWithheld,
|
||||
info = info
|
||||
)
|
||||
}
|
||||
TrailType.IncomingKeyRequest.name -> {
|
||||
val info = tryOrNull {
|
||||
MoshiProvider.providesMoshi().adapter(IncomingKeyRequestInfo::class.java).fromJson(contentJson)
|
||||
} ?: return null
|
||||
AuditTrail(
|
||||
ageLocalTs = entity.ageLocalTs ?: 0,
|
||||
type = TrailType.IncomingKeyRequest,
|
||||
info = info
|
||||
)
|
||||
}
|
||||
TrailType.IncomingKeyForward.name -> {
|
||||
val info = tryOrNull {
|
||||
MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson)
|
||||
} ?: return null
|
||||
AuditTrail(
|
||||
ageLocalTs = entity.ageLocalTs ?: 0,
|
||||
type = TrailType.IncomingKeyForward,
|
||||
info = info
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
AuditTrail(
|
||||
ageLocalTs = entity.ageLocalTs ?: 0,
|
||||
type = TrailType.Unknown,
|
||||
info = UnknownInfo
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,65 +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.model
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.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() {
|
||||
|
||||
companion object
|
||||
|
||||
fun getMasterKey() = crossSigningKeys.firstOrNull { it.usages.contains(KeyUsage.MASTER.value) }
|
||||
|
||||
fun setMasterKey(info: KeyInfoEntity?) {
|
||||
crossSigningKeys
|
||||
.filter { it.usages.contains(KeyUsage.MASTER.value) }
|
||||
.forEach { crossSigningKeys.remove(it) }
|
||||
info?.let { crossSigningKeys.add(it) }
|
||||
}
|
||||
|
||||
fun getSelfSignedKey() = crossSigningKeys.firstOrNull { it.usages.contains(KeyUsage.SELF_SIGNING.value) }
|
||||
|
||||
fun setSelfSignedKey(info: KeyInfoEntity?) {
|
||||
crossSigningKeys
|
||||
.filter { it.usages.contains(KeyUsage.SELF_SIGNING.value) }
|
||||
.forEach { crossSigningKeys.remove(it) }
|
||||
info?.let { crossSigningKeys.add(it) }
|
||||
}
|
||||
|
||||
fun getUserSigningKey() = crossSigningKeys.firstOrNull { it.usages.contains(KeyUsage.USER_SIGNING.value) }
|
||||
|
||||
fun setUserSignedKey(info: KeyInfoEntity?) {
|
||||
crossSigningKeys
|
||||
.filter { it.usages.contains(KeyUsage.USER_SIGNING.value) }
|
||||
.forEach { crossSigningKeys.remove(it) }
|
||||
info?.let { crossSigningKeys.add(it) }
|
||||
}
|
||||
}
|
||||
|
||||
internal fun CrossSigningInfoEntity.deleteOnCascade() {
|
||||
crossSigningKeys.clearWith { it.deleteOnCascade() }
|
||||
deleteFromRealm()
|
||||
}
|
|
@ -1,123 +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.model
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
|
||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.UnsignedDeviceInfo
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.internal.di.SerializeNulls
|
||||
import timber.log.Timber
|
||||
|
||||
internal object CryptoMapper {
|
||||
|
||||
private val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build()
|
||||
private val listMigrationAdapter = moshi.adapter<List<String>>(
|
||||
Types.newParameterizedType(
|
||||
List::class.java,
|
||||
String::class.java,
|
||||
Any::class.java
|
||||
)
|
||||
)
|
||||
private val mapMigrationAdapter = moshi.adapter<JsonDict>(
|
||||
Types.newParameterizedType(
|
||||
Map::class.java,
|
||||
String::class.java,
|
||||
Any::class.java
|
||||
)
|
||||
)
|
||||
private val mapOfStringMigrationAdapter = moshi.adapter<Map<String, Map<String, String>>>(
|
||||
Types.newParameterizedType(
|
||||
Map::class.java,
|
||||
String::class.java,
|
||||
Any::class.java
|
||||
)
|
||||
)
|
||||
|
||||
internal fun mapToEntity(deviceInfo: CryptoDeviceInfo): DeviceInfoEntity {
|
||||
return DeviceInfoEntity(primaryKey = DeviceInfoEntity.createPrimaryKey(deviceInfo.userId, deviceInfo.deviceId))
|
||||
.also { updateDeviceInfoEntity(it, deviceInfo) }
|
||||
}
|
||||
|
||||
internal fun updateDeviceInfoEntity(entity: DeviceInfoEntity, deviceInfo: CryptoDeviceInfo) {
|
||||
entity.userId = deviceInfo.userId
|
||||
entity.deviceId = deviceInfo.deviceId
|
||||
entity.algorithmListJson = listMigrationAdapter.toJson(deviceInfo.algorithms)
|
||||
entity.keysMapJson = mapMigrationAdapter.toJson(deviceInfo.keys)
|
||||
entity.signatureMapJson = mapMigrationAdapter.toJson(deviceInfo.signatures)
|
||||
entity.isBlocked = deviceInfo.isBlocked
|
||||
val deviceInfoTrustLevel = deviceInfo.trustLevel
|
||||
if (deviceInfoTrustLevel == null) {
|
||||
entity.trustLevelEntity?.deleteFromRealm()
|
||||
entity.trustLevelEntity = null
|
||||
} else {
|
||||
if (entity.trustLevelEntity == null) {
|
||||
// Create a new TrustLevelEntity object
|
||||
entity.trustLevelEntity = TrustLevelEntity()
|
||||
}
|
||||
// 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
|
||||
}
|
||||
|
||||
internal fun mapToModel(deviceInfoEntity: DeviceInfoEntity): CryptoDeviceInfo {
|
||||
return CryptoDeviceInfo(
|
||||
userId = deviceInfoEntity.userId ?: "",
|
||||
deviceId = deviceInfoEntity.deviceId ?: "",
|
||||
isBlocked = deviceInfoEntity.isBlocked ?: false,
|
||||
trustLevel = deviceInfoEntity.trustLevelEntity?.let {
|
||||
DeviceTrustLevel(it.crossSignedVerified ?: false, it.locallyVerified)
|
||||
},
|
||||
unsigned = deviceInfoEntity.unsignedMapJson?.let { UnsignedDeviceInfo(deviceDisplayName = it) },
|
||||
signatures = deviceInfoEntity.signatureMapJson?.let {
|
||||
try {
|
||||
mapOfStringMigrationAdapter.fromJson(it)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure)
|
||||
null
|
||||
}
|
||||
},
|
||||
keys = deviceInfoEntity.keysMapJson?.let {
|
||||
try {
|
||||
moshi.adapter<Map<String, String>>(
|
||||
Types.newParameterizedType(
|
||||
Map::class.java,
|
||||
String::class.java,
|
||||
Any::class.java
|
||||
)
|
||||
).fromJson(it)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure)
|
||||
null
|
||||
}
|
||||
},
|
||||
algorithms = deviceInfoEntity.algorithmListJson?.let {
|
||||
try {
|
||||
listMigrationAdapter.fromJson(it)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure)
|
||||
null
|
||||
}
|
||||
},
|
||||
firstTimeSeenLocalTs = deviceInfoEntity.firstTimeSeenLocalTs
|
||||
)
|
||||
}
|
||||
}
|
|
@ -26,10 +26,6 @@ internal open class CryptoRoomEntity(
|
|||
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,
|
||||
|
|
|
@ -1,54 +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.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.RealmResults
|
||||
import io.realm.annotations.LinkingObjects
|
||||
import io.realm.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() {
|
||||
|
||||
@LinkingObjects("devices")
|
||||
val users: RealmResults<UserEntity>? = null
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
internal fun DeviceInfoEntity.deleteOnCascade() {
|
||||
trustLevelEntity?.deleteFromRealm()
|
||||
deleteFromRealm()
|
||||
}
|
|
@ -1,37 +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.model
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.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 fun KeyInfoEntity.deleteOnCascade() {
|
||||
trustLevelEntity?.deleteFromRealm()
|
||||
deleteFromRealm()
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.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() {
|
||||
companion object
|
||||
|
||||
fun getEvent(): Event? {
|
||||
return eventJson?.let {
|
||||
MoshiProvider.providesMoshi().adapter(Event::class.java).fromJson(it)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +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.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.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()
|
|
@ -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.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
|
||||
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,
|
||||
|
||||
// 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,
|
||||
|
||||
// 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,
|
||||
|
||||
// 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() {
|
||||
|
||||
// fun getInboundGroupSession(): OlmInboundGroupSessionWrapper2? {
|
||||
// return try {
|
||||
// deserializeFromRealm<OlmInboundGroupSessionWrapper2?>(olmInboundGroupSessionData)
|
||||
// } catch (failure: Throwable) {
|
||||
// Timber.e(failure, "## Deserialization failure")
|
||||
// return null
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun putInboundGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2?) {
|
||||
// olmInboundGroupSessionData = serializeForRealm(olmInboundGroupSessionWrapper)
|
||||
// }
|
||||
|
||||
companion object {
|
||||
private val adapter = MoshiProvider.providesMoshi()
|
||||
.adapter(InboundGroupSessionData::class.java)
|
||||
}
|
||||
}
|
|
@ -1,35 +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.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
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() {
|
||||
|
||||
companion object
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
|
||||
internal open class OutboundGroupSessionInfoEntity(
|
||||
var serializedOutboundSessionData: String? = null,
|
||||
var creationTime: Long? = null,
|
||||
var shouldShareHistory: Boolean = false
|
||||
) : RealmObject() {
|
||||
|
||||
companion object
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.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 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
|
||||
import org.matrix.android.sdk.api.session.crypto.RequestReply
|
||||
import org.matrix.android.sdk.api.session.crypto.RequestResult
|
||||
import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
|
||||
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,
|
||||
|
||||
var replies: RealmList<KeyRequestReplyEntity> = RealmList()
|
||||
) : RealmObject() {
|
||||
|
||||
@Index private var requestStateStr: String = OutgoingRoomKeyRequestState.UNSENT.name
|
||||
|
||||
companion object {
|
||||
|
||||
private val recipientsDataMapper: JsonAdapter<Map<String, List<String>>> =
|
||||
MoshiProvider
|
||||
.providesMoshi()
|
||||
.adapter(
|
||||
Types.newParameterizedType(Map::class.java, String::class.java, List::class.java)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getRequestedKeyInfo(): RoomKeyRequestBody? = RoomKeyRequestBody.fromJson(requestedInfoStr)
|
||||
|
||||
fun setRequestBody(body: RoomKeyRequestBody) {
|
||||
requestedInfoStr = body.toJson()
|
||||
roomId = body.roomId
|
||||
megolmSessionId = body.sessionId
|
||||
}
|
||||
|
||||
var requestState: OutgoingRoomKeyRequestState
|
||||
get() {
|
||||
return tryOrNull { OutgoingRoomKeyRequestState.valueOf(requestStateStr) }
|
||||
?: OutgoingRoomKeyRequestState.UNSENT
|
||||
}
|
||||
set(value) {
|
||||
requestStateStr = value.name
|
||||
}
|
||||
|
||||
private fun getRecipients(): Map<String, List<String>>? {
|
||||
return this.recipientsData?.let { recipientsDataMapper.fromJson(it) }
|
||||
}
|
||||
|
||||
fun setRecipients(recipients: Map<String, List<String>>) {
|
||||
this.recipientsData = recipientsDataMapper.toJson(recipients)
|
||||
}
|
||||
|
||||
fun addReply(userId: String, fromDevice: String?, event: Event) {
|
||||
val newReply = KeyRequestReplyEntity(
|
||||
senderId = userId,
|
||||
fromDevice = fromDevice,
|
||||
eventJson = MoshiProvider.providesMoshi().adapter(Event::class.java).toJson(event)
|
||||
)
|
||||
replies.add(newReply)
|
||||
}
|
||||
|
||||
fun toOutgoingKeyRequest(): OutgoingKeyRequest {
|
||||
return OutgoingKeyRequest(
|
||||
requestBody = getRequestedKeyInfo(),
|
||||
recipients = getRecipients().orEmpty(),
|
||||
requestId = requestId ?: "",
|
||||
fromIndex = requestedIndex ?: 0,
|
||||
state = requestState,
|
||||
results = replies.mapNotNull { entity ->
|
||||
val userId = entity.senderId ?: return@mapNotNull null
|
||||
val result = entity.eventJson?.let {
|
||||
MoshiProvider.providesMoshi().adapter(Event::class.java).fromJson(it)
|
||||
}?.let { event ->
|
||||
eventToResult(event)
|
||||
} ?: return@mapNotNull null
|
||||
RequestReply(
|
||||
userId = userId,
|
||||
fromDevice = entity.fromDevice,
|
||||
result = result
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun eventToResult(event: Event): RequestResult? {
|
||||
return when (event.getClearType()) {
|
||||
in EventType.ROOM_KEY_WITHHELD.values -> {
|
||||
event.content.toModel<RoomKeyWithHeldContent>()?.code?.let {
|
||||
RequestResult.Failure(it)
|
||||
}
|
||||
}
|
||||
EventType.FORWARDED_ROOM_KEY -> {
|
||||
RequestResult.Success((event.content?.get("chain_index") as? Number)?.toInt() ?: 0)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun OutgoingKeyRequestEntity.deleteOnCascade() {
|
||||
replies.deleteAllFromRealm()
|
||||
deleteFromRealm()
|
||||
}
|
|
@ -1,38 +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.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.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() {
|
||||
|
||||
companion object
|
||||
}
|
|
@ -1,29 +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.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
|
||||
internal open class TrustLevelEntity(
|
||||
var crossSignedVerified: Boolean? = null,
|
||||
var locallyVerified: Boolean? = null
|
||||
) : RealmObject() {
|
||||
|
||||
companion object
|
||||
|
||||
fun isVerified(): Boolean = crossSignedVerified == true || locallyVerified == true
|
||||
}
|
|
@ -1,38 +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.model
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import org.matrix.android.sdk.internal.extensions.clearWith
|
||||
|
||||
internal open class UserEntity(
|
||||
@PrimaryKey var userId: String? = null,
|
||||
var devices: RealmList<DeviceInfoEntity> = RealmList(),
|
||||
var crossSigningInfoEntity: CrossSigningInfoEntity? = null,
|
||||
var deviceTrackingStatus: Int = 0
|
||||
) : RealmObject() {
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
internal fun UserEntity.deleteOnCascade() {
|
||||
devices.clearWith { it.deleteOnCascade() }
|
||||
crossSigningInfoEntity?.deleteOnCascade()
|
||||
deleteFromRealm()
|
||||
}
|
|
@ -1,48 +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.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Index
|
||||
import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
|
||||
|
||||
/**
|
||||
* When an encrypted message is sent in a room, the megolm key might not be sent to all devices present in the room.
|
||||
* Sometimes this may be inadvertent (for example, if the sending device is not aware of some devices that have joined),
|
||||
* but some times, this may be purposeful.
|
||||
* 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() {
|
||||
|
||||
var code: WithHeldCode?
|
||||
get() {
|
||||
return WithHeldCode.fromCode(codeString)
|
||||
}
|
||||
set(code) {
|
||||
codeString = code?.value
|
||||
}
|
||||
|
||||
companion object
|
||||
}
|
|
@ -1,36 +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.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 fun CrossSigningInfoEntity.Companion.get(realm: Realm, userId: String): CrossSigningInfoEntity? {
|
||||
return realm.where<CrossSigningInfoEntity>()
|
||||
.equalTo(UserEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.createPrimaryKey
|
||||
|
||||
/**
|
||||
* Get or create a device info.
|
||||
*/
|
||||
internal fun DeviceInfoEntity.Companion.getOrCreate(realm: Realm, userId: String, deviceId: String): DeviceInfoEntity {
|
||||
val key = DeviceInfoEntity.createPrimaryKey(userId, deviceId)
|
||||
|
||||
return realm.where<DeviceInfoEntity>()
|
||||
.equalTo(DeviceInfoEntityFields.PRIMARY_KEY, key)
|
||||
.findFirst()
|
||||
?: realm.createObject<DeviceInfoEntity>(key)
|
||||
.apply {
|
||||
this.deviceId = deviceId
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmResults
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields
|
||||
|
||||
internal fun SharedSessionEntity.Companion.get(
|
||||
realm: Realm,
|
||||
roomId: String?,
|
||||
sessionId: String,
|
||||
userId: String,
|
||||
deviceId: String,
|
||||
deviceIdentityKey: String?
|
||||
): SharedSessionEntity? {
|
||||
return realm.where<SharedSessionEntity>()
|
||||
.equalTo(SharedSessionEntityFields.ROOM_ID, roomId)
|
||||
.equalTo(SharedSessionEntityFields.SESSION_ID, sessionId)
|
||||
.equalTo(SharedSessionEntityFields.ALGORITHM, MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
.equalTo(SharedSessionEntityFields.USER_ID, userId)
|
||||
.equalTo(SharedSessionEntityFields.DEVICE_ID, deviceId)
|
||||
.equalTo(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, deviceIdentityKey)
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
internal fun SharedSessionEntity.Companion.get(realm: Realm, roomId: String?, sessionId: String): RealmResults<SharedSessionEntity> {
|
||||
return realm.where<SharedSessionEntity>()
|
||||
.equalTo(SharedSessionEntityFields.ROOM_ID, roomId)
|
||||
.equalTo(SharedSessionEntityFields.SESSION_ID, sessionId)
|
||||
.equalTo(SharedSessionEntityFields.ALGORITHM, MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
.findAll()
|
||||
}
|
||||
|
||||
internal fun SharedSessionEntity.Companion.create(
|
||||
realm: Realm,
|
||||
roomId: String?,
|
||||
sessionId: String,
|
||||
userId: String,
|
||||
deviceId: String,
|
||||
deviceIdentityKey: String,
|
||||
chainIndex: Int
|
||||
): SharedSessionEntity {
|
||||
return realm.createObject<SharedSessionEntity>().apply {
|
||||
this.roomId = roomId
|
||||
this.algorithm = MXCRYPTO_ALGORITHM_MEGOLM
|
||||
this.sessionId = sessionId
|
||||
this.userId = userId
|
||||
this.deviceId = deviceId
|
||||
this.deviceIdentityKey = deviceIdentityKey
|
||||
this.chainIndex = chainIndex
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.deleteOnCascade
|
||||
|
||||
/**
|
||||
* Get or create a user.
|
||||
*/
|
||||
internal fun UserEntity.Companion.getOrCreate(realm: Realm, userId: String): UserEntity {
|
||||
return realm.where<UserEntity>()
|
||||
.equalTo(UserEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
?: realm.createObject(userId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a user.
|
||||
*/
|
||||
internal fun UserEntity.Companion.delete(realm: Realm, userId: String) {
|
||||
realm.where<UserEntity>()
|
||||
.equalTo(UserEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
?.deleteOnCascade()
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue