mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 13:38:49 +03:00
Setup cross signing after initial sync if not yet done
Use grace period if available, if not fail silently
This commit is contained in:
parent
6c9b16088f
commit
0bc203e0d5
1 changed files with 52 additions and 79 deletions
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue