SoftLogout: handle the case where user sign in with SSO on another account

This commit is contained in:
Benoit Marty 2019-12-13 11:58:02 +01:00
parent 050519e998
commit 1de85daad9
6 changed files with 107 additions and 20 deletions

View File

@ -29,6 +29,7 @@ import im.vector.matrix.android.api.failure.MatrixError
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.platform.OnBackPressed import im.vector.riotx.core.platform.OnBackPressed
import im.vector.riotx.core.platform.VectorBaseFragment import im.vector.riotx.core.platform.VectorBaseFragment
import io.reactivex.android.schedulers.AndroidSchedulers
import javax.net.ssl.HttpsURLConnection import javax.net.ssl.HttpsURLConnection
/** /**
@ -60,6 +61,7 @@ abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed {
loginViewModel.viewEvents loginViewModel.viewEvents
.observe() .observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { .subscribe {
handleLoginViewEvents(it) handleLoginViewEvents(it)
} }

View File

@ -44,6 +44,7 @@ import im.vector.riotx.features.home.HomeActivity
import im.vector.riotx.features.login.terms.LoginTermsFragment import im.vector.riotx.features.login.terms.LoginTermsFragment
import im.vector.riotx.features.login.terms.LoginTermsFragmentArgument import im.vector.riotx.features.login.terms.LoginTermsFragmentArgument
import im.vector.riotx.features.login.terms.toLocalizedLoginTerms import im.vector.riotx.features.login.terms.toLocalizedLoginTerms
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.activity_login.* import kotlinx.android.synthetic.main.activity_login.*
import javax.inject.Inject import javax.inject.Inject
@ -112,6 +113,7 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
loginViewModel.viewEvents loginViewModel.viewEvents
.observe() .observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { .subscribe {
handleLoginViewEvents(it) handleLoginViewEvents(it)
} }

View File

@ -18,17 +18,21 @@ package im.vector.riotx.features.signout.soft
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager
import com.airbnb.mvrx.Success import com.airbnb.mvrx.Success
import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.viewModel
import im.vector.matrix.android.api.failure.GlobalError import im.vector.matrix.android.api.failure.GlobalError
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.error.ErrorFormatter
import im.vector.riotx.core.extensions.replaceFragment import im.vector.riotx.core.extensions.replaceFragment
import im.vector.riotx.features.MainActivity import im.vector.riotx.features.MainActivity
import im.vector.riotx.features.MainActivityArgs import im.vector.riotx.features.MainActivityArgs
import im.vector.riotx.features.login.LoginActivity import im.vector.riotx.features.login.LoginActivity
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.activity_login.* import kotlinx.android.synthetic.main.activity_login.*
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -43,6 +47,7 @@ class SoftLogoutActivity : LoginActivity() {
@Inject lateinit var softLogoutViewModelFactory: SoftLogoutViewModel.Factory @Inject lateinit var softLogoutViewModelFactory: SoftLogoutViewModel.Factory
@Inject lateinit var session: Session @Inject lateinit var session: Session
@Inject lateinit var errorFormatter: ErrorFormatter
override fun injectWith(injector: ScreenComponent) { override fun injectWith(injector: ScreenComponent) {
super.injectWith(injector) super.injectWith(injector)
@ -56,6 +61,40 @@ class SoftLogoutActivity : LoginActivity() {
.subscribe(this) { .subscribe(this) {
updateWithState(it) updateWithState(it)
} }
softLogoutViewModel.viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
handleSoftLogoutViewEvents(it)
}
.disposeOnDestroy()
}
private fun handleSoftLogoutViewEvents(softLogoutViewEvents: SoftLogoutViewEvents) {
when (softLogoutViewEvents) {
is SoftLogoutViewEvents.Error ->
showError(errorFormatter.toHumanReadable(softLogoutViewEvents.throwable))
is SoftLogoutViewEvents.ErrorNotSameUser -> {
// Pop the backstack
supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
// And inform the user
showError(getString(
R.string.soft_logout_sso_not_same_user_error,
softLogoutViewEvents.currentUserId,
softLogoutViewEvents.newUserId)
)
}
}
}
private fun showError(message: String) {
AlertDialog.Builder(this)
.setTitle(R.string.dialog_title_error)
.setMessage(message)
.setPositiveButton(R.string.ok, null)
.show()
} }
override fun addFirstFragment() { override fun addFirstFragment() {

View File

@ -0,0 +1,26 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package im.vector.riotx.features.signout.soft
/**
* Transient events for SoftLogout
*/
sealed class SoftLogoutViewEvents {
data class ErrorNotSameUser(val currentUserId: String, val newUserId: String) : SoftLogoutViewEvents()
data class Error(val throwable: Throwable) : SoftLogoutViewEvents()
}

View File

@ -28,7 +28,10 @@ import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.extensions.hasUnsavedKeys import im.vector.riotx.core.extensions.hasUnsavedKeys
import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.utils.DataSource
import im.vector.riotx.core.utils.PublishDataSource
import im.vector.riotx.features.login.LoginMode import im.vector.riotx.features.login.LoginMode
import timber.log.Timber
/** /**
* TODO Test push: disable the pushers? * TODO Test push: disable the pushers?
@ -68,6 +71,9 @@ class SoftLogoutViewModel @AssistedInject constructor(
private var currentTask: Cancelable? = null private var currentTask: Cancelable? = null
private val _viewEvents = PublishDataSource<SoftLogoutViewEvents>()
val viewEvents: DataSource<SoftLogoutViewEvents> = _viewEvents
init { init {
// Get the supported login flow // Get the supported login flow
getSupportedLoginFlow() getSupportedLoginFlow()
@ -88,7 +94,6 @@ class SoftLogoutViewModel @AssistedInject constructor(
currentTask = authenticationService.getLoginFlow(homeServerConnectionConfig, object : MatrixCallback<LoginFlowResult> { currentTask = authenticationService.getLoginFlow(homeServerConnectionConfig, object : MatrixCallback<LoginFlowResult> {
override fun onFailure(failure: Throwable) { override fun onFailure(failure: Throwable) {
// TODO _viewEvents.post(LoginViewEvents.Error(failure))
setState { setState {
copy( copy(
asyncHomeServerLoginFlowRequest = Fail(failure) asyncHomeServerLoginFlowRequest = Fail(failure)
@ -167,26 +172,38 @@ class SoftLogoutViewModel @AssistedInject constructor(
} }
private fun handleWebLoginSuccess(action: SoftLogoutAction.WebLoginSuccess) { private fun handleWebLoginSuccess(action: SoftLogoutAction.WebLoginSuccess) {
setState { // User may have been connected with SSO with another userId
copy( // We have to check this
asyncLoginAction = Loading() withState { softLogoutViewState ->
) if (softLogoutViewState.userId != action.credentials.userId) {
} Timber.w("User login again with SSO, but using another account")
currentTask = session.updateCredentials(action.credentials, _viewEvents.post(SoftLogoutViewEvents.ErrorNotSameUser(
object : MatrixCallback<Unit> { softLogoutViewState.userId,
override fun onFailure(failure: Throwable) { action.credentials.userId))
setState { } else {
copy( setState {
asyncLoginAction = Fail(failure) copy(
) asyncLoginAction = Loading()
} )
}
override fun onSuccess(data: Unit) {
onSessionRestored()
}
} }
) currentTask = session.updateCredentials(action.credentials,
object : MatrixCallback<Unit> {
override fun onFailure(failure: Throwable) {
_viewEvents.post(SoftLogoutViewEvents.Error(failure))
setState {
copy(
asyncLoginAction = Uninitialized
)
}
}
override fun onSuccess(data: Unit) {
onSessionRestored()
}
}
)
}
}
} }
private fun handleSignInAgain(action: SoftLogoutAction.SignInAgain) { private fun handleSignInAgain(action: SoftLogoutAction.SignInAgain) {

View File

@ -159,5 +159,6 @@
<string name="soft_logout_clear_data_dialog_content">Clear all data currently stored on this device?\nSign in again to access your account data and messages.</string> <string name="soft_logout_clear_data_dialog_content">Clear all data currently stored on this device?\nSign in again to access your account data and messages.</string>
<string name="soft_logout_clear_data_dialog_e2e_warning_content">Youll lose access to secure messages unless you sign in to recover your encryption keys.</string> <string name="soft_logout_clear_data_dialog_e2e_warning_content">Youll lose access to secure messages unless you sign in to recover your encryption keys.</string>
<string name="soft_logout_clear_data_dialog_submit">Clear data</string> <string name="soft_logout_clear_data_dialog_submit">Clear data</string>
<string name="soft_logout_sso_not_same_user_error">The current session is for user %1$s and you provide credentials for user %2$s. This is not supported by RiotX.\nPlease first clear data, then sign in again on another account.</string>
</resources> </resources>