Fix / cross signing info live data not always updated

This commit is contained in:
Valere 2020-01-28 11:02:12 +01:00
parent ea6e8a6789
commit 83e44ac96e
7 changed files with 151 additions and 141 deletions

View file

@ -877,10 +877,10 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati
}
override fun setMyCrossSigningInfo(info: MXCrossSigningInfo?) {
doRealmQueryAndCopy(realmConfiguration) {
it.where<CryptoMetadataEntity>().findFirst()
}?.userId?.let {
setCrossSigningInfo(it, info)
doRealmTransaction(realmConfiguration) { realm ->
realm.where<CryptoMetadataEntity>().findFirst()?.userId?.let { userId ->
addOrUpdateCrossSigningInfo(realm, userId, info)
}
}
}
@ -998,31 +998,36 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati
override fun setCrossSigningInfo(userId: String, info: MXCrossSigningInfo?) {
doRealmTransaction(realmConfiguration) { realm ->
var existing = CrossSigningInfoEntity.get(realm, userId)
if (info == null) {
// Delete known if needed
existing?.deleteFromRealm()
// TODO notify, we might need to untrust things?
} else {
// Just override existing, caller should check and untrust id needed
existing = CrossSigningInfoEntity.getOrCreate(realm, userId)
val xkeys = RealmList<KeyInfoEntity>()
info.crossSigningKeys.forEach { info ->
xkeys.add(
realm.createObject(KeyInfoEntity::class.java).also { keyInfoEntity ->
keyInfoEntity.publicKeyBase64 = info.unpaddedBase64PublicKey
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
}
addOrUpdateCrossSigningInfo(realm, userId, info)
}
}
private fun addOrUpdateCrossSigningInfo(realm: Realm, userId: String, info: MXCrossSigningInfo?): CrossSigningInfoEntity? {
var existing = CrossSigningInfoEntity.get(realm, userId)
if (info == null) {
// Delete known if needed
existing?.deleteFromRealm()
// TODO notify, we might need to untrust things?
} else {
// Just override existing, caller should check and untrust id needed
existing = CrossSigningInfoEntity.getOrCreate(realm, userId)
// existing.crossSigningKeys.forEach { it.deleteFromRealm() }
val xkeys = RealmList<KeyInfoEntity>()
info.crossSigningKeys.forEach { cryptoCrossSigningKey ->
xkeys.add(
realm.createObject(KeyInfoEntity::class.java).also { keyInfoEntity ->
keyInfoEntity.publicKeyBase64 = cryptoCrossSigningKey.unpaddedBase64PublicKey
keyInfoEntity.usages = cryptoCrossSigningKey.usages?.let { RealmList(*it.toTypedArray()) }
?: RealmList()
keyInfoEntity.putSignatures(cryptoCrossSigningKey.signatures)
// TODO how to handle better, check if same keys?
// reset trust
keyInfoEntity.trustLevelEntity = null
}
)
}
existing.crossSigningKeys = xkeys
}
return existing
}
}

View file

@ -46,7 +46,6 @@ import im.vector.matrix.rx.mapOptional
import im.vector.matrix.rx.rx
import im.vector.matrix.rx.unwrap
import im.vector.riotx.R
import im.vector.riotx.core.di.HasScreenInjector
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.DataSource
@ -75,7 +74,6 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
val fragment: RoomMemberProfileFragment = (viewModelContext as FragmentViewModelContext).fragment()
return fragment.viewModelFactory.create(state)
}
}
private val _viewEvents = PublishDataSource<RoomMemberProfileViewEvents>()
@ -118,11 +116,8 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
}
session.rx().liveCrossSigningInfo(initialState.userId)
.map {
it.getOrNull()
}
.execute {
copy(userMXCrossSigningInfo = it)
copy(userMXCrossSigningInfo = it.invoke()?.getOrNull())
}
}
}
@ -150,7 +145,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
private fun prepareVerification(action: RoomMemberProfileAction.VerifyUser) = withState { state ->
// Sanity
if (state.isRoomEncrypted) {
if (!state.isMine && state.userMXCrossSigningInfo.invoke()?.isTrusted() == false) {
if (!state.isMine && state.userMXCrossSigningInfo?.isTrusted() == false) {
// ok, let's find or create the DM room
_actionResultLiveData.postValue(
LiveEvent(Success(action.copy(userId = state.userId)))

View file

@ -35,7 +35,7 @@ data class RoomMemberProfileViewState(
val powerLevelsContent: Async<PowerLevelsContent> = Uninitialized,
val userPowerLevelString: Async<String> = Uninitialized,
val userMatrixItem: Async<MatrixItem> = Uninitialized,
val userMXCrossSigningInfo: Async<MXCrossSigningInfo?> = Uninitialized,
val userMXCrossSigningInfo: MXCrossSigningInfo? = null,
val allDevicesAreTrusted: Async<Boolean> = Uninitialized
) : MvRxState {

View file

@ -74,11 +74,8 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva
}
session.rx().liveCrossSigningInfo(userId)
.map {
it.getOrNull()
}
.execute {
copy(memberCrossSigningKey = it.invoke())
copy(memberCrossSigningKey = it.invoke()?.getOrNull())
}
}

View file

@ -105,6 +105,7 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
super.onResume()
// My device name may have been updated
refreshMyDevice()
refreshXSigningStatus()
mCryptographyCategory.isVisible = vectorPreferences.developerMode()
}
@ -128,6 +129,10 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
}
}
refreshXSigningStatus()
}
private fun refreshXSigningStatus() {
if (vectorPreferences.developerMode()) {
val crossSigningKeys = session.getCrossSigningService().getMyCrossSigningKeys()
val xSigningIsEnableInAccount = crossSigningKeys != null

View file

@ -16,8 +16,6 @@
package im.vector.riotx.features.settings.crosssigning
import com.airbnb.epoxy.TypedEpoxyController
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.Success
import im.vector.riotx.R
import im.vector.riotx.core.epoxy.loadingItem
import im.vector.riotx.core.resources.ColorProvider
@ -50,14 +48,16 @@ class CrossSigningEpoxyController @Inject constructor(
titleIconResourceId(R.drawable.ic_shield_trusted)
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_complete))
}
bottomSheetVerificationActionItem {
id("resetkeys")
title("Reset keys")
titleColor(colorProvider.getColor(R.color.riotx_destructive_accent))
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_destructive_accent))
listener {
interactionListener?.onResetCrossSigningKeys()
if (!data.isUploadingKeys) {
bottomSheetVerificationActionItem {
id("resetkeys")
title("Reset keys")
titleColor(colorProvider.getColor(R.color.riotx_destructive_accent))
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_destructive_accent))
listener {
interactionListener?.onResetCrossSigningKeys()
}
}
}
} else if (data.xSigningKeysAreTrusted) {
@ -66,30 +66,32 @@ class CrossSigningEpoxyController @Inject constructor(
titleIconResourceId(R.drawable.ic_shield_warning)
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_trusted))
}
bottomSheetVerificationActionItem {
id("resetkeys")
title("Reset keys")
titleColor(colorProvider.getColor(R.color.riotx_destructive_accent))
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_destructive_accent))
listener {
interactionListener?.onResetCrossSigningKeys()
if (!data.isUploadingKeys) {
bottomSheetVerificationActionItem {
id("resetkeys")
title("Reset keys")
titleColor(colorProvider.getColor(R.color.riotx_destructive_accent))
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_destructive_accent))
listener {
interactionListener?.onResetCrossSigningKeys()
}
}
}
} else if (data.xSigningIsEnableInAccount) {
genericItem {
id("enable")
titleIconResourceId(R.drawable.ic_shield_black)
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_not_trusted))
}
bottomSheetVerificationActionItem {
id("resetkeys")
title("Reset keys")
titleColor(colorProvider.getColor(R.color.riotx_destructive_accent))
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_destructive_accent))
listener {
interactionListener?.onResetCrossSigningKeys()
} else if (data.xSigningIsEnableInAccount) {
genericItem {
id("enable")
titleIconResourceId(R.drawable.ic_shield_black)
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_not_trusted))
}
bottomSheetVerificationActionItem {
id("resetkeys")
title("Reset keys")
titleColor(colorProvider.getColor(R.color.riotx_destructive_accent))
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_destructive_accent))
listener {
interactionListener?.onResetCrossSigningKeys()
}
}
}
} else {
@ -97,75 +99,74 @@ class CrossSigningEpoxyController @Inject constructor(
id("not")
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_disabled))
}
bottomSheetVerificationActionItem {
id("initKeys")
title("Initialize keys")
titleColor(colorProvider.getColor(R.color.riotx_positive_accent))
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_positive_accent))
listener {
interactionListener?.onInitializeCrossSigningKeys()
if (!data.isUploadingKeys) {
bottomSheetVerificationActionItem {
id("initKeys")
title("Initialize keys")
titleColor(colorProvider.getColor(R.color.riotx_positive_accent))
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_positive_accent))
listener {
interactionListener?.onInitializeCrossSigningKeys()
}
}
}
}
when (data.crossSigningInfo) {
is Loading -> {
loadingItem {
id("loading")
if (data.isUploadingKeys) {
loadingItem {
id("loading")
}
} else {
val crossSigningKeys = data.crossSigningInfo
crossSigningKeys?.masterKey()?.let {
genericItemWithValue {
id("msk")
titleIconResourceId(R.drawable.key_small)
title(
span {
+"Master Key:\n"
span {
text = it.unpaddedBase64PublicKey ?: ""
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary)
textSize = dimensionConverter.spToPx(12)
}
}
)
}
}
is Success -> {
val crossSigningKeys = data.crossSigningInfo.invoke()
crossSigningKeys?.masterKey()?.let {
genericItemWithValue {
id("msk")
titleIconResourceId(R.drawable.key_small)
title(
crossSigningKeys?.userKey()?.let {
genericItemWithValue {
id("usk")
titleIconResourceId(R.drawable.key_small)
title(
span {
+"User Key:\n"
span {
+"Master Key:\n"
span {
text = it.unpaddedBase64PublicKey ?: ""
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary)
textSize = dimensionConverter.spToPx(12)
}
text = it.unpaddedBase64PublicKey ?: ""
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary)
textSize = dimensionConverter.spToPx(12)
}
)
}
}
)
}
crossSigningKeys?.userKey()?.let {
genericItemWithValue {
id("usk")
titleIconResourceId(R.drawable.key_small)
title(
}
crossSigningKeys?.selfSigningKey()?.let {
genericItemWithValue {
id("ssk")
titleIconResourceId(R.drawable.key_small)
title(
span {
+"Self Signed Key:\n"
span {
+"User Key:\n"
span {
text = it.unpaddedBase64PublicKey ?: ""
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary)
textSize = dimensionConverter.spToPx(12)
}
text = it.unpaddedBase64PublicKey ?: ""
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary)
textSize = dimensionConverter.spToPx(12)
}
)
}
}
crossSigningKeys?.selfSigningKey()?.let {
genericItemWithValue {
id("ssk")
titleIconResourceId(R.drawable.key_small)
title(
span {
+"Self Signed Key:\n"
span {
text = it.unpaddedBase64PublicKey ?: ""
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary)
textSize = dimensionConverter.spToPx(12)
}
}
)
}
}
)
}
}
}

View file

@ -20,7 +20,6 @@ import androidx.lifecycle.MutableLiveData
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
@ -44,10 +43,11 @@ import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.LiveEvent
data class CrossSigningSettingsViewState(
val crossSigningInfo: Async<MXCrossSigningInfo?> = Uninitialized,
val crossSigningInfo: MXCrossSigningInfo? = null,
val xSigningIsEnableInAccount: Boolean = false,
val xSigningKeysAreTrusted: Boolean = false,
val xSigningKeyCanSign: Boolean = true
val xSigningKeyCanSign: Boolean = true,
val isUploadingKeys: Boolean = false
) : MvRxState
sealed class CrossSigningAction : VectorViewModelAction {
@ -67,16 +67,13 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted privat
init {
session.rx().liveCrossSigningInfo(session.myUserId)
.map {
it.getOrNull()
}
.execute {
val crossSigningKeys = it.invoke()
val crossSigningKeys = it.invoke()?.getOrNull()
val xSigningIsEnableInAccount = crossSigningKeys != null
val xSigningKeysAreTrusted = session.getCrossSigningService().checkUserTrust(session.myUserId).isVerified()
val xSigningKeyCanSign = session.getCrossSigningService().canCrossSign()
copy(
crossSigningInfo = it,
crossSigningInfo = crossSigningKeys,
xSigningIsEnableInAccount = xSigningIsEnableInAccount,
xSigningKeysAreTrusted = xSigningKeysAreTrusted,
xSigningKeyCanSign = xSigningKeyCanSign
@ -99,9 +96,16 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted privat
private fun initializeCrossSigning(auth: UserPasswordAuth?) {
setState {
copy(crossSigningInfo = Loading())
copy(isUploadingKeys = true)
}
session.getCrossSigningService().initializeCrossSigning(auth, object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
setState {
copy(isUploadingKeys = false)
}
}
override fun onFailure(failure: Throwable) {
if (failure is Failure.OtherServerError
&& failure.httpCode == 401
@ -125,6 +129,9 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted privat
}
}
_requestLiveData.postValue(LiveEvent(Fail(Throwable("You cannot do that from mobile"))))
setState {
copy(isUploadingKeys = false)
}
}
})
}