From 982410ece8200f3f8a5fce6607a6b646d2006a92 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 21 Nov 2024 18:20:59 +0100 Subject: [PATCH] fix : protect some more calls to client and rework the concerned apis --- .../appnav/loggedin/LoggedInPresenter.kt | 18 +++++++++++++---- .../appnav/loggedin/LoggedInPresenterTest.kt | 11 +++++----- .../roomlist/impl/RoomListPresenter.kt | 20 ++++++++++++++----- .../libraries/matrix/api/MatrixClient.kt | 16 ++++++++------- .../matrix/api/sync/SlidingSyncVersion.kt | 14 +++++++++++++ .../libraries/matrix/impl/RustMatrixClient.kt | 19 +++++++++--------- .../matrix/impl/sync/SlidingSyncVersion.kt | 19 ++++++++++++++++++ .../libraries/matrix/test/FakeMatrixClient.kt | 18 +++++++---------- 8 files changed, 93 insertions(+), 42 deletions(-) create mode 100644 libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/sync/SlidingSyncVersion.kt create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncVersion.kt diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt index 91f5d7da19..e96b603d21 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt @@ -28,6 +28,7 @@ import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.api.roomlist.RoomListService +import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase @@ -102,10 +103,7 @@ class LoggedInPresenter @Inject constructor( } } LoggedInEvents.CheckSlidingSyncProxyAvailability -> coroutineScope.launch { - // Force the user to log out if they were using the proxy sliding sync and it's no longer available, but native sliding sync is. - forceNativeSlidingSyncMigration = !matrixClient.isUsingNativeSlidingSync() && - matrixClient.isNativeSlidingSyncSupported() && - !matrixClient.isSlidingSyncProxySupported() + forceNativeSlidingSyncMigration = matrixClient.forceNativeSlidingSyncMigration().getOrDefault(false) } LoggedInEvents.LogoutAndMigrateToNativeSlidingSync -> coroutineScope.launch { // Enable native sliding sync if it wasn't already the case @@ -125,6 +123,18 @@ class LoggedInPresenter @Inject constructor( ) } + // Force the user to log out if they were using the proxy sliding sync and it's no longer available, but native sliding sync is. + private suspend fun MatrixClient.forceNativeSlidingSyncMigration(): Result = runCatching { + val currentSlidingSyncVersion = currentSlidingSyncVersion().getOrThrow() + if (currentSlidingSyncVersion == SlidingSyncVersion.Proxy) { + val availableSlidingSyncVersions = availableSlidingSyncVersions().getOrThrow() + availableSlidingSyncVersions.contains(SlidingSyncVersion.Native) && + !availableSlidingSyncVersions.contains(SlidingSyncVersion.Proxy) + } else { + false + } + } + private suspend fun ensurePusherIsRegistered(pusherRegistrationState: MutableState>) { Timber.tag(pusherTag.value).d("Ensure pusher is registered") val currentPushProvider = pushService.getCurrentPushProvider() diff --git a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt index ec44876634..0785ba73cd 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt @@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.api.roomlist.RoomListService +import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.test.AN_EXCEPTION @@ -501,9 +502,8 @@ class LoggedInPresenterTest { // - The sliding sync proxy is no longer supported // - The native sliding sync is supported val matrixClient = FakeMatrixClient( - isUsingNativeSlidingSyncLambda = { false }, - isSlidingSyncProxySupportedLambda = { false }, - isNativeSlidingSyncSupportedLambda = { true }, + currentSlidingSyncVersionLambda = { Result.success(SlidingSyncVersion.Proxy) }, + availableSlidingSyncVersionsLambda = { Result.success(listOf(SlidingSyncVersion.Native)) }, ) val presenter = createLoggedInPresenter(matrixClient = matrixClient) moleculeFlow(RecompositionMode.Immediate) { @@ -521,9 +521,8 @@ class LoggedInPresenterTest { @Test fun `present - CheckSlidingSyncProxyAvailability will not force the migration if native sliding sync is not supported too`() = runTest { val matrixClient = FakeMatrixClient( - isUsingNativeSlidingSyncLambda = { false }, - isSlidingSyncProxySupportedLambda = { false }, - isNativeSlidingSyncSupportedLambda = { false }, + currentSlidingSyncVersionLambda = { Result.success(SlidingSyncVersion.Proxy) }, + availableSlidingSyncVersionsLambda = { Result.success(emptyList()) }, ) val presenter = createLoggedInPresenter(matrixClient = matrixClient) moleculeFlow(RecompositionMode.Immediate) { diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt index 248d788f6c..a5fce4fc39 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt @@ -39,7 +39,6 @@ import io.element.android.features.roomlist.impl.search.RoomListSearchEvents import io.element.android.features.roomlist.impl.search.RoomListSearchState import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState import io.element.android.libraries.featureflag.api.FeatureFlagService @@ -51,6 +50,7 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.api.roomlist.RoomList +import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion import io.element.android.libraries.matrix.api.timeline.ReceiptType import io.element.android.libraries.preferences.api.store.SessionPreferencesStore import io.element.android.libraries.push.api.notifications.NotificationCleaner @@ -231,10 +231,7 @@ class RoomListPresenter @Inject constructor( } } val needsSlidingSyncMigration by produceState(false) { - value = runCatching { - // Note: this can fail when the session is destroyed from another client. - client.isNativeSlidingSyncSupported() && !client.isUsingNativeSlidingSync() - }.getOrNull().orFalse() + value = client.needsSlidingSyncMigration().getOrDefault(false) } return when { showEmpty -> RoomListContentState.Empty @@ -315,6 +312,19 @@ class RoomListPresenter @Inject constructor( } } + /** + * Checks if the user needs to migrate to a native sliding sync version. + */ + private suspend fun MatrixClient.needsSlidingSyncMigration(): Result = runCatching { + val currentSlidingSyncVersion = currentSlidingSyncVersion().getOrThrow() + if (currentSlidingSyncVersion != SlidingSyncVersion.Native) { + val availableSlidingSyncVersions = availableSlidingSyncVersions().getOrThrow() + availableSlidingSyncVersions.contains(SlidingSyncVersion.Native) + } else { + false + } + } + private var currentUpdateVisibleRangeJob: Job? = null private fun CoroutineScope.updateVisibleRange(range: IntRange) { currentUpdateVisibleRangeJob?.cancel() diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt index 38b0edac82..db7b5f8f11 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt @@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion import io.element.android.libraries.matrix.api.sync.SyncService import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults import io.element.android.libraries.matrix.api.user.MatrixUser @@ -145,14 +146,15 @@ interface MatrixClient : Closeable { suspend fun getUrl(url: String): Result suspend fun getRoomPreviewInfo(roomIdOrAlias: RoomIdOrAlias, serverNames: List): Result - /** Returns `true` if the home server supports native sliding sync. */ - suspend fun isNativeSlidingSyncSupported(): Boolean + /** + * Returns the currently used sliding sync version. + */ + suspend fun currentSlidingSyncVersion(): Result - /** Returns `true` if the home server supports sliding sync using a proxy. */ - suspend fun isSlidingSyncProxySupported(): Boolean - - /** Returns `true` if the current session is using native sliding sync, `false` if it's using a proxy. */ - fun isUsingNativeSlidingSync(): Boolean + /** + * Returns the available sliding sync versions for the current user. + */ + suspend fun availableSlidingSyncVersions(): Result> fun canDeactivateAccount(): Boolean suspend fun deactivateAccount(password: String, eraseData: Boolean): Result diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/sync/SlidingSyncVersion.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/sync/SlidingSyncVersion.kt new file mode 100644 index 0000000000..119c5af194 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/sync/SlidingSyncVersion.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.matrix.api.sync + +sealed interface SlidingSyncVersion { + data object None : SlidingSyncVersion + data object Proxy : SlidingSyncVersion + data object Native : SlidingSyncVersion +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index cabb208b50..17e75afad1 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -42,6 +42,7 @@ import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion import io.element.android.libraries.matrix.api.sync.SyncService import io.element.android.libraries.matrix.api.sync.SyncState import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults @@ -63,6 +64,7 @@ import io.element.android.libraries.matrix.impl.roomdirectory.RustRoomDirectoryS import io.element.android.libraries.matrix.impl.roomlist.RoomListFactory import io.element.android.libraries.matrix.impl.roomlist.RustRoomListService import io.element.android.libraries.matrix.impl.sync.RustSyncService +import io.element.android.libraries.matrix.impl.sync.map import io.element.android.libraries.matrix.impl.usersearch.UserProfileMapper import io.element.android.libraries.matrix.impl.usersearch.UserSearchResultMapper import io.element.android.libraries.matrix.impl.util.SessionPathsProvider @@ -101,7 +103,6 @@ import org.matrix.rustcomponents.sdk.IgnoredUsersListener import org.matrix.rustcomponents.sdk.NotificationProcessSetup import org.matrix.rustcomponents.sdk.PowerLevels import org.matrix.rustcomponents.sdk.SendQueueRoomErrorListener -import org.matrix.rustcomponents.sdk.SlidingSyncVersion import org.matrix.rustcomponents.sdk.TaskHandle import org.matrix.rustcomponents.sdk.use import timber.log.Timber @@ -634,16 +635,16 @@ class RustMatrixClient( }) }.buffer(Channel.UNLIMITED) - override suspend fun isNativeSlidingSyncSupported(): Boolean { - return client.availableSlidingSyncVersions().contains(SlidingSyncVersion.Native) + override suspend fun availableSlidingSyncVersions(): Result> = withContext(sessionDispatcher) { + runCatching { + client.availableSlidingSyncVersions().map { it.map() } + } } - override suspend fun isSlidingSyncProxySupported(): Boolean { - return client.availableSlidingSyncVersions().any { it is SlidingSyncVersion.Proxy } - } - - override fun isUsingNativeSlidingSync(): Boolean { - return client.session().slidingSyncVersion == SlidingSyncVersion.Native + override suspend fun currentSlidingSyncVersion(): Result = withContext(sessionDispatcher) { + runCatching { + client.session().slidingSyncVersion.map() + } } private suspend fun File.getCacheSize( diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncVersion.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncVersion.kt new file mode 100644 index 0000000000..05b3fe877a --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncVersion.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.sync + +import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion +import org.matrix.rustcomponents.sdk.SlidingSyncVersion as RustSlidingSyncVersion + +internal fun RustSlidingSyncVersion.map(): SlidingSyncVersion { + return when (this) { + RustSlidingSyncVersion.None -> SlidingSyncVersion.None + is RustSlidingSyncVersion.Proxy -> SlidingSyncVersion.Proxy + RustSlidingSyncVersion.Native -> SlidingSyncVersion.Native + } +} diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index e912fd2f40..f4e1839dac 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.verification.SessionVerificationService @@ -84,9 +85,8 @@ class FakeMatrixClient( private val getUrlLambda: (String) -> Result = { lambdaError() }, private val canDeactivateAccountResult: () -> Boolean = { lambdaError() }, private val deactivateAccountResult: (String, Boolean) -> Result = { _, _ -> lambdaError() }, - var isNativeSlidingSyncSupportedLambda: suspend () -> Boolean = { true }, - var isSlidingSyncProxySupportedLambda: suspend () -> Boolean = { true }, - var isUsingNativeSlidingSyncLambda: () -> Boolean = { true }, + private val currentSlidingSyncVersionLambda: () -> Result = { lambdaError() }, + private val availableSlidingSyncVersionsLambda: () -> Result> = { lambdaError() } ) : MatrixClient { var setDisplayNameCalled: Boolean = false private set @@ -340,15 +340,11 @@ class FakeMatrixClient( return getUrlLambda(url) } - override suspend fun isNativeSlidingSyncSupported(): Boolean { - return isNativeSlidingSyncSupportedLambda() + override suspend fun currentSlidingSyncVersion(): Result { + return currentSlidingSyncVersionLambda() } - override suspend fun isSlidingSyncProxySupported(): Boolean { - return isSlidingSyncProxySupportedLambda() - } - - override fun isUsingNativeSlidingSync(): Boolean { - return isUsingNativeSlidingSyncLambda() + override suspend fun availableSlidingSyncVersions(): Result> { + return availableSlidingSyncVersionsLambda() } }