diff --git a/CHANGES.md b/CHANGES.md index b58135decd..4079c96bc5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,7 @@ Bugfix 🐛: - VoIP : fix audio devices output - Fix crash after initial sync on Dendrite - Fix crash reported by PlayStore (#2707) + - Fix crash when deactivating an account Translations 🗣: - diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt index b0df6fcb44..9bb5c45380 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt @@ -46,12 +46,13 @@ class DeactivateAccountTest : InstrumentedTest { @Test fun deactivateAccountTest() { - val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false)) + val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true)) // Deactivate the account commonTestHelper.runBlockingTest { session.deactivateAccount( - object : UserInteractiveAuthInterceptor { + eraseAllData = false, + userInteractiveAuthInterceptor = object : UserInteractiveAuthInterceptor { override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation) { promise.resume( UserPasswordAuth( @@ -61,7 +62,8 @@ class DeactivateAccountTest : InstrumentedTest { ) ) } - }, false) + } + ) } // Try to login on the previous account, it will fail (M_USER_DEACTIVATED) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt index c06cdd9e23..e0ee9f36ba 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt @@ -53,22 +53,24 @@ fun Throwable.isInvalidUIAAuth(): Boolean { * Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible */ fun Throwable.toRegistrationFlowResponse(): RegistrationFlowResponse? { - return if (this is Failure.OtherServerError && this.httpCode == 401) { + return if (this is Failure.OtherServerError && httpCode == 401) { tryOrNull { MoshiProvider.providesMoshi() .adapter(RegistrationFlowResponse::class.java) - .fromJson(this.errorBody) + .fromJson(errorBody) } - } else if (this is Failure.ServerError && this.httpCode == 401 && this.error.code == MatrixError.M_FORBIDDEN) { + } else if (this is Failure.ServerError && httpCode == 401 && 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) { + if (error.session != null && error.flows != null) { RegistrationFlowResponse( - flows = this.error.flows, - session = this.error.session, - completedStages = this.error.completedStages, - params = this.error.params + flows = error.flows, + session = error.session, + completedStages = error.completedStages, + params = error.params ) - } else null + } else { + null + } } else { null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt index eb327dfd56..1f28dbd8af 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt @@ -27,7 +27,8 @@ interface AccountService { * @param password Current password. * @param newPassword New password */ - suspend fun changePassword(password: String, newPassword: String) + suspend fun changePassword(password: String, + newPassword: String) /** * Deactivate the account. @@ -41,9 +42,10 @@ interface AccountService { * be shared with any new or unregistered users, but registered users who already have access to these messages will still * have access to their copy. * - * @param password the account password * @param eraseAllData set to true to forget all messages that have been sent. Warning: this will cause future users to see * an incomplete view of conversations + * @param userInteractiveAuthInterceptor see [UserInteractiveAuthInterceptor] */ - suspend fun deactivateAccount(userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, eraseAllData: Boolean) + suspend fun deactivateAccount(eraseAllData: Boolean, + userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index fa5ea359e8..eead9b4ab7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -56,8 +56,6 @@ interface CryptoService { fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, callback: MatrixCallback) - fun deleteDeviceWithUserPassword(deviceId: String, authSession: String?, password: String, callback: MatrixCallback) - fun getCryptoVersion(context: Context, longFormat: Boolean): String fun isCryptoEnabled(): Boolean diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt index 1a0383cb22..da0866a5fd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt @@ -16,14 +16,25 @@ package org.matrix.android.sdk.internal.auth.registration +import org.matrix.android.sdk.api.auth.UIABaseAuth 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.auth.UIABaseAuth import timber.log.Timber import kotlin.coroutines.suspendCoroutine -internal suspend fun handleUIA(failure: Throwable, interceptor: UserInteractiveAuthInterceptor, retryBlock: suspend (UIABaseAuth) -> Unit): Boolean { +/** + * Handle a UIA challenge + * + * @param failure the failure to handle + * @param interceptor see doc in [UserInteractiveAuthInterceptor] + * @param retryBlock called at the end of the process, in this block generally retry executing the task, with + * provided authUpdate + * @return true if UIA is handled without error + */ +internal suspend fun handleUIA(failure: Throwable, + interceptor: UserInteractiveAuthInterceptor, + retryBlock: suspend (UIABaseAuth) -> Unit): Boolean { Timber.d("## UIA: check error ${failure.message}") val flowResponse = failure.toRegistrationFlowResponse() ?: return false.also { @@ -38,16 +49,16 @@ internal suspend fun handleUIA(failure: Throwable, interceptor: UserInteractiveA suspendCoroutine { continuation -> interceptor.performStage(flowResponse, (failure as? Failure.ServerError)?.error?.code, continuation) } - } catch (failure: Throwable) { - Timber.w(failure, "## UIA: failed to participate") + } catch (failure2: Throwable) { + Timber.w(failure2, "## UIA: failed to participate") return false } - Timber.d("## UIA: updated auth $authUpdate") + Timber.d("## UIA: updated auth") return try { retryBlock(authUpdate) true - } catch (failure: Throwable) { - handleUIA(failure, interceptor, retryBlock) + } catch (failure3: Throwable) { + handleUIA(failure3, interceptor, retryBlock) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt index a786ebd4b2..e114f86a99 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt @@ -61,7 +61,6 @@ import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule import org.matrix.android.sdk.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultClaimOneTimeKeysForUsersDevice import org.matrix.android.sdk.internal.crypto.tasks.DefaultDeleteDeviceTask -import org.matrix.android.sdk.internal.crypto.tasks.DefaultDeleteDeviceWithUserPasswordTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultDownloadKeysForUsers import org.matrix.android.sdk.internal.crypto.tasks.DefaultEncryptEventTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultGetDeviceInfoTask @@ -75,7 +74,6 @@ import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadKeysTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadSignaturesTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadSigningKeysTask import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask -import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceWithUserPasswordTask import org.matrix.android.sdk.internal.crypto.tasks.DownloadKeysForUsersTask import org.matrix.android.sdk.internal.crypto.tasks.EncryptEventTask import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask @@ -240,9 +238,6 @@ internal abstract class CryptoModule { @Binds abstract fun bindClaimOneTimeKeysForUsersDeviceTask(task: DefaultClaimOneTimeKeysForUsersDevice): ClaimOneTimeKeysForUsersDeviceTask - @Binds - abstract fun bindDeleteDeviceWithUserPasswordTask(task: DefaultDeleteDeviceWithUserPasswordTask): DeleteDeviceWithUserPasswordTask - @Binds abstract fun bindCrossSigningService(service: DefaultCrossSigningService): CrossSigningService diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index 678bc9819f..67229a5eae 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -75,7 +75,6 @@ import org.matrix.android.sdk.internal.crypto.model.toRest import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask -import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceWithUserPasswordTask import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask @@ -153,9 +152,8 @@ internal class DefaultCryptoService @Inject constructor( // Repository private val megolmEncryptionFactory: MXMegolmEncryptionFactory, private val olmEncryptionFactory: MXOlmEncryptionFactory, - private val deleteDeviceTask: DeleteDeviceTask, - private val deleteDeviceWithUserPasswordTask: DeleteDeviceWithUserPasswordTask, // Tasks + private val deleteDeviceTask: DeleteDeviceTask, private val getDevicesTask: GetDevicesTask, private val getDeviceInfoTask: GetDeviceInfoTask, private val setDeviceNameTask: SetDeviceNameTask, @@ -217,15 +215,6 @@ internal class DefaultCryptoService @Inject constructor( .executeBy(taskExecutor) } - override fun deleteDeviceWithUserPassword(deviceId: String, authSession: String?, password: String, callback: MatrixCallback) { - deleteDeviceWithUserPasswordTask - .configureWith(DeleteDeviceWithUserPasswordTask.Params(deviceId, authSession, password)) { - this.executionThread = TaskThread.CRYPTO - this.callback = callback - } - .executeBy(taskExecutor) - } - override fun getCryptoVersion(context: Context, longFormat: Boolean): String { return if (longFormat) olmManager.getDetailedVersion(context) else olmManager.version } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt index ff25ac0f66..61596bb5b6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt @@ -47,12 +47,16 @@ internal class DefaultDeleteDeviceTask @Inject constructor( } } catch (throwable: Throwable) { if (params.userInteractiveAuthInterceptor == null - || !handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth -> - execute(params.copy(userAuthParam = auth)) - } + || !handleUIA( + failure = throwable, + interceptor = params.userInteractiveAuthInterceptor, + retryBlock = { authUpdate -> + execute(params.copy(userAuthParam = authUpdate)) + } + ) ) { Timber.d("## UIA: propagate failure") - throw throwable + throw throwable } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt deleted file mode 100644 index dc0077425e..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2020 The Matrix.org Foundation C.I.C. - * - * 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 org.matrix.android.sdk.internal.crypto.tasks - -import org.matrix.android.sdk.api.auth.data.LoginFlowTypes -import org.matrix.android.sdk.internal.crypto.api.CryptoApi -import org.matrix.android.sdk.internal.crypto.model.rest.DeleteDeviceParams -import org.matrix.android.sdk.api.auth.UserPasswordAuth -import org.matrix.android.sdk.internal.di.UserId -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 javax.inject.Inject - -internal interface DeleteDeviceWithUserPasswordTask : Task { - data class Params( - val deviceId: String, - val authSession: String?, - val password: String - ) -} - -internal class DefaultDeleteDeviceWithUserPasswordTask @Inject constructor( - private val cryptoApi: CryptoApi, - @UserId private val userId: String, - private val globalErrorReceiver: GlobalErrorReceiver -) : DeleteDeviceWithUserPasswordTask { - - override suspend fun execute(params: DeleteDeviceWithUserPasswordTask.Params) { - return executeRequest(globalErrorReceiver) { - apiCall = cryptoApi.deleteDevice(params.deviceId, - DeleteDeviceParams( - auth = UserPasswordAuth( - type = LoginFlowTypes.PASSWORD, - session = params.authSession, - user = userId, - password = params.password - ).asMap() - ) - ) - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt index ef31130f55..f8a8354e48 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt @@ -126,11 +126,16 @@ internal class DefaultInitializeCrossSigningTask @Inject constructor( uploadSigningKeysTask.execute(uploadSigningKeysParams) } catch (failure: Throwable) { if (params.interactiveAuthInterceptor == null - || !handleUIA(failure, params.interactiveAuthInterceptor) { authUpdate -> - uploadSigningKeysTask.execute(uploadSigningKeysParams.copy(userAuthParam = authUpdate)) - }) { + || !handleUIA( + failure = failure, + interceptor = params.interactiveAuthInterceptor, + retryBlock = { authUpdate -> + uploadSigningKeysTask.execute(uploadSigningKeysParams.copy(userAuthParam = authUpdate)) + } + ) + ) { Timber.d("## UIA: propagate failure") - throw failure + throw failure } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt index d67b21567e..ca6b0554a9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt @@ -16,10 +16,9 @@ package org.matrix.android.sdk.internal.session.account +import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.internal.auth.registration.handleUIA -import org.matrix.android.sdk.api.auth.UIABaseAuth -import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.cleanup.CleanupSession @@ -30,8 +29,8 @@ import javax.inject.Inject internal interface DeactivateAccountTask : Task { data class Params( - val userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, val eraseAllData: Boolean, + val userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, val userAuthParam: UIABaseAuth? = null ) } @@ -39,7 +38,6 @@ internal interface DeactivateAccountTask : Task(globalErrorReceiver) { apiCall = accountAPI.deactivate(deactivateAccountParams) } + true } catch (throwable: Throwable) { - if (!handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth -> - execute(params.copy(userAuthParam = auth)) - } + if (!handleUIA( + failure = throwable, + interceptor = params.userInteractiveAuthInterceptor, + retryBlock = { authUpdate -> + execute(params.copy(userAuthParam = authUpdate)) + } + ) ) { Timber.d("## UIA: propagate failure") - throw throwable + throw throwable + } else { + false } } - // Logout from identity server if any, ignoring errors - runCatching { identityDisconnectTask.execute(Unit) } - .onFailure { Timber.w(it, "Unable to disconnect identity server") } - cleanupSession.handle() + if (canCleanup) { + // Logout from identity server if any, ignoring errors + runCatching { identityDisconnectTask.execute(Unit) } + .onFailure { Timber.w(it, "Unable to disconnect identity server") } + + cleanupSession.handle() + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt index 25b67159a9..dc77d7bffb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt @@ -27,7 +27,7 @@ internal class DefaultAccountService @Inject constructor(private val changePassw changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword)) } - override suspend fun deactivateAccount(userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, eraseAllData: Boolean) { - deactivateAccountTask.execute(DeactivateAccountTask.Params(userInteractiveAuthInterceptor, eraseAllData)) + override suspend fun deactivateAccount(eraseAllData: Boolean, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) { + deactivateAccountTask.execute(DeactivateAccountTask.Params(eraseAllData, userInteractiveAuthInterceptor)) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt index 916a602936..c2a38af093 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt @@ -26,7 +26,6 @@ import org.matrix.android.sdk.api.auth.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 -import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task @@ -47,11 +46,12 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor( private val profileAPI: ProfileAPI, @SessionDatabase private val monarchy: Monarchy, private val pendingThreePidMapper: PendingThreePidMapper, - @UserId private val userId: String, private val globalErrorReceiver: GlobalErrorReceiver) : FinalizeAddingThreePidTask() { override suspend fun execute(params: Params) { - if (params.userWantsToCancel.not()) { + val canCleanup = if (params.userWantsToCancel) { + true + } else { // Get the required pending data val pendingThreePids = monarchy.fetchAllMappedSync( { it.where(PendingThreePidEntity::class.java) }, @@ -69,21 +69,30 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor( ) apiCall = profileAPI.finalizeAddThreePid(body) } + true } catch (throwable: Throwable) { if (params.userInteractiveAuthInterceptor == null - || !handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth -> - execute(params.copy(userAuthParam = auth)) - } + || !handleUIA( + failure = throwable, + interceptor = params.userInteractiveAuthInterceptor, + retryBlock = { authUpdate -> + execute(params.copy(userAuthParam = authUpdate)) + } + ) ) { Timber.d("## UIA: propagate failure") - throw throwable.toRegistrationFlowResponse() + throw throwable.toRegistrationFlowResponse() ?.let { Failure.RegistrationFlowError(it) } ?: throwable + } else { + false } } } - cleanupDatabase(params) + if (canCleanup) { + cleanupDatabase(params) + } } private suspend fun cleanupDatabase(params: Params) { diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt index 0385973386..ce23111a95 100644 --- a/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt +++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt @@ -113,7 +113,7 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory { override fun onResume() { super.onResume() - // It's the only way we have to know if sso falback flow was successful + // It's the only way we have to know if sso fallback flow was successful withState(sharedViewModel) { if (it.ssoFallbackPageWasShown) { Timber.d("## UIA ssoFallbackPageWasShown tentative success") diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt index 42278cd948..fe55d81cc4 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt @@ -55,6 +55,7 @@ import org.matrix.android.sdk.internal.util.awaitCallback import java.io.OutputStream import kotlin.coroutines.Continuation import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException class BootstrapSharedViewModel @AssistedInject constructor( @Assisted initialState: BootstrapViewState, @@ -421,7 +422,7 @@ class BootstrapSharedViewModel @AssistedInject constructor( _viewEvents.post(BootstrapViewEvents.RequestReAuth(flowResponse, errCode)) } else -> { - promise.resumeWith(Result.failure(UnsupportedOperationException())) + promise.resumeWithException(UnsupportedOperationException()) } } } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt index 44e02fea0b..62bdc61b63 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt @@ -52,6 +52,7 @@ import org.matrix.android.sdk.rx.rx import timber.log.Timber import kotlin.coroutines.Continuation import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException class HomeActivityViewModel @AssistedInject constructor( @Assisted initialState: HomeActivityViewState, @@ -228,7 +229,7 @@ class HomeActivityViewModel @AssistedInject constructor( ) ) } else { - promise.resumeWith(Result.failure(Exception("Cannot silently initialize cross signing, UIA missing"))) + promise.resumeWithException(Exception("Cannot silently initialize cross signing, UIA missing")) } } }, diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt index 49cb75c9d6..80af64d9f3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt @@ -38,6 +38,7 @@ import org.matrix.android.sdk.api.auth.UserPasswordAuth import timber.log.Timber import kotlin.coroutines.Continuation import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException data class DeactivateAccountViewState( val passwordShown: Boolean = false @@ -64,7 +65,7 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v if (pendingAuth != null) { uiaContinuation?.resume(pendingAuth!!) } else { - uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException()))) + uiaContinuation?.resumeWithException(IllegalArgumentException()) } } is DeactivateAccountAction.PasswordAuthDone -> { @@ -79,7 +80,7 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v } DeactivateAccountAction.ReAuthCancelled -> { Timber.d("## UIA - Reauth cancelled") - uiaContinuation?.resumeWith(Result.failure((Exception()))) + uiaContinuation?.resumeWithException(Exception()) uiaContinuation = null pendingAuth = null } @@ -98,13 +99,15 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v viewModelScope.launch { val event = try { session.deactivateAccount( + action.eraseAllData, object : UserInteractiveAuthInterceptor { override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation) { _viewEvents.post(DeactivateAccountViewEvents.RequestReAuth(flowResponse, errCode)) pendingAuth = DefaultBaseAuth(session = flowResponse.session) uiaContinuation = promise } - }, action.eraseAllData) + } + ) DeactivateAccountViewEvents.Done } catch (failure: Exception) { if (failure.isInvalidUIAAuth()) { diff --git a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt index 566dea2cd4..8bdf97b6ec 100644 --- a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt @@ -49,6 +49,7 @@ import org.matrix.android.sdk.rx.rx import timber.log.Timber import kotlin.coroutines.Continuation import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException class CrossSigningSettingsViewModel @AssistedInject constructor( @Assisted private val initialState: CrossSigningSettingsViewState, @@ -130,7 +131,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( if (pendingAuth != null) { uiaContinuation?.resume(pendingAuth!!) } else { - uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException()))) + uiaContinuation?.resumeWithException(IllegalArgumentException()) } } is CrossSigningSettingsAction.PasswordAuthDone -> { @@ -146,7 +147,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( CrossSigningSettingsAction.ReAuthCancelled -> { Timber.d("## UIA - Reauth cancelled") _viewEvents.post(CrossSigningSettingsViewEvents.HideModalWaitingView) - uiaContinuation?.resumeWith(Result.failure((Exception()))) + uiaContinuation?.resumeWithException(Exception()) uiaContinuation = null pendingAuth = null } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index a56a7b8d48..c48b08e806 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -64,6 +64,7 @@ import java.util.concurrent.TimeUnit import javax.net.ssl.HttpsURLConnection import kotlin.coroutines.Continuation import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException data class DevicesViewState( val myDeviceId: String = "", @@ -217,7 +218,7 @@ class DevicesViewModel @AssistedInject constructor( if (pendingAuth != null) { uiaContinuation?.resume(pendingAuth!!) } else { - uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException()))) + uiaContinuation?.resumeWithException(IllegalArgumentException()) } Unit } @@ -235,7 +236,7 @@ class DevicesViewModel @AssistedInject constructor( DevicesAction.ReAuthCancelled -> { Timber.d("## UIA - Reauth cancelled") // _viewEvents.post(DevicesViewEvents.Loading) - uiaContinuation?.resumeWith(Result.failure((Exception()))) + uiaContinuation?.resumeWithException(Exception()) uiaContinuation = null pendingAuth = null } diff --git a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt index a1d4d6227b..89d632b813 100644 --- a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt @@ -46,6 +46,7 @@ import org.matrix.android.sdk.rx.rx import timber.log.Timber import kotlin.coroutines.Continuation import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException class ThreePidsSettingsViewModel @AssistedInject constructor( @Assisted initialState: ThreePidsSettingsViewState, @@ -140,7 +141,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( if (pendingAuth != null) { uiaContinuation?.resume(pendingAuth!!) } else { - uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException()))) + uiaContinuation?.resumeWithException(IllegalArgumentException()) } } is ThreePidsSettingsAction.PasswordAuthDone -> { @@ -155,7 +156,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( } ThreePidsSettingsAction.ReAuthCancelled -> { Timber.d("## UIA - Reauth cancelled") - uiaContinuation?.resumeWith(Result.failure((Exception()))) + uiaContinuation?.resumeWithException(Exception()) uiaContinuation = null pendingAuth = null }