mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-01-31 03:17:13 +01:00
SDK / update trust on key change + live method in Service
This commit is contained in:
parent
d60351bcb7
commit
665c577747
@ -16,7 +16,9 @@
|
||||
|
||||
package im.vector.matrix.android.api.session.crypto.crosssigning
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustResult
|
||||
import im.vector.matrix.android.internal.crypto.crosssigning.UserTrustResult
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.SignatureUploadResponse
|
||||
@ -40,6 +42,8 @@ interface CrossSigningService {
|
||||
|
||||
fun getUserCrossSigningKeys(userId: String): MXCrossSigningInfo?
|
||||
|
||||
fun getLiveCrossSigningKeys(userId: String): LiveData<Optional<MXCrossSigningInfo>>
|
||||
|
||||
fun getMyCrossSigningKeys(): MXCrossSigningInfo?
|
||||
fun canCrossSign(): Boolean
|
||||
|
||||
|
@ -23,13 +23,13 @@ data class MXCrossSigningInfo(
|
||||
|
||||
var userId: String,
|
||||
|
||||
var crossSigningKeys: List<CryptoCrossSigningKey> = ArrayList(),
|
||||
|
||||
// TODO this should at the key level no?
|
||||
val isTrusted: Boolean = false
|
||||
var crossSigningKeys: List<CryptoCrossSigningKey> = ArrayList()
|
||||
|
||||
) {
|
||||
|
||||
fun isTrusted() : Boolean = masterKey()?.trustLevel?.isVerified() == true
|
||||
&& selfSigningKey()?.trustLevel?.isVerified() == true
|
||||
|
||||
fun masterKey(): CryptoCrossSigningKey? = crossSigningKeys
|
||||
.firstOrNull { it.usages?.contains(KeyUsage.MASTER.value) == true }
|
||||
|
||||
|
@ -27,6 +27,7 @@ import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DownloadKeysForUsersTask
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
|
||||
import okhttp3.internal.toImmutableList
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -38,6 +39,30 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||
private val credentials: Credentials,
|
||||
private val downloadKeysForUsersTask: DownloadKeysForUsersTask) {
|
||||
|
||||
interface UserDevicesUpdateListener {
|
||||
fun onUsersDeviceUpdate(users: List<String>)
|
||||
}
|
||||
|
||||
private val deviceChangeListeners = ArrayList<UserDevicesUpdateListener>()
|
||||
|
||||
fun addListener(listener: UserDevicesUpdateListener) {
|
||||
deviceChangeListeners.add(listener)
|
||||
}
|
||||
|
||||
fun removeListener(listener: UserDevicesUpdateListener) {
|
||||
deviceChangeListeners.remove(listener)
|
||||
}
|
||||
|
||||
fun dispatchDeviceChange(users: List<String>) {
|
||||
deviceChangeListeners.forEach {
|
||||
try {
|
||||
it.onUsersDeviceUpdate(users)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "Failed to dispatch device chande")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HS not ready for retry
|
||||
private val notReadyToRetryHS = mutableSetOf<String>()
|
||||
|
||||
@ -210,6 +235,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||
}
|
||||
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
|
||||
|
||||
dispatchDeviceChange(userIds.toImmutableList())
|
||||
return usersDevicesInfoMap
|
||||
}
|
||||
|
||||
@ -338,6 +364,10 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||
userSigningKey
|
||||
)
|
||||
}
|
||||
|
||||
// Update devices trust for these users
|
||||
dispatchDeviceChange(downloadUsers)
|
||||
|
||||
return onKeysDownloadSucceed(filteredUsers, response.failures)
|
||||
}
|
||||
|
||||
|
@ -16,12 +16,14 @@
|
||||
|
||||
package im.vector.matrix.android.internal.crypto.crosssigning
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import dagger.Lazy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.crosssigning.CrossSigningService
|
||||
import im.vector.matrix.android.api.session.crypto.crosssigning.CrossSigningState
|
||||
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.MyDeviceInfoHolder
|
||||
@ -63,7 +65,7 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
private val uploadSignaturesTask: UploadSignaturesTask,
|
||||
private val cryptoCoroutineScope: CoroutineScope,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val taskExecutor: TaskExecutor) : CrossSigningService {
|
||||
private val taskExecutor: TaskExecutor) : CrossSigningService, DeviceListManager.UserDevicesUpdateListener {
|
||||
|
||||
private var olmUtility: OlmUtility? = null
|
||||
|
||||
@ -120,16 +122,22 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recover local trust in case private key are there?
|
||||
cryptoStore.setUserKeysAsTrusted(userId, checkUserTrust(userId).isVerified())
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
// Mmm this kind of a big issue
|
||||
Timber.e(e, "Failed to initialize Cross Signing")
|
||||
}
|
||||
|
||||
deviceListManager.addListener(this)
|
||||
}
|
||||
|
||||
fun release() {
|
||||
olmUtility?.releaseUtility()
|
||||
listOf(masterPkSigning, userPkSigning, selfSigningPkSigning).forEach { it?.releaseSigning() }
|
||||
deviceListManager.removeListener(this)
|
||||
}
|
||||
|
||||
protected fun finalize() {
|
||||
@ -251,13 +259,13 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
resetTrustOnKeyChange()
|
||||
uploadSignaturesTask.configureWith(UploadSignaturesTask.Params(uploadSignatureQueryBuilder.build())) {
|
||||
this.retryCount = 3
|
||||
this.constraints = TaskConstraints(true)
|
||||
this.callback = object : MatrixCallback<SignatureUploadResponse> {
|
||||
override fun onSuccess(data: SignatureUploadResponse) {
|
||||
Timber.i("## CrossSigning - signatures succesfuly uploaded")
|
||||
|
||||
// Force download of my keys now
|
||||
kotlin.runCatching {
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
@ -291,6 +299,12 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
}.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
|
||||
private fun resetTrustOnKeyChange() {
|
||||
Timber.i("## CrossSigning - Clear all other user trust")
|
||||
cryptoStore.clearOtherUserTrust()
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* ┏━━━━━━━━┓ ┏━━━━━━━━┓
|
||||
@ -310,7 +324,7 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
* └──────────────┘
|
||||
*/
|
||||
override fun isUserTrusted(userId: String): Boolean {
|
||||
return cryptoStore.getCrossSigningInfo(userId)?.isTrusted == true
|
||||
return cryptoStore.getCrossSigningInfo(userId)?.isTrusted() == true
|
||||
}
|
||||
|
||||
/**
|
||||
@ -331,7 +345,7 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
val myUserKey = myCrossSigningInfo?.userKey()
|
||||
?: return UserTrustResult.CrossSigningNotConfigured(credentials.userId)
|
||||
|
||||
if (!myCrossSigningInfo.isTrusted) {
|
||||
if (!myCrossSigningInfo.isTrusted()) {
|
||||
return UserTrustResult.KeysNotTrusted(myCrossSigningInfo)
|
||||
}
|
||||
|
||||
@ -455,6 +469,10 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
return cryptoStore.getCrossSigningInfo(userId)
|
||||
}
|
||||
|
||||
override fun getLiveCrossSigningKeys(userId: String): LiveData<Optional<MXCrossSigningInfo>> {
|
||||
return cryptoStore.getLiveCrossSigningInfo(userId)
|
||||
}
|
||||
|
||||
override fun getMyCrossSigningKeys(): MXCrossSigningInfo? {
|
||||
return cryptoStore.getMyCrossSigningInfo()
|
||||
}
|
||||
@ -464,20 +482,21 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
}
|
||||
|
||||
override fun trustUser(userId: String, callback: MatrixCallback<SignatureUploadResponse>) {
|
||||
Timber.d("## CrossSigning - Mark user $userId as trusted ")
|
||||
// We should have this user keys
|
||||
val otherMasterKeys = getUserCrossSigningKeys(userId)?.masterKey()
|
||||
if (otherMasterKeys == null) {
|
||||
callback.onFailure(Throwable("Other master signing key is not known"))
|
||||
callback.onFailure(Throwable("## CrossSigning - Other master signing key is not known"))
|
||||
return
|
||||
}
|
||||
val myKeys = getUserCrossSigningKeys(credentials.userId)
|
||||
if (myKeys == null) {
|
||||
callback.onFailure(Throwable("CrossSigning is not setup for this account"))
|
||||
callback.onFailure(Throwable("## CrossSigning - CrossSigning is not setup for this account"))
|
||||
return
|
||||
}
|
||||
val userPubKey = myKeys.userKey()?.unpaddedBase64PublicKey
|
||||
if (userPubKey == null || userPkSigning == null) {
|
||||
callback.onFailure(Throwable("Cannot sign from this account, privateKeyUnknown $userPubKey"))
|
||||
callback.onFailure(Throwable("## CrossSigning - Cannot sign from this account, privateKeyUnknown $userPubKey"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -487,18 +506,45 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
|
||||
if (newSignature == null) {
|
||||
// race??
|
||||
callback.onFailure(Throwable("Failed to sign"))
|
||||
callback.onFailure(Throwable("## CrossSigning - Failed to sign"))
|
||||
return
|
||||
}
|
||||
|
||||
cryptoStore.setUserKeysAsTrusted(userId, true)
|
||||
// TODO update local copy with new signature directly here? kind of local echo of trust?
|
||||
|
||||
|
||||
Timber.d("## CrossSigning - Upload signature of $userId MSK signed by USK")
|
||||
val uploadQuery = UploadSignatureQueryBuilder()
|
||||
.withSigningKeyInfo(otherMasterKeys.addSignatureAndCopy(credentials.userId, userPubKey, newSignature))
|
||||
.withSigningKeyInfo(otherMasterKeys.copyForSignature(credentials.userId, userPubKey, newSignature))
|
||||
.build()
|
||||
uploadSignaturesTask.configureWith(UploadSignaturesTask.Params(uploadQuery)) {
|
||||
this.callback = callback
|
||||
this.callback = object: MatrixCallback<SignatureUploadResponse> {
|
||||
override fun onSuccess(data: SignatureUploadResponse) {
|
||||
//force a key download to refresh trust?
|
||||
val uldata = data
|
||||
kotlin.runCatching {
|
||||
Timber.d("## CrossSigning - Force download of user keys")
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||
deviceListManager.downloadKeys(listOf(userId), true)
|
||||
}
|
||||
}.foldToCallback(object : MatrixCallback<Any> {
|
||||
override fun onSuccess(data: Any) {
|
||||
callback.onSuccess(uldata)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.e("## CrossSigning - fail to download keys", failure)
|
||||
callback.onFailure(failure)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.e("## CrossSigning - fail to upload signature", failure)
|
||||
callback.onFailure(failure)
|
||||
}
|
||||
}
|
||||
}.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
@ -570,13 +616,13 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
val myKeys = getUserCrossSigningKeys(credentials.userId)
|
||||
?: return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.CrossSigningNotConfigured(credentials.userId))
|
||||
|
||||
if (!myKeys.isTrusted) return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.KeysNotTrusted(myKeys))
|
||||
if (!myKeys.isTrusted()) return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.KeysNotTrusted(myKeys))
|
||||
|
||||
val otherKeys = getUserCrossSigningKeys(userId)
|
||||
?: return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.CrossSigningNotConfigured(userId))
|
||||
|
||||
// TODO should we force verification ?
|
||||
if (!otherKeys.isTrusted) return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.KeysNotTrusted(otherKeys))
|
||||
if (!otherKeys.isTrusted()) return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.KeysNotTrusted(otherKeys))
|
||||
|
||||
// Check if the trust chain is valid
|
||||
/*
|
||||
@ -618,4 +664,24 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||
crossSignTrustFail
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUsersDeviceUpdate(users: List<String>) {
|
||||
|
||||
Timber.d("## CrossSigning - onUsersDeviceUpdate for ${users.size} users")
|
||||
users.forEach { userId ->
|
||||
|
||||
checkUserTrust(userId).let {
|
||||
Timber.d("## CrossSigning - update trust for ${userId} , verified=${it.isVerified()}")
|
||||
cryptoStore.setUserKeysAsTrusted(userId, it.isVerified())
|
||||
}
|
||||
|
||||
// TODO if my keys have changes, i should recheck all devices of all users?
|
||||
val devices = cryptoStore.getUserDeviceList(userId)
|
||||
devices?.forEach { device ->
|
||||
val updatedTrust = checkDeviceTrust(userId, device.deviceId, device.trustLevel?.isLocallyVerified() ?: false)
|
||||
Timber.d("## CrossSigning - update trust for device ${device.deviceId} of user ${userId} , verified=$updatedTrust")
|
||||
cryptoStore.setDeviceTrust(userId, device.deviceId, updatedTrust.isCrossSignedVerified(), updatedTrust.isLocallyVerified())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,3 +29,4 @@ sealed class DeviceTrustResult {
|
||||
|
||||
fun DeviceTrustResult.isSuccess(): Boolean = this is DeviceTrustResult.Success
|
||||
fun DeviceTrustResult.isCrossSignedVerified(): Boolean = (this as? DeviceTrustResult.Success)?.level?.isCrossSigningVerified() == true
|
||||
fun DeviceTrustResult.isLocallyVerified(): Boolean = (this as? DeviceTrustResult.Success)?.level?.isLocallyVerified() == true
|
||||
|
@ -41,6 +41,12 @@ data class CryptoCrossSigningKey(
|
||||
)
|
||||
}
|
||||
|
||||
fun copyForSignature(userId: String, signedWithNoPrefix: String, signature: String): CryptoCrossSigningKey {
|
||||
return this.copy(
|
||||
signatures = mapOf(userId to mapOf("ed25519:$signedWithNoPrefix" to signature))
|
||||
)
|
||||
}
|
||||
|
||||
data class Builder(
|
||||
val userId: String,
|
||||
val usage: KeyUsage,
|
||||
|
@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.crypto.store
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
|
||||
import im.vector.matrix.android.internal.crypto.NewSessionListener
|
||||
import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest
|
||||
@ -403,10 +404,14 @@ internal interface IMXCryptoStore {
|
||||
fun setMyCrossSigningInfo(info: MXCrossSigningInfo?)
|
||||
|
||||
fun getCrossSigningInfo(userId: String) : MXCrossSigningInfo?
|
||||
fun getLiveCrossSigningInfo(userId: String) : LiveData<Optional<MXCrossSigningInfo>>
|
||||
fun setCrossSigningInfo(userId: String, info: MXCrossSigningInfo?)
|
||||
|
||||
fun storePrivateKeysInfo(msk: String?, usk: String?, ssk: String?)
|
||||
fun getCrossSigningPrivateKeys() : PrivateKeysInfo?
|
||||
|
||||
fun setUserKeysAsTrusted(userId: String, trusted: Boolean = true)
|
||||
fun setDeviceTrust(userId: String, deviceId: String, crossSignedVerified: Boolean, locallyVerified : Boolean)
|
||||
|
||||
fun clearOtherUserTrust()
|
||||
}
|
||||
|
@ -21,9 +21,12 @@ import androidx.lifecycle.Transformations
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import im.vector.matrix.android.api.util.toOptional
|
||||
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
|
||||
import im.vector.matrix.android.internal.crypto.NewSessionListener
|
||||
import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest
|
||||
import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustLevel
|
||||
import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey
|
||||
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper
|
||||
@ -883,17 +886,54 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati
|
||||
|
||||
override fun setUserKeysAsTrusted(userId: String, trusted: Boolean) {
|
||||
doRealmTransaction(realmConfiguration) { realm ->
|
||||
val info = realm.where(CrossSigningInfoEntity::class.java)
|
||||
val xInfoEntity = realm.where(CrossSigningInfoEntity::class.java)
|
||||
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
|
||||
.findFirst()
|
||||
if (info != null) {
|
||||
xInfoEntity?.crossSigningKeys?.forEach { info ->
|
||||
val level = info.trustLevelEntity
|
||||
if (level == null) {
|
||||
val newLevel = realm.createObject(TrustLevelEntity::class.java)
|
||||
newLevel.locallyVerified = true
|
||||
newLevel.locallyVerified = trusted
|
||||
newLevel.crossSignedVerified = trusted
|
||||
info.trustLevelEntity = newLevel
|
||||
} else {
|
||||
level.locallyVerified = true
|
||||
level.locallyVerified = trusted
|
||||
level.crossSignedVerified = trusted
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setDeviceTrust(userId: String, deviceId: String, crossSignedVerified: Boolean, locallyVerified: Boolean) {
|
||||
doRealmTransaction(realmConfiguration) { realm ->
|
||||
realm.where(DeviceInfoEntity::class.java)
|
||||
.equalTo(DeviceInfoEntityFields.PRIMARY_KEY, DeviceInfoEntity.createPrimaryKey(userId, deviceId))
|
||||
.findFirst()?.let { deviceInfoEntity ->
|
||||
val trustEntity = deviceInfoEntity.trustLevelEntity
|
||||
if (trustEntity == null) {
|
||||
realm.createObject(TrustLevelEntity::class.java).let {
|
||||
it.locallyVerified = locallyVerified
|
||||
it.crossSignedVerified = crossSignedVerified
|
||||
deviceInfoEntity.trustLevelEntity = it
|
||||
}
|
||||
} else {
|
||||
trustEntity.locallyVerified = locallyVerified
|
||||
trustEntity.crossSignedVerified = crossSignedVerified
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearOtherUserTrust() {
|
||||
doRealmTransaction(realmConfiguration) { realm ->
|
||||
val xInfoEntities = realm.where(CrossSigningInfoEntity::class.java)
|
||||
.findAll()
|
||||
xInfoEntities?.forEach { info ->
|
||||
//Need to ignore mine
|
||||
if (info.userId != credentials.userId) {
|
||||
info.crossSigningKeys.forEach {
|
||||
it.trustLevelEntity = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -913,15 +953,49 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati
|
||||
userId = userId,
|
||||
keys = mapOf("ed25519:$pubKey" to pubKey),
|
||||
usages = it.usages.map { it },
|
||||
signatures = it.getSignatures()
|
||||
signatures = it.getSignatures(),
|
||||
trustLevel = it.trustLevelEntity?.let {
|
||||
DeviceTrustLevel(
|
||||
crossSigningVerified = it.crossSignedVerified ?: false,
|
||||
locallyVerified = it.locallyVerified ?: false
|
||||
)
|
||||
}
|
||||
|
||||
)
|
||||
},
|
||||
isTrusted = xsignInfo.trustLevelEntity?.isVerified() ?: false // TODO
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLiveCrossSigningInfo(userId: String): LiveData<Optional<MXCrossSigningInfo>> {
|
||||
val liveData = monarchy.findAllMappedWithChanges(
|
||||
{ realm: Realm -> realm.where<CrossSigningInfoEntity>().equalTo(UserEntityFields.USER_ID, userId) },
|
||||
{ entity ->
|
||||
MXCrossSigningInfo(
|
||||
userId = userId,
|
||||
crossSigningKeys = entity.crossSigningKeys.mapNotNull {
|
||||
val pubKey = it.publicKeyBase64 ?: return@mapNotNull null
|
||||
CryptoCrossSigningKey(
|
||||
userId = userId,
|
||||
keys = mapOf("ed25519:$pubKey" to pubKey),
|
||||
usages = it.usages.map { it },
|
||||
signatures = it.getSignatures(),
|
||||
trustLevel = it.trustLevelEntity?.let {
|
||||
DeviceTrustLevel(
|
||||
crossSigningVerified = it.crossSignedVerified ?: false,
|
||||
locallyVerified = it.locallyVerified ?: false
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
return Transformations.map(liveData) {
|
||||
it.firstOrNull().toOptional()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setCrossSigningInfo(userId: String, info: MXCrossSigningInfo?) {
|
||||
doRealmTransaction(realmConfiguration) { realm ->
|
||||
|
||||
@ -941,19 +1015,13 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati
|
||||
keyInfoEntity.usages = info.usages?.let { RealmList(*it.toTypedArray()) }
|
||||
?: RealmList()
|
||||
keyInfoEntity.putSignatures(info.signatures)
|
||||
// TODO how to handle better, check if same keys?
|
||||
// reset trust
|
||||
keyInfoEntity.trustLevelEntity = null
|
||||
}
|
||||
)
|
||||
}
|
||||
existing.crossSigningKeys = xkeys
|
||||
val existingTrust = existing.trustLevelEntity
|
||||
if (existingTrust != null) {
|
||||
existingTrust.locallyVerified = true
|
||||
} else {
|
||||
realm.createObject(TrustLevelEntity::class.java).let {
|
||||
it.locallyVerified = info.isTrusted
|
||||
existing.trustLevelEntity = it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,22 +43,23 @@ internal object RealmCryptoStoreMigration : RealmMigration {
|
||||
Timber.d("Step 0 -> 1")
|
||||
Timber.d("Create KeyInfoEntity")
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
.addRealmObjectField(CrossSigningInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelentityEntitySchema)
|
||||
.addPrimaryKey(CrossSigningInfoEntityFields.USER_ID)
|
||||
.addRealmListField(CrossSigningInfoEntityFields.CROSS_SIGNING_KEYS.`$`, keyInfoEntitySchema)
|
||||
|
||||
|
@ -24,8 +24,7 @@ import io.realm.annotations.PrimaryKey
|
||||
internal open class CrossSigningInfoEntity(
|
||||
@PrimaryKey
|
||||
var userId: String? = null,
|
||||
var crossSigningKeys: RealmList<KeyInfoEntity> = RealmList(),
|
||||
var trustLevelEntity: TrustLevelEntity? = null
|
||||
var crossSigningKeys: RealmList<KeyInfoEntity> = RealmList()
|
||||
) : RealmObject() {
|
||||
|
||||
companion object
|
||||
|
@ -29,7 +29,8 @@ internal open class KeyInfoEntity(
|
||||
* The signature of this MXDeviceInfo.
|
||||
* A map from "<userId>" to a map from "<key type>:<Publickey>" to "<signature>"
|
||||
*/
|
||||
var signatures: String? = null
|
||||
var signatures: String? = null,
|
||||
var trustLevelEntity: TrustLevelEntity? = null
|
||||
) : RealmObject() {
|
||||
|
||||
// Deserialize data
|
||||
|
@ -163,7 +163,7 @@ internal abstract class SASDefaultVerificationTransaction(
|
||||
|
||||
keyMap[keyId] = macString
|
||||
|
||||
cryptoStore.getMyCrossSigningInfo()?.takeIf { it.isTrusted }
|
||||
cryptoStore.getMyCrossSigningInfo()?.takeIf { it.isTrusted() }
|
||||
?.masterKey()
|
||||
?.unpaddedBase64PublicKey
|
||||
?.let { masterPublicKey ->
|
||||
|
Loading…
x
Reference in New Issue
Block a user