mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 11:59:12 +03:00
warn on cross signing reset
This commit is contained in:
parent
dc9451aeba
commit
c8f0792997
16 changed files with 208 additions and 44 deletions
1
changelog.d/6702.bugfix
Normal file
1
changelog.d/6702.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Add Warning shield when a user previously verified rotated his cross signing keys
|
|
@ -18,7 +18,8 @@ package org.matrix.android.sdk.api.session.crypto.crosssigning
|
||||||
|
|
||||||
data class MXCrossSigningInfo(
|
data class MXCrossSigningInfo(
|
||||||
val userId: String,
|
val userId: String,
|
||||||
val crossSigningKeys: List<CryptoCrossSigningKey>
|
val crossSigningKeys: List<CryptoCrossSigningKey>,
|
||||||
|
val wasTrustedOnce: Boolean
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun isTrusted(): Boolean = masterKey()?.trustLevel?.isVerified() == true &&
|
fun isTrusted(): Boolean = masterKey()?.trustLevel?.isVerified() == true &&
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* 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.api.session.crypto.model
|
||||||
|
|
||||||
|
enum class UserVerificationLevel {
|
||||||
|
|
||||||
|
VERIFIED_ALL_DEVICES_TRUSTED,
|
||||||
|
|
||||||
|
VERIFIED_WITH_DEVICES_UNTRUSTED,
|
||||||
|
|
||||||
|
UNVERIFIED_BUT_WAS_PREVIOUSLY,
|
||||||
|
|
||||||
|
WAS_NEVER_VERIFIED,
|
||||||
|
}
|
|
@ -167,7 +167,11 @@ internal class DefaultCrossSigningService @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSuccess(data: InitializeCrossSigningTask.Result) {
|
override fun onSuccess(data: InitializeCrossSigningTask.Result) {
|
||||||
val crossSigningInfo = MXCrossSigningInfo(userId, listOf(data.masterKeyInfo, data.userKeyInfo, data.selfSignedKeyInfo))
|
val crossSigningInfo = MXCrossSigningInfo(
|
||||||
|
userId,
|
||||||
|
listOf(data.masterKeyInfo, data.userKeyInfo, data.selfSignedKeyInfo),
|
||||||
|
true
|
||||||
|
)
|
||||||
cryptoStore.setMyCrossSigningInfo(crossSigningInfo)
|
cryptoStore.setMyCrossSigningInfo(crossSigningInfo)
|
||||||
setUserKeysAsTrusted(userId, true)
|
setUserKeysAsTrusted(userId, true)
|
||||||
cryptoStore.storePrivateKeysInfo(data.masterKeyPK, data.userKeyPK, data.selfSigningKeyPK)
|
cryptoStore.storePrivateKeysInfo(data.masterKeyPK, data.userKeyPK, data.selfSigningKeyPK)
|
||||||
|
|
|
@ -259,21 +259,27 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||||
cryptoRealm.where(CrossSigningInfoEntity::class.java)
|
cryptoRealm.where(CrossSigningInfoEntity::class.java)
|
||||||
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
|
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
?.crossSigningKeys
|
?.let { userKeyInfo ->
|
||||||
?.forEach { info ->
|
userKeyInfo
|
||||||
// optimization to avoid trigger updates when there is no change..
|
.crossSigningKeys
|
||||||
if (info.trustLevelEntity?.isVerified() != verified) {
|
.forEach { key ->
|
||||||
Timber.d("## CrossSigning - Trust change for $userId : $verified")
|
// optimization to avoid trigger updates when there is no change..
|
||||||
val level = info.trustLevelEntity
|
if (key.trustLevelEntity?.isVerified() != verified) {
|
||||||
if (level == null) {
|
Timber.d("## CrossSigning - Trust change for $userId : $verified")
|
||||||
info.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also {
|
val level = key.trustLevelEntity
|
||||||
it.locallyVerified = verified
|
if (level == null) {
|
||||||
it.crossSignedVerified = verified
|
key.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also {
|
||||||
|
it.locallyVerified = verified
|
||||||
|
it.crossSignedVerified = verified
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
level.locallyVerified = verified
|
||||||
|
level.crossSignedVerified = verified
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
if (verified) {
|
||||||
level.locallyVerified = verified
|
userKeyInfo.wasUserVerifiedOnce = true
|
||||||
level.crossSignedVerified = verified
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,8 +305,18 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||||
getCrossSigningInfo(cryptoRealm, userId)?.isTrusted() == true
|
getCrossSigningInfo(cryptoRealm, userId)?.isTrusted() == true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val resetTrust = listToCheck
|
||||||
|
.filter { userId ->
|
||||||
|
val crossSigningInfo = getCrossSigningInfo(cryptoRealm, userId)
|
||||||
|
crossSigningInfo?.isTrusted() != true && crossSigningInfo?.wasTrustedOnce == true
|
||||||
|
}
|
||||||
|
|
||||||
return if (allTrustedUserIds.isEmpty()) {
|
return if (allTrustedUserIds.isEmpty()) {
|
||||||
RoomEncryptionTrustLevel.Default
|
if (resetTrust.isEmpty()) {
|
||||||
|
RoomEncryptionTrustLevel.Default
|
||||||
|
} else {
|
||||||
|
RoomEncryptionTrustLevel.Warning
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// If one of the verified user as an untrusted device -> warning
|
// If one of the verified user as an untrusted device -> warning
|
||||||
// If all devices of all verified users are trusted -> green
|
// If all devices of all verified users are trusted -> green
|
||||||
|
@ -327,11 +343,15 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||||
if (hasWarning) {
|
if (hasWarning) {
|
||||||
RoomEncryptionTrustLevel.Warning
|
RoomEncryptionTrustLevel.Warning
|
||||||
} else {
|
} else {
|
||||||
if (listToCheck.size == allTrustedUserIds.size) {
|
if (resetTrust.isEmpty()) {
|
||||||
// all users are trusted and all devices are verified
|
if (listToCheck.size == allTrustedUserIds.size) {
|
||||||
RoomEncryptionTrustLevel.Trusted
|
// all users are trusted and all devices are verified
|
||||||
|
RoomEncryptionTrustLevel.Trusted
|
||||||
|
} else {
|
||||||
|
RoomEncryptionTrustLevel.Default
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
RoomEncryptionTrustLevel.Default
|
RoomEncryptionTrustLevel.Warning
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,7 +364,8 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
|
||||||
userId = userId,
|
userId = userId,
|
||||||
crossSigningKeys = xsignInfo.crossSigningKeys.mapNotNull {
|
crossSigningKeys = xsignInfo.crossSigningKeys.mapNotNull {
|
||||||
crossSigningKeysMapper.map(userId, it)
|
crossSigningKeysMapper.map(userId, it)
|
||||||
}
|
},
|
||||||
|
wasTrustedOnce = xsignInfo.wasUserVerifiedOnce
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1611,7 +1611,8 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
userId = userId,
|
userId = userId,
|
||||||
crossSigningKeys = xsignInfo.crossSigningKeys.mapNotNull {
|
crossSigningKeys = xsignInfo.crossSigningKeys.mapNotNull {
|
||||||
crossSigningKeysMapper.map(userId, it)
|
crossSigningKeysMapper.map(userId, it)
|
||||||
}
|
},
|
||||||
|
wasTrustedOnce = xsignInfo.wasUserVerifiedOnce
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo016
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo016
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo017
|
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo017
|
||||||
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo018
|
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.util.database.MatrixRealmMigration
|
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
|
||||||
import org.matrix.android.sdk.internal.util.time.Clock
|
import org.matrix.android.sdk.internal.util.time.Clock
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -49,7 +50,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(
|
||||||
private val clock: Clock,
|
private val clock: Clock,
|
||||||
) : MatrixRealmMigration(
|
) : MatrixRealmMigration(
|
||||||
dbName = "Crypto",
|
dbName = "Crypto",
|
||||||
schemaVersion = 18L,
|
schemaVersion = 19L,
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Forces all RealmCryptoStoreMigration instances to be equal.
|
* Forces all RealmCryptoStoreMigration instances to be equal.
|
||||||
|
@ -77,5 +78,6 @@ internal class RealmCryptoStoreMigration @Inject constructor(
|
||||||
if (oldVersion < 16) MigrateCryptoTo016(realm).perform()
|
if (oldVersion < 16) MigrateCryptoTo016(realm).perform()
|
||||||
if (oldVersion < 17) MigrateCryptoTo017(realm).perform()
|
if (oldVersion < 17) MigrateCryptoTo017(realm).perform()
|
||||||
if (oldVersion < 18) MigrateCryptoTo018(realm).perform()
|
if (oldVersion < 18) MigrateCryptoTo018(realm).perform()
|
||||||
|
if (oldVersion < 19) MigrateCryptoTo019(realm).perform()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.internal.crypto.store.db.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import io.realm.DynamicRealmObject
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.KeyUsage
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This migration is adding support for trusted flags on megolm sessions.
|
||||||
|
* We can't really assert the trust of existing keys, so for the sake of simplicity we are going to
|
||||||
|
* mark existing keys as safe.
|
||||||
|
* This migration can take long depending on the account
|
||||||
|
*/
|
||||||
|
internal class MigrateCryptoTo019(realm: DynamicRealm) : RealmMigrator(realm, 18) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("CrossSigningInfoEntity")
|
||||||
|
?.addField(CrossSigningInfoEntityFields.WAS_USER_VERIFIED_ONCE, Boolean::class.java)
|
||||||
|
?.transform { dynamicObject ->
|
||||||
|
|
||||||
|
val knowKeys = dynamicObject.getList(CrossSigningInfoEntityFields.CROSS_SIGNING_KEYS.`$`)
|
||||||
|
val msk = knowKeys.firstOrNull {
|
||||||
|
it.getList(KeyInfoEntityFields.USAGES.`$`, String::class.java).orEmpty().contains(KeyUsage.MASTER.value)
|
||||||
|
}
|
||||||
|
val ssk = knowKeys.firstOrNull {
|
||||||
|
it.getList(KeyInfoEntityFields.USAGES.`$`, String::class.java).orEmpty().contains(KeyUsage.SELF_SIGNING.value)
|
||||||
|
}
|
||||||
|
val isTrusted = isDynamicKeyInfoTrusted(msk?.get<DynamicRealmObject>(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`)) &&
|
||||||
|
isDynamicKeyInfoTrusted(ssk?.get<DynamicRealmObject>(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`))
|
||||||
|
|
||||||
|
dynamicObject.setBoolean(CrossSigningInfoEntityFields.WAS_USER_VERIFIED_ONCE, isTrusted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isDynamicKeyInfoTrusted(keyInfo: DynamicRealmObject?): Boolean {
|
||||||
|
if (keyInfo == null) return false
|
||||||
|
return !keyInfo.isNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED) && keyInfo.getBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED) &&
|
||||||
|
!keyInfo.isNull(TrustLevelEntityFields.LOCALLY_VERIFIED) && keyInfo.getBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED)
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ import org.matrix.android.sdk.internal.extensions.clearWith
|
||||||
internal open class CrossSigningInfoEntity(
|
internal open class CrossSigningInfoEntity(
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
var userId: String? = null,
|
var userId: String? = null,
|
||||||
|
var wasUserVerifiedOnce: Boolean = false,
|
||||||
var crossSigningKeys: RealmList<KeyInfoEntity> = RealmList()
|
var crossSigningKeys: RealmList<KeyInfoEntity> = RealmList()
|
||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ import im.vector.app.core.epoxy.onClick
|
||||||
import im.vector.app.core.extensions.setTextOrHide
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
import org.matrix.android.sdk.api.session.crypto.model.UserVerificationLevel
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
|
|
||||||
abstract class BaseProfileMatrixItem<T : ProfileMatrixItem.Holder>(@LayoutRes layoutId: Int) : VectorEpoxyModel<T>(layoutId) {
|
abstract class BaseProfileMatrixItem<T : ProfileMatrixItem.Holder>(@LayoutRes layoutId: Int) : VectorEpoxyModel<T>(layoutId) {
|
||||||
|
@ -35,7 +35,7 @@ abstract class BaseProfileMatrixItem<T : ProfileMatrixItem.Holder>(@LayoutRes la
|
||||||
@EpoxyAttribute var editable: Boolean = true
|
@EpoxyAttribute var editable: Boolean = true
|
||||||
|
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var userEncryptionTrustLevel: RoomEncryptionTrustLevel? = null
|
var userVerificationLevel: UserVerificationLevel? = null
|
||||||
|
|
||||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
|
||||||
var clickListener: ClickListener? = null
|
var clickListener: ClickListener? = null
|
||||||
|
@ -53,6 +53,6 @@ abstract class BaseProfileMatrixItem<T : ProfileMatrixItem.Holder>(@LayoutRes la
|
||||||
holder.subtitleView.setTextOrHide(matrixId)
|
holder.subtitleView.setTextOrHide(matrixId)
|
||||||
holder.editableView.isVisible = editable
|
holder.editableView.isVisible = editable
|
||||||
avatarRenderer.render(matrixItem, holder.avatarImageView)
|
avatarRenderer.render(matrixItem, holder.avatarImageView)
|
||||||
holder.avatarDecorationImageView.render(userEncryptionTrustLevel)
|
holder.avatarDecorationImageView.renderUser(userVerificationLevel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import androidx.core.view.isVisible
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.features.home.room.detail.timeline.item.E2EDecoration
|
import im.vector.app.features.home.room.detail.timeline.item.E2EDecoration
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.model.UserVerificationLevel
|
||||||
|
|
||||||
class ShieldImageView @JvmOverloads constructor(
|
class ShieldImageView @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@ -102,6 +103,35 @@ class ShieldImageView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun renderUser(userVerificationLevel: UserVerificationLevel?, borderLess: Boolean = false) {
|
||||||
|
isVisible = userVerificationLevel != null
|
||||||
|
when (userVerificationLevel) {
|
||||||
|
UserVerificationLevel.VERIFIED_ALL_DEVICES_TRUSTED -> {
|
||||||
|
contentDescription = context.getString(R.string.a11y_trust_level_trusted)
|
||||||
|
setImageResource(
|
||||||
|
if (borderLess) R.drawable.ic_shield_trusted_no_border
|
||||||
|
else R.drawable.ic_shield_trusted
|
||||||
|
)
|
||||||
|
}
|
||||||
|
UserVerificationLevel.UNVERIFIED_BUT_WAS_PREVIOUSLY,
|
||||||
|
UserVerificationLevel.VERIFIED_WITH_DEVICES_UNTRUSTED -> {
|
||||||
|
contentDescription = context.getString(R.string.a11y_trust_level_warning)
|
||||||
|
setImageResource(
|
||||||
|
if (borderLess) R.drawable.ic_shield_warning_no_border
|
||||||
|
else R.drawable.ic_shield_warning
|
||||||
|
)
|
||||||
|
}
|
||||||
|
UserVerificationLevel.WAS_NEVER_VERIFIED -> {
|
||||||
|
contentDescription = context.getString(R.string.a11y_trust_level_default)
|
||||||
|
setImageResource(
|
||||||
|
if (borderLess) R.drawable.ic_shield_black_no_border
|
||||||
|
else R.drawable.ic_shield_black
|
||||||
|
)
|
||||||
|
}
|
||||||
|
null -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DrawableRes
|
@DrawableRes
|
||||||
|
|
|
@ -59,7 +59,7 @@ import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorPr
|
||||||
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
|
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
|
||||||
import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
|
import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
import org.matrix.android.sdk.api.session.crypto.model.UserVerificationLevel
|
||||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -235,23 +235,27 @@ class RoomMemberProfileFragment :
|
||||||
if (state.userMXCrossSigningInfo.isTrusted()) {
|
if (state.userMXCrossSigningInfo.isTrusted()) {
|
||||||
// User is trusted
|
// User is trusted
|
||||||
if (state.allDevicesAreCrossSignedTrusted) {
|
if (state.allDevicesAreCrossSignedTrusted) {
|
||||||
RoomEncryptionTrustLevel.Trusted
|
UserVerificationLevel.VERIFIED_ALL_DEVICES_TRUSTED
|
||||||
} else {
|
} else {
|
||||||
RoomEncryptionTrustLevel.Warning
|
UserVerificationLevel.VERIFIED_WITH_DEVICES_UNTRUSTED
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RoomEncryptionTrustLevel.Default
|
if (state.userMXCrossSigningInfo.wasTrustedOnce) {
|
||||||
|
UserVerificationLevel.UNVERIFIED_BUT_WAS_PREVIOUSLY
|
||||||
|
} else {
|
||||||
|
UserVerificationLevel.WAS_NEVER_VERIFIED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Legacy
|
// Legacy
|
||||||
if (state.allDevicesAreTrusted) {
|
if (state.allDevicesAreTrusted) {
|
||||||
RoomEncryptionTrustLevel.Trusted
|
UserVerificationLevel.VERIFIED_ALL_DEVICES_TRUSTED
|
||||||
} else {
|
} else {
|
||||||
RoomEncryptionTrustLevel.Warning
|
UserVerificationLevel.VERIFIED_WITH_DEVICES_UNTRUSTED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
headerViews.memberProfileDecorationImageView.render(trustLevel)
|
headerViews.memberProfileDecorationImageView.renderUser(trustLevel)
|
||||||
views.matrixProfileDecorationToolbarAvatarImageView.render(trustLevel)
|
views.matrixProfileDecorationToolbarAvatarImageView.renderUser(trustLevel)
|
||||||
} else {
|
} else {
|
||||||
headerViews.memberProfileDecorationImageView.isVisible = false
|
headerViews.memberProfileDecorationImageView.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,7 @@ class RoomMemberListController @Inject constructor(
|
||||||
id(roomMember.userId)
|
id(roomMember.userId)
|
||||||
matrixItem(roomMember.toMatrixItem())
|
matrixItem(roomMember.toMatrixItem())
|
||||||
avatarRenderer(host.avatarRenderer)
|
avatarRenderer(host.avatarRenderer)
|
||||||
userEncryptionTrustLevel(data.trustLevelMap.invoke()?.get(roomMember.userId))
|
userVerificationLevel(data.trustLevelMap.invoke()?.get(roomMember.userId))
|
||||||
clickListener {
|
clickListener {
|
||||||
host.callback?.onRoomMemberClicked(roomMember)
|
host.callback?.onRoomMemberClicked(roomMember)
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
import org.matrix.android.sdk.api.session.crypto.model.UserVerificationLevel
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
import org.matrix.android.sdk.api.session.getRoom
|
import org.matrix.android.sdk.api.session.getRoom
|
||||||
|
@ -119,10 +119,22 @@ class RoomMemberListViewModel @AssistedInject constructor(
|
||||||
val allDeviceTrusted = it.value.fold(it.value.isNotEmpty()) { prev, next ->
|
val allDeviceTrusted = it.value.fold(it.value.isNotEmpty()) { prev, next ->
|
||||||
prev && next.trustLevel?.isCrossSigningVerified().orFalse()
|
prev && next.trustLevel?.isCrossSigningVerified().orFalse()
|
||||||
}
|
}
|
||||||
if (session.cryptoService().crossSigningService().getUserCrossSigningKeys(it.key)?.isTrusted().orFalse()) {
|
val mxCrossSigningInfo = session.cryptoService().crossSigningService().getUserCrossSigningKeys(it.key)
|
||||||
if (allDeviceTrusted) RoomEncryptionTrustLevel.Trusted else RoomEncryptionTrustLevel.Warning
|
when {
|
||||||
} else {
|
mxCrossSigningInfo == null -> {
|
||||||
RoomEncryptionTrustLevel.Default
|
UserVerificationLevel.WAS_NEVER_VERIFIED
|
||||||
|
}
|
||||||
|
mxCrossSigningInfo.isTrusted() -> {
|
||||||
|
if (allDeviceTrusted) UserVerificationLevel.VERIFIED_ALL_DEVICES_TRUSTED
|
||||||
|
else UserVerificationLevel.VERIFIED_WITH_DEVICES_UNTRUSTED
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
if (mxCrossSigningInfo.wasTrustedOnce) {
|
||||||
|
UserVerificationLevel.UNVERIFIED_BUT_WAS_PREVIOUSLY
|
||||||
|
} else {
|
||||||
|
UserVerificationLevel.WAS_NEVER_VERIFIED
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import com.airbnb.mvrx.Uninitialized
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.GenericIdArgs
|
import im.vector.app.core.platform.GenericIdArgs
|
||||||
import im.vector.app.features.roomprofile.RoomProfileArgs
|
import im.vector.app.features.roomprofile.RoomProfileArgs
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
import org.matrix.android.sdk.api.session.crypto.model.UserVerificationLevel
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
@ -36,7 +36,7 @@ data class RoomMemberListViewState(
|
||||||
val ignoredUserIds: List<String> = emptyList(),
|
val ignoredUserIds: List<String> = emptyList(),
|
||||||
val filter: String = "",
|
val filter: String = "",
|
||||||
val threePidInvites: Async<List<Event>> = Uninitialized,
|
val threePidInvites: Async<List<Event>> = Uninitialized,
|
||||||
val trustLevelMap: Async<Map<String, RoomEncryptionTrustLevel?>> = Uninitialized,
|
val trustLevelMap: Async<Map<String, UserVerificationLevel>> = Uninitialized,
|
||||||
val actionsPermissions: ActionPermissions = ActionPermissions()
|
val actionsPermissions: ActionPermissions = ActionPermissions()
|
||||||
) : MavericksState {
|
) : MavericksState {
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ class SpacePeopleListController @Inject constructor(
|
||||||
id(roomMember.userId)
|
id(roomMember.userId)
|
||||||
matrixItem(roomMember.toMatrixItem())
|
matrixItem(roomMember.toMatrixItem())
|
||||||
avatarRenderer(host.avatarRenderer)
|
avatarRenderer(host.avatarRenderer)
|
||||||
userEncryptionTrustLevel(data.trustLevelMap.invoke()?.get(roomMember.userId))
|
userVerificationLevel(data.trustLevelMap.invoke()?.get(roomMember.userId))
|
||||||
.apply {
|
.apply {
|
||||||
val pl = host.toPowerLevelLabel(memberEntry.first)
|
val pl = host.toPowerLevelLabel(memberEntry.first)
|
||||||
if (memberEntry.first == RoomMemberListCategories.INVITE) {
|
if (memberEntry.first == RoomMemberListCategories.INVITE) {
|
||||||
|
|
Loading…
Reference in a new issue