SSO UIA for add 3pid + refactoring move RegistrationFlow to api
This commit is contained in:
parent
2a3962265b
commit
0211197c47
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.matrix.android.sdk.api.auth
|
||||
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.UIABaseAuth
|
||||
import kotlin.coroutines.Continuation
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.auth.registration
|
||||
package org.matrix.android.sdk.api.auth.registration
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
@ -109,3 +109,9 @@ fun RegistrationFlowResponse.toFlowResult(): FlowResult {
|
|||
|
||||
return FlowResult(missingStage, completedStage)
|
||||
}
|
||||
|
||||
|
||||
fun RegistrationFlowResponse.nextUncompletedStage(flowIndex: Int = 0): String? {
|
||||
val completed = completedStages ?: emptyList()
|
||||
return flows?.getOrNull(flowIndex)?.stages?.firstOrNull { completed.contains(it).not() }
|
||||
}
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
package org.matrix.android.sdk.api.failure
|
||||
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import java.io.IOException
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
|
@ -59,7 +59,7 @@ fun Throwable.toRegistrationFlowResponse(): RegistrationFlowResponse? {
|
|||
.adapter(RegistrationFlowResponse::class.java)
|
||||
.fromJson(this.errorBody)
|
||||
}
|
||||
} else if (this is Failure.ServerError && this.error.code == MatrixError.M_FORBIDDEN) {
|
||||
} else if (this is Failure.ServerError && this.httpCode == 401 && this.error.code == MatrixError.M_FORBIDDEN) {
|
||||
// This happens when the submission for this stage was bad (like bad password)
|
||||
if (this.error.session != null && this.error.flows != null) {
|
||||
RegistrationFlowResponse(
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
package org.matrix.android.sdk.api.failure
|
||||
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.internal.network.ssl.Fingerprint
|
||||
import java.io.IOException
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.matrix.android.sdk.api.session.profile
|
|||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
|
@ -107,8 +108,7 @@ interface ProfileService {
|
|||
* Finalize adding a 3Pids. Call this method once the user has validated that he owns the ThreePid
|
||||
*/
|
||||
fun finalizeAddingThreePid(threePid: ThreePid,
|
||||
uiaSession: String?,
|
||||
accountPassword: String?,
|
||||
userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor,
|
||||
matrixCallback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
|||
import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationResult
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationWizard
|
||||
import org.matrix.android.sdk.api.auth.registration.toFlowResult
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.api.failure.Failure.RegistrationFlowError
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
|
|
|
@ -23,11 +23,6 @@ import org.matrix.android.sdk.internal.crypto.model.rest.UIABaseAuth
|
|||
import timber.log.Timber
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
fun RegistrationFlowResponse.nextUncompletedStage(flowIndex: Int = 0): String? {
|
||||
val completed = completedStages ?: emptyList()
|
||||
return flows?.getOrNull(flowIndex)?.stages?.firstOrNull { completed.contains(it).not() }
|
||||
}
|
||||
|
||||
suspend fun handleUIA(failure: Throwable, interceptor: UserInteractiveAuthInterceptor, retryBlock: suspend (UIABaseAuth) -> Unit): Boolean {
|
||||
Timber.d("## UIA: check error ${failure.message}")
|
||||
val flowResponse = failure.toRegistrationFlowResponse()
|
||||
|
|
|
@ -22,6 +22,7 @@ import androidx.lifecycle.LiveData
|
|||
import com.zhuinden.monarchy.Monarchy
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.api.session.profile.ProfileService
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
|
@ -170,14 +171,12 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
|
|||
}
|
||||
|
||||
override fun finalizeAddingThreePid(threePid: ThreePid,
|
||||
uiaSession: String?,
|
||||
accountPassword: String?,
|
||||
userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor,
|
||||
matrixCallback: MatrixCallback<Unit>): Cancelable {
|
||||
return finalizeAddingThreePidTask
|
||||
.configureWith(FinalizeAddingThreePidTask.Params(
|
||||
threePid = threePid,
|
||||
session = uiaSession,
|
||||
accountPassword = accountPassword,
|
||||
userInteractiveAuthInterceptor = userInteractiveAuthInterceptor,
|
||||
userWantsToCancel = false
|
||||
)) {
|
||||
callback = alsoRefresh(matrixCallback)
|
||||
|
@ -189,8 +188,7 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
|
|||
return finalizeAddingThreePidTask
|
||||
.configureWith(FinalizeAddingThreePidTask.Params(
|
||||
threePid = threePid,
|
||||
session = null,
|
||||
accountPassword = null,
|
||||
userInteractiveAuthInterceptor = null,
|
||||
userWantsToCancel = true
|
||||
)) {
|
||||
callback = alsoRefresh(matrixCallback)
|
||||
|
|
|
@ -17,7 +17,6 @@ package org.matrix.android.sdk.internal.session.profile
|
|||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class FinalizeAddThreePidBody(
|
||||
|
@ -37,5 +36,5 @@ internal data class FinalizeAddThreePidBody(
|
|||
* Additional authentication information for the user-interactive authentication API.
|
||||
*/
|
||||
@Json(name = "auth")
|
||||
val auth: UserPasswordAuth?
|
||||
val auth: Map<String, *>? = null
|
||||
)
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
package org.matrix.android.sdk.internal.session.profile
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth
|
||||
import org.matrix.android.sdk.internal.auth.registration.handleUIA
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.UIABaseAuth
|
||||
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity
|
||||
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
|
@ -29,13 +31,14 @@ import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
|||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import org.matrix.android.sdk.internal.util.awaitTransaction
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal abstract class FinalizeAddingThreePidTask : Task<FinalizeAddingThreePidTask.Params, Unit> {
|
||||
data class Params(
|
||||
val threePid: ThreePid,
|
||||
val session: String?,
|
||||
val accountPassword: String?,
|
||||
val userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor?,
|
||||
val userAuthParam: UIABaseAuth? = null,
|
||||
val userWantsToCancel: Boolean
|
||||
)
|
||||
}
|
||||
|
@ -62,22 +65,23 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor(
|
|||
val body = FinalizeAddThreePidBody(
|
||||
clientSecret = pendingThreePids.clientSecret,
|
||||
sid = pendingThreePids.sid,
|
||||
auth = if (params.session != null && params.accountPassword != null) {
|
||||
UserPasswordAuth(
|
||||
session = params.session,
|
||||
user = userId,
|
||||
password = params.accountPassword
|
||||
)
|
||||
} else null
|
||||
auth = params.userAuthParam?.asMap()
|
||||
)
|
||||
apiCall = profileAPI.finalizeAddThreePid(body)
|
||||
}
|
||||
} catch (throwable: Throwable) {
|
||||
if (params.userInteractiveAuthInterceptor == null
|
||||
|| !handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth ->
|
||||
execute(params.copy(userAuthParam = auth))
|
||||
}
|
||||
) {
|
||||
Timber.d("## UIA: propagate failure")
|
||||
throw throwable.toRegistrationFlowResponse()
|
||||
?.let { Failure.RegistrationFlowError(it) }
|
||||
?: throwable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanupDatabase(params)
|
||||
}
|
||||
|
|
|
@ -105,11 +105,13 @@ class DefaultErrorFormatter @Inject constructor(
|
|||
HttpURLConnection.HTTP_NOT_FOUND ->
|
||||
// homeserver not found
|
||||
stringProvider.getString(R.string.login_error_no_homeserver_found)
|
||||
HttpURLConnection.HTTP_UNAUTHORIZED ->
|
||||
// uia errors?
|
||||
stringProvider.getString(R.string.error_unauthorized)
|
||||
else ->
|
||||
throwable.localizedMessage
|
||||
}
|
||||
}
|
||||
is SsoFlowNotSupportedYet -> stringProvider.getString(R.string.error_sso_flow_not_supported_yet)
|
||||
else -> throwable.localizedMessage
|
||||
}
|
||||
?: stringProvider.getString(R.string.unknown_error)
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 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.app.core.error
|
||||
|
||||
class SsoFlowNotSupportedYet : Throwable()
|
|
@ -200,6 +200,7 @@ abstract class VectorBaseFragment<VB: ViewBinding> : BaseMvRxFragment(), HasScre
|
|||
}
|
||||
|
||||
protected fun showLoadingDialog(message: CharSequence? = null, cancelable: Boolean = false) {
|
||||
progress?.dismiss()
|
||||
progress = ProgressDialog(requireContext()).apply {
|
||||
setCancelable(cancelable)
|
||||
setMessage(message ?: getString(R.string.please_wait))
|
||||
|
|
|
@ -37,8 +37,8 @@ import im.vector.app.core.utils.openUrlInChromeCustomTab
|
|||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
|
@ -43,8 +43,8 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
|||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package im.vector.app.features.crypto.recover
|
||||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
|
||||
sealed class BootstrapViewEvents : VectorViewEvents {
|
||||
data class Dismiss(val success: Boolean) : BootstrapViewEvents()
|
||||
|
|
|
@ -40,8 +40,8 @@ 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.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
|
||||
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.rest.UIABaseAuth
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package im.vector.app.features.settings.account.deactivation
|
||||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
|
||||
/**
|
||||
* Transient events for deactivate account settings screen
|
||||
|
|
|
@ -30,7 +30,7 @@ import kotlinx.coroutines.launch
|
|||
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
||||
import org.matrix.android.sdk.api.failure.isInvalidUIAAuth
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.UIABaseAuth
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package im.vector.app.features.settings.crosssigning
|
||||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
|
||||
/**
|
||||
* Transient events for cross signing settings screen
|
||||
|
|
|
@ -37,8 +37,8 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
|||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth
|
||||
|
|
|
@ -19,7 +19,7 @@ package im.vector.app.features.settings.devices
|
|||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
|
||||
|
||||
|
|
|
@ -49,8 +49,8 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
|||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
||||
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
|
||||
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
||||
|
|
|
@ -25,6 +25,11 @@ sealed class ThreePidsSettingsAction : VectorViewModelAction {
|
|||
data class SubmitCode(val threePid: ThreePid.Msisdn, val code: String) : ThreePidsSettingsAction()
|
||||
data class ContinueThreePid(val threePid: ThreePid) : ThreePidsSettingsAction()
|
||||
data class CancelThreePid(val threePid: ThreePid) : ThreePidsSettingsAction()
|
||||
data class AccountPassword(val password: String) : ThreePidsSettingsAction()
|
||||
|
||||
// data class AccountPassword(val password: String) : ThreePidsSettingsAction()
|
||||
data class DeleteThreePid(val threePid: ThreePid) : ThreePidsSettingsAction()
|
||||
|
||||
object SsoAuthDone : ThreePidsSettingsAction()
|
||||
data class PasswordAuthDone(val password: String) : ThreePidsSettingsAction()
|
||||
object ReAuthCancelled : ThreePidsSettingsAction()
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.app.features.settings.threepids
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -26,7 +27,6 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.dialogs.PromptPasswordDialog
|
||||
import im.vector.app.core.dialogs.withColoredButton
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
|
@ -35,10 +35,12 @@ import im.vector.app.core.extensions.getFormattedValue
|
|||
import im.vector.app.core.extensions.hideKeyboard
|
||||
import im.vector.app.core.extensions.isEmail
|
||||
import im.vector.app.core.extensions.isMsisdn
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.OnBackPressed
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
||||
|
||||
import im.vector.app.features.auth.ReAuthActivity
|
||||
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -65,14 +67,41 @@ class ThreePidsSettingsFragment @Inject constructor(
|
|||
viewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is ThreePidsSettingsViewEvents.Failure -> displayErrorDialog(it.throwable)
|
||||
ThreePidsSettingsViewEvents.RequestPassword -> askUserPassword()
|
||||
is ThreePidsSettingsViewEvents.RequestReAuth -> askAuthentication(it)
|
||||
}.exhaustive
|
||||
}
|
||||
}
|
||||
|
||||
private fun askUserPassword() {
|
||||
PromptPasswordDialog().show(requireActivity()) { password ->
|
||||
viewModel.handle(ThreePidsSettingsAction.AccountPassword(password))
|
||||
// private fun askUserPassword() {
|
||||
// PromptPasswordDialog().show(requireActivity()) { password ->
|
||||
// viewModel.handle(ThreePidsSettingsAction.AccountPassword(password))
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun askAuthentication(event: ThreePidsSettingsViewEvents.RequestReAuth) {
|
||||
ReAuthActivity.newIntent(requireContext(),
|
||||
event.registrationFlowResponse,
|
||||
event.lastErrorCode,
|
||||
getString(R.string.settings_add_email_address)).let { intent ->
|
||||
reAuthActivityResultLauncher.launch(intent)
|
||||
}
|
||||
}
|
||||
private val reAuthActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
when (activityResult.data?.extras?.getString(ReAuthActivity.RESULT_FLOW_TYPE)) {
|
||||
LoginFlowTypes.SSO -> {
|
||||
viewModel.handle(ThreePidsSettingsAction.SsoAuthDone)
|
||||
}
|
||||
LoginFlowTypes.PASSWORD -> {
|
||||
val password = activityResult.data?.extras?.getString(ReAuthActivity.RESULT_VALUE) ?: ""
|
||||
viewModel.handle(ThreePidsSettingsAction.PasswordAuthDone(password))
|
||||
}
|
||||
else -> {
|
||||
viewModel.handle(ThreePidsSettingsAction.ReAuthCancelled)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
viewModel.handle(ThreePidsSettingsAction.ReAuthCancelled)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
package im.vector.app.features.settings.threepids
|
||||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
|
||||
sealed class ThreePidsSettingsViewEvents : VectorViewEvents {
|
||||
data class Failure(val throwable: Throwable) : ThreePidsSettingsViewEvents()
|
||||
object RequestPassword : ThreePidsSettingsViewEvents()
|
||||
// object RequestPassword : ThreePidsSettingsViewEvents()
|
||||
data class RequestReAuth(val registrationFlowResponse: RegistrationFlowResponse, val lastErrorCode: String?) : ThreePidsSettingsViewEvents()
|
||||
}
|
||||
|
|
|
@ -24,21 +24,28 @@ import com.airbnb.mvrx.Loading
|
|||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.error.SsoFlowNotSupportedYet
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.utils.ReadOnceTrue
|
||||
import im.vector.app.features.auth.ReAuthActivity
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth
|
||||
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.rx.rx
|
||||
import timber.log.Timber
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
class ThreePidsSettingsViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: ThreePidsSettingsViewState,
|
||||
|
@ -48,36 +55,16 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
|
|||
|
||||
// UIA session
|
||||
private var pendingThreePid: ThreePid? = null
|
||||
private var pendingSession: String? = null
|
||||
// private var pendingSession: String? = null
|
||||
|
||||
private val loadingCallback: MatrixCallback<Unit> = object : MatrixCallback<Unit> {
|
||||
override fun onFailure(failure: Throwable) {
|
||||
isLoading(false)
|
||||
|
||||
if (failure is Failure.RegistrationFlowError) {
|
||||
var isPasswordRequestFound = false
|
||||
|
||||
// We only support LoginFlowTypes.PASSWORD
|
||||
// Check if we can provide the user password
|
||||
failure.registrationFlowResponse.flows?.forEach { interactiveAuthenticationFlow ->
|
||||
isPasswordRequestFound = isPasswordRequestFound || interactiveAuthenticationFlow.stages?.any { it == LoginFlowTypes.PASSWORD } == true
|
||||
}
|
||||
|
||||
if (isPasswordRequestFound) {
|
||||
pendingSession = failure.registrationFlowResponse.session
|
||||
_viewEvents.post(ThreePidsSettingsViewEvents.RequestPassword)
|
||||
} else {
|
||||
// LoginFlowTypes.PASSWORD not supported, and this is the only one Element supports so far...
|
||||
_viewEvents.post(ThreePidsSettingsViewEvents.Failure(SsoFlowNotSupportedYet()))
|
||||
}
|
||||
} else {
|
||||
_viewEvents.post(ThreePidsSettingsViewEvents.Failure(failure))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSuccess(data: Unit) {
|
||||
pendingThreePid = null
|
||||
pendingSession = null
|
||||
isLoading(false)
|
||||
}
|
||||
}
|
||||
|
@ -146,12 +133,46 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
|
|||
is ThreePidsSettingsAction.ContinueThreePid -> handleContinueThreePid(action)
|
||||
is ThreePidsSettingsAction.SubmitCode -> handleSubmitCode(action)
|
||||
is ThreePidsSettingsAction.CancelThreePid -> handleCancelThreePid(action)
|
||||
is ThreePidsSettingsAction.AccountPassword -> handleAccountPassword(action)
|
||||
is ThreePidsSettingsAction.DeleteThreePid -> handleDeleteThreePid(action)
|
||||
is ThreePidsSettingsAction.ChangeUiState -> handleChangeUiState(action)
|
||||
ThreePidsSettingsAction.SsoAuthDone -> {
|
||||
Timber.d("## UIA - FallBack success")
|
||||
if (pendingAuth != null) {
|
||||
uiaContinuation?.resume(pendingAuth!!)
|
||||
} else {
|
||||
uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException())))
|
||||
}
|
||||
}
|
||||
is ThreePidsSettingsAction.PasswordAuthDone -> {
|
||||
val decryptedPass = session.loadSecureSecret<String>(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS)
|
||||
uiaContinuation?.resume(
|
||||
UserPasswordAuth(
|
||||
session = pendingAuth?.session,
|
||||
password = decryptedPass,
|
||||
user = session.myUserId
|
||||
)
|
||||
)
|
||||
}
|
||||
ThreePidsSettingsAction.ReAuthCancelled -> {
|
||||
Timber.d("## UIA - Reauth cancelled")
|
||||
uiaContinuation?.resumeWith(Result.failure((Exception())))
|
||||
uiaContinuation = null
|
||||
pendingAuth = null
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
var uiaContinuation: Continuation<UIABaseAuth>? = null
|
||||
var pendingAuth: UIABaseAuth? = null
|
||||
|
||||
private val uiaInterceptor = object : UserInteractiveAuthInterceptor {
|
||||
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
|
||||
_viewEvents.post(ThreePidsSettingsViewEvents.RequestReAuth(flowResponse, errCode))
|
||||
pendingAuth = DefaultBaseAuth(session = flowResponse.session)
|
||||
uiaContinuation = promise
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSubmitCode(action: ThreePidsSettingsAction.SubmitCode) {
|
||||
isLoading(true)
|
||||
setState {
|
||||
|
@ -168,7 +189,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
|
|||
override fun onSuccess(data: Unit) {
|
||||
// then finalize
|
||||
pendingThreePid = action.threePid
|
||||
session.finalizeAddingThreePid(action.threePid, null, null, loadingCallback)
|
||||
session.finalizeAddingThreePid(action.threePid, uiaInterceptor, loadingCallback)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
|
@ -232,7 +253,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
|
|||
isLoading(true)
|
||||
pendingThreePid = action.threePid
|
||||
viewModelScope.launch {
|
||||
session.finalizeAddingThreePid(action.threePid, null, null, loadingCallback)
|
||||
session.finalizeAddingThreePid(action.threePid, uiaInterceptor, loadingCallback)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,16 +264,14 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleAccountPassword(action: ThreePidsSettingsAction.AccountPassword) {
|
||||
val safeSession = pendingSession ?: return Unit
|
||||
.also { _viewEvents.post(ThreePidsSettingsViewEvents.Failure(IllegalStateException("No pending session"))) }
|
||||
val safeThreePid = pendingThreePid ?: return Unit
|
||||
.also { _viewEvents.post(ThreePidsSettingsViewEvents.Failure(IllegalStateException("No pending threePid"))) }
|
||||
isLoading(true)
|
||||
viewModelScope.launch {
|
||||
session.finalizeAddingThreePid(safeThreePid, safeSession, action.password, loadingCallback)
|
||||
}
|
||||
}
|
||||
// private fun handleAccountPassword(action: ThreePidsSettingsAction.AccountPassword) {
|
||||
// val safeThreePid = pendingThreePid ?: return Unit
|
||||
// .also { _viewEvents.post(ThreePidsSettingsViewEvents.Failure(IllegalStateException("No pending threePid"))) }
|
||||
// isLoading(true)
|
||||
// viewModelScope.launch {
|
||||
// session.finalizeAddingThreePid(safeThreePid, uiaInterceptor, loadingCallback)
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun handleDeleteThreePid(action: ThreePidsSettingsAction.DeleteThreePid) {
|
||||
isLoading(true)
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
<string name="login_error_ssl_handshake">Your device is using an outdated TLS security protocol, vulnerable to attack, for your security you will not be able to connect</string>
|
||||
|
||||
<string name="login_error_forbidden">Invalid username/password</string>
|
||||
<string name="error_unauthorized">Unauthorized, missing valid authentication credentials</string>
|
||||
<string name="login_error_unknown_token">The access token specified was not recognised</string>
|
||||
<string name="login_error_bad_json">Malformed JSON</string>
|
||||
<string name="login_error_not_json">Did not contain valid JSON</string>
|
||||
|
|
Loading…
Reference in New Issue