Don't reset the SSS toggle when logged out.
Instead, force a logout when toggling the option so user needs to log in again and create a new session using SSS.
This commit is contained in:
parent
e037521b64
commit
f70a7fcd34
7 changed files with 81 additions and 7 deletions
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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
|
||||||
|
*
|
||||||
|
* https://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 io.element.android.features.logout.api
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to trigger a log out of the current user from any part of the app.
|
||||||
|
*/
|
||||||
|
interface LogoutUseCase {
|
||||||
|
/**
|
||||||
|
* Log out the current user and then perform any needed cleanup tasks.
|
||||||
|
* @param ignoreSdkError if true, the SDK error will be ignored and the user will be logged out anyway.
|
||||||
|
*/
|
||||||
|
suspend fun logout(ignoreSdkError: Boolean)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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
|
||||||
|
*
|
||||||
|
* https://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 io.element.android.features.logout.impl
|
||||||
|
|
||||||
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
|
import io.element.android.features.logout.api.LogoutUseCase
|
||||||
|
import io.element.android.libraries.di.SessionScope
|
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ContributesBinding(SessionScope::class)
|
||||||
|
class DefaultLogoutUseCase @Inject constructor(
|
||||||
|
private val matrixClient: MatrixClient
|
||||||
|
) : LogoutUseCase {
|
||||||
|
override suspend fun logout(ignoreSdkError: Boolean) {
|
||||||
|
matrixClient.logout(ignoreSdkError = ignoreSdkError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,6 +28,7 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.snapshots.SnapshotStateMap
|
import androidx.compose.runtime.snapshots.SnapshotStateMap
|
||||||
import io.element.android.appconfig.ElementCallConfig
|
import io.element.android.appconfig.ElementCallConfig
|
||||||
|
import io.element.android.features.logout.api.LogoutUseCase
|
||||||
import io.element.android.features.preferences.impl.tasks.ClearCacheUseCase
|
import io.element.android.features.preferences.impl.tasks.ClearCacheUseCase
|
||||||
import io.element.android.features.preferences.impl.tasks.ComputeCacheSizeUseCase
|
import io.element.android.features.preferences.impl.tasks.ComputeCacheSizeUseCase
|
||||||
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesPresenter
|
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesPresenter
|
||||||
|
|
@ -55,6 +56,7 @@ class DeveloperSettingsPresenter @Inject constructor(
|
||||||
private val rageshakePresenter: RageshakePreferencesPresenter,
|
private val rageshakePresenter: RageshakePreferencesPresenter,
|
||||||
private val appPreferencesStore: AppPreferencesStore,
|
private val appPreferencesStore: AppPreferencesStore,
|
||||||
private val buildMeta: BuildMeta,
|
private val buildMeta: BuildMeta,
|
||||||
|
private val logoutUseCase: LogoutUseCase,
|
||||||
) : Presenter<DeveloperSettingsState> {
|
) : Presenter<DeveloperSettingsState> {
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): DeveloperSettingsState {
|
override fun present(): DeveloperSettingsState {
|
||||||
|
|
@ -119,6 +121,7 @@ class DeveloperSettingsPresenter @Inject constructor(
|
||||||
DeveloperSettingsEvents.ClearCache -> coroutineScope.clearCache(clearCacheAction)
|
DeveloperSettingsEvents.ClearCache -> coroutineScope.clearCache(clearCacheAction)
|
||||||
is DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled -> coroutineScope.launch {
|
is DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled -> coroutineScope.launch {
|
||||||
appPreferencesStore.setSimplifiedSlidingSyncEnabled(event.isEnabled)
|
appPreferencesStore.setSimplifiedSlidingSyncEnabled(event.isEnabled)
|
||||||
|
logoutUseCase.logout(ignoreSdkError = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ fun DeveloperSettingsView(
|
||||||
)
|
)
|
||||||
PreferenceSwitch(
|
PreferenceSwitch(
|
||||||
title = "Enable Simplified Sliding Sync",
|
title = "Enable Simplified Sliding Sync",
|
||||||
subtitle = "This option requires an app restart to work.",
|
subtitle = "When toggled you'll be logged out of the app and will need to log in again.",
|
||||||
isChecked = state.isSimpleSlidingSyncEnabled,
|
isChecked = state.isSimpleSlidingSyncEnabled,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
state.eventSink(DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled(it))
|
state.eventSink(DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled(it))
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import app.cash.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.appconfig.ElementCallConfig
|
import io.element.android.appconfig.ElementCallConfig
|
||||||
|
import io.element.android.features.logout.api.LogoutUseCase
|
||||||
import io.element.android.features.preferences.impl.tasks.FakeClearCacheUseCase
|
import io.element.android.features.preferences.impl.tasks.FakeClearCacheUseCase
|
||||||
import io.element.android.features.preferences.impl.tasks.FakeComputeCacheSizeUseCase
|
import io.element.android.features.preferences.impl.tasks.FakeComputeCacheSizeUseCase
|
||||||
import io.element.android.features.rageshake.impl.preferences.DefaultRageshakePreferencesPresenter
|
import io.element.android.features.rageshake.impl.preferences.DefaultRageshakePreferencesPresenter
|
||||||
|
|
@ -163,9 +164,10 @@ class DeveloperSettingsPresenterTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - toggling simplified sliding sync changes the preferences`() = runTest {
|
fun `present - toggling simplified sliding sync changes the preferences and logs out the user`() = runTest {
|
||||||
|
val logoutUseCase = FakeLogoutUseCase()
|
||||||
val preferences = InMemoryAppPreferencesStore()
|
val preferences = InMemoryAppPreferencesStore()
|
||||||
val presenter = createDeveloperSettingsPresenter(preferencesStore = preferences)
|
val presenter = createDeveloperSettingsPresenter(preferencesStore = preferences, logoutUseCase = logoutUseCase)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
@ -175,10 +177,12 @@ class DeveloperSettingsPresenterTest {
|
||||||
initialState.eventSink(DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled(true))
|
initialState.eventSink(DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled(true))
|
||||||
assertThat(awaitItem().isSimpleSlidingSyncEnabled).isTrue()
|
assertThat(awaitItem().isSimpleSlidingSyncEnabled).isTrue()
|
||||||
assertThat(preferences.isSimplifiedSlidingSyncEnabledFlow().first()).isTrue()
|
assertThat(preferences.isSimplifiedSlidingSyncEnabledFlow().first()).isTrue()
|
||||||
|
assertThat(logoutUseCase.logoutCallCount).isEqualTo(1)
|
||||||
|
|
||||||
initialState.eventSink(DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled(false))
|
initialState.eventSink(DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled(false))
|
||||||
assertThat(awaitItem().isSimpleSlidingSyncEnabled).isFalse()
|
assertThat(awaitItem().isSimpleSlidingSyncEnabled).isFalse()
|
||||||
assertThat(preferences.isSimplifiedSlidingSyncEnabledFlow().first()).isFalse()
|
assertThat(preferences.isSimplifiedSlidingSyncEnabledFlow().first()).isFalse()
|
||||||
|
assertThat(logoutUseCase.logoutCallCount).isEqualTo(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,6 +193,7 @@ class DeveloperSettingsPresenterTest {
|
||||||
rageshakePresenter: DefaultRageshakePreferencesPresenter = DefaultRageshakePreferencesPresenter(FakeRageShake(), FakeRageshakeDataStore()),
|
rageshakePresenter: DefaultRageshakePreferencesPresenter = DefaultRageshakePreferencesPresenter(FakeRageShake(), FakeRageshakeDataStore()),
|
||||||
preferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(),
|
preferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(),
|
||||||
buildMeta: BuildMeta = aBuildMeta(),
|
buildMeta: BuildMeta = aBuildMeta(),
|
||||||
|
logoutUseCase: FakeLogoutUseCase = FakeLogoutUseCase()
|
||||||
): DeveloperSettingsPresenter {
|
): DeveloperSettingsPresenter {
|
||||||
return DeveloperSettingsPresenter(
|
return DeveloperSettingsPresenter(
|
||||||
featureFlagService = featureFlagService,
|
featureFlagService = featureFlagService,
|
||||||
|
|
@ -197,6 +202,16 @@ class DeveloperSettingsPresenterTest {
|
||||||
rageshakePresenter = rageshakePresenter,
|
rageshakePresenter = rageshakePresenter,
|
||||||
appPreferencesStore = preferencesStore,
|
appPreferencesStore = preferencesStore,
|
||||||
buildMeta = buildMeta,
|
buildMeta = buildMeta,
|
||||||
|
logoutUseCase = logoutUseCase,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class FakeLogoutUseCase : LogoutUseCase {
|
||||||
|
var logoutCallCount = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
override suspend fun logout(ignoreSdkError: Boolean) {
|
||||||
|
logoutCallCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,6 @@ import io.element.android.libraries.matrix.impl.util.anonymizedTokens
|
||||||
import io.element.android.libraries.matrix.impl.util.cancelAndDestroy
|
import io.element.android.libraries.matrix.impl.util.cancelAndDestroy
|
||||||
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
|
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
|
||||||
import io.element.android.libraries.matrix.impl.verification.RustSessionVerificationService
|
import io.element.android.libraries.matrix.impl.verification.RustSessionVerificationService
|
||||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
|
||||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
@ -127,7 +126,6 @@ class RustMatrixClient(
|
||||||
private val baseDirectory: File,
|
private val baseDirectory: File,
|
||||||
baseCacheDirectory: File,
|
baseCacheDirectory: File,
|
||||||
private val clock: SystemClock,
|
private val clock: SystemClock,
|
||||||
private val appPreferencesStore: AppPreferencesStore,
|
|
||||||
) : MatrixClient {
|
) : MatrixClient {
|
||||||
override val sessionId: UserId = UserId(client.userId())
|
override val sessionId: UserId = UserId(client.userId())
|
||||||
override val deviceId: String = client.deviceId()
|
override val deviceId: String = client.deviceId()
|
||||||
|
|
@ -556,7 +554,6 @@ class RustMatrixClient(
|
||||||
}
|
}
|
||||||
close()
|
close()
|
||||||
deleteSessionDirectory(deleteCryptoDb = true)
|
deleteSessionDirectory(deleteCryptoDb = true)
|
||||||
appPreferencesStore.setSimplifiedSlidingSyncEnabled(false)
|
|
||||||
if (removeSession) {
|
if (removeSession) {
|
||||||
sessionStore.removeSession(sessionId.value)
|
sessionStore.removeSession(sessionId.value)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,6 @@ class RustMatrixClientFactory @Inject constructor(
|
||||||
baseDirectory = baseDirectory,
|
baseDirectory = baseDirectory,
|
||||||
baseCacheDirectory = cacheDirectory,
|
baseCacheDirectory = cacheDirectory,
|
||||||
clock = clock,
|
clock = clock,
|
||||||
appPreferencesStore = appPreferencesStore,
|
|
||||||
).also {
|
).also {
|
||||||
Timber.tag(it.toString()).d("Creating Client with access token '$anonymizedAccessToken' and refresh token '$anonymizedRefreshToken'")
|
Timber.tag(it.toString()).d("Creating Client with access token '$anonymizedAccessToken' and refresh token '$anonymizedRefreshToken'")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue