mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-01-27 09:31:20 +01:00
Merge pull request #2844 from vector-im/feature/bma/fix_account_deactivation
Fix account deactivation crash
This commit is contained in:
commit
9614d55612
@ -14,6 +14,7 @@ Bugfix 🐛:
|
|||||||
- VoIP : fix audio devices output
|
- VoIP : fix audio devices output
|
||||||
- Fix crash after initial sync on Dendrite
|
- Fix crash after initial sync on Dendrite
|
||||||
- Fix crash reported by PlayStore (#2707)
|
- Fix crash reported by PlayStore (#2707)
|
||||||
|
- Fix crash when deactivating an account
|
||||||
|
|
||||||
Translations 🗣:
|
Translations 🗣:
|
||||||
-
|
-
|
||||||
|
@ -46,12 +46,13 @@ class DeactivateAccountTest : InstrumentedTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun deactivateAccountTest() {
|
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
|
// Deactivate the account
|
||||||
commonTestHelper.runBlockingTest {
|
commonTestHelper.runBlockingTest {
|
||||||
session.deactivateAccount(
|
session.deactivateAccount(
|
||||||
object : UserInteractiveAuthInterceptor {
|
eraseAllData = false,
|
||||||
|
userInteractiveAuthInterceptor = object : UserInteractiveAuthInterceptor {
|
||||||
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
|
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
|
||||||
promise.resume(
|
promise.resume(
|
||||||
UserPasswordAuth(
|
UserPasswordAuth(
|
||||||
@ -61,7 +62,8 @@ class DeactivateAccountTest : InstrumentedTest {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}, false)
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to login on the previous account, it will fail (M_USER_DEACTIVATED)
|
// Try to login on the previous account, it will fail (M_USER_DEACTIVATED)
|
||||||
|
@ -53,22 +53,24 @@ fun Throwable.isInvalidUIAAuth(): Boolean {
|
|||||||
* Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible
|
* Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible
|
||||||
*/
|
*/
|
||||||
fun Throwable.toRegistrationFlowResponse(): RegistrationFlowResponse? {
|
fun Throwable.toRegistrationFlowResponse(): RegistrationFlowResponse? {
|
||||||
return if (this is Failure.OtherServerError && this.httpCode == 401) {
|
return if (this is Failure.OtherServerError && httpCode == 401) {
|
||||||
tryOrNull {
|
tryOrNull {
|
||||||
MoshiProvider.providesMoshi()
|
MoshiProvider.providesMoshi()
|
||||||
.adapter(RegistrationFlowResponse::class.java)
|
.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)
|
// 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(
|
RegistrationFlowResponse(
|
||||||
flows = this.error.flows,
|
flows = error.flows,
|
||||||
session = this.error.session,
|
session = error.session,
|
||||||
completedStages = this.error.completedStages,
|
completedStages = error.completedStages,
|
||||||
params = this.error.params
|
params = error.params
|
||||||
)
|
)
|
||||||
} else null
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,8 @@ interface AccountService {
|
|||||||
* @param password Current password.
|
* @param password Current password.
|
||||||
* @param newPassword New password
|
* @param newPassword New password
|
||||||
*/
|
*/
|
||||||
suspend fun changePassword(password: String, newPassword: String)
|
suspend fun changePassword(password: String,
|
||||||
|
newPassword: String)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deactivate the account.
|
* 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
|
* 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.
|
* 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
|
* @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
|
* an incomplete view of conversations
|
||||||
|
* @param userInteractiveAuthInterceptor see [UserInteractiveAuthInterceptor]
|
||||||
*/
|
*/
|
||||||
suspend fun deactivateAccount(userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, eraseAllData: Boolean)
|
suspend fun deactivateAccount(eraseAllData: Boolean,
|
||||||
|
userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor)
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,6 @@ interface CryptoService {
|
|||||||
|
|
||||||
fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, callback: MatrixCallback<Unit>)
|
fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, callback: MatrixCallback<Unit>)
|
||||||
|
|
||||||
fun deleteDeviceWithUserPassword(deviceId: String, authSession: String?, password: String, callback: MatrixCallback<Unit>)
|
|
||||||
|
|
||||||
fun getCryptoVersion(context: Context, longFormat: Boolean): String
|
fun getCryptoVersion(context: Context, longFormat: Boolean): String
|
||||||
|
|
||||||
fun isCryptoEnabled(): Boolean
|
fun isCryptoEnabled(): Boolean
|
||||||
|
@ -16,14 +16,25 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.auth.registration
|
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.auth.UserInteractiveAuthInterceptor
|
||||||
import org.matrix.android.sdk.api.failure.Failure
|
import org.matrix.android.sdk.api.failure.Failure
|
||||||
import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse
|
import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse
|
||||||
import org.matrix.android.sdk.api.auth.UIABaseAuth
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.coroutines.suspendCoroutine
|
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}")
|
Timber.d("## UIA: check error ${failure.message}")
|
||||||
val flowResponse = failure.toRegistrationFlowResponse()
|
val flowResponse = failure.toRegistrationFlowResponse()
|
||||||
?: return false.also {
|
?: return false.also {
|
||||||
@ -38,16 +49,16 @@ internal suspend fun handleUIA(failure: Throwable, interceptor: UserInteractiveA
|
|||||||
suspendCoroutine<UIABaseAuth> { continuation ->
|
suspendCoroutine<UIABaseAuth> { continuation ->
|
||||||
interceptor.performStage(flowResponse, (failure as? Failure.ServerError)?.error?.code, continuation)
|
interceptor.performStage(flowResponse, (failure as? Failure.ServerError)?.error?.code, continuation)
|
||||||
}
|
}
|
||||||
} catch (failure: Throwable) {
|
} catch (failure2: Throwable) {
|
||||||
Timber.w(failure, "## UIA: failed to participate")
|
Timber.w(failure2, "## UIA: failed to participate")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
Timber.d("## UIA: updated auth $authUpdate")
|
Timber.d("## UIA: updated auth")
|
||||||
return try {
|
return try {
|
||||||
retryBlock(authUpdate)
|
retryBlock(authUpdate)
|
||||||
true
|
true
|
||||||
} catch (failure: Throwable) {
|
} catch (failure3: Throwable) {
|
||||||
handleUIA(failure, interceptor, retryBlock)
|
handleUIA(failure3, interceptor, retryBlock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.ClaimOneTimeKeysForUsersDeviceTask
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.DefaultClaimOneTimeKeysForUsersDevice
|
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.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.DefaultDownloadKeysForUsers
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.DefaultEncryptEventTask
|
import org.matrix.android.sdk.internal.crypto.tasks.DefaultEncryptEventTask
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.DefaultGetDeviceInfoTask
|
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.DefaultUploadSignaturesTask
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadSigningKeysTask
|
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.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.DownloadKeysForUsersTask
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.EncryptEventTask
|
import org.matrix.android.sdk.internal.crypto.tasks.EncryptEventTask
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
|
import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
|
||||||
@ -240,9 +238,6 @@ internal abstract class CryptoModule {
|
|||||||
@Binds
|
@Binds
|
||||||
abstract fun bindClaimOneTimeKeysForUsersDeviceTask(task: DefaultClaimOneTimeKeysForUsersDevice): ClaimOneTimeKeysForUsersDeviceTask
|
abstract fun bindClaimOneTimeKeysForUsersDeviceTask(task: DefaultClaimOneTimeKeysForUsersDevice): ClaimOneTimeKeysForUsersDeviceTask
|
||||||
|
|
||||||
@Binds
|
|
||||||
abstract fun bindDeleteDeviceWithUserPasswordTask(task: DefaultDeleteDeviceWithUserPasswordTask): DeleteDeviceWithUserPasswordTask
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindCrossSigningService(service: DefaultCrossSigningService): CrossSigningService
|
abstract fun bindCrossSigningService(service: DefaultCrossSigningService): CrossSigningService
|
||||||
|
|
||||||
|
@ -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.repository.WarnOnUnknownDeviceRepository
|
||||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
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.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.GetDeviceInfoTask
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask
|
import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask
|
import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask
|
||||||
@ -153,9 +152,8 @@ internal class DefaultCryptoService @Inject constructor(
|
|||||||
// Repository
|
// Repository
|
||||||
private val megolmEncryptionFactory: MXMegolmEncryptionFactory,
|
private val megolmEncryptionFactory: MXMegolmEncryptionFactory,
|
||||||
private val olmEncryptionFactory: MXOlmEncryptionFactory,
|
private val olmEncryptionFactory: MXOlmEncryptionFactory,
|
||||||
private val deleteDeviceTask: DeleteDeviceTask,
|
|
||||||
private val deleteDeviceWithUserPasswordTask: DeleteDeviceWithUserPasswordTask,
|
|
||||||
// Tasks
|
// Tasks
|
||||||
|
private val deleteDeviceTask: DeleteDeviceTask,
|
||||||
private val getDevicesTask: GetDevicesTask,
|
private val getDevicesTask: GetDevicesTask,
|
||||||
private val getDeviceInfoTask: GetDeviceInfoTask,
|
private val getDeviceInfoTask: GetDeviceInfoTask,
|
||||||
private val setDeviceNameTask: SetDeviceNameTask,
|
private val setDeviceNameTask: SetDeviceNameTask,
|
||||||
@ -217,15 +215,6 @@ internal class DefaultCryptoService @Inject constructor(
|
|||||||
.executeBy(taskExecutor)
|
.executeBy(taskExecutor)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deleteDeviceWithUserPassword(deviceId: String, authSession: String?, password: String, callback: MatrixCallback<Unit>) {
|
|
||||||
deleteDeviceWithUserPasswordTask
|
|
||||||
.configureWith(DeleteDeviceWithUserPasswordTask.Params(deviceId, authSession, password)) {
|
|
||||||
this.executionThread = TaskThread.CRYPTO
|
|
||||||
this.callback = callback
|
|
||||||
}
|
|
||||||
.executeBy(taskExecutor)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCryptoVersion(context: Context, longFormat: Boolean): String {
|
override fun getCryptoVersion(context: Context, longFormat: Boolean): String {
|
||||||
return if (longFormat) olmManager.getDetailedVersion(context) else olmManager.version
|
return if (longFormat) olmManager.getDetailedVersion(context) else olmManager.version
|
||||||
}
|
}
|
||||||
|
@ -47,12 +47,16 @@ internal class DefaultDeleteDeviceTask @Inject constructor(
|
|||||||
}
|
}
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
if (params.userInteractiveAuthInterceptor == null
|
if (params.userInteractiveAuthInterceptor == null
|
||||||
|| !handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth ->
|
|| !handleUIA(
|
||||||
execute(params.copy(userAuthParam = auth))
|
failure = throwable,
|
||||||
}
|
interceptor = params.userInteractiveAuthInterceptor,
|
||||||
|
retryBlock = { authUpdate ->
|
||||||
|
execute(params.copy(userAuthParam = authUpdate))
|
||||||
|
}
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
Timber.d("## UIA: propagate failure")
|
Timber.d("## UIA: propagate failure")
|
||||||
throw throwable
|
throw throwable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<DeleteDeviceWithUserPasswordTask.Params, Unit> {
|
|
||||||
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()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -126,11 +126,16 @@ internal class DefaultInitializeCrossSigningTask @Inject constructor(
|
|||||||
uploadSigningKeysTask.execute(uploadSigningKeysParams)
|
uploadSigningKeysTask.execute(uploadSigningKeysParams)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
if (params.interactiveAuthInterceptor == null
|
if (params.interactiveAuthInterceptor == null
|
||||||
|| !handleUIA(failure, params.interactiveAuthInterceptor) { authUpdate ->
|
|| !handleUIA(
|
||||||
uploadSigningKeysTask.execute(uploadSigningKeysParams.copy(userAuthParam = authUpdate))
|
failure = failure,
|
||||||
}) {
|
interceptor = params.interactiveAuthInterceptor,
|
||||||
|
retryBlock = { authUpdate ->
|
||||||
|
uploadSigningKeysTask.execute(uploadSigningKeysParams.copy(userAuthParam = authUpdate))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
) {
|
||||||
Timber.d("## UIA: propagate failure")
|
Timber.d("## UIA: propagate failure")
|
||||||
throw failure
|
throw failure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,10 +16,9 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.account
|
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.api.auth.UserInteractiveAuthInterceptor
|
||||||
import org.matrix.android.sdk.internal.auth.registration.handleUIA
|
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.GlobalErrorReceiver
|
||||||
import org.matrix.android.sdk.internal.network.executeRequest
|
import org.matrix.android.sdk.internal.network.executeRequest
|
||||||
import org.matrix.android.sdk.internal.session.cleanup.CleanupSession
|
import org.matrix.android.sdk.internal.session.cleanup.CleanupSession
|
||||||
@ -30,8 +29,8 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
internal interface DeactivateAccountTask : Task<DeactivateAccountTask.Params, Unit> {
|
internal interface DeactivateAccountTask : Task<DeactivateAccountTask.Params, Unit> {
|
||||||
data class Params(
|
data class Params(
|
||||||
val userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor,
|
|
||||||
val eraseAllData: Boolean,
|
val eraseAllData: Boolean,
|
||||||
|
val userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor,
|
||||||
val userAuthParam: UIABaseAuth? = null
|
val userAuthParam: UIABaseAuth? = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -39,7 +38,6 @@ internal interface DeactivateAccountTask : Task<DeactivateAccountTask.Params, Un
|
|||||||
internal class DefaultDeactivateAccountTask @Inject constructor(
|
internal class DefaultDeactivateAccountTask @Inject constructor(
|
||||||
private val accountAPI: AccountAPI,
|
private val accountAPI: AccountAPI,
|
||||||
private val globalErrorReceiver: GlobalErrorReceiver,
|
private val globalErrorReceiver: GlobalErrorReceiver,
|
||||||
@UserId private val userId: String,
|
|
||||||
private val identityDisconnectTask: IdentityDisconnectTask,
|
private val identityDisconnectTask: IdentityDisconnectTask,
|
||||||
private val cleanupSession: CleanupSession
|
private val cleanupSession: CleanupSession
|
||||||
) : DeactivateAccountTask {
|
) : DeactivateAccountTask {
|
||||||
@ -47,23 +45,33 @@ internal class DefaultDeactivateAccountTask @Inject constructor(
|
|||||||
override suspend fun execute(params: DeactivateAccountTask.Params) {
|
override suspend fun execute(params: DeactivateAccountTask.Params) {
|
||||||
val deactivateAccountParams = DeactivateAccountParams.create(params.userAuthParam, params.eraseAllData)
|
val deactivateAccountParams = DeactivateAccountParams.create(params.userAuthParam, params.eraseAllData)
|
||||||
|
|
||||||
try {
|
val canCleanup = try {
|
||||||
executeRequest<Unit>(globalErrorReceiver) {
|
executeRequest<Unit>(globalErrorReceiver) {
|
||||||
apiCall = accountAPI.deactivate(deactivateAccountParams)
|
apiCall = accountAPI.deactivate(deactivateAccountParams)
|
||||||
}
|
}
|
||||||
|
true
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
if (!handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth ->
|
if (!handleUIA(
|
||||||
execute(params.copy(userAuthParam = auth))
|
failure = throwable,
|
||||||
}
|
interceptor = params.userInteractiveAuthInterceptor,
|
||||||
|
retryBlock = { authUpdate ->
|
||||||
|
execute(params.copy(userAuthParam = authUpdate))
|
||||||
|
}
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
Timber.d("## UIA: propagate failure")
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ internal class DefaultAccountService @Inject constructor(private val changePassw
|
|||||||
changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword))
|
changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword))
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deactivateAccount(userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, eraseAllData: Boolean) {
|
override suspend fun deactivateAccount(eraseAllData: Boolean, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) {
|
||||||
deactivateAccountTask.execute(DeactivateAccountTask.Params(userInteractiveAuthInterceptor, eraseAllData))
|
deactivateAccountTask.execute(DeactivateAccountTask.Params(eraseAllData, userInteractiveAuthInterceptor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.PendingThreePidEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields
|
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields
|
||||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
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.GlobalErrorReceiver
|
||||||
import org.matrix.android.sdk.internal.network.executeRequest
|
import org.matrix.android.sdk.internal.network.executeRequest
|
||||||
import org.matrix.android.sdk.internal.task.Task
|
import org.matrix.android.sdk.internal.task.Task
|
||||||
@ -47,11 +46,12 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor(
|
|||||||
private val profileAPI: ProfileAPI,
|
private val profileAPI: ProfileAPI,
|
||||||
@SessionDatabase private val monarchy: Monarchy,
|
@SessionDatabase private val monarchy: Monarchy,
|
||||||
private val pendingThreePidMapper: PendingThreePidMapper,
|
private val pendingThreePidMapper: PendingThreePidMapper,
|
||||||
@UserId private val userId: String,
|
|
||||||
private val globalErrorReceiver: GlobalErrorReceiver) : FinalizeAddingThreePidTask() {
|
private val globalErrorReceiver: GlobalErrorReceiver) : FinalizeAddingThreePidTask() {
|
||||||
|
|
||||||
override suspend fun execute(params: Params) {
|
override suspend fun execute(params: Params) {
|
||||||
if (params.userWantsToCancel.not()) {
|
val canCleanup = if (params.userWantsToCancel) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
// Get the required pending data
|
// Get the required pending data
|
||||||
val pendingThreePids = monarchy.fetchAllMappedSync(
|
val pendingThreePids = monarchy.fetchAllMappedSync(
|
||||||
{ it.where(PendingThreePidEntity::class.java) },
|
{ it.where(PendingThreePidEntity::class.java) },
|
||||||
@ -69,21 +69,30 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor(
|
|||||||
)
|
)
|
||||||
apiCall = profileAPI.finalizeAddThreePid(body)
|
apiCall = profileAPI.finalizeAddThreePid(body)
|
||||||
}
|
}
|
||||||
|
true
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
if (params.userInteractiveAuthInterceptor == null
|
if (params.userInteractiveAuthInterceptor == null
|
||||||
|| !handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth ->
|
|| !handleUIA(
|
||||||
execute(params.copy(userAuthParam = auth))
|
failure = throwable,
|
||||||
}
|
interceptor = params.userInteractiveAuthInterceptor,
|
||||||
|
retryBlock = { authUpdate ->
|
||||||
|
execute(params.copy(userAuthParam = authUpdate))
|
||||||
|
}
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
Timber.d("## UIA: propagate failure")
|
Timber.d("## UIA: propagate failure")
|
||||||
throw throwable.toRegistrationFlowResponse()
|
throw throwable.toRegistrationFlowResponse()
|
||||||
?.let { Failure.RegistrationFlowError(it) }
|
?.let { Failure.RegistrationFlowError(it) }
|
||||||
?: throwable
|
?: throwable
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupDatabase(params)
|
if (canCleanup) {
|
||||||
|
cleanupDatabase(params)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun cleanupDatabase(params: Params) {
|
private suspend fun cleanupDatabase(params: Params) {
|
||||||
|
@ -113,7 +113,7 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory {
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.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) {
|
withState(sharedViewModel) {
|
||||||
if (it.ssoFallbackPageWasShown) {
|
if (it.ssoFallbackPageWasShown) {
|
||||||
Timber.d("## UIA ssoFallbackPageWasShown tentative success")
|
Timber.d("## UIA ssoFallbackPageWasShown tentative success")
|
||||||
|
@ -55,6 +55,7 @@ import org.matrix.android.sdk.internal.util.awaitCallback
|
|||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.resumeWithException
|
||||||
|
|
||||||
class BootstrapSharedViewModel @AssistedInject constructor(
|
class BootstrapSharedViewModel @AssistedInject constructor(
|
||||||
@Assisted initialState: BootstrapViewState,
|
@Assisted initialState: BootstrapViewState,
|
||||||
@ -421,7 +422,7 @@ class BootstrapSharedViewModel @AssistedInject constructor(
|
|||||||
_viewEvents.post(BootstrapViewEvents.RequestReAuth(flowResponse, errCode))
|
_viewEvents.post(BootstrapViewEvents.RequestReAuth(flowResponse, errCode))
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
promise.resumeWith(Result.failure(UnsupportedOperationException()))
|
promise.resumeWithException(UnsupportedOperationException())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ import org.matrix.android.sdk.rx.rx
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.resumeWithException
|
||||||
|
|
||||||
class HomeActivityViewModel @AssistedInject constructor(
|
class HomeActivityViewModel @AssistedInject constructor(
|
||||||
@Assisted initialState: HomeActivityViewState,
|
@Assisted initialState: HomeActivityViewState,
|
||||||
@ -228,7 +229,7 @@ class HomeActivityViewModel @AssistedInject constructor(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
promise.resumeWith(Result.failure(Exception("Cannot silently initialize cross signing, UIA missing")))
|
promise.resumeWithException(Exception("Cannot silently initialize cross signing, UIA missing"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -38,6 +38,7 @@ import org.matrix.android.sdk.api.auth.UserPasswordAuth
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.resumeWithException
|
||||||
|
|
||||||
data class DeactivateAccountViewState(
|
data class DeactivateAccountViewState(
|
||||||
val passwordShown: Boolean = false
|
val passwordShown: Boolean = false
|
||||||
@ -64,7 +65,7 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v
|
|||||||
if (pendingAuth != null) {
|
if (pendingAuth != null) {
|
||||||
uiaContinuation?.resume(pendingAuth!!)
|
uiaContinuation?.resume(pendingAuth!!)
|
||||||
} else {
|
} else {
|
||||||
uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException())))
|
uiaContinuation?.resumeWithException(IllegalArgumentException())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is DeactivateAccountAction.PasswordAuthDone -> {
|
is DeactivateAccountAction.PasswordAuthDone -> {
|
||||||
@ -79,7 +80,7 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v
|
|||||||
}
|
}
|
||||||
DeactivateAccountAction.ReAuthCancelled -> {
|
DeactivateAccountAction.ReAuthCancelled -> {
|
||||||
Timber.d("## UIA - Reauth cancelled")
|
Timber.d("## UIA - Reauth cancelled")
|
||||||
uiaContinuation?.resumeWith(Result.failure((Exception())))
|
uiaContinuation?.resumeWithException(Exception())
|
||||||
uiaContinuation = null
|
uiaContinuation = null
|
||||||
pendingAuth = null
|
pendingAuth = null
|
||||||
}
|
}
|
||||||
@ -98,13 +99,15 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val event = try {
|
val event = try {
|
||||||
session.deactivateAccount(
|
session.deactivateAccount(
|
||||||
|
action.eraseAllData,
|
||||||
object : UserInteractiveAuthInterceptor {
|
object : UserInteractiveAuthInterceptor {
|
||||||
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
|
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
|
||||||
_viewEvents.post(DeactivateAccountViewEvents.RequestReAuth(flowResponse, errCode))
|
_viewEvents.post(DeactivateAccountViewEvents.RequestReAuth(flowResponse, errCode))
|
||||||
pendingAuth = DefaultBaseAuth(session = flowResponse.session)
|
pendingAuth = DefaultBaseAuth(session = flowResponse.session)
|
||||||
uiaContinuation = promise
|
uiaContinuation = promise
|
||||||
}
|
}
|
||||||
}, action.eraseAllData)
|
}
|
||||||
|
)
|
||||||
DeactivateAccountViewEvents.Done
|
DeactivateAccountViewEvents.Done
|
||||||
} catch (failure: Exception) {
|
} catch (failure: Exception) {
|
||||||
if (failure.isInvalidUIAAuth()) {
|
if (failure.isInvalidUIAAuth()) {
|
||||||
|
@ -49,6 +49,7 @@ import org.matrix.android.sdk.rx.rx
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.resumeWithException
|
||||||
|
|
||||||
class CrossSigningSettingsViewModel @AssistedInject constructor(
|
class CrossSigningSettingsViewModel @AssistedInject constructor(
|
||||||
@Assisted private val initialState: CrossSigningSettingsViewState,
|
@Assisted private val initialState: CrossSigningSettingsViewState,
|
||||||
@ -130,7 +131,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
|
|||||||
if (pendingAuth != null) {
|
if (pendingAuth != null) {
|
||||||
uiaContinuation?.resume(pendingAuth!!)
|
uiaContinuation?.resume(pendingAuth!!)
|
||||||
} else {
|
} else {
|
||||||
uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException())))
|
uiaContinuation?.resumeWithException(IllegalArgumentException())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is CrossSigningSettingsAction.PasswordAuthDone -> {
|
is CrossSigningSettingsAction.PasswordAuthDone -> {
|
||||||
@ -146,7 +147,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
|
|||||||
CrossSigningSettingsAction.ReAuthCancelled -> {
|
CrossSigningSettingsAction.ReAuthCancelled -> {
|
||||||
Timber.d("## UIA - Reauth cancelled")
|
Timber.d("## UIA - Reauth cancelled")
|
||||||
_viewEvents.post(CrossSigningSettingsViewEvents.HideModalWaitingView)
|
_viewEvents.post(CrossSigningSettingsViewEvents.HideModalWaitingView)
|
||||||
uiaContinuation?.resumeWith(Result.failure((Exception())))
|
uiaContinuation?.resumeWithException(Exception())
|
||||||
uiaContinuation = null
|
uiaContinuation = null
|
||||||
pendingAuth = null
|
pendingAuth = null
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,7 @@ import java.util.concurrent.TimeUnit
|
|||||||
import javax.net.ssl.HttpsURLConnection
|
import javax.net.ssl.HttpsURLConnection
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.resumeWithException
|
||||||
|
|
||||||
data class DevicesViewState(
|
data class DevicesViewState(
|
||||||
val myDeviceId: String = "",
|
val myDeviceId: String = "",
|
||||||
@ -217,7 +218,7 @@ class DevicesViewModel @AssistedInject constructor(
|
|||||||
if (pendingAuth != null) {
|
if (pendingAuth != null) {
|
||||||
uiaContinuation?.resume(pendingAuth!!)
|
uiaContinuation?.resume(pendingAuth!!)
|
||||||
} else {
|
} else {
|
||||||
uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException())))
|
uiaContinuation?.resumeWithException(IllegalArgumentException())
|
||||||
}
|
}
|
||||||
Unit
|
Unit
|
||||||
}
|
}
|
||||||
@ -235,7 +236,7 @@ class DevicesViewModel @AssistedInject constructor(
|
|||||||
DevicesAction.ReAuthCancelled -> {
|
DevicesAction.ReAuthCancelled -> {
|
||||||
Timber.d("## UIA - Reauth cancelled")
|
Timber.d("## UIA - Reauth cancelled")
|
||||||
// _viewEvents.post(DevicesViewEvents.Loading)
|
// _viewEvents.post(DevicesViewEvents.Loading)
|
||||||
uiaContinuation?.resumeWith(Result.failure((Exception())))
|
uiaContinuation?.resumeWithException(Exception())
|
||||||
uiaContinuation = null
|
uiaContinuation = null
|
||||||
pendingAuth = null
|
pendingAuth = null
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ import org.matrix.android.sdk.rx.rx
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.resumeWithException
|
||||||
|
|
||||||
class ThreePidsSettingsViewModel @AssistedInject constructor(
|
class ThreePidsSettingsViewModel @AssistedInject constructor(
|
||||||
@Assisted initialState: ThreePidsSettingsViewState,
|
@Assisted initialState: ThreePidsSettingsViewState,
|
||||||
@ -140,7 +141,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
|
|||||||
if (pendingAuth != null) {
|
if (pendingAuth != null) {
|
||||||
uiaContinuation?.resume(pendingAuth!!)
|
uiaContinuation?.resume(pendingAuth!!)
|
||||||
} else {
|
} else {
|
||||||
uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException())))
|
uiaContinuation?.resumeWithException(IllegalArgumentException())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ThreePidsSettingsAction.PasswordAuthDone -> {
|
is ThreePidsSettingsAction.PasswordAuthDone -> {
|
||||||
@ -155,7 +156,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
ThreePidsSettingsAction.ReAuthCancelled -> {
|
ThreePidsSettingsAction.ReAuthCancelled -> {
|
||||||
Timber.d("## UIA - Reauth cancelled")
|
Timber.d("## UIA - Reauth cancelled")
|
||||||
uiaContinuation?.resumeWith(Result.failure((Exception())))
|
uiaContinuation?.resumeWithException(Exception())
|
||||||
uiaContinuation = null
|
uiaContinuation = null
|
||||||
pendingAuth = null
|
pendingAuth = null
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user