Create isRecoverySetup()

This commit is contained in:
Benoit Marty 2020-06-17 11:25:30 +02:00 committed by Valere
parent bcd78a96bf
commit 12a4f6f05b
7 changed files with 74 additions and 42 deletions

View File

@ -99,7 +99,9 @@ interface CryptoService {
fun removeRoomKeysRequestListener(listener: GossipingRequestListener) fun removeRoomKeysRequestListener(listener: GossipingRequestListener)
fun fetchDevicesList(callback: MatrixCallback<DevicesListResponse>) fun fetchDevicesList(callback: MatrixCallback<DevicesListResponse>)
fun getMyDevicesInfo() : List<DeviceInfo> fun getMyDevicesInfo() : List<DeviceInfo>
fun getLiveMyDevicesInfo() : LiveData<List<DeviceInfo>> fun getLiveMyDevicesInfo() : LiveData<List<DeviceInfo>>
fun getDeviceInfo(deviceId: String, callback: MatrixCallback<DeviceInfo>) fun getDeviceInfo(deviceId: String, callback: MatrixCallback<DeviceInfo>)

View File

@ -18,6 +18,9 @@ package im.vector.matrix.android.api.session.securestorage
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.listeners.ProgressListener import im.vector.matrix.android.api.listeners.ProgressListener
import im.vector.matrix.android.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
import im.vector.matrix.android.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
import im.vector.matrix.android.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
/** /**
* Some features may require clients to store encrypted data on the server so that it can be shared securely between clients. * Some features may require clients to store encrypted data on the server so that it can be shared securely between clients.
@ -111,7 +114,17 @@ interface SharedSecretStorageService {
*/ */
fun getSecret(name: String, keyId: String?, secretKey: SsssKeySpec, callback: MatrixCallback<String>) fun getSecret(name: String, keyId: String?, secretKey: SsssKeySpec, callback: MatrixCallback<String>)
fun checkShouldBeAbleToAccessSecrets(secretNames: List<String>, keyId: String?) : IntegrityResult /**
* Return true if SSSS is configured
*/
fun isRecoverySetup(): Boolean {
return checkShouldBeAbleToAccessSecrets(
secretNames = listOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME),
keyId = null
) is IntegrityResult.Success
}
fun checkShouldBeAbleToAccessSecrets(secretNames: List<String>, keyId: String?): IntegrityResult
fun requestSecret(name: String, myOtherDeviceId: String) fun requestSecret(name: String, myOtherDeviceId: String)

View File

@ -212,7 +212,9 @@ internal interface IMXCryptoStore {
fun getLiveDeviceList(): LiveData<List<CryptoDeviceInfo>> fun getLiveDeviceList(): LiveData<List<CryptoDeviceInfo>>
fun getMyDevicesInfo() : List<DeviceInfo> fun getMyDevicesInfo() : List<DeviceInfo>
fun getLiveMyDevicesInfo() : LiveData<List<DeviceInfo>> fun getLiveMyDevicesInfo() : LiveData<List<DeviceInfo>>
fun saveMyDevicesInfo(info: List<DeviceInfo>) fun saveMyDevicesInfo(info: List<DeviceInfo>)
/** /**
* Store the crypto algorithm for a room. * Store the crypto algorithm for a room.

View File

@ -44,7 +44,6 @@ import im.vector.matrix.android.api.session.crypto.verification.VerificationTran
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
import im.vector.matrix.android.api.session.events.model.LocalEcho import im.vector.matrix.android.api.session.events.model.LocalEcho
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
import im.vector.matrix.android.api.session.securestorage.IntegrityResult
import im.vector.matrix.android.api.util.MatrixItem import im.vector.matrix.android.api.util.MatrixItem
import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.matrix.android.internal.crypto.crosssigning.fromBase64 import im.vector.matrix.android.internal.crypto.crosssigning.fromBase64
@ -118,10 +117,6 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
session.cryptoService().verificationService().getExistingTransaction(args.otherUserId, it) as? QrCodeVerificationTransaction session.cryptoService().verificationService().getExistingTransaction(args.otherUserId, it) as? QrCodeVerificationTransaction
} }
val ssssOk = session.sharedSecretStorageService.checkShouldBeAbleToAccessSecrets(
listOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME),
null // default key
) is IntegrityResult.Success
setState { setState {
copy( copy(
otherUserMxItem = userItem?.toMatrixItem(), otherUserMxItem = userItem?.toMatrixItem(),
@ -133,7 +128,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
roomId = args.roomId, roomId = args.roomId,
isMe = args.otherUserId == session.myUserId, isMe = args.otherUserId == session.myUserId,
currentDeviceCanCrossSign = session.cryptoService().crossSigningService().canCrossSign(), currentDeviceCanCrossSign = session.cryptoService().crossSigningService().canCrossSign(),
quadSContainsSecrets = ssssOk quadSContainsSecrets = session.sharedSecretStorageService.isRecoverySetup()
) )
} }

View File

@ -41,34 +41,37 @@ class CrossSigningSettingsController @Inject constructor(
override fun buildModels(data: CrossSigningSettingsViewState?) { override fun buildModels(data: CrossSigningSettingsViewState?) {
if (data == null) return if (data == null) return
if (data.xSigningKeyCanSign) { when {
genericItem { data.xSigningKeyCanSign -> {
id("can") genericItem {
titleIconResourceId(R.drawable.ic_shield_trusted) id("can")
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_complete)) titleIconResourceId(R.drawable.ic_shield_trusted)
} title(stringProvider.getString(R.string.encryption_information_dg_xsigning_complete))
} else if (data.xSigningKeysAreTrusted) {
genericItem {
id("trusted")
titleIconResourceId(R.drawable.ic_shield_custom)
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_trusted))
}
bottomSheetVerificationActionItem {
id("verify")
title(stringProvider.getString(R.string.crosssigning_verify_this_session))
titleColor(colorProvider.getColor(R.color.riotx_positive_accent))
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_positive_accent))
listener {
interactionListener?.verifySession()
} }
} }
} else if (data.xSigningIsEnableInAccount) { data.xSigningKeysAreTrusted -> {
genericItem { genericItem {
id("enable") id("trusted")
titleIconResourceId(R.drawable.ic_shield_black) titleIconResourceId(R.drawable.ic_shield_custom)
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_not_trusted)) title(stringProvider.getString(R.string.encryption_information_dg_xsigning_trusted))
}
} }
data.xSigningIsEnableInAccount -> {
genericItem {
id("enable")
titleIconResourceId(R.drawable.ic_shield_black)
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_not_trusted))
}
}
else -> {
genericItem {
id("not")
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_disabled))
}
}
}
if (data.recoveryHasToBeSetUp) {
bottomSheetVerificationActionItem { bottomSheetVerificationActionItem {
id("setup_recovery") id("setup_recovery")
title(stringProvider.getString(R.string.settings_setup_secure_backup)) title(stringProvider.getString(R.string.settings_setup_secure_backup))
@ -78,6 +81,9 @@ class CrossSigningSettingsController @Inject constructor(
interactionListener?.setupRecovery() interactionListener?.setupRecovery()
} }
} }
}
if (data.deviceHasToBeVerified) {
bottomSheetVerificationActionItem { bottomSheetVerificationActionItem {
id("verify") id("verify")
title(stringProvider.getString(R.string.crosssigning_verify_this_session)) title(stringProvider.getString(R.string.crosssigning_verify_this_session))
@ -88,11 +94,6 @@ class CrossSigningSettingsController @Inject constructor(
interactionListener?.verifySession() interactionListener?.verifySession()
} }
} }
} else {
genericItem {
id("not")
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_disabled))
}
} }
val crossSigningKeys = data.crossSigningInfo val crossSigningKeys = data.crossSigningInfo

View File

@ -21,27 +21,43 @@ import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
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.crosssigning.isVerified import im.vector.matrix.android.internal.crypto.crosssigning.isVerified
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
import im.vector.matrix.rx.rx import im.vector.matrix.rx.rx
import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.extensions.exhaustive
import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.platform.VectorViewModel
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted private val initialState: CrossSigningSettingsViewState, class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted private val initialState: CrossSigningSettingsViewState,
private val session: Session) private val session: Session)
: VectorViewModel<CrossSigningSettingsViewState, CrossSigningSettingsAction, CrossSigningSettingsViewEvents>(initialState) { : VectorViewModel<CrossSigningSettingsViewState, CrossSigningSettingsAction, CrossSigningSettingsViewEvents>(initialState) {
init { init {
session.rx().liveCrossSigningInfo(session.myUserId) Observable.combineLatest<List<DeviceInfo>, Optional<MXCrossSigningInfo>, Pair<List<DeviceInfo>, Optional<MXCrossSigningInfo>>>(
.execute { session.rx().liveMyDeviceInfo(),
val crossSigningKeys = it.invoke()?.getOrNull() session.rx().liveCrossSigningInfo(session.myUserId),
BiFunction { myDeviceInfo, mxCrossSigningInfo ->
(myDeviceInfo to mxCrossSigningInfo)
}
)
.execute { data ->
val crossSigningKeys = data.invoke()?.second?.getOrNull()
val xSigningIsEnableInAccount = crossSigningKeys != null val xSigningIsEnableInAccount = crossSigningKeys != null
val xSigningKeysAreTrusted = session.cryptoService().crossSigningService().checkUserTrust(session.myUserId).isVerified() val xSigningKeysAreTrusted = session.cryptoService().crossSigningService().checkUserTrust(session.myUserId).isVerified()
val xSigningKeyCanSign = session.cryptoService().crossSigningService().canCrossSign() val xSigningKeyCanSign = session.cryptoService().crossSigningService().canCrossSign()
val hasSeveralDevices = data.invoke()?.first?.size ?: 0 > 1
copy( copy(
crossSigningInfo = crossSigningKeys, crossSigningInfo = crossSigningKeys,
xSigningIsEnableInAccount = xSigningIsEnableInAccount, xSigningIsEnableInAccount = xSigningIsEnableInAccount,
xSigningKeysAreTrusted = xSigningKeysAreTrusted, xSigningKeysAreTrusted = xSigningKeysAreTrusted,
xSigningKeyCanSign = xSigningKeyCanSign xSigningKeyCanSign = xSigningKeyCanSign,
deviceHasToBeVerified = hasSeveralDevices && (xSigningIsEnableInAccount || xSigningKeysAreTrusted),
recoveryHasToBeSetUp = !session.sharedSecretStorageService.isRecoverySetup()
) )
} }
} }

View File

@ -23,5 +23,8 @@ data class CrossSigningSettingsViewState(
val crossSigningInfo: MXCrossSigningInfo? = null, val crossSigningInfo: MXCrossSigningInfo? = null,
val xSigningIsEnableInAccount: Boolean = false, val xSigningIsEnableInAccount: Boolean = false,
val xSigningKeysAreTrusted: Boolean = false, val xSigningKeysAreTrusted: Boolean = false,
val xSigningKeyCanSign: Boolean = true val xSigningKeyCanSign: Boolean = true,
val deviceHasToBeVerified: Boolean = false,
val recoveryHasToBeSetUp: Boolean = false
) : MvRxState ) : MvRxState