mirror of
https://github.com/element-hq/element-android
synced 2024-11-23 18:05:36 +03:00
promoting the accept certificate to an explict ViewEvent
- allows a retryAction to be provided to the event to avoid mutatble state within the view model along with providing a clear path of execution
This commit is contained in:
parent
0dcab56e34
commit
457f7fffee
6 changed files with 36 additions and 25 deletions
|
@ -93,6 +93,8 @@ fun Throwable.isMissingEmailVerification() = this is Failure.ServerError &&
|
|||
error.code == MatrixError.M_UNAUTHORIZED &&
|
||||
error.message == "Unable to get validated threepid"
|
||||
|
||||
fun Throwable.isUnrecognisedCertificate() = this is Failure.UnrecognizedCertificateFailure
|
||||
|
||||
/**
|
||||
* Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible
|
||||
*/
|
||||
|
|
|
@ -82,7 +82,7 @@ sealed interface OnboardingAction : VectorViewModelAction {
|
|||
|
||||
data class PostViewEvent(val viewEvent: OnboardingViewEvents) : OnboardingAction
|
||||
|
||||
data class UserAcceptCertificate(val fingerprint: Fingerprint) : OnboardingAction
|
||||
data class UserAcceptCertificate(val fingerprint: Fingerprint, val retryAction: OnboardingAction) : OnboardingAction
|
||||
|
||||
object PersonalizeProfile : OnboardingAction
|
||||
data class UpdateDisplayName(val displayName: String) : OnboardingAction
|
||||
|
|
|
@ -21,6 +21,7 @@ import im.vector.app.core.platform.VectorViewEvents
|
|||
import im.vector.app.features.login.ServerType
|
||||
import im.vector.app.features.login.SignMode
|
||||
import org.matrix.android.sdk.api.auth.registration.Stage
|
||||
import org.matrix.android.sdk.api.failure.Failure as SdkFailure
|
||||
|
||||
/**
|
||||
* Transient events for Login.
|
||||
|
@ -29,6 +30,7 @@ sealed class OnboardingViewEvents : VectorViewEvents {
|
|||
data class Loading(val message: CharSequence? = null) : OnboardingViewEvents()
|
||||
data class Failure(val throwable: Throwable) : OnboardingViewEvents()
|
||||
data class DeeplinkAuthenticationFailure(val retryAction: OnboardingAction) : OnboardingViewEvents()
|
||||
data class UnrecognisedCertificateFailure(val retryAction: OnboardingAction, val cause: SdkFailure.UnrecognizedCertificateFailure) : OnboardingViewEvents()
|
||||
|
||||
object DisplayRegistrationFallback : OnboardingViewEvents()
|
||||
data class DisplayRegistrationStage(val stage: Stage) : OnboardingViewEvents()
|
||||
|
|
|
@ -60,7 +60,9 @@ import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
|||
import org.matrix.android.sdk.api.auth.login.LoginWizard
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationAvailability
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationWizard
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.api.failure.isHomeserverUnavailable
|
||||
import org.matrix.android.sdk.api.failure.isUnrecognisedCertificate
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.util.BuildVersionSdkIntProvider
|
||||
import timber.log.Timber
|
||||
|
@ -113,8 +115,6 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
// Store the last action, to redo it after user has trusted the untrusted certificate
|
||||
private var lastAction: OnboardingAction? = null
|
||||
private var currentHomeServerConnectionConfig: HomeServerConnectionConfig? = null
|
||||
|
||||
private val matrixOrgUrl = stringProvider.getString(R.string.matrix_org_server_url).ensureTrailingSlash()
|
||||
|
@ -146,9 +146,9 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||
is OnboardingAction.UpdateServerType -> handleUpdateServerType(action)
|
||||
is OnboardingAction.UpdateSignMode -> handleUpdateSignMode(action)
|
||||
is OnboardingAction.InitWith -> handleInitWith(action)
|
||||
is OnboardingAction.HomeServerChange -> withAction(action) { handleHomeserverChange(action) }
|
||||
is OnboardingAction.HomeServerChange -> handleHomeserverChange(action)
|
||||
is OnboardingAction.UserNameEnteredAction -> handleUserNameEntered(action)
|
||||
is AuthenticateAction -> withAction(action) { handleAuthenticateAction(action) }
|
||||
is AuthenticateAction -> handleAuthenticateAction(action)
|
||||
is OnboardingAction.LoginWithToken -> handleLoginWithToken(action)
|
||||
is OnboardingAction.WebLoginSuccess -> handleWebLoginSuccess(action)
|
||||
is OnboardingAction.ResetPassword -> handleResetPassword(action)
|
||||
|
@ -221,11 +221,6 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun withAction(action: OnboardingAction, block: (OnboardingAction) -> Unit) {
|
||||
lastAction = action
|
||||
block(action)
|
||||
}
|
||||
|
||||
private fun handleAuthenticateAction(action: AuthenticateAction) {
|
||||
when (action) {
|
||||
is AuthenticateAction.Register -> handleRegisterWith(action.username, action.password, action.initialDeviceName)
|
||||
|
@ -276,15 +271,15 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||
private fun handleUserAcceptCertificate(action: OnboardingAction.UserAcceptCertificate) {
|
||||
// It happens when we get the login flow, or during direct authentication.
|
||||
// So alter the homeserver config and retrieve again the login flow
|
||||
when (val finalLastAction = lastAction) {
|
||||
is OnboardingAction.HomeServerChange.SelectHomeServer -> {
|
||||
when (action.retryAction) {
|
||||
is OnboardingAction.HomeServerChange -> {
|
||||
currentHomeServerConnectionConfig
|
||||
?.let { it.copy(allowedFingerprints = it.allowedFingerprints + action.fingerprint) }
|
||||
?.let { startAuthenticationFlow(finalLastAction, it, serverTypeOverride = null) }
|
||||
?.let { startAuthenticationFlow(action.retryAction, it, serverTypeOverride = null) }
|
||||
}
|
||||
is AuthenticateAction.LoginDirect ->
|
||||
handleDirectLogin(
|
||||
finalLastAction,
|
||||
action.retryAction,
|
||||
HomeServerConnectionConfig.Builder()
|
||||
// Will be replaced by the task
|
||||
.withHomeServerUri("https://dummy.org")
|
||||
|
@ -589,9 +584,19 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||
currentJob = viewModelScope.launch {
|
||||
directLoginUseCase.execute(action, homeServerConnectionConfig).fold(
|
||||
onSuccess = { onSessionCreated(it, authenticationDescription = AuthenticationDescription.Login) },
|
||||
onFailure = {
|
||||
onFailure = { error ->
|
||||
setState { copy(isLoading = false) }
|
||||
_viewEvents.post(OnboardingViewEvents.Failure(it))
|
||||
when {
|
||||
error.isUnrecognisedCertificate() -> {
|
||||
_viewEvents.post(
|
||||
OnboardingViewEvents.UnrecognisedCertificateFailure(
|
||||
retryAction = action,
|
||||
cause = error as Failure.UnrecognizedCertificateFailure
|
||||
)
|
||||
)
|
||||
}
|
||||
else -> _viewEvents.post(OnboardingViewEvents.Failure(error))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -723,9 +728,10 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||
retryAction = (trigger as OnboardingAction.HomeServerChange.SelectHomeServer).resetToDefaultUrl()
|
||||
)
|
||||
)
|
||||
else -> _viewEvents.post(
|
||||
OnboardingViewEvents.Failure(error)
|
||||
)
|
||||
error.isUnrecognisedCertificate() -> {
|
||||
_viewEvents.post(OnboardingViewEvents.UnrecognisedCertificateFailure(trigger, error as Failure.UnrecognizedCertificateFailure))
|
||||
}
|
||||
else -> _viewEvents.post(OnboardingViewEvents.Failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ import im.vector.app.features.onboarding.OnboardingViewEvents
|
|||
import im.vector.app.features.onboarding.OnboardingViewModel
|
||||
import im.vector.app.features.onboarding.OnboardingViewState
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
|
||||
/**
|
||||
* Parent Fragment for all the login/registration screens.
|
||||
|
@ -68,6 +67,7 @@ abstract class AbstractFtueAuthFragment<VB : ViewBinding> : VectorBaseFragment<V
|
|||
private fun handleOnboardingViewEvents(viewEvents: OnboardingViewEvents) {
|
||||
when (viewEvents) {
|
||||
is OnboardingViewEvents.Failure -> showFailure(viewEvents.throwable)
|
||||
is OnboardingViewEvents.UnrecognisedCertificateFailure -> showUnrecognizedCertificateFailure(viewEvents)
|
||||
else ->
|
||||
// This is handled by the Activity
|
||||
Unit
|
||||
|
@ -84,20 +84,20 @@ abstract class AbstractFtueAuthFragment<VB : ViewBinding> : VectorBaseFragment<V
|
|||
is CancellationException ->
|
||||
/* Ignore this error, user has cancelled the action */
|
||||
Unit
|
||||
is Failure.UnrecognizedCertificateFailure -> showUnrecognizedCertificateFailure(throwable)
|
||||
else -> onError(throwable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUnrecognizedCertificateFailure(failure: Failure.UnrecognizedCertificateFailure) {
|
||||
private fun showUnrecognizedCertificateFailure(event: OnboardingViewEvents.UnrecognisedCertificateFailure) {
|
||||
// Ask the user to accept the certificate
|
||||
val cause = event.cause
|
||||
unrecognizedCertificateDialog.show(requireActivity(),
|
||||
failure.fingerprint,
|
||||
failure.url,
|
||||
cause.fingerprint,
|
||||
cause.url,
|
||||
object : UnrecognizedCertificateDialog.Callback {
|
||||
override fun onAccept() {
|
||||
// User accept the certificate
|
||||
viewModel.handle(OnboardingAction.UserAcceptCertificate(failure.fingerprint))
|
||||
viewModel.handle(OnboardingAction.UserAcceptCertificate(cause.fingerprint, event.retryAction))
|
||||
}
|
||||
|
||||
override fun onIgnore() {
|
||||
|
|
|
@ -202,6 +202,7 @@ class FtueAuthVariant(
|
|||
openMsisdnConfirmation(viewEvents.msisdn)
|
||||
}
|
||||
is OnboardingViewEvents.Failure,
|
||||
is OnboardingViewEvents.UnrecognisedCertificateFailure,
|
||||
is OnboardingViewEvents.Loading ->
|
||||
// This is handled by the Fragments
|
||||
Unit
|
||||
|
|
Loading…
Reference in a new issue