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.core.platform.OnBackPressed
import im.vector.riotx.core.platform.VectorBaseFragment
import io.reactivex.android.schedulers.AndroidSchedulers
import javax.net.ssl.HttpsURLConnection
/**
@ -60,6 +61,7 @@ abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed {
loginViewModel.viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
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.LoginTermsFragmentArgument
import im.vector.riotx.features.login.terms.toLocalizedLoginTerms
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.activity_login.*
import javax.inject.Inject
@ -112,6 +113,7 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
loginViewModel.viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
handleLoginViewEvents(it)
}

View File

@ -18,17 +18,21 @@ package im.vector.riotx.features.signout.soft
import android.content.Context
import android.content.Intent
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.viewModel
import im.vector.matrix.android.api.failure.GlobalError
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.R
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.features.MainActivity
import im.vector.riotx.features.MainActivityArgs
import im.vector.riotx.features.login.LoginActivity
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.activity_login.*
import timber.log.Timber
import javax.inject.Inject
@ -43,6 +47,7 @@ class SoftLogoutActivity : LoginActivity() {
@Inject lateinit var softLogoutViewModelFactory: SoftLogoutViewModel.Factory
@Inject lateinit var session: Session
@Inject lateinit var errorFormatter: ErrorFormatter
override fun injectWith(injector: ScreenComponent) {
super.injectWith(injector)
@ -56,6 +61,40 @@ class SoftLogoutActivity : LoginActivity() {
.subscribe(this) {
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() {

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

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_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_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>