diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/Extensions.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/Extensions.kt index 3a068af076..b325be4451 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/Extensions.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/Extensions.kt @@ -16,6 +16,9 @@ package im.vector.matrix.android.api.failure +import im.vector.matrix.android.api.extensions.tryThis +import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse +import im.vector.matrix.android.internal.di.MoshiProvider import javax.net.ssl.HttpsURLConnection fun Throwable.is401() = @@ -37,3 +40,18 @@ fun Throwable.isInvalidPassword(): Boolean { && error.code == MatrixError.M_FORBIDDEN && error.message == "Invalid password" } + +/** + * 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) { + tryThis { + MoshiProvider.providesMoshi() + .adapter(RegistrationFlowResponse::class.java) + .fromJson(this.errorBody) + } + } else { + null + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/registration/RegisterTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/registration/RegisterTask.kt index 69976b063f..473b960d94 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/registration/RegisterTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/registration/RegisterTask.kt @@ -18,8 +18,8 @@ package im.vector.matrix.android.internal.auth.registration import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.failure.Failure +import im.vector.matrix.android.api.failure.toRegistrationFlowResponse import im.vector.matrix.android.internal.auth.AuthAPI -import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task @@ -39,25 +39,9 @@ internal class DefaultRegisterTask( apiCall = authAPI.register(params.registrationParams) } } catch (throwable: Throwable) { - if (throwable is Failure.OtherServerError && throwable.httpCode == 401) { - // Parse to get a RegistrationFlowResponse - val registrationFlowResponse = try { - MoshiProvider.providesMoshi() - .adapter(RegistrationFlowResponse::class.java) - .fromJson(throwable.errorBody) - } catch (e: Exception) { - null - } - // check if the server response can be cast - if (registrationFlowResponse != null) { - throw Failure.RegistrationFlowError(registrationFlowResponse) - } else { - throw throwable - } - } else { - // Other error - throw throwable - } + throw throwable.toRegistrationFlowResponse() + ?.let { Failure.RegistrationFlowError(it) } + ?: throwable } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceTask.kt index fbbaa0e0f7..809ec0be44 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceTask.kt @@ -17,10 +17,9 @@ package im.vector.matrix.android.internal.crypto.tasks import im.vector.matrix.android.api.failure.Failure -import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse +import im.vector.matrix.android.api.failure.toRegistrationFlowResponse import im.vector.matrix.android.internal.crypto.api.CryptoApi import im.vector.matrix.android.internal.crypto.model.rest.DeleteDeviceParams -import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task import org.greenrobot.eventbus.EventBus @@ -43,25 +42,9 @@ internal class DefaultDeleteDeviceTask @Inject constructor( apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams()) } } catch (throwable: Throwable) { - if (throwable is Failure.OtherServerError && throwable.httpCode == 401) { - // Parse to get a RegistrationFlowResponse - val registrationFlowResponse = try { - MoshiProvider.providesMoshi() - .adapter(RegistrationFlowResponse::class.java) - .fromJson(throwable.errorBody) - } catch (e: Exception) { - null - } - // check if the server response can be casted - if (registrationFlowResponse != null) { - throw Failure.RegistrationFlowError(registrationFlowResponse) - } else { - throw throwable - } - } else { - // Other error - throw throwable - } + throw throwable.toRegistrationFlowResponse() + ?.let { Failure.RegistrationFlowError(it) } + ?: throwable } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/UploadSigningKeysTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/UploadSigningKeysTask.kt index 0a69039219..a66a20617c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/UploadSigningKeysTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/UploadSigningKeysTask.kt @@ -17,14 +17,13 @@ package im.vector.matrix.android.internal.crypto.tasks import im.vector.matrix.android.api.failure.Failure -import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse +import im.vector.matrix.android.api.failure.toRegistrationFlowResponse import im.vector.matrix.android.internal.crypto.api.CryptoApi import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey import im.vector.matrix.android.internal.crypto.model.rest.KeysQueryResponse import im.vector.matrix.android.internal.crypto.model.rest.UploadSigningKeysBody import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth import im.vector.matrix.android.internal.crypto.model.toRest -import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task import org.greenrobot.eventbus.EventBus @@ -65,37 +64,25 @@ internal class DefaultUploadSigningKeysTask @Inject constructor( } return } catch (throwable: Throwable) { - if (throwable is Failure.OtherServerError - && throwable.httpCode == 401 + val registrationFlowResponse = throwable.toRegistrationFlowResponse() + if (registrationFlowResponse != null && params.userPasswordAuth != null /* Avoid infinite loop */ && params.userPasswordAuth.session.isNullOrEmpty() ) { - try { - MoshiProvider.providesMoshi() - .adapter(RegistrationFlowResponse::class.java) - .fromJson(throwable.errorBody) - } catch (e: Exception) { - null - }?.let { - // Retry with authentication - try { - val req = executeRequest(eventBus) { - apiCall = cryptoApi.uploadSigningKeys( - uploadQuery.copy(auth = params.userPasswordAuth.copy(session = it.session)) - ) - } - if (req.failures?.isNotEmpty() == true) { - throw UploadSigningKeys(req.failures) - } - return - } catch (failure: Throwable) { - throw failure - } + // Retry with authentication + val req = executeRequest(eventBus) { + apiCall = cryptoApi.uploadSigningKeys( + uploadQuery.copy(auth = params.userPasswordAuth.copy(session = registrationFlowResponse.session)) + ) } + if (req.failures?.isNotEmpty() == true) { + throw UploadSigningKeys(req.failures) + } + } else { + // Other error + throw throwable } - // Other error - throw throwable } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/account/ChangePasswordTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/account/ChangePasswordTask.kt index 6400253d9f..60cf92e5d1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/account/ChangePasswordTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/account/ChangePasswordTask.kt @@ -16,9 +16,7 @@ package im.vector.matrix.android.internal.session.account -import im.vector.matrix.android.api.failure.Failure -import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse -import im.vector.matrix.android.internal.di.MoshiProvider +import im.vector.matrix.android.api.failure.toRegistrationFlowResponse import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task @@ -45,31 +43,20 @@ internal class DefaultChangePasswordTask @Inject constructor( apiCall = accountAPI.changePassword(changePasswordParams) } } catch (throwable: Throwable) { - if (throwable is Failure.OtherServerError - && throwable.httpCode == 401 + val registrationFlowResponse = throwable.toRegistrationFlowResponse() + + if (registrationFlowResponse != null /* Avoid infinite loop */ && changePasswordParams.auth?.session == null) { - try { - MoshiProvider.providesMoshi() - .adapter(RegistrationFlowResponse::class.java) - .fromJson(throwable.errorBody) - } catch (e: Exception) { - null - }?.let { - // Retry with authentication - try { - executeRequest(eventBus) { - apiCall = accountAPI.changePassword( - changePasswordParams.copy(auth = changePasswordParams.auth?.copy(session = it.session)) - ) - } - return - } catch (failure: Throwable) { - throw failure - } + // Retry with authentication + executeRequest(eventBus) { + apiCall = accountAPI.changePassword( + changePasswordParams.copy(auth = changePasswordParams.auth?.copy(session = registrationFlowResponse.session)) + ) } + } else { + throw throwable } - throw throwable } } } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapCrossSigningTask.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapCrossSigningTask.kt index 75ddb737f4..b70902631a 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapCrossSigningTask.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapCrossSigningTask.kt @@ -18,6 +18,7 @@ package im.vector.riotx.features.crypto.recover import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.failure.MatrixError +import im.vector.matrix.android.api.failure.toRegistrationFlowResponse import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME @@ -28,13 +29,11 @@ import im.vector.matrix.android.api.session.securestorage.SharedSecretStorageSer import im.vector.matrix.android.api.session.securestorage.SsssKeyCreationInfo import im.vector.matrix.android.api.session.securestorage.SsssKeySpec import im.vector.matrix.android.internal.auth.data.LoginFlowTypes -import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse import im.vector.matrix.android.internal.crypto.crosssigning.toBase64NoPadding import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCreationInfo import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion import im.vector.matrix.android.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth -import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.util.awaitCallback import im.vector.riotx.R import im.vector.riotx.core.platform.ViewModelTask @@ -230,15 +229,10 @@ class BootstrapCrossSigningTask @Inject constructor( private fun handleInitializeXSigningError(failure: Throwable): BootstrapResult { if (failure is Failure.ServerError && failure.error.code == MatrixError.M_FORBIDDEN) { return BootstrapResult.InvalidPasswordError(failure.error) - } else if (failure is Failure.OtherServerError && failure.httpCode == 401) { - try { - MoshiProvider.providesMoshi() - .adapter(RegistrationFlowResponse::class.java) - .fromJson(failure.errorBody) - } catch (e: Exception) { - null - }?.let { flowResponse -> - if (flowResponse.flows?.any { it.stages?.contains(LoginFlowTypes.PASSWORD) == true } != true) { + } else { + val registrationFlowResponse = failure.toRegistrationFlowResponse() + if (registrationFlowResponse != null) { + if (registrationFlowResponse.flows?.any { it.stages?.contains(LoginFlowTypes.PASSWORD) == true } != true) { // can't do this from here return BootstrapResult.UnsupportedAuthFlow() } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt index f18e0b3cc7..24fc1bfdf8 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt @@ -22,14 +22,12 @@ import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback -import im.vector.matrix.android.api.failure.Failure +import im.vector.matrix.android.api.failure.toRegistrationFlowResponse import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo import im.vector.matrix.android.internal.auth.data.LoginFlowTypes -import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse import im.vector.matrix.android.internal.crypto.crosssigning.isVerified import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth -import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.rx.rx import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.VectorViewModel @@ -113,35 +111,26 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted privat override fun onFailure(failure: Throwable) { _pendingSession = null - if (failure is Failure.OtherServerError && failure.httpCode == 401) { - try { - MoshiProvider.providesMoshi() - .adapter(RegistrationFlowResponse::class.java) - .fromJson(failure.errorBody) - } catch (e: Exception) { - null - }?.let { flowResponse -> - // Retry with authentication - if (flowResponse.flows?.any { it.stages?.contains(LoginFlowTypes.PASSWORD) == true } == true) { - _pendingSession = flowResponse.session ?: "" - _viewEvents.post(CrossSigningSettingsViewEvents.RequestPassword) - return - } else { - // can't do this from here - _viewEvents.post(CrossSigningSettingsViewEvents.Failure(Throwable("You cannot do that from mobile"))) + val registrationFlowResponse = failure.toRegistrationFlowResponse() + if (registrationFlowResponse != null) { + // Retry with authentication + if (registrationFlowResponse.flows?.any { it.stages?.contains(LoginFlowTypes.PASSWORD) == true } == true) { + _pendingSession = registrationFlowResponse.session ?: "" + _viewEvents.post(CrossSigningSettingsViewEvents.RequestPassword) + } else { + // can't do this from here + _viewEvents.post(CrossSigningSettingsViewEvents.Failure(Throwable("You cannot do that from mobile"))) - setState { - copy(isUploadingKeys = false) - } - return + setState { + copy(isUploadingKeys = false) } } - } + } else { + _viewEvents.post(CrossSigningSettingsViewEvents.Failure(failure)) - _viewEvents.post(CrossSigningSettingsViewEvents.Failure(failure)) - - setState { - copy(isUploadingKeys = false) + setState { + copy(isUploadingKeys = false) + } } } })