mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-09 00:29:00 +01:00
Merge pull request #6207 from vector-im/feature/adm/sdk-signout-all-devices
SDK - Logout all devices
This commit is contained in:
commit
ccb4f2d1dd
1
changelog.d/6191.sdk
Normal file
1
changelog.d/6191.sdk
Normal file
@ -0,0 +1 @@
|
|||||||
|
Add support for MSC2457 - opting in or out of logging out all devices when changing password
|
@ -21,5 +21,6 @@ data class LoginFlowResult(
|
|||||||
val ssoIdentityProviders: List<SsoIdentityProvider>?,
|
val ssoIdentityProviders: List<SsoIdentityProvider>?,
|
||||||
val isLoginAndRegistrationSupported: Boolean,
|
val isLoginAndRegistrationSupported: Boolean,
|
||||||
val homeServerUrl: String,
|
val homeServerUrl: String,
|
||||||
val isOutdatedHomeserver: Boolean
|
val isOutdatedHomeserver: Boolean,
|
||||||
|
val isLogoutDevicesSupported: Boolean
|
||||||
)
|
)
|
||||||
|
@ -72,7 +72,9 @@ interface LoginWizard {
|
|||||||
* Confirm the new password, once the user has checked their email
|
* Confirm the new password, once the user has checked their email
|
||||||
* When this method succeed, tha account password will be effectively modified.
|
* 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 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)
|
suspend fun resetPasswordMailConfirmed(newPassword: String, logoutAllDevices: Boolean = true)
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,13 @@ import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
|||||||
interface AccountService {
|
interface AccountService {
|
||||||
/**
|
/**
|
||||||
* Ask the homeserver to change the password.
|
* Ask the homeserver to change the password.
|
||||||
|
*
|
||||||
* @param password Current password.
|
* @param password Current password.
|
||||||
* @param newPassword New 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(
|
suspend fun changePassword(password: String, newPassword: String, logoutAllDevices: Boolean = true)
|
||||||
password: String,
|
|
||||||
newPassword: String
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deactivate the account.
|
* Deactivate the account.
|
||||||
|
@ -54,7 +54,12 @@ data class HomeServerCapabilities(
|
|||||||
/**
|
/**
|
||||||
* True if the home server support threading.
|
* 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 {
|
enum class RoomCapabilitySupport {
|
||||||
|
@ -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.login.DirectLoginTask
|
||||||
import org.matrix.android.sdk.internal.auth.registration.DefaultRegistrationWizard
|
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.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.isLoginAndRegistrationSupportedBySdk
|
||||||
import org.matrix.android.sdk.internal.auth.version.isSupportedBySdk
|
import org.matrix.android.sdk.internal.auth.version.isSupportedBySdk
|
||||||
import org.matrix.android.sdk.internal.di.Unauthenticated
|
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,
|
ssoIdentityProviders = loginFlowResponse.flows.orEmpty().firstOrNull { it.type == LoginFlowTypes.SSO }?.ssoIdentityProvider,
|
||||||
isLoginAndRegistrationSupported = versions.isLoginAndRegistrationSupportedBySdk(),
|
isLoginAndRegistrationSupported = versions.isLoginAndRegistrationSupportedBySdk(),
|
||||||
homeServerUrl = homeServerUrl,
|
homeServerUrl = homeServerUrl,
|
||||||
isOutdatedHomeserver = !versions.isSupportedBySdk()
|
isOutdatedHomeserver = !versions.isSupportedBySdk(),
|
||||||
|
isLogoutDevicesSupported = versions.doesServerSupportLogoutDevices()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,12 +121,13 @@ internal class DefaultLoginWizard(
|
|||||||
.also { pendingSessionStore.savePendingSessionData(it) }
|
.also { pendingSessionStore.savePendingSessionData(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
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 resetPasswordData = pendingSessionData.resetPasswordData ?: throw IllegalStateException("Developer error - Must call resetPassword first")
|
||||||
val param = ResetPasswordMailConfirmed.create(
|
val param = ResetPasswordMailConfirmed.create(
|
||||||
pendingSessionData.clientSecret,
|
pendingSessionData.clientSecret,
|
||||||
resetPasswordData.addThreePidRegistrationResponse.sid,
|
resetPasswordData.addThreePidRegistrationResponse.sid,
|
||||||
newPassword
|
newPassword,
|
||||||
|
logoutAllDevices
|
||||||
)
|
)
|
||||||
|
|
||||||
executeRequest(null) {
|
executeRequest(null) {
|
||||||
|
@ -30,13 +30,17 @@ internal data class ResetPasswordMailConfirmed(
|
|||||||
|
|
||||||
// the new password
|
// the new password
|
||||||
@Json(name = "new_password")
|
@Json(name = "new_password")
|
||||||
val newPassword: String? = null
|
val newPassword: String? = null,
|
||||||
|
|
||||||
|
@Json(name = "logout_devices")
|
||||||
|
val logoutDevices: Boolean? = null
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun create(clientSecret: String, sid: String, newPassword: String): ResetPasswordMailConfirmed {
|
fun create(clientSecret: String, sid: String, newPassword: String, logoutDevices: Boolean?): ResetPasswordMailConfirmed {
|
||||||
return ResetPasswordMailConfirmed(
|
return ResetPasswordMailConfirmed(
|
||||||
auth = AuthParams.createForResetPassword(clientSecret, sid),
|
auth = AuthParams.createForResetPassword(clientSecret, sid),
|
||||||
newPassword = newPassword
|
newPassword = newPassword,
|
||||||
|
logoutDevices = logoutDevices
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ internal data class HomeServerVersion(
|
|||||||
val r0_4_0 = HomeServerVersion(major = 0, minor = 4, patch = 0)
|
val r0_4_0 = HomeServerVersion(major = 0, minor = 4, patch = 0)
|
||||||
val r0_5_0 = HomeServerVersion(major = 0, minor = 5, 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_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)
|
val v1_3_0 = HomeServerVersion(major = 1, minor = 3, patch = 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,15 @@ private fun Versions.doesServerSeparatesAddAndBind(): Boolean {
|
|||||||
unstableFeatures?.get(FEATURE_SEPARATE_ADD_AND_BIND) ?: false
|
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 {
|
private fun Versions.getMaxVersion(): HomeServerVersion {
|
||||||
return supportedVersions
|
return supportedVersions
|
||||||
?.mapNotNull { HomeServerVersion.parse(it) }
|
?.mapNotNull { HomeServerVersion.parse(it) }
|
||||||
|
@ -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.MigrateSessionTo028
|
||||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo029
|
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.MigrateSessionTo030
|
||||||
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo031
|
||||||
import org.matrix.android.sdk.internal.util.Normalizer
|
import org.matrix.android.sdk.internal.util.Normalizer
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -62,7 +63,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||||||
override fun equals(other: Any?) = other is RealmSessionStoreMigration
|
override fun equals(other: Any?) = other is RealmSessionStoreMigration
|
||||||
override fun hashCode() = 1000
|
override fun hashCode() = 1000
|
||||||
|
|
||||||
val schemaVersion = 30L
|
val schemaVersion = 31L
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
Timber.d("Migrating Realm Session from $oldVersion to $newVersion")
|
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 < 28) MigrateSessionTo028(realm).perform()
|
||||||
if (oldVersion < 29) MigrateSessionTo029(realm).perform()
|
if (oldVersion < 29) MigrateSessionTo029(realm).perform()
|
||||||
if (oldVersion < 30) MigrateSessionTo030(realm).perform()
|
if (oldVersion < 30) MigrateSessionTo030(realm).perform()
|
||||||
|
if (oldVersion < 31) MigrateSessionTo031(realm).perform()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,8 @@ internal object HomeServerCapabilitiesMapper {
|
|||||||
lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported,
|
lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported,
|
||||||
defaultIdentityServerUrl = entity.defaultIdentityServerUrl,
|
defaultIdentityServerUrl = entity.defaultIdentityServerUrl,
|
||||||
roomVersions = mapRoomVersion(entity.roomVersionsJson),
|
roomVersions = mapRoomVersion(entity.roomVersionsJson),
|
||||||
canUseThreading = entity.canUseThreading
|
canUseThreading = entity.canUseThreading,
|
||||||
|
canControlLogoutDevices = entity.canControlLogoutDevices
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
|||||||
* Migrating to:
|
* Migrating to:
|
||||||
* Live location sharing aggregated summary: adding new field userId.
|
* 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) {
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
|
realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
@ -29,7 +29,8 @@ internal open class HomeServerCapabilitiesEntity(
|
|||||||
var lastVersionIdentityServerSupported: Boolean = false,
|
var lastVersionIdentityServerSupported: Boolean = false,
|
||||||
var defaultIdentityServerUrl: String? = null,
|
var defaultIdentityServerUrl: String? = null,
|
||||||
var lastUpdatedTimestamp: Long = 0L,
|
var lastUpdatedTimestamp: Long = 0L,
|
||||||
var canUseThreading: Boolean = false
|
var canUseThreading: Boolean = false,
|
||||||
|
var canControlLogoutDevices: Boolean = false
|
||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
companion object
|
companion object
|
||||||
|
@ -29,13 +29,17 @@ internal data class ChangePasswordParams(
|
|||||||
val auth: UserPasswordAuth? = null,
|
val auth: UserPasswordAuth? = null,
|
||||||
|
|
||||||
@Json(name = "new_password")
|
@Json(name = "new_password")
|
||||||
val newPassword: String? = null
|
val newPassword: String? = null,
|
||||||
|
|
||||||
|
@Json(name = "logout_devices")
|
||||||
|
val logoutDevices: Boolean = true
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun create(userId: String, oldPassword: String, newPassword: String): ChangePasswordParams {
|
fun create(userId: String, oldPassword: String, newPassword: String, logoutAllDevices: Boolean): ChangePasswordParams {
|
||||||
return ChangePasswordParams(
|
return ChangePasswordParams(
|
||||||
auth = UserPasswordAuth(user = userId, password = oldPassword),
|
auth = UserPasswordAuth(user = userId, password = oldPassword),
|
||||||
newPassword = newPassword
|
newPassword = newPassword,
|
||||||
|
logoutDevices = logoutAllDevices
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,8 @@ import javax.inject.Inject
|
|||||||
internal interface ChangePasswordTask : Task<ChangePasswordTask.Params, Unit> {
|
internal interface ChangePasswordTask : Task<ChangePasswordTask.Params, Unit> {
|
||||||
data class Params(
|
data class Params(
|
||||||
val password: String,
|
val password: String,
|
||||||
val newPassword: String
|
val newPassword: String,
|
||||||
|
val logoutAllDevices: Boolean
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ internal class DefaultChangePasswordTask @Inject constructor(
|
|||||||
) : ChangePasswordTask {
|
) : ChangePasswordTask {
|
||||||
|
|
||||||
override suspend fun execute(params: ChangePasswordTask.Params) {
|
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 {
|
try {
|
||||||
executeRequest(globalErrorReceiver) {
|
executeRequest(globalErrorReceiver) {
|
||||||
accountAPI.changePassword(changePasswordParams)
|
accountAPI.changePassword(changePasswordParams)
|
||||||
|
@ -25,8 +25,8 @@ internal class DefaultAccountService @Inject constructor(
|
|||||||
private val deactivateAccountTask: DeactivateAccountTask
|
private val deactivateAccountTask: DeactivateAccountTask
|
||||||
) : AccountService {
|
) : AccountService {
|
||||||
|
|
||||||
override suspend fun changePassword(password: String, newPassword: String) {
|
override suspend fun changePassword(password: String, newPassword: String, logoutAllDevices: Boolean) {
|
||||||
changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword))
|
changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword, logoutAllDevices))
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deactivateAccount(eraseAllData: Boolean, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) {
|
override suspend fun deactivateAccount(eraseAllData: Boolean, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) {
|
||||||
|
@ -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.extensions.orTrue
|
||||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
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.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.doesServerSupportThreads
|
||||||
import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk
|
import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk
|
||||||
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
||||||
@ -142,6 +143,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
|||||||
|
|
||||||
if (getVersionResult != null) {
|
if (getVersionResult != null) {
|
||||||
homeServerCapabilitiesEntity.lastVersionIdentityServerSupported = getVersionResult.isLoginAndRegistrationSupportedBySdk()
|
homeServerCapabilitiesEntity.lastVersionIdentityServerSupported = getVersionResult.isLoginAndRegistrationSupportedBySdk()
|
||||||
|
homeServerCapabilitiesEntity.canControlLogoutDevices = getVersionResult.doesServerSupportLogoutDevices()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) {
|
if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) {
|
||||||
|
@ -444,10 +444,11 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
currentJob = viewModelScope.launch {
|
currentJob = viewModelScope.launch {
|
||||||
runCatching { safeLoginWizard.resetPassword(action.email) }.fold(
|
runCatching { safeLoginWizard.resetPassword(action.email) }.fold(
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
|
val state = awaitState()
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
resetState = ResetState(email = action.email, newPassword = action.newPassword)
|
resetState = createResetState(action, state.selectedHomeserver)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_viewEvents.post(OnboardingViewEvents.OnResetPasswordSendThreePidDone)
|
_viewEvents.post(OnboardingViewEvents.OnResetPasswordSendThreePidDone)
|
||||||
@ -460,6 +461,12 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createResetState(action: OnboardingAction.ResetPassword, selectedHomeserverState: SelectedHomeserverState) = ResetState(
|
||||||
|
email = action.email,
|
||||||
|
newPassword = action.newPassword,
|
||||||
|
supportsLogoutAllDevices = selectedHomeserverState.isLogoutDevicesSupported
|
||||||
|
)
|
||||||
|
|
||||||
private fun handleResetPasswordMailConfirmed() {
|
private fun handleResetPasswordMailConfirmed() {
|
||||||
setState { copy(isLoading = true) }
|
setState { copy(isLoading = true) }
|
||||||
currentJob = viewModelScope.launch {
|
currentJob = viewModelScope.launch {
|
||||||
|
@ -71,6 +71,7 @@ data class SelectedHomeserverState(
|
|||||||
val upstreamUrl: String? = null,
|
val upstreamUrl: String? = null,
|
||||||
val preferredLoginMode: LoginMode = LoginMode.Unknown,
|
val preferredLoginMode: LoginMode = LoginMode.Unknown,
|
||||||
val supportedLoginTypes: List<String> = emptyList(),
|
val supportedLoginTypes: List<String> = emptyList(),
|
||||||
|
val isLogoutDevicesSupported: Boolean = false,
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@ -88,6 +89,7 @@ data class PersonalizationState(
|
|||||||
data class ResetState(
|
data class ResetState(
|
||||||
val email: String? = null,
|
val email: String? = null,
|
||||||
val newPassword: String? = null,
|
val newPassword: String? = null,
|
||||||
|
val supportsLogoutAllDevices: Boolean = false
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
@ -53,7 +53,8 @@ class StartAuthenticationFlowUseCase @Inject constructor(
|
|||||||
userFacingUrl = config.homeServerUri.toString(),
|
userFacingUrl = config.homeServerUri.toString(),
|
||||||
upstreamUrl = authFlow.homeServerUrl,
|
upstreamUrl = authFlow.homeServerUrl,
|
||||||
preferredLoginMode = preferredLoginMode,
|
preferredLoginMode = preferredLoginMode,
|
||||||
supportedLoginTypes = authFlow.supportedLoginTypes
|
supportedLoginTypes = authFlow.supportedLoginTypes,
|
||||||
|
isLogoutDevicesSupported = authFlow.isLogoutDevicesSupported
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun matrixOrgUrl() = stringProvider.getString(R.string.matrix_org_server_url).ensureTrailingSlash()
|
private fun matrixOrgUrl() = stringProvider.getString(R.string.matrix_org_server_url).ensureTrailingSlash()
|
||||||
|
@ -178,9 +178,10 @@ class VectorSettingsGeneralFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val homeServerCapabilities = session.homeServerCapabilitiesService().getHomeServerCapabilities()
|
||||||
// Password
|
// Password
|
||||||
// Hide the preference if password can not be updated
|
// Hide the preference if password can not be updated
|
||||||
if (session.homeServerCapabilitiesService().getHomeServerCapabilities().canChangePassword) {
|
if (homeServerCapabilities.canChangePassword) {
|
||||||
mPasswordPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
mPasswordPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
onPasswordUpdateClick()
|
onPasswordUpdateClick()
|
||||||
false
|
false
|
||||||
|
@ -65,6 +65,7 @@ private val A_DIRECT_LOGIN = OnboardingAction.AuthenticateAction.LoginDirect("@a
|
|||||||
private const val A_HOMESERVER_URL = "https://edited-homeserver.org"
|
private const val A_HOMESERVER_URL = "https://edited-homeserver.org"
|
||||||
private val A_HOMESERVER_CONFIG = HomeServerConnectionConfig(FakeUri().instance)
|
private val A_HOMESERVER_CONFIG = HomeServerConnectionConfig(FakeUri().instance)
|
||||||
private val SELECTED_HOMESERVER_STATE = SelectedHomeserverState(preferredLoginMode = LoginMode.Password)
|
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 AN_EMAIL = "hello@example.com"
|
||||||
private const val A_PASSWORD = "a-password"
|
private const val A_PASSWORD = "a-password"
|
||||||
|
|
||||||
@ -478,6 +479,7 @@ class OnboardingViewModelTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given can successfully reset password, when resetting password, then emits reset done event`() = runTest {
|
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()
|
val test = viewModel.test()
|
||||||
fakeLoginWizard.givenResetPasswordSuccess(AN_EMAIL)
|
fakeLoginWizard.givenResetPasswordSuccess(AN_EMAIL)
|
||||||
fakeAuthenticationService.givenLoginWizard(fakeLoginWizard)
|
fakeAuthenticationService.givenLoginWizard(fakeLoginWizard)
|
||||||
@ -488,7 +490,10 @@ class OnboardingViewModelTest {
|
|||||||
.assertStatesChanges(
|
.assertStatesChanges(
|
||||||
initialState,
|
initialState,
|
||||||
{ copy(isLoading = true) },
|
{ copy(isLoading = true) },
|
||||||
{ copy(isLoading = false, resetState = ResetState(AN_EMAIL, A_PASSWORD)) }
|
{
|
||||||
|
val resetState = ResetState(AN_EMAIL, A_PASSWORD, supportsLogoutAllDevices = true)
|
||||||
|
copy(isLoading = false, resetState = resetState)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
.assertEvents(OnboardingViewEvents.OnResetPasswordSendThreePidDone)
|
.assertEvents(OnboardingViewEvents.OnResetPasswordSendThreePidDone)
|
||||||
.finish()
|
.finish()
|
||||||
|
@ -128,7 +128,8 @@ class StartAuthenticationFlowUseCaseTest {
|
|||||||
ssoIdentityProviders = SSO_IDENTITY_PROVIDERS,
|
ssoIdentityProviders = SSO_IDENTITY_PROVIDERS,
|
||||||
isLoginAndRegistrationSupported = true,
|
isLoginAndRegistrationSupported = true,
|
||||||
homeServerUrl = A_DECLARED_HOMESERVER_URL,
|
homeServerUrl = A_DECLARED_HOMESERVER_URL,
|
||||||
isOutdatedHomeserver = false
|
isOutdatedHomeserver = false,
|
||||||
|
isLogoutDevicesSupported = false
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun expectedResult(
|
private fun expectedResult(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user