From 924e66802391392e45fb9256d16c06f7bc8288d0 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 30 May 2022 13:51:33 +0100 Subject: [PATCH 01/12] adding missing loading state when confirming password reset - adds reset test cases to the onboarding view model --- .../im/vector/app/test/fakes/FakeAuthenticationService.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeAuthenticationService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeAuthenticationService.kt index cc606497f5..335cc90d42 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeAuthenticationService.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeAuthenticationService.kt @@ -41,6 +41,10 @@ class FakeAuthenticationService : AuthenticationService by mockk() { every { getLoginWizard() } returns loginWizard } + fun givenLoginWizard(loginWizard: LoginWizard) { + every { getLoginWizard() } returns loginWizard + } + fun givenLoginFlow(config: HomeServerConnectionConfig, result: LoginFlowResult) { coEvery { getLoginFlow(config) } returns result } From c10254dbfa2bcbcb810c6b30343367cc2c79655c Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 30 May 2022 16:51:23 +0100 Subject: [PATCH 02/12] exposing if the homeserver supports signing out all devices when starting the reset process --- .../android/sdk/api/auth/login/LoginWizard.kt | 4 ++- .../internal/auth/login/DefaultLoginWizard.kt | 10 ++++++- .../internal/auth/login/ResetCapabilities.kt | 27 +++++++++++++++++++ .../auth/version/HomeServerVersion.kt | 1 + .../sdk/internal/auth/version/Versions.kt | 9 +++++++ .../onboarding/OnboardingViewState.kt | 2 +- 6 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetCapabilities.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt index 5b8d2328c7..43c117860f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.auth.login import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.internal.auth.login.ResetCapabilities /** * Set of methods to be able to login to an existing account on a homeserver. @@ -65,8 +66,9 @@ interface LoginWizard { * [resetPasswordMailConfirmed] is successfully called. * * @param email an email previously associated to the account the user wants the password to be reset. + * @return a [ResetCapabilities] if the reset is successful */ - suspend fun resetPassword(email: String) + suspend fun resetPassword(email: String): ResetCapabilities /** * Confirm the new password, once the user has checked their email diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt index 20b056f1c7..2a0d792597 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt @@ -31,6 +31,7 @@ import org.matrix.android.sdk.internal.auth.data.TokenLoginParams import org.matrix.android.sdk.internal.auth.db.PendingSessionData import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistrationParams import org.matrix.android.sdk.internal.auth.registration.RegisterAddThreePidTask +import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.content.DefaultContentUrlResolver import org.matrix.android.sdk.internal.session.contentscanner.DisabledContentScannerService @@ -103,7 +104,7 @@ internal class DefaultLoginWizard( return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig) } - override suspend fun resetPassword(email: String) { + override suspend fun resetPassword(email: String): ResetCapabilities { val param = RegisterAddThreePidTask.Params( RegisterThreePid.Email(email), pendingSessionData.clientSecret, @@ -119,6 +120,13 @@ internal class DefaultLoginWizard( pendingSessionData = pendingSessionData.copy(resetPasswordData = ResetPasswordData(result)) .also { pendingSessionStore.savePendingSessionData(it) } + + + val versions = executeRequest(null) { + authAPI.versions() + } + + return ResetCapabilities(supportsLogoutAllDevices = versions.doesServerSupportLogoutDevices()) } override suspend fun resetPasswordMailConfirmed(newPassword: String) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetCapabilities.kt new file mode 100644 index 0000000000..ed3b473062 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetCapabilities.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 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 org.matrix.android.sdk.internal.auth.login + +/** + * The reset capabilities of the selected Homeserver + */ +data class ResetCapabilities( + /** + * True if the server supports MSC2457 `logout_devices` parameter when setting a new password. + */ + val supportsLogoutAllDevices: Boolean +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt index cd38b68a85..75639c6a21 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt @@ -58,6 +58,7 @@ internal data class HomeServerVersion( val r0_4_0 = HomeServerVersion(major = 0, minor = 4, patch = 0) val r0_5_0 = HomeServerVersion(major = 0, minor = 5, patch = 0) val r0_6_0 = HomeServerVersion(major = 0, minor = 6, patch = 0) + val r0_6_1 = HomeServerVersion(major = 0, minor = 6, patch = 1) val v1_3_0 = HomeServerVersion(major = 1, minor = 3, patch = 0) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt index cee4b12138..4e53f4d3f9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt @@ -111,6 +111,15 @@ private fun Versions.doesServerSeparatesAddAndBind(): Boolean { unstableFeatures?.get(FEATURE_SEPARATE_ADD_AND_BIND) ?: false } +/** + * Indicate if the server supports MSC2457 `logout_devices` parameter when setting a new password + * + * @return true if logout_devices is supported + */ +internal fun Versions.doesServerSupportLogoutDevices(): Boolean { + return getMaxVersion() >= HomeServerVersion.r0_6_1 +} + private fun Versions.getMaxVersion(): HomeServerVersion { return supportedVersions ?.mapNotNull { HomeServerVersion.parse(it) } diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt index 268b1e7d49..680d2192ed 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt @@ -87,7 +87,7 @@ data class PersonalizationState( @Parcelize data class ResetState( val email: String? = null, - val newPassword: String? = null, + val newPassword: String? = null ) : Parcelable @Parcelize From f21e30f7c7ec040a4f0c9bae753e5f45247c4ca0 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 30 May 2022 17:23:24 +0100 Subject: [PATCH 03/12] passing the logout devices parameters to the account/password endpoint --- .../matrix/android/sdk/api/auth/login/LoginWizard.kt | 9 ++++++--- .../sdk/internal/auth/login/DefaultLoginWizard.kt | 6 +++--- .../internal/auth/login/ResetPasswordMailConfirmed.kt | 10 +++++++--- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt index 43c117860f..638ff079c4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt @@ -66,7 +66,7 @@ interface LoginWizard { * [resetPasswordMailConfirmed] is successfully called. * * @param email an email previously associated to the account the user wants the password to be reset. - * @return a [ResetCapabilities] if the reset is successful + * @return a [ResetCapabilities] if the reset is successful. */ suspend fun resetPassword(email: String): ResetCapabilities @@ -74,7 +74,10 @@ interface LoginWizard { * Confirm the new password, once the user has checked their email * When this method succeed, tha account password will be effectively modified. * - * @param newPassword the desired new password + * @param newPassword the desired new password. + * @param logoutAllDevices when true, all devices will be logged out. False values will only be taken into account + * if [ResetCapabilities.supportsLogoutAllDevices] is supported. + * When [ResetCapabilities.supportsLogoutAllDevices] is false the default behaviour is to logout all devices. */ - suspend fun resetPasswordMailConfirmed(newPassword: String) + suspend fun resetPasswordMailConfirmed(newPassword: String, logoutAllDevices: Boolean = true) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt index 2a0d792597..0d73d398fc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt @@ -121,7 +121,6 @@ internal class DefaultLoginWizard( pendingSessionData = pendingSessionData.copy(resetPasswordData = ResetPasswordData(result)) .also { pendingSessionStore.savePendingSessionData(it) } - val versions = executeRequest(null) { authAPI.versions() } @@ -129,12 +128,13 @@ internal class DefaultLoginWizard( return ResetCapabilities(supportsLogoutAllDevices = versions.doesServerSupportLogoutDevices()) } - override suspend fun resetPasswordMailConfirmed(newPassword: String) { + override suspend fun resetPasswordMailConfirmed(newPassword: String, logoutAllDevices: Boolean) { val resetPasswordData = pendingSessionData.resetPasswordData ?: throw IllegalStateException("Developer error - Must call resetPassword first") val param = ResetPasswordMailConfirmed.create( pendingSessionData.clientSecret, resetPasswordData.addThreePidRegistrationResponse.sid, - newPassword + newPassword, + logoutAllDevices ) executeRequest(null) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordMailConfirmed.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordMailConfirmed.kt index 4e0c000f87..01481f70dc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordMailConfirmed.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordMailConfirmed.kt @@ -30,13 +30,17 @@ internal data class ResetPasswordMailConfirmed( // the new password @Json(name = "new_password") - val newPassword: String? = null + val newPassword: String? = null, + + @Json(name = "logout_devices") + val logoutDevices: Boolean? = null ) { companion object { - fun create(clientSecret: String, sid: String, newPassword: String): ResetPasswordMailConfirmed { + fun create(clientSecret: String, sid: String, newPassword: String, logoutDevices: Boolean?): ResetPasswordMailConfirmed { return ResetPasswordMailConfirmed( auth = AuthParams.createForResetPassword(clientSecret, sid), - newPassword = newPassword + newPassword = newPassword, + logoutDevices = logoutDevices ) } } From a2646c56cf6371f18d496399f2729e32818178db Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 30 May 2022 17:29:19 +0100 Subject: [PATCH 04/12] adding the logout all devices state to the reset state in preparation for the UI to take it into account --- .../app/features/onboarding/OnboardingViewModel.kt | 11 +++++++++-- .../app/features/onboarding/OnboardingViewState.kt | 3 ++- .../features/onboarding/OnboardingViewModelTest.kt | 9 +++++++-- .../java/im/vector/app/test/fakes/FakeLoginWizard.kt | 6 ++++-- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt index 50e68dd324..254bca2c7b 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt @@ -60,6 +60,7 @@ import org.matrix.android.sdk.api.auth.login.LoginWizard import org.matrix.android.sdk.api.auth.registration.RegistrationWizard import org.matrix.android.sdk.api.failure.isHomeserverUnavailable import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.internal.auth.login.ResetCapabilities import timber.log.Timber import java.util.UUID import java.util.concurrent.CancellationException @@ -443,11 +444,11 @@ class OnboardingViewModel @AssistedInject constructor( setState { copy(isLoading = true) } currentJob = viewModelScope.launch { runCatching { safeLoginWizard.resetPassword(action.email) }.fold( - onSuccess = { + onSuccess = { resetCapabilities -> setState { copy( isLoading = false, - resetState = ResetState(email = action.email, newPassword = action.newPassword) + resetState = createResetState(action, resetCapabilities) ) } _viewEvents.post(OnboardingViewEvents.OnResetPasswordSendThreePidDone) @@ -460,6 +461,12 @@ class OnboardingViewModel @AssistedInject constructor( } } + private fun createResetState(action: OnboardingAction.ResetPassword, it: ResetCapabilities) = ResetState( + email = action.email, + newPassword = action.newPassword, + supportsLogoutAllDevices = it.supportsLogoutAllDevices + ) + private fun handleResetPasswordMailConfirmed() { setState { copy(isLoading = true) } currentJob = viewModelScope.launch { diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt index 680d2192ed..93d5892bf1 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt @@ -87,7 +87,8 @@ data class PersonalizationState( @Parcelize data class ResetState( val email: String? = null, - val newPassword: String? = null + val newPassword: String? = null, + val supportsLogoutAllDevices: Boolean = false ) : Parcelable @Parcelize diff --git a/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt b/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt index c5d24c0ec3..3cefeb46be 100644 --- a/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt @@ -52,6 +52,7 @@ import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.registration.Stage import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities +import org.matrix.android.sdk.internal.auth.login.ResetCapabilities private const val A_DISPLAY_NAME = "a display name" private const val A_PICTURE_FILENAME = "a-picture.png" @@ -67,6 +68,7 @@ private val A_HOMESERVER_CONFIG = HomeServerConnectionConfig(FakeUri().instance) private val SELECTED_HOMESERVER_STATE = SelectedHomeserverState(preferredLoginMode = LoginMode.Password) private const val AN_EMAIL = "hello@example.com" private const val A_PASSWORD = "a-password" +private val A_RESET_CAPABILITIES = ResetCapabilities(supportsLogoutAllDevices = true) class OnboardingViewModelTest { @@ -479,7 +481,7 @@ class OnboardingViewModelTest { @Test fun `given can successfully reset password, when resetting password, then emits reset done event`() = runTest { val test = viewModel.test() - fakeLoginWizard.givenResetPasswordSuccess(AN_EMAIL) + fakeLoginWizard.givenResetPasswordSuccess(AN_EMAIL, A_RESET_CAPABILITIES) fakeAuthenticationService.givenLoginWizard(fakeLoginWizard) viewModel.handle(OnboardingAction.ResetPassword(email = AN_EMAIL, newPassword = A_PASSWORD)) @@ -488,7 +490,10 @@ class OnboardingViewModelTest { .assertStatesChanges( initialState, { copy(isLoading = true) }, - { copy(isLoading = false, resetState = ResetState(AN_EMAIL, A_PASSWORD)) } + { + val resetState = ResetState(AN_EMAIL, A_PASSWORD, supportsLogoutAllDevices = A_RESET_CAPABILITIES.supportsLogoutAllDevices) + copy(isLoading = false, resetState = resetState) + } ) .assertEvents(OnboardingViewEvents.OnResetPasswordSendThreePidDone) .finish() diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeLoginWizard.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeLoginWizard.kt index 38bb75087c..c0f9f98f5f 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeLoginWizard.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeLoginWizard.kt @@ -16,14 +16,16 @@ package im.vector.app.test.fakes +import io.mockk.coEvery import io.mockk.coJustRun import io.mockk.mockk import org.matrix.android.sdk.api.auth.login.LoginWizard +import org.matrix.android.sdk.internal.auth.login.ResetCapabilities class FakeLoginWizard : LoginWizard by mockk() { - fun givenResetPasswordSuccess(email: String) { - coJustRun { resetPassword(email) } + fun givenResetPasswordSuccess(email: String, resetCapabilities: ResetCapabilities) { + coEvery { resetPassword(email) } returns resetCapabilities } fun givenConfirmResetPasswordSuccess(password: String) { From 62e8394218ecb028397d4c63cff967510510a32a Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 30 May 2022 17:38:50 +0100 Subject: [PATCH 05/12] adding changelog entry --- changelog.d/6191.sdk | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6191.sdk diff --git a/changelog.d/6191.sdk b/changelog.d/6191.sdk new file mode 100644 index 0000000000..d7fcf1b40f --- /dev/null +++ b/changelog.d/6191.sdk @@ -0,0 +1 @@ +Add support for MSC2457 - opting in or out of logging out all devices when changing password From 2d44e47e6a0956ba212422a5b36fd2f90d114186 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 31 May 2022 12:10:52 +0100 Subject: [PATCH 06/12] adding can control sign out homeserver version flag to the HomeserverCapabilities - Includes DB version update and HomeserverCapability migration --- .../database/RealmSessionStoreMigration.kt | 4 ++- .../database/migration/MigrateSessionTo029.kt | 2 +- .../database/migration/MigrateSessionTo031.kt | 31 +++++++++++++++++++ .../model/HomeServerCapabilitiesEntity.kt | 3 +- .../GetHomeServerCapabilitiesTask.kt | 2 ++ 5 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo031.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index 6a8589bc5e..665567bf2a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -48,6 +48,7 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo027 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo028 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo029 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo030 +import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo031 import org.matrix.android.sdk.internal.util.Normalizer import timber.log.Timber import javax.inject.Inject @@ -62,7 +63,7 @@ internal class RealmSessionStoreMigration @Inject constructor( override fun equals(other: Any?) = other is RealmSessionStoreMigration override fun hashCode() = 1000 - val schemaVersion = 30L + val schemaVersion = 31L override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { Timber.d("Migrating Realm Session from $oldVersion to $newVersion") @@ -97,5 +98,6 @@ internal class RealmSessionStoreMigration @Inject constructor( if (oldVersion < 28) MigrateSessionTo028(realm).perform() if (oldVersion < 29) MigrateSessionTo029(realm).perform() if (oldVersion < 30) MigrateSessionTo030(realm).perform() + if (oldVersion < 31) MigrateSessionTo031(realm).perform() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt index aebca11c2b..17dc0f7c82 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt @@ -25,7 +25,7 @@ import org.matrix.android.sdk.internal.util.database.RealmMigrator * Migrating to: * Live location sharing aggregated summary: adding new field userId. */ -internal class MigrateSessionTo029(realm: DynamicRealm) : RealmMigrator(realm, 28) { +internal class MigrateSessionTo029(realm: DynamicRealm) : RealmMigrator(realm, 29) { override fun doMigrate(realm: DynamicRealm) { realm.schema.get("LiveLocationShareAggregatedSummaryEntity") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo031.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo031.kt new file mode 100644 index 0000000000..e278b74756 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo031.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 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.database.migration + +import io.realm.DynamicRealm +import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields +import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities +import org.matrix.android.sdk.internal.util.database.RealmMigrator + +internal class MigrateSessionTo031(realm: DynamicRealm) : RealmMigrator(realm, 31) { + + override fun doMigrate(realm: DynamicRealm) { + realm.schema.get("HomeServerCapabilitiesEntity") + ?.addField(HomeServerCapabilitiesEntityFields.CAN_CONTROL_LOGOUT_DEVICES, Boolean::class.java) + ?.forceRefreshOfHomeServerCapabilities() + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt index 47a83f0ed9..9d90973f8a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt @@ -29,7 +29,8 @@ internal open class HomeServerCapabilitiesEntity( var lastVersionIdentityServerSupported: Boolean = false, var defaultIdentityServerUrl: String? = null, var lastUpdatedTimestamp: Long = 0L, - var canUseThreading: Boolean = false + var canUseThreading: Boolean = false, + var canControlLogoutDevices: Boolean = false ) : RealmObject() { companion object diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt index d22da8f6f2..add69dd8c7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt @@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orTrue import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.internal.auth.version.Versions +import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices import org.matrix.android.sdk.internal.auth.version.doesServerSupportThreads import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity @@ -142,6 +143,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( if (getVersionResult != null) { homeServerCapabilitiesEntity.lastVersionIdentityServerSupported = getVersionResult.isLoginAndRegistrationSupportedBySdk() + homeServerCapabilitiesEntity.canControlLogoutDevices = getVersionResult.doesServerSupportLogoutDevices() } if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) { From 6e3283cb3490406d9498a16dc6317559d0ee939a Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 31 May 2022 12:50:26 +0100 Subject: [PATCH 07/12] moving homeserver feature for logout all devices to the selected homeserver state via the LoginFlowResult --- .../sdk/api/auth/data/LoginFlowResult.kt | 3 ++- .../android/sdk/api/auth/login/LoginWizard.kt | 4 +-- .../auth/DefaultAuthenticationService.kt | 4 ++- .../internal/auth/login/DefaultLoginWizard.kt | 9 +------ .../internal/auth/login/ResetCapabilities.kt | 27 ------------------- .../onboarding/OnboardingViewModel.kt | 10 +++---- .../onboarding/OnboardingViewState.kt | 1 + .../StartAuthenticationFlowUseCase.kt | 3 ++- .../onboarding/OnboardingViewModelTest.kt | 8 +++--- .../StartAuthenticationFlowUseCaseTest.kt | 3 ++- .../vector/app/test/fakes/FakeLoginWizard.kt | 6 ++--- 11 files changed, 23 insertions(+), 55 deletions(-) delete mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetCapabilities.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/LoginFlowResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/LoginFlowResult.kt index 7d1407c0d8..5b6c1897bf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/LoginFlowResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/LoginFlowResult.kt @@ -21,5 +21,6 @@ data class LoginFlowResult( val ssoIdentityProviders: List?, val isLoginAndRegistrationSupported: Boolean, val homeServerUrl: String, - val isOutdatedHomeserver: Boolean + val isOutdatedHomeserver: Boolean, + val isLogoutDevicesSupported: Boolean ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt index 638ff079c4..27a4618737 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.api.auth.login import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.util.JsonDict -import org.matrix.android.sdk.internal.auth.login.ResetCapabilities /** * Set of methods to be able to login to an existing account on a homeserver. @@ -66,9 +65,8 @@ interface LoginWizard { * [resetPasswordMailConfirmed] is successfully called. * * @param email an email previously associated to the account the user wants the password to be reset. - * @return a [ResetCapabilities] if the reset is successful. */ - suspend fun resetPassword(email: String): ResetCapabilities + suspend fun resetPassword(email: String) /** * Confirm the new password, once the user has checked their email diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 92852e4722..9d6b018a67 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -40,6 +40,7 @@ import org.matrix.android.sdk.internal.auth.login.DefaultLoginWizard import org.matrix.android.sdk.internal.auth.login.DirectLoginTask import org.matrix.android.sdk.internal.auth.registration.DefaultRegistrationWizard import org.matrix.android.sdk.internal.auth.version.Versions +import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk import org.matrix.android.sdk.internal.auth.version.isSupportedBySdk import org.matrix.android.sdk.internal.di.Unauthenticated @@ -292,7 +293,8 @@ internal class DefaultAuthenticationService @Inject constructor( ssoIdentityProviders = loginFlowResponse.flows.orEmpty().firstOrNull { it.type == LoginFlowTypes.SSO }?.ssoIdentityProvider, isLoginAndRegistrationSupported = versions.isLoginAndRegistrationSupportedBySdk(), homeServerUrl = homeServerUrl, - isOutdatedHomeserver = !versions.isSupportedBySdk() + isOutdatedHomeserver = !versions.isSupportedBySdk(), + isLogoutDevicesSupported = versions.doesServerSupportLogoutDevices() ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt index 0d73d398fc..656a4f671b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt @@ -31,7 +31,6 @@ import org.matrix.android.sdk.internal.auth.data.TokenLoginParams import org.matrix.android.sdk.internal.auth.db.PendingSessionData import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistrationParams import org.matrix.android.sdk.internal.auth.registration.RegisterAddThreePidTask -import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.content.DefaultContentUrlResolver import org.matrix.android.sdk.internal.session.contentscanner.DisabledContentScannerService @@ -104,7 +103,7 @@ internal class DefaultLoginWizard( return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig) } - override suspend fun resetPassword(email: String): ResetCapabilities { + override suspend fun resetPassword(email: String) { val param = RegisterAddThreePidTask.Params( RegisterThreePid.Email(email), pendingSessionData.clientSecret, @@ -120,12 +119,6 @@ internal class DefaultLoginWizard( pendingSessionData = pendingSessionData.copy(resetPasswordData = ResetPasswordData(result)) .also { pendingSessionStore.savePendingSessionData(it) } - - val versions = executeRequest(null) { - authAPI.versions() - } - - return ResetCapabilities(supportsLogoutAllDevices = versions.doesServerSupportLogoutDevices()) } override suspend fun resetPasswordMailConfirmed(newPassword: String, logoutAllDevices: Boolean) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetCapabilities.kt deleted file mode 100644 index ed3b473062..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetCapabilities.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2022 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 org.matrix.android.sdk.internal.auth.login - -/** - * The reset capabilities of the selected Homeserver - */ -data class ResetCapabilities( - /** - * True if the server supports MSC2457 `logout_devices` parameter when setting a new password. - */ - val supportsLogoutAllDevices: Boolean -) diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt index 254bca2c7b..38a72441e0 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt @@ -60,7 +60,6 @@ import org.matrix.android.sdk.api.auth.login.LoginWizard import org.matrix.android.sdk.api.auth.registration.RegistrationWizard import org.matrix.android.sdk.api.failure.isHomeserverUnavailable import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.internal.auth.login.ResetCapabilities import timber.log.Timber import java.util.UUID import java.util.concurrent.CancellationException @@ -444,11 +443,12 @@ class OnboardingViewModel @AssistedInject constructor( setState { copy(isLoading = true) } currentJob = viewModelScope.launch { runCatching { safeLoginWizard.resetPassword(action.email) }.fold( - onSuccess = { resetCapabilities -> + onSuccess = { + val state = awaitState() setState { copy( isLoading = false, - resetState = createResetState(action, resetCapabilities) + resetState = createResetState(action, state.selectedHomeserver) ) } _viewEvents.post(OnboardingViewEvents.OnResetPasswordSendThreePidDone) @@ -461,10 +461,10 @@ class OnboardingViewModel @AssistedInject constructor( } } - private fun createResetState(action: OnboardingAction.ResetPassword, it: ResetCapabilities) = ResetState( + private fun createResetState(action: OnboardingAction.ResetPassword, selectedHomeserverState: SelectedHomeserverState) = ResetState( email = action.email, newPassword = action.newPassword, - supportsLogoutAllDevices = it.supportsLogoutAllDevices + supportsLogoutAllDevices = selectedHomeserverState.isLogoutDevicesSupported ) private fun handleResetPasswordMailConfirmed() { diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt index 93d5892bf1..c072f13bca 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt @@ -71,6 +71,7 @@ data class SelectedHomeserverState( val upstreamUrl: String? = null, val preferredLoginMode: LoginMode = LoginMode.Unknown, val supportedLoginTypes: List = emptyList(), + val isLogoutDevicesSupported: Boolean = false, ) : Parcelable @Parcelize diff --git a/vector/src/main/java/im/vector/app/features/onboarding/StartAuthenticationFlowUseCase.kt b/vector/src/main/java/im/vector/app/features/onboarding/StartAuthenticationFlowUseCase.kt index 922258778b..7b6205bfce 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/StartAuthenticationFlowUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/StartAuthenticationFlowUseCase.kt @@ -53,7 +53,8 @@ class StartAuthenticationFlowUseCase @Inject constructor( userFacingUrl = config.homeServerUri.toString(), upstreamUrl = authFlow.homeServerUrl, preferredLoginMode = preferredLoginMode, - supportedLoginTypes = authFlow.supportedLoginTypes + supportedLoginTypes = authFlow.supportedLoginTypes, + isLogoutDevicesSupported = authFlow.isLogoutDevicesSupported ) private fun matrixOrgUrl() = stringProvider.getString(R.string.matrix_org_server_url).ensureTrailingSlash() diff --git a/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt b/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt index 3cefeb46be..933e9aa972 100644 --- a/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt @@ -52,7 +52,6 @@ import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.registration.Stage import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities -import org.matrix.android.sdk.internal.auth.login.ResetCapabilities private const val A_DISPLAY_NAME = "a display name" private const val A_PICTURE_FILENAME = "a-picture.png" @@ -66,9 +65,9 @@ private val A_DIRECT_LOGIN = OnboardingAction.AuthenticateAction.LoginDirect("@a private const val A_HOMESERVER_URL = "https://edited-homeserver.org" private val A_HOMESERVER_CONFIG = HomeServerConnectionConfig(FakeUri().instance) private val SELECTED_HOMESERVER_STATE = SelectedHomeserverState(preferredLoginMode = LoginMode.Password) +private val SELECTED_HOMESERVER_STATE_SUPPORTED_LOGOUT_DEVICES = SelectedHomeserverState(isLogoutDevicesSupported = true) private const val AN_EMAIL = "hello@example.com" private const val A_PASSWORD = "a-password" -private val A_RESET_CAPABILITIES = ResetCapabilities(supportsLogoutAllDevices = true) class OnboardingViewModelTest { @@ -480,8 +479,9 @@ class OnboardingViewModelTest { @Test fun `given can successfully reset password, when resetting password, then emits reset done event`() = runTest { + viewModelWith(initialState.copy(selectedHomeserver = SELECTED_HOMESERVER_STATE_SUPPORTED_LOGOUT_DEVICES)) val test = viewModel.test() - fakeLoginWizard.givenResetPasswordSuccess(AN_EMAIL, A_RESET_CAPABILITIES) + fakeLoginWizard.givenResetPasswordSuccess(AN_EMAIL) fakeAuthenticationService.givenLoginWizard(fakeLoginWizard) viewModel.handle(OnboardingAction.ResetPassword(email = AN_EMAIL, newPassword = A_PASSWORD)) @@ -491,7 +491,7 @@ class OnboardingViewModelTest { initialState, { copy(isLoading = true) }, { - val resetState = ResetState(AN_EMAIL, A_PASSWORD, supportsLogoutAllDevices = A_RESET_CAPABILITIES.supportsLogoutAllDevices) + val resetState = ResetState(AN_EMAIL, A_PASSWORD, supportsLogoutAllDevices = true) copy(isLoading = false, resetState = resetState) } ) diff --git a/vector/src/test/java/im/vector/app/features/onboarding/StartAuthenticationFlowUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/onboarding/StartAuthenticationFlowUseCaseTest.kt index b75ec231fd..810f2b43c9 100644 --- a/vector/src/test/java/im/vector/app/features/onboarding/StartAuthenticationFlowUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/onboarding/StartAuthenticationFlowUseCaseTest.kt @@ -128,7 +128,8 @@ class StartAuthenticationFlowUseCaseTest { ssoIdentityProviders = SSO_IDENTITY_PROVIDERS, isLoginAndRegistrationSupported = true, homeServerUrl = A_DECLARED_HOMESERVER_URL, - isOutdatedHomeserver = false + isOutdatedHomeserver = false, + isLogoutDevicesSupported = false ) private fun expectedResult( diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeLoginWizard.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeLoginWizard.kt index c0f9f98f5f..38bb75087c 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeLoginWizard.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeLoginWizard.kt @@ -16,16 +16,14 @@ package im.vector.app.test.fakes -import io.mockk.coEvery import io.mockk.coJustRun import io.mockk.mockk import org.matrix.android.sdk.api.auth.login.LoginWizard -import org.matrix.android.sdk.internal.auth.login.ResetCapabilities class FakeLoginWizard : LoginWizard by mockk() { - fun givenResetPasswordSuccess(email: String, resetCapabilities: ResetCapabilities) { - coEvery { resetPassword(email) } returns resetCapabilities + fun givenResetPasswordSuccess(email: String) { + coJustRun { resetPassword(email) } } fun givenConfirmResetPasswordSuccess(password: String) { From d9fd627bb12d8678234c68ca38b843ea8b8d5912 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 31 May 2022 12:54:45 +0100 Subject: [PATCH 08/12] passing the control of logout devices to the homeserver capabilities model from the entity --- .../sdk/api/session/homeserver/HomeServerCapabilities.kt | 7 ++++++- .../database/mapper/HomeServerCapabilitiesMapper.kt | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt index c78fb9cf79..b5d6d891e4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt @@ -54,7 +54,12 @@ data class HomeServerCapabilities( /** * True if the home server support threading. */ - val canUseThreading: Boolean = false + val canUseThreading: Boolean = false, + + /** + * True if the home server supports controlling the logout of all devices when changing password. + */ + val canControlLogoutDevices: Boolean = false ) { enum class RoomCapabilitySupport { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt index 20af43530c..184a0108b9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt @@ -42,7 +42,8 @@ internal object HomeServerCapabilitiesMapper { lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported, defaultIdentityServerUrl = entity.defaultIdentityServerUrl, roomVersions = mapRoomVersion(entity.roomVersionsJson), - canUseThreading = entity.canUseThreading + canUseThreading = entity.canUseThreading, + canControlLogoutDevices = entity.canControlLogoutDevices ) } From 4f091606974c2857e7c3e1c6616bd5c532272ae2 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 31 May 2022 13:21:09 +0100 Subject: [PATCH 09/12] adding logout_devices parameter to the password change sdk api, matching reset password --- .../matrix/android/sdk/api/auth/login/LoginWizard.kt | 5 ++--- .../android/sdk/api/session/account/AccountService.kt | 8 ++++---- .../internal/session/account/ChangePasswordParams.kt | 10 +++++++--- .../sdk/internal/session/account/ChangePasswordTask.kt | 5 +++-- .../internal/session/account/DefaultAccountService.kt | 4 ++-- .../features/settings/VectorSettingsGeneralFragment.kt | 4 +++- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt index 27a4618737..145cdbdc22 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt @@ -73,9 +73,8 @@ interface LoginWizard { * When this method succeed, tha account password will be effectively modified. * * @param newPassword the desired new password. - * @param logoutAllDevices when true, all devices will be logged out. False values will only be taken into account - * if [ResetCapabilities.supportsLogoutAllDevices] is supported. - * When [ResetCapabilities.supportsLogoutAllDevices] is false the default behaviour is to logout all devices. + * @param logoutAllDevices defaults to true, all devices will be logged out. False values will only be taken into account + * if [org.matrix.android.sdk.api.auth.data.LoginFlowResult.isLogoutDevicesSupported] is true. */ suspend fun resetPasswordMailConfirmed(newPassword: String, logoutAllDevices: Boolean = true) } 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 e3d52adfc5..094c66f6f7 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 @@ -24,13 +24,13 @@ import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor interface AccountService { /** * Ask the homeserver to change the password. + * * @param password Current password. * @param newPassword New password + * @param logoutAllDevices defaults to true, all devices will be logged out. False values will only be taken into account + * if [org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities.canControlLogoutDevices] is true. */ - suspend fun changePassword( - password: String, - newPassword: String - ) + suspend fun changePassword(password: String, newPassword: String, logoutAllDevices: Boolean = true) /** * Deactivate the account. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt index 1b95820918..ffe7eba9cb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt @@ -29,13 +29,17 @@ internal data class ChangePasswordParams( val auth: UserPasswordAuth? = null, @Json(name = "new_password") - val newPassword: String? = null + val newPassword: String? = null, + + @Json(name = "logout_devices") + val logoutDevices: Boolean = true ) { companion object { - fun create(userId: String, oldPassword: String, newPassword: String): ChangePasswordParams { + fun create(userId: String, oldPassword: String, newPassword: String, logoutDevices: Boolean): ChangePasswordParams { return ChangePasswordParams( auth = UserPasswordAuth(user = userId, password = oldPassword), - newPassword = newPassword + newPassword = newPassword, + logoutDevices = logoutDevices ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordTask.kt index 7b21ba2e63..e767950ff7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordTask.kt @@ -26,7 +26,8 @@ import javax.inject.Inject internal interface ChangePasswordTask : Task { data class Params( val password: String, - val newPassword: String + val newPassword: String, + val logoutAllDevices: Boolean ) } @@ -37,7 +38,7 @@ internal class DefaultChangePasswordTask @Inject constructor( ) : ChangePasswordTask { override suspend fun execute(params: ChangePasswordTask.Params) { - val changePasswordParams = ChangePasswordParams.create(userId, params.password, params.newPassword) + val changePasswordParams = ChangePasswordParams.create(userId, params.password, params.newPassword, params.logoutAllDevices) try { executeRequest(globalErrorReceiver) { accountAPI.changePassword(changePasswordParams) 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 bb830a5e41..9d03ec479b 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 @@ -25,8 +25,8 @@ internal class DefaultAccountService @Inject constructor( private val deactivateAccountTask: DeactivateAccountTask ) : AccountService { - override suspend fun changePassword(password: String, newPassword: String) { - changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword)) + override suspend fun changePassword(password: String, newPassword: String, logoutAllDevices: Boolean) { + changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword, logoutAllDevices)) } override suspend fun deactivateAccount(eraseAllData: Boolean, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt index 99acea79df..8075adba93 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt @@ -66,6 +66,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.api.session.getUser +import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerConfig import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService import org.matrix.android.sdk.flow.flow @@ -178,9 +179,10 @@ class VectorSettingsGeneralFragment @Inject constructor( } } + val homeServerCapabilities = session.homeServerCapabilitiesService().getHomeServerCapabilities() // Password // Hide the preference if password can not be updated - if (session.homeServerCapabilitiesService().getHomeServerCapabilities().canChangePassword) { + if (homeServerCapabilities.canChangePassword) { mPasswordPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener { onPasswordUpdateClick() false From 7ac46a2fd153a180c1605d23776eeb2f40edc447 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 31 May 2022 14:03:32 +0100 Subject: [PATCH 10/12] using consistent parameter name --- .../sdk/internal/session/account/ChangePasswordParams.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt index ffe7eba9cb..f6778327d9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt @@ -35,11 +35,11 @@ internal data class ChangePasswordParams( val logoutDevices: Boolean = true ) { companion object { - fun create(userId: String, oldPassword: String, newPassword: String, logoutDevices: Boolean): ChangePasswordParams { + fun create(userId: String, oldPassword: String, newPassword: String, logoutAllDevices: Boolean): ChangePasswordParams { return ChangePasswordParams( auth = UserPasswordAuth(user = userId, password = oldPassword), newPassword = newPassword, - logoutDevices = logoutDevices + logoutDevices = logoutAllDevices ) } } From c6ef972e3c7dadb9f19968e159622a4766e95856 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 1 Jun 2022 14:38:28 +0100 Subject: [PATCH 11/12] adding missing fullstop and removing unused import --- .../org/matrix/android/sdk/internal/auth/version/Versions.kt | 2 +- .../app/features/settings/VectorSettingsGeneralFragment.kt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt index 4e53f4d3f9..915b25134b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt @@ -112,7 +112,7 @@ private fun Versions.doesServerSeparatesAddAndBind(): Boolean { } /** - * Indicate if the server supports MSC2457 `logout_devices` parameter when setting a new password + * Indicate if the server supports MSC2457 `logout_devices` parameter when setting a new password. * * @return true if logout_devices is supported */ diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt index 8075adba93..7906de3796 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt @@ -66,7 +66,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.api.session.getUser -import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerConfig import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService import org.matrix.android.sdk.flow.flow From e655a540649c3d40ba80a5e8d64286bd37b7f972 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 8 Jun 2022 12:03:24 +0100 Subject: [PATCH 12/12] removing duplicate fake method --- .../im/vector/app/test/fakes/FakeAuthenticationService.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeAuthenticationService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeAuthenticationService.kt index 335cc90d42..cc606497f5 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeAuthenticationService.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeAuthenticationService.kt @@ -41,10 +41,6 @@ class FakeAuthenticationService : AuthenticationService by mockk() { every { getLoginWizard() } returns loginWizard } - fun givenLoginWizard(loginWizard: LoginWizard) { - every { getLoginWizard() } returns loginWizard - } - fun givenLoginFlow(config: HomeServerConnectionConfig, result: LoginFlowResult) { coEvery { getLoginFlow(config) } returns result }