Setup cross signing after initial sync if not yet done

Use grace period if available, if not fail silently
This commit is contained in:
Valere 2021-02-02 09:02:10 +01:00
parent 6c9b16088f
commit 0bc203e0d5

View file

@ -29,12 +29,12 @@ import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.login.ReAuthHelper import im.vector.app.features.login.ReAuthHelper
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.pushrules.RuleIds import org.matrix.android.sdk.api.pushrules.RuleIds
import org.matrix.android.sdk.api.session.InitialSyncProgressService import org.matrix.android.sdk.api.session.InitialSyncProgressService
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
@ -46,6 +46,7 @@ import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
import org.matrix.android.sdk.internal.crypto.model.rest.UIABaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.UIABaseAuth
import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth
import org.matrix.android.sdk.internal.util.awaitCallback
import org.matrix.android.sdk.rx.asObservable import org.matrix.android.sdk.rx.asObservable
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
import timber.log.Timber import timber.log.Timber
@ -81,7 +82,6 @@ class HomeActivityViewModel @AssistedInject constructor(
init { init {
cleanupFiles() cleanupFiles()
observeInitialSync() observeInitialSync()
mayBeInitializeCrossSigning()
checkSessionPushIsOn() checkSessionPushIsOn()
observeCrossSigningReset() observeCrossSigningReset()
} }
@ -132,7 +132,7 @@ class HomeActivityViewModel @AssistedInject constructor(
is InitialSyncProgressService.Status.Idle -> { is InitialSyncProgressService.Status.Idle -> {
if (checkBootstrap) { if (checkBootstrap) {
checkBootstrap = false checkBootstrap = false
maybeBootstrapCrossSigning() maybeBootstrapCrossSigningAfterInitialSync()
} }
} }
} }
@ -146,37 +146,6 @@ class HomeActivityViewModel @AssistedInject constructor(
.disposeOnClear() .disposeOnClear()
} }
private fun mayBeInitializeCrossSigning() {
if (args.accountCreation) {
val password = reAuthHelper.data ?: return Unit.also {
Timber.w("No password to init cross signing")
}
val session = activeSessionHolder.getSafeActiveSession() ?: return Unit.also {
Timber.w("No session to init cross signing")
}
// We do not use the viewModel context because we do not want to cancel this action
Timber.d("Initialize cross signing")
session.cryptoService().crossSigningService().initializeCrossSigning(
object : UserInteractiveAuthInterceptor {
override fun performStage(flow: RegistrationFlowResponse, errorCode: String?, promise: Continuation<UIABaseAuth>) {
if (flow.nextUncompletedStage() == LoginFlowTypes.PASSWORD) {
promise.resume(
UserPasswordAuth(
session = flow.session,
user = session.myUserId,
password = password
)
)
} else promise.resumeWith(Result.failure(UnsupportedOperationException()))
}
},
callback = NoOpMatrixCallback()
)
}
}
/** /**
* After migration from riot to element some users reported that their * After migration from riot to element some users reported that their
* push setting for the session was set to off * push setting for the session was set to off
@ -212,62 +181,66 @@ class HomeActivityViewModel @AssistedInject constructor(
} }
} }
private fun maybeBootstrapCrossSigning() { private fun maybeBootstrapCrossSigningAfterInitialSync() {
// In case of account creation, it is already done before // We do not use the viewModel context because we do not want to tie this action to activity view model
if (args.accountCreation) return GlobalScope.launch(Dispatchers.IO) {
val session = activeSessionHolder.getSafeActiveSession() ?: return@launch
val session = activeSessionHolder.getSafeActiveSession() ?: return tryOrNull("## MaybeBootstrapCrossSigning: Failed to download keys") {
awaitCallback<MXUsersDevicesMap<CryptoDeviceInfo>> {
session.cryptoService().downloadKeys(listOf(session.myUserId), true, it)
}
}
// Ensure keys of the user are downloaded // From there we are up to date with server
session.cryptoService().downloadKeys(listOf(session.myUserId), true, object : MatrixCallback<MXUsersDevicesMap<CryptoDeviceInfo>> { // Is there already cross signing keys here?
override fun onSuccess(data: MXUsersDevicesMap<CryptoDeviceInfo>) { val mxCrossSigningInfo = session.cryptoService().crossSigningService().getMyCrossSigningKeys()
// Is there already cross signing keys here? if (mxCrossSigningInfo != null) {
val mxCrossSigningInfo = session.cryptoService().crossSigningService().getMyCrossSigningKeys() // Cross-signing is already set up for this user, is it trusted?
if (mxCrossSigningInfo != null) { if (!mxCrossSigningInfo.isTrusted()) {
// Cross-signing is already set up for this user, is it trusted? // New session
if (!mxCrossSigningInfo.isTrusted()) { _viewEvents.post(
// New session HomeActivityViewEvents.OnNewSession(
_viewEvents.post( session.getUser(session.myUserId)?.toMatrixItem(),
HomeActivityViewEvents.OnNewSession( // If it's an old unverified, we should send requests
session.getUser(session.myUserId)?.toMatrixItem(), // instead of waiting for an incoming one
// If it's an old unverified, we should send requests reAuthHelper.data != null
// instead of waiting for an incoming one )
reAuthHelper.data != null )
) }
) } else {
} // Try to initialize cross signing in background if possible
} else { Timber.d("Initialize cross signing...")
// Initialize cross-signing awaitCallback<Unit> {
val password = reAuthHelper.data try {
if (password == null) {
// Check this is not an SSO account
if (session.getHomeServerCapabilities().canChangePassword) {
// Ask password to the user: Upgrade security
_viewEvents.post(HomeActivityViewEvents.AskPasswordToInitCrossSigning(session.getUser(session.myUserId)?.toMatrixItem()))
}
// Else (SSO) just ignore for the moment
} else {
// We do not use the viewModel context because we do not want to cancel this action
Timber.d("Initialize cross signing")
session.cryptoService().crossSigningService().initializeCrossSigning( session.cryptoService().crossSigningService().initializeCrossSigning(
object : UserInteractiveAuthInterceptor { object : UserInteractiveAuthInterceptor {
override fun performStage(flow: RegistrationFlowResponse, errorCode: String?, promise: Continuation<UIABaseAuth>) { override fun performStage(flow: RegistrationFlowResponse, errorCode: String?, promise: Continuation<UIABaseAuth>) {
if (flow.nextUncompletedStage() == LoginFlowTypes.PASSWORD) { // We missed server grace period or it's not setup, see if we remember locally password
UserPasswordAuth( if (flow.nextUncompletedStage() == LoginFlowTypes.PASSWORD
session = flow.session, && errorCode == null
user = session.myUserId, && reAuthHelper.data != null) {
password = password promise.resume(
UserPasswordAuth(
session = flow.session,
user = session.myUserId,
password = reAuthHelper.data
)
) )
} else null } else {
promise.resumeWith(Result.failure(Exception("Cannot silently initialize cross signing, UIA missing")))
}
} }
}, },
callback = NoOpMatrixCallback() callback = it
) )
Timber.d("Initialize cross signing SUCCESS")
} catch (failure: Throwable) {
Timber.e(failure, "Failed to initialize cross signing")
} }
} }
} }
}) }
} }
override fun handle(action: HomeActivityViewActions) { override fun handle(action: HomeActivityViewActions) {