From 81beccdd8e8d123106c581230166a2729e6526e4 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 14 Sep 2022 10:59:29 +0200 Subject: [PATCH 01/11] Adding changelog entry --- changelog.d/7114.wip | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7114.wip diff --git a/changelog.d/7114.wip b/changelog.d/7114.wip new file mode 100644 index 0000000000..d5bd584feb --- /dev/null +++ b/changelog.d/7114.wip @@ -0,0 +1 @@ +[Device management] Verify a session From 5759a0f7da39c55dc4507e8da6508fb66309d43e Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 14 Sep 2022 11:14:53 +0200 Subject: [PATCH 02/11] Adding click listeners on verify button --- .../settings/devices/v2/VectorSettingsDevicesFragment.kt | 3 +++ .../features/settings/devices/v2/list/SessionInfoView.kt | 1 + .../devices/v2/overview/SessionOverviewFragment.kt | 7 +++++++ 3 files changed, 11 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index 1e91384c3a..01d87b4142 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -227,6 +227,9 @@ class VectorSettingsDevicesFragment : views.deviceListCurrentSession.viewDetailsButton.debouncedClicks { currentDeviceInfo.deviceInfo.deviceId?.let { deviceId -> navigateToSessionOverview(deviceId) } } + views.deviceListCurrentSession.viewVerifyButton.debouncedClicks { + // TODO show bottom Sheet verification process + } } ?: run { hideCurrentSessionView() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt index 555d216dfc..38bc0cb5d8 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt @@ -49,6 +49,7 @@ class SessionInfoView @JvmOverloads constructor( } val viewDetailsButton = views.sessionInfoViewDetailsButton + val viewVerifyButton = views.sessionInfoVerifySessionButton fun render( sessionInfoViewState: SessionInfoViewState, diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index 3fea7a9316..ed8ec1a55f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -81,6 +81,7 @@ class SessionOverviewFragment : override fun invalidate() = withState(viewModel) { state -> updateToolbar(state.isCurrentSession) + updateVerifyButton() updateEntryDetails(state.deviceId) if (state.deviceInfo is Success) { renderSessionInfo(state.isCurrentSession, state.deviceInfo.invoke()) @@ -96,6 +97,12 @@ class SessionOverviewFragment : ?.setTitle(titleResId) } + private fun updateVerifyButton() { + views.sessionOverviewInfo.viewVerifyButton.debouncedClicks { + // TODO show bottom Sheet verification process + } + } + private fun updateEntryDetails(deviceId: String) { views.sessionOverviewEntryDetails.setOnClickListener { viewNavigator.navigateToSessionDetails(requireContext(), deviceId) From 8cd7b0744ae3db7f945220141223639cb64717a6 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 14 Sep 2022 15:50:11 +0200 Subject: [PATCH 03/11] Verification process for the current Session --- .../settings/devices/v2/DevicesAction.kt | 1 + .../settings/devices/v2/DevicesViewModel.kt | 17 +++++++ .../v2/VectorSettingsDevicesFragment.kt | 2 +- ...eckIfCurrentSessionCanBeVerifiedUseCase.kt | 48 +++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesAction.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesAction.kt index 8c7718bfcf..c7437db44c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesAction.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesAction.kt @@ -20,5 +20,6 @@ import im.vector.app.core.platform.VectorViewModelAction import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo sealed class DevicesAction : VectorViewModelAction { + object VerifyCurrentSession : DevicesAction() data class MarkAsManuallyVerified(val cryptoDeviceInfo: CryptoDeviceInfo) : DevicesAction() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt index 9c1b70a7e2..44dc599765 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt @@ -25,6 +25,7 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType +import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -37,6 +38,7 @@ class DevicesViewModel @AssistedInject constructor( private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase, private val refreshDevicesOnCryptoDevicesChangeUseCase: RefreshDevicesOnCryptoDevicesChangeUseCase, refreshDevicesUseCase: RefreshDevicesUseCase, + private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, ) : VectorSessionsListViewModel(initialState, activeSessionHolder, refreshDevicesUseCase) { @AssistedFactory @@ -94,10 +96,25 @@ class DevicesViewModel @AssistedInject constructor( override fun handle(action: DevicesAction) { when (action) { + is DevicesAction.VerifyCurrentSession -> handleVerifyCurrentSessionAction() is DevicesAction.MarkAsManuallyVerified -> handleMarkAsManuallyVerifiedAction() } } + // TODO add unit tests + private fun handleVerifyCurrentSessionAction() { + viewModelScope.launch { + val currentSessionCanBeVerified = checkIfCurrentSessionCanBeVerifiedUseCase.execute() + if (currentSessionCanBeVerified) { + activeSessionHolder.getSafeActiveSession()?.let { session -> + _viewEvents.post(DevicesViewEvent.SelfVerification(session)) + } + } else { + _viewEvents.post(DevicesViewEvent.PromptResetSecrets) + } + } + } + private fun handleMarkAsManuallyVerifiedAction() { // TODO implement when needed } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index 01d87b4142..3713357b19 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -228,7 +228,7 @@ class VectorSettingsDevicesFragment : currentDeviceInfo.deviceInfo.deviceId?.let { deviceId -> navigateToSessionOverview(deviceId) } } views.deviceListCurrentSession.viewVerifyButton.debouncedClicks { - // TODO show bottom Sheet verification process + viewModel.handle(DevicesAction.VerifyCurrentSession) } } ?: run { hideCurrentSessionView() diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt new file mode 100644 index 0000000000..36e4e981df --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt @@ -0,0 +1,48 @@ +/* + * 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 im.vector.app.features.settings.devices.v2.verification + +import im.vector.app.core.di.ActiveSessionHolder +import kotlinx.coroutines.flow.firstOrNull +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.flow.flow +import timber.log.Timber +import javax.inject.Inject + +// TODO add unit tests +class CheckIfCurrentSessionCanBeVerifiedUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, +) { + + suspend fun execute(): Boolean { + val session = activeSessionHolder.getSafeActiveSession() + val cryptoSessionsCount = session?.flow() + ?.liveUserCryptoDevices(session.myUserId) + ?.firstOrNull() + ?.size + ?: 0 + val hasOtherSessions = cryptoSessionsCount > 1 + + val isRecoverySetup = session + ?.sharedSecretStorageService() + ?.isRecoverySetup() + .orFalse() + + Timber.d("hasOtherSessions=$hasOtherSessions (otherSessionsCount=$cryptoSessionsCount), isRecoverySetup=$isRecoverySetup") + return hasOtherSessions || isRecoverySetup + } +} From d8263277731ded17ac8fb1fff9135aef5d413f28 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 14 Sep 2022 17:08:27 +0200 Subject: [PATCH 04/11] Adding unit tests for CheckIfCurrentSessionCanBeVerifiedUseCase --- ...eckIfCurrentSessionCanBeVerifiedUseCase.kt | 1 - .../devices/v2/DevicesViewModelTest.kt | 3 + ...fCurrentSessionCanBeVerifiedUseCaseTest.kt | 124 ++++++++++++++++++ .../fakes/FakeSharedSecretStorageService.kt | 8 +- 4 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCaseTest.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt index 36e4e981df..3fdef1a98f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt @@ -23,7 +23,6 @@ import org.matrix.android.sdk.flow.flow import timber.log.Timber import javax.inject.Inject -// TODO add unit tests class CheckIfCurrentSessionCanBeVerifiedUseCase @Inject constructor( private val activeSessionHolder: ActiveSessionHolder, ) { diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index 351d6b8eb0..d9a64c82ef 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -18,6 +18,7 @@ package im.vector.app.features.settings.devices.v2 import com.airbnb.mvrx.Success import com.airbnb.mvrx.test.MvRxTestRule +import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeVerificationService import im.vector.app.test.test @@ -45,6 +46,7 @@ class DevicesViewModelTest { private val getDeviceFullInfoListUseCase = mockk() private val refreshDevicesUseCase = mockk() private val refreshDevicesOnCryptoDevicesChangeUseCase = mockk() + private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk() private fun createViewModel(): DevicesViewModel { return DevicesViewModel( @@ -54,6 +56,7 @@ class DevicesViewModelTest { getDeviceFullInfoListUseCase, refreshDevicesOnCryptoDevicesChangeUseCase, refreshDevicesUseCase, + checkIfCurrentSessionCanBeVerifiedUseCase, ) } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCaseTest.kt new file mode 100644 index 0000000000..22bc0edae1 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCaseTest.kt @@ -0,0 +1,124 @@ +/* + * 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 im.vector.app.features.settings.devices.v2.verification + +import im.vector.app.test.fakes.FakeActiveSessionHolder +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkAll +import io.mockk.verify +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import org.amshove.kluent.shouldBeEqualTo +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo +import org.matrix.android.sdk.flow.FlowSession +import org.matrix.android.sdk.flow.flow + +class CheckIfCurrentSessionCanBeVerifiedUseCaseTest { + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + + private val checkIfCurrentSessionCanBeVerifiedUseCase = CheckIfCurrentSessionCanBeVerifiedUseCase( + activeSessionHolder = fakeActiveSessionHolder.instance + ) + + @Before + fun setUp() { + mockkStatic("org.matrix.android.sdk.flow.FlowSessionKt") + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given there are other sessions when checking if session can be verified then result is true`() = runTest { + // Given + val device1 = givenACryptoDevice() + val device2 = givenACryptoDevice() + val devices = listOf(device1, device2) + val fakeSession = fakeActiveSessionHolder.fakeSession + val flowSession = mockk() + every { fakeSession.flow() } returns flowSession + every { flowSession.liveUserCryptoDevices(any()) } returns flowOf(devices) + + fakeSession.fakeSharedSecretStorageService.givenIsRecoverySetupReturns(false) + + // When + val result = checkIfCurrentSessionCanBeVerifiedUseCase.execute() + + // Then + result shouldBeEqualTo true + verify { + flowSession.liveUserCryptoDevices(fakeSession.myUserId) + fakeSession.fakeSharedSecretStorageService.isRecoverySetup() + } + } + + @Test + fun `given recovery is setup when checking if session can be verified then result is true`() = runTest { + // Given + val device1 = givenACryptoDevice() + val devices = listOf(device1) + val fakeSession = fakeActiveSessionHolder.fakeSession + val flowSession = mockk() + every { fakeSession.flow() } returns flowSession + every { flowSession.liveUserCryptoDevices(any()) } returns flowOf(devices) + + fakeSession.fakeSharedSecretStorageService.givenIsRecoverySetupReturns(true) + + // When + val result = checkIfCurrentSessionCanBeVerifiedUseCase.execute() + + // Then + result shouldBeEqualTo true + verify { + flowSession.liveUserCryptoDevices(fakeSession.myUserId) + fakeSession.fakeSharedSecretStorageService.isRecoverySetup() + } + } + + @Test + fun `given recovery is not setup and there are no other sessions when checking if session can be verified then result is false`() = runTest { + // Given + val device1 = givenACryptoDevice() + val devices = listOf(device1) + val fakeSession = fakeActiveSessionHolder.fakeSession + val flowSession = mockk() + every { fakeSession.flow() } returns flowSession + every { flowSession.liveUserCryptoDevices(any()) } returns flowOf(devices) + + fakeSession.fakeSharedSecretStorageService.givenIsRecoverySetupReturns(false) + + // When + val result = checkIfCurrentSessionCanBeVerifiedUseCase.execute() + + // Then + result shouldBeEqualTo false + verify { + flowSession.liveUserCryptoDevices(fakeSession.myUserId) + fakeSession.fakeSharedSecretStorageService.isRecoverySetup() + } + } + + private fun givenACryptoDevice(): CryptoDeviceInfo = mockk() +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSharedSecretStorageService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSharedSecretStorageService.kt index 6ec9a4b593..1dc36de709 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeSharedSecretStorageService.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSharedSecretStorageService.kt @@ -16,6 +16,8 @@ package im.vector.app.test.fakes +import io.mockk.every +import io.mockk.mockk import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.api.session.securestorage.IntegrityResult import org.matrix.android.sdk.api.session.securestorage.KeyInfoResult @@ -26,7 +28,7 @@ import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageServi import org.matrix.android.sdk.api.session.securestorage.SsssKeyCreationInfo import org.matrix.android.sdk.api.session.securestorage.SsssKeySpec -class FakeSharedSecretStorageService : SharedSecretStorageService { +class FakeSharedSecretStorageService : SharedSecretStorageService by mockk() { var integrityResult: IntegrityResult = IntegrityResult.Error(SharedSecretStorageError.OtherError(IllegalStateException())) var _defaultKey: KeyInfoResult = KeyInfoResult.Error(SharedSecretStorageError.OtherError(IllegalStateException())) @@ -76,4 +78,8 @@ class FakeSharedSecretStorageService : SharedSecretStorageService { override suspend fun requestSecret(name: String, myOtherDeviceId: String) { TODO("Not yet implemented") } + + fun givenIsRecoverySetupReturns(isRecoverySetup: Boolean) { + every { isRecoverySetup() } returns isRecoverySetup + } } From 35db958279e51ec2599bb84a7410995f00c5cd8c Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 14 Sep 2022 17:39:41 +0200 Subject: [PATCH 05/11] Adding unit tests for new action in DevicesViewModel --- .../settings/devices/v2/DevicesViewModel.kt | 1 - .../devices/v2/DevicesViewModelTest.kt | 48 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt index 44dc599765..5667b1cc57 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt @@ -101,7 +101,6 @@ class DevicesViewModel @AssistedInject constructor( } } - // TODO add unit tests private fun handleVerifyCurrentSessionAction() { viewModelScope.launch { val currentSessionCanBeVerified = checkIfCurrentSessionCanBeVerifiedUseCase.execute() diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index d9a64c82ef..18796191af 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -145,6 +145,54 @@ class DevicesViewModelTest { coVerify { refreshDevicesOnCryptoDevicesChangeUseCase.execute() } } + @Test + fun `given current session can be verified when handling verify current session action then self verification event is posted`() { + // Given + givenVerificationService() + givenCurrentSessionCrossSigningInfo() + givenDeviceFullInfoList() + givenRefreshDevicesOnCryptoDevicesChange() + val verifyCurrentSessionAction = DevicesAction.VerifyCurrentSession + coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns true + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(verifyCurrentSessionAction) + + // Then + viewModelTest + .assertEvent { it is DevicesViewEvent.SelfVerification } + .finish() + coVerify { + checkIfCurrentSessionCanBeVerifiedUseCase.execute() + } + } + + @Test + fun `given current session cannot be verified when handling verify current session action then reset secrets event is posted`() { + // Given + givenVerificationService() + givenCurrentSessionCrossSigningInfo() + givenDeviceFullInfoList() + givenRefreshDevicesOnCryptoDevicesChange() + val verifyCurrentSessionAction = DevicesAction.VerifyCurrentSession + coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns false + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(verifyCurrentSessionAction) + + // Then + viewModelTest + .assertEvent { it is DevicesViewEvent.PromptResetSecrets } + .finish() + coVerify { + checkIfCurrentSessionCanBeVerifiedUseCase.execute() + } + } + private fun givenVerificationService(): FakeVerificationService { val fakeVerificationService = fakeActiveSessionHolder .fakeSession From 32b560649844636f6830e7c48abed34df0292891 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 15 Sep 2022 11:03:01 +0200 Subject: [PATCH 06/11] Fixing missing event to start verification process --- .../features/settings/devices/VectorSettingsDevicesFragment.kt | 3 +-- .../settings/devices/v2/VectorSettingsDevicesFragment.kt | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt index 5b19b7a8d2..135c684e76 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt @@ -85,8 +85,7 @@ class VectorSettingsDevicesFragment : ).show(childFragmentManager, "REQPOP") } is DevicesViewEvents.SelfVerification -> { - VerificationBottomSheet.forSelfVerification(it.session) - .show(childFragmentManager, "REQPOP") + navigator.requestSelfSessionVerification(requireActivity()) } is DevicesViewEvents.ShowManuallyVerify -> { ManuallyVerifyDialog.show(requireActivity(), it.cryptoDeviceInfo) { diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index 3713357b19..7cfa218bf0 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -101,8 +101,7 @@ class VectorSettingsDevicesFragment : ).show(childFragmentManager, "REQPOP") } is DevicesViewEvent.SelfVerification -> { - VerificationBottomSheet.forSelfVerification(it.session) - .show(childFragmentManager, "REQPOP") + navigator.requestSelfSessionVerification(requireActivity()) } is DevicesViewEvent.ShowManuallyVerify -> { ManuallyVerifyDialog.show(requireActivity(), it.cryptoDeviceInfo) { From fa990351afa08d7a845d90dc3c8db659cea9da91 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 15 Sep 2022 14:00:08 +0200 Subject: [PATCH 07/11] Editing changelog entry --- changelog.d/7114.wip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/7114.wip b/changelog.d/7114.wip index d5bd584feb..79ad705132 100644 --- a/changelog.d/7114.wip +++ b/changelog.d/7114.wip @@ -1 +1 @@ -[Device management] Verify a session +[Device management] Verify current session From 584c6994099b093da8ecaf8b7ae259d1d4ecb153 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 15 Sep 2022 14:42:22 +0200 Subject: [PATCH 08/11] Verify current session in Session overview screen --- .../devices/v2/IsCurrentSessionUseCase.kt | 30 +++++++ .../v2/overview/SessionOverviewAction.kt | 4 +- .../v2/overview/SessionOverviewFragment.kt | 21 ++++- .../v2/overview/SessionOverviewViewEvent.kt | 25 ++++++ .../v2/overview/SessionOverviewViewModel.kt | 43 ++++++++-- .../devices/v2/IsCurrentSessionUseCaseTest.kt | 82 +++++++++++++++++++ .../overview/SessionOverviewViewModelTest.kt | 77 +++++++++++++---- 7 files changed, 256 insertions(+), 26 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCase.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt create mode 100644 vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCase.kt new file mode 100644 index 0000000000..885908120a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCase.kt @@ -0,0 +1,30 @@ +/* + * 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 im.vector.app.features.settings.devices.v2 + +import im.vector.app.core.di.ActiveSessionHolder +import javax.inject.Inject + +class IsCurrentSessionUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, +) { + + fun execute(deviceId: String): Boolean { + val currentDeviceId = activeSessionHolder.getSafeActiveSession()?.sessionParams?.deviceId.orEmpty() + return deviceId.isNotEmpty() && deviceId == currentDeviceId + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt index c028c08ec4..0e923b4c9b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt @@ -18,4 +18,6 @@ package im.vector.app.features.settings.devices.v2.overview import im.vector.app.core.platform.VectorViewModelAction -sealed class SessionOverviewAction : VectorViewModelAction +sealed class SessionOverviewAction : VectorViewModelAction { + data class VerifySession(val deviceId: String) : SessionOverviewAction() +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index ed8ec1a55f..98f4eb823b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -34,6 +34,7 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.DrawableProvider import im.vector.app.databinding.FragmentSessionOverviewBinding +import im.vector.app.features.crypto.recover.SetupMode import im.vector.app.features.settings.devices.v2.DeviceFullInfo import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState import javax.inject.Inject @@ -62,6 +63,7 @@ class SessionOverviewFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initSessionInfoView() + observeViewEvents() } private fun initSessionInfoView() { @@ -70,6 +72,19 @@ class SessionOverviewFragment : } } + private fun observeViewEvents() { + viewModel.observeViewEvents { + when (it) { + is SessionOverviewViewEvent.SelfVerification -> { + navigator.requestSelfSessionVerification(requireActivity()) + } + is SessionOverviewViewEvent.PromptResetSecrets -> { + navigator.open4SSetup(requireActivity(), SetupMode.PASSPHRASE_AND_NEEDED_SECRETS_RESET) + } + } + } + } + override fun onDestroyView() { cleanUpSessionInfoView() super.onDestroyView() @@ -81,7 +96,7 @@ class SessionOverviewFragment : override fun invalidate() = withState(viewModel) { state -> updateToolbar(state.isCurrentSession) - updateVerifyButton() + updateVerifyButton(state.deviceId) updateEntryDetails(state.deviceId) if (state.deviceInfo is Success) { renderSessionInfo(state.isCurrentSession, state.deviceInfo.invoke()) @@ -97,9 +112,9 @@ class SessionOverviewFragment : ?.setTitle(titleResId) } - private fun updateVerifyButton() { + private fun updateVerifyButton(deviceId: String) { views.sessionOverviewInfo.viewVerifyButton.debouncedClicks { - // TODO show bottom Sheet verification process + viewModel.handle(SessionOverviewAction.VerifySession(deviceId)) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt new file mode 100644 index 0000000000..3b1ee2609e --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt @@ -0,0 +1,25 @@ +/* + * 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 im.vector.app.features.settings.devices.v2.overview + +import im.vector.app.core.platform.VectorViewEvents +import org.matrix.android.sdk.api.session.Session + +sealed class SessionOverviewViewEvent : VectorViewEvents { + data class SelfVerification(val session: Session) : SessionOverviewViewEvent() + object PromptResetSecrets : SessionOverviewViewEvent() +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index bdcdc40c56..32c6aed541 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -21,19 +21,23 @@ import com.airbnb.mvrx.Success import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory -import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.settings.devices.v2.IsCurrentSessionUseCase +import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import org.matrix.android.sdk.api.session.Session +import kotlinx.coroutines.launch class SessionOverviewViewModel @AssistedInject constructor( @Assisted val initialState: SessionOverviewViewState, - session: Session, + private val activeSessionHolder: ActiveSessionHolder, + private val isCurrentSessionUseCase: IsCurrentSessionUseCase, private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, -) : VectorViewModel(initialState) { + private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, +) : VectorViewModel(initialState) { companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() @@ -43,14 +47,16 @@ class SessionOverviewViewModel @AssistedInject constructor( } init { - val currentDeviceId = session.sessionParams.deviceId.orEmpty() setState { - copy(isCurrentSession = deviceId.isNotEmpty() && deviceId == currentDeviceId) + copy(isCurrentSession = isCurrentSession(deviceId)) } - observeSessionInfo(initialState.deviceId) } + private fun isCurrentSession(deviceId: String): Boolean { + return isCurrentSessionUseCase.execute(deviceId) + } + private fun observeSessionInfo(deviceId: String) { getDeviceFullInfoUseCase.execute(deviceId) .onEach { setState { copy(deviceInfo = Success(it)) } } @@ -58,6 +64,27 @@ class SessionOverviewViewModel @AssistedInject constructor( } override fun handle(action: SessionOverviewAction) { - TODO("Implement when adding the first action") + when (action) { + is SessionOverviewAction.VerifySession -> handleVerifySessionAction(action) + } + } + + private fun handleVerifySessionAction(verifySession: SessionOverviewAction.VerifySession) { + if (isCurrentSession(verifySession.deviceId)) { + handleVerifyCurrentSession() + } + } + + private fun handleVerifyCurrentSession() { + viewModelScope.launch { + val currentSessionCanBeVerified = checkIfCurrentSessionCanBeVerifiedUseCase.execute() + if (currentSessionCanBeVerified) { + activeSessionHolder.getSafeActiveSession()?.let { session -> + _viewEvents.post(SessionOverviewViewEvent.SelfVerification(session)) + } + } else { + _viewEvents.post(SessionOverviewViewEvent.PromptResetSecrets) + } + } } } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt new file mode 100644 index 0000000000..25cd150b21 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt @@ -0,0 +1,82 @@ +/* + * 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 im.vector.app.features.settings.devices.v2 + +import im.vector.app.test.fakes.FakeActiveSessionHolder +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.amshove.kluent.shouldBe +import org.junit.Test +import org.matrix.android.sdk.api.auth.data.SessionParams + +private const val A_SESSION_ID_1 = "session-id-1" +private const val A_SESSION_ID_2 = "session-id-2" + +class IsCurrentSessionUseCaseTest { + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + + private val isCurrentSessionUseCase = IsCurrentSessionUseCase( + activeSessionHolder = fakeActiveSessionHolder.instance, + ) + + @Test + fun `given the session id of the current session when checking if id is current session then result is true`() { + // Given + val sessionParams = givenIdForCurrentSession(A_SESSION_ID_1) + + // When + val result = isCurrentSessionUseCase.execute(A_SESSION_ID_1) + + // Then + result shouldBe true + verify { sessionParams.deviceId } + } + + @Test + fun `given a session id different from the current session id when checking if id is current session then result is false`() { + // Given + val sessionParams = givenIdForCurrentSession(A_SESSION_ID_1) + + // When + val result = isCurrentSessionUseCase.execute(A_SESSION_ID_2) + + // Then + result shouldBe false + verify { sessionParams.deviceId } + } + + @Test + fun `given no current active session when checking if id is current session then result is false`() { + // Given + fakeActiveSessionHolder.givenGetSafeActiveSessionReturns(null) + + // When + val result = isCurrentSessionUseCase.execute(A_SESSION_ID_1) + + // Then + result shouldBe false + } + + private fun givenIdForCurrentSession(deviceId: String): SessionParams { + val sessionParams = mockk() + every { sessionParams.deviceId } returns deviceId + fakeActiveSessionHolder.fakeSession.givenSessionParams(sessionParams) + return sessionParams + } +} diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index 8d4e49ef85..1fb14f678b 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -19,16 +19,19 @@ package im.vector.app.features.settings.devices.v2.overview import com.airbnb.mvrx.Success import com.airbnb.mvrx.test.MvRxTestRule import im.vector.app.features.settings.devices.v2.DeviceFullInfo -import im.vector.app.test.fakes.FakeSession +import im.vector.app.features.settings.devices.v2.IsCurrentSessionUseCase +import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase +import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.test import im.vector.app.test.testDispatcher +import io.mockk.coEvery +import io.mockk.coVerify import io.mockk.every import io.mockk.mockk import io.mockk.verify import kotlinx.coroutines.flow.flowOf import org.junit.Rule import org.junit.Test -import org.matrix.android.sdk.api.auth.data.SessionParams private const val A_SESSION_ID = "session-id" @@ -40,24 +43,29 @@ class SessionOverviewViewModelTest { private val args = SessionOverviewArgs( deviceId = A_SESSION_ID ) - private val fakeSession = FakeSession() + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val isCurrentSessionUseCase = mockk() private val getDeviceFullInfoUseCase = mockk() + private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk() private fun createViewModel() = SessionOverviewViewModel( initialState = SessionOverviewViewState(args), - session = fakeSession, - getDeviceFullInfoUseCase = getDeviceFullInfoUseCase + activeSessionHolder = fakeActiveSessionHolder.instance, + isCurrentSessionUseCase = isCurrentSessionUseCase, + getDeviceFullInfoUseCase = getDeviceFullInfoUseCase, + checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase, ) @Test fun `given the viewModel has been initialized then viewState is updated with session info`() { // Given - val sessionParams = givenIdForSession(A_SESSION_ID) val deviceFullInfo = mockk() every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) + val isCurrentSession = true + every { isCurrentSessionUseCase.execute(any()) } returns isCurrentSession val expectedState = SessionOverviewViewState( deviceId = A_SESSION_ID, - isCurrentSession = true, + isCurrentSession = isCurrentSession, deviceInfo = Success(deviceFullInfo) ) @@ -68,14 +76,55 @@ class SessionOverviewViewModelTest { viewModel.test() .assertLatestState { state -> state == expectedState } .finish() - verify { sessionParams.deviceId } - verify { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } + verify { + isCurrentSessionUseCase.execute(A_SESSION_ID) + getDeviceFullInfoUseCase.execute(A_SESSION_ID) + } } - private fun givenIdForSession(deviceId: String): SessionParams { - val sessionParams = mockk() - every { sessionParams.deviceId } returns deviceId - fakeSession.givenSessionParams(sessionParams) - return sessionParams + @Test + fun `given current session can be verified when handling verify current session action then self verification event is posted`() { + // Given + val deviceFullInfo = mockk() + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) + every { isCurrentSessionUseCase.execute(any()) } returns true + val verifySessionAction = SessionOverviewAction.VerifySession(A_SESSION_ID) + coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns true + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(verifySessionAction) + + // Then + viewModelTest + .assertEvent { it is SessionOverviewViewEvent.SelfVerification } + .finish() + coVerify { + checkIfCurrentSessionCanBeVerifiedUseCase.execute() + } + } + + @Test + fun `given current session cannot be verified when handling verify current session action then reset secrets event is posted`() { + // Given + val deviceFullInfo = mockk() + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) + every { isCurrentSessionUseCase.execute(any()) } returns true + val verifySessionAction = SessionOverviewAction.VerifySession(A_SESSION_ID) + coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns false + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(verifySessionAction) + + // Then + viewModelTest + .assertEvent { it is SessionOverviewViewEvent.PromptResetSecrets } + .finish() + coVerify { + checkIfCurrentSessionCanBeVerifiedUseCase.execute() + } } } From e0c4706cf956a8056863b42a1c041ffa20c0da52 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 09:39:30 +0200 Subject: [PATCH 09/11] Removing non necessary session arg from ViewEvent --- .../app/features/settings/devices/v2/DevicesViewEvent.kt | 3 +-- .../app/features/settings/devices/v2/DevicesViewModel.kt | 4 +--- .../devices/v2/overview/SessionOverviewViewEvent.kt | 3 +-- .../devices/v2/overview/SessionOverviewViewModel.kt | 6 +----- .../devices/v2/overview/SessionOverviewViewModelTest.kt | 3 --- 5 files changed, 4 insertions(+), 15 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewEvent.kt index e83004843d..c78c20f792 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewEvent.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewEvent.kt @@ -18,7 +18,6 @@ package im.vector.app.features.settings.devices.v2 import im.vector.app.core.platform.VectorViewEvents import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse -import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo @@ -28,7 +27,7 @@ sealed class DevicesViewEvent : VectorViewEvents { data class RequestReAuth(val registrationFlowResponse: RegistrationFlowResponse, val lastErrorCode: String?) : DevicesViewEvent() data class PromptRenameDevice(val deviceInfo: DeviceInfo) : DevicesViewEvent() data class ShowVerifyDevice(val userId: String, val transactionId: String?) : DevicesViewEvent() - data class SelfVerification(val session: Session) : DevicesViewEvent() + object SelfVerification : DevicesViewEvent() data class ShowManuallyVerify(val cryptoDeviceInfo: CryptoDeviceInfo) : DevicesViewEvent() object PromptResetSecrets : DevicesViewEvent() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt index 5667b1cc57..730400bfcf 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt @@ -105,9 +105,7 @@ class DevicesViewModel @AssistedInject constructor( viewModelScope.launch { val currentSessionCanBeVerified = checkIfCurrentSessionCanBeVerifiedUseCase.execute() if (currentSessionCanBeVerified) { - activeSessionHolder.getSafeActiveSession()?.let { session -> - _viewEvents.post(DevicesViewEvent.SelfVerification(session)) - } + _viewEvents.post(DevicesViewEvent.SelfVerification) } else { _viewEvents.post(DevicesViewEvent.PromptResetSecrets) } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt index 3b1ee2609e..83d438ecb4 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt @@ -17,9 +17,8 @@ package im.vector.app.features.settings.devices.v2.overview import im.vector.app.core.platform.VectorViewEvents -import org.matrix.android.sdk.api.session.Session sealed class SessionOverviewViewEvent : VectorViewEvents { - data class SelfVerification(val session: Session) : SessionOverviewViewEvent() + object SelfVerification : SessionOverviewViewEvent() object PromptResetSecrets : SessionOverviewViewEvent() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 32c6aed541..5b51483afe 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -21,7 +21,6 @@ import com.airbnb.mvrx.Success import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel @@ -33,7 +32,6 @@ import kotlinx.coroutines.launch class SessionOverviewViewModel @AssistedInject constructor( @Assisted val initialState: SessionOverviewViewState, - private val activeSessionHolder: ActiveSessionHolder, private val isCurrentSessionUseCase: IsCurrentSessionUseCase, private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, @@ -79,9 +77,7 @@ class SessionOverviewViewModel @AssistedInject constructor( viewModelScope.launch { val currentSessionCanBeVerified = checkIfCurrentSessionCanBeVerifiedUseCase.execute() if (currentSessionCanBeVerified) { - activeSessionHolder.getSafeActiveSession()?.let { session -> - _viewEvents.post(SessionOverviewViewEvent.SelfVerification(session)) - } + _viewEvents.post(SessionOverviewViewEvent.SelfVerification) } else { _viewEvents.post(SessionOverviewViewEvent.PromptResetSecrets) } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index 1fb14f678b..f25c25bb8e 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -21,7 +21,6 @@ import com.airbnb.mvrx.test.MvRxTestRule import im.vector.app.features.settings.devices.v2.DeviceFullInfo import im.vector.app.features.settings.devices.v2.IsCurrentSessionUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase -import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.test import im.vector.app.test.testDispatcher import io.mockk.coEvery @@ -43,14 +42,12 @@ class SessionOverviewViewModelTest { private val args = SessionOverviewArgs( deviceId = A_SESSION_ID ) - private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val isCurrentSessionUseCase = mockk() private val getDeviceFullInfoUseCase = mockk() private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk() private fun createViewModel() = SessionOverviewViewModel( initialState = SessionOverviewViewState(args), - activeSessionHolder = fakeActiveSessionHolder.instance, isCurrentSessionUseCase = isCurrentSessionUseCase, getDeviceFullInfoUseCase = getDeviceFullInfoUseCase, checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase, From cf6b8d76a822623d7eed51338fddb3b25b4b97ff Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 09:44:46 +0200 Subject: [PATCH 10/11] Removing non necessary session id arg from ViewAction --- .../devices/v2/overview/SessionOverviewAction.kt | 2 +- .../v2/overview/SessionOverviewFragment.kt | 16 ++++++++-------- .../v2/overview/SessionOverviewViewModel.kt | 6 +++--- .../v2/overview/SessionOverviewViewModelTest.kt | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt index 0e923b4c9b..1118c5dc5b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt @@ -19,5 +19,5 @@ package im.vector.app.features.settings.devices.v2.overview import im.vector.app.core.platform.VectorViewModelAction sealed class SessionOverviewAction : VectorViewModelAction { - data class VerifySession(val deviceId: String) : SessionOverviewAction() + object VerifySession : SessionOverviewAction() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index 98f4eb823b..4c83408fe7 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -62,8 +62,9 @@ class SessionOverviewFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - initSessionInfoView() observeViewEvents() + initSessionInfoView() + initVerifyButton() } private fun initSessionInfoView() { @@ -72,6 +73,12 @@ class SessionOverviewFragment : } } + private fun initVerifyButton() { + views.sessionOverviewInfo.viewVerifyButton.debouncedClicks { + viewModel.handle(SessionOverviewAction.VerifySession) + } + } + private fun observeViewEvents() { viewModel.observeViewEvents { when (it) { @@ -96,7 +103,6 @@ class SessionOverviewFragment : override fun invalidate() = withState(viewModel) { state -> updateToolbar(state.isCurrentSession) - updateVerifyButton(state.deviceId) updateEntryDetails(state.deviceId) if (state.deviceInfo is Success) { renderSessionInfo(state.isCurrentSession, state.deviceInfo.invoke()) @@ -112,12 +118,6 @@ class SessionOverviewFragment : ?.setTitle(titleResId) } - private fun updateVerifyButton(deviceId: String) { - views.sessionOverviewInfo.viewVerifyButton.debouncedClicks { - viewModel.handle(SessionOverviewAction.VerifySession(deviceId)) - } - } - private fun updateEntryDetails(deviceId: String) { views.sessionOverviewEntryDetails.setOnClickListener { viewNavigator.navigateToSessionDetails(requireContext(), deviceId) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 5b51483afe..bcf7542783 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -63,12 +63,12 @@ class SessionOverviewViewModel @AssistedInject constructor( override fun handle(action: SessionOverviewAction) { when (action) { - is SessionOverviewAction.VerifySession -> handleVerifySessionAction(action) + is SessionOverviewAction.VerifySession -> handleVerifySessionAction() } } - private fun handleVerifySessionAction(verifySession: SessionOverviewAction.VerifySession) { - if (isCurrentSession(verifySession.deviceId)) { + private fun handleVerifySessionAction() = withState { viewState -> + if (isCurrentSession(viewState.deviceId)) { handleVerifyCurrentSession() } } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index f25c25bb8e..71978129d3 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -85,7 +85,7 @@ class SessionOverviewViewModelTest { val deviceFullInfo = mockk() every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) every { isCurrentSessionUseCase.execute(any()) } returns true - val verifySessionAction = SessionOverviewAction.VerifySession(A_SESSION_ID) + val verifySessionAction = SessionOverviewAction.VerifySession coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns true // When @@ -108,7 +108,7 @@ class SessionOverviewViewModelTest { val deviceFullInfo = mockk() every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) every { isCurrentSessionUseCase.execute(any()) } returns true - val verifySessionAction = SessionOverviewAction.VerifySession(A_SESSION_ID) + val verifySessionAction = SessionOverviewAction.VerifySession coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns false // When From 54a4dc7e9a794fc9f85ef61a8d027e0ca044d7c3 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 14:46:24 +0200 Subject: [PATCH 11/11] Inverting some arguments to ease readability --- .../vector/app/features/settings/devices/v2/DevicesViewModel.kt | 2 +- .../app/features/settings/devices/v2/DevicesViewModelTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt index 730400bfcf..96d169bf02 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt @@ -37,8 +37,8 @@ class DevicesViewModel @AssistedInject constructor( private val getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase, private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase, private val refreshDevicesOnCryptoDevicesChangeUseCase: RefreshDevicesOnCryptoDevicesChangeUseCase, - refreshDevicesUseCase: RefreshDevicesUseCase, private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, + refreshDevicesUseCase: RefreshDevicesUseCase, ) : VectorSessionsListViewModel(initialState, activeSessionHolder, refreshDevicesUseCase) { @AssistedFactory diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index 18796191af..0e04c2ab51 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -55,8 +55,8 @@ class DevicesViewModelTest { getCurrentSessionCrossSigningInfoUseCase, getDeviceFullInfoListUseCase, refreshDevicesOnCryptoDevicesChangeUseCase, - refreshDevicesUseCase, checkIfCurrentSessionCanBeVerifiedUseCase, + refreshDevicesUseCase, ) }