From 1ca334127494186bde0ec44eb5cfe90e7ba6ef29 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:05:33 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20OtherUser=20devices:=20wrong=20MLS=20dat?= =?UTF-8?q?a=20[WPB-8908]=20=F0=9F=8D=92=20(#3075)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: boris --- .../ui/authentication/devices/DeviceItem.kt | 16 +++++----- .../ui/authentication/devices/model/Device.kt | 16 +++++----- .../settings/devices/DeviceDetailsScreen.kt | 27 +++++++++------- .../devices/DeviceDetailsViewModel.kt | 2 +- .../settings/devices/SelfDevicesViewModel.kt | 4 +-- .../other/OtherUserDevicesScreen.kt | 2 +- .../other/OtherUserProfileScreenViewModel.kt | 2 +- .../devices/DeviceDetailsViewModelTest.kt | 31 +++++++++++++++++++ 8 files changed, 67 insertions(+), 33 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/devices/DeviceItem.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/devices/DeviceItem.kt index 2b19ebb5c43..7d945ccb578 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/devices/DeviceItem.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/devices/DeviceItem.kt @@ -183,13 +183,15 @@ private fun DeviceItemTexts( ) if (shouldShowVerifyLabel) { if (shouldShowE2EIInfo) { - MLSVerificationIcon(device.e2eiCertificateStatus) + MLSVerificationIcon(device.e2eiCertificate?.status) } Spacer(modifier = Modifier.width(MaterialTheme.wireDimensions.spacing8x)) - if (device.isVerifiedProteus && !isCurrentClient) ProteusVerifiedIcon( - Modifier - .wrapContentWidth() - .align(Alignment.CenterVertically)) + if (device.isVerifiedProteus && !isCurrentClient) { + ProteusVerifiedIcon( + Modifier + .wrapContentWidth() + .align(Alignment.CenterVertically)) + } } } @@ -206,7 +208,7 @@ private fun DeviceItemTexts( Spacer(modifier = Modifier.height(MaterialTheme.wireDimensions.removeDeviceItemTitleVerticalPadding)) - device.mlsPublicKeys?.values?.firstOrNull()?.let { mlsThumbprint -> + device.e2eiCertificate?.let { certificate -> Text( style = MaterialTheme.wireTypography.subline01, color = MaterialTheme.wireColorScheme.labelText, @@ -214,7 +216,7 @@ private fun DeviceItemTexts( overflow = TextOverflow.Ellipsis, text = stringResource( R.string.remove_device_mls_thumbprint_label, - mlsThumbprint.formatAsFingerPrint() + certificate.thumbprint.formatAsFingerPrint() ), modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/devices/model/Device.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/devices/model/Device.kt index 4f5e3911eb0..435d8443803 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/devices/model/Device.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/devices/model/Device.kt @@ -26,7 +26,7 @@ import com.wire.android.R import com.wire.android.util.ui.UIText import com.wire.kalium.logic.data.client.Client import com.wire.kalium.logic.data.conversation.ClientId -import com.wire.kalium.logic.feature.e2ei.CertificateStatus +import com.wire.kalium.logic.feature.e2ei.E2eiCertificate import com.wire.kalium.logic.util.inWholeWeeks import com.wire.kalium.util.DateTimeUtil.toIsoDateTimeString import kotlinx.datetime.Clock @@ -38,18 +38,16 @@ data class Device( val lastActiveInWholeWeeks: Int? = null, val isValid: Boolean = true, val isVerifiedProteus: Boolean = false, - val mlsPublicKeys: Map? = null, - val e2eiCertificateStatus: CertificateStatus? = null + val e2eiCertificate: E2eiCertificate? = null ) { - constructor(client: Client, e2eiCertificateStatus: CertificateStatus? = null) : this( + constructor(client: Client, e2eiCertificate: E2eiCertificate? = null) : this( name = client.displayName(), clientId = client.id, registrationTime = client.registrationTime?.toIsoDateTimeString(), lastActiveInWholeWeeks = client.lastActiveInWholeWeeks(), isValid = client.isValid, isVerifiedProteus = client.isVerified, - mlsPublicKeys = client.mlsPublicKeys, - e2eiCertificateStatus = e2eiCertificateStatus + e2eiCertificate = e2eiCertificate ) fun updateFromClient(client: Client): Device = copy( @@ -59,11 +57,11 @@ data class Device( lastActiveInWholeWeeks = client.lastActiveInWholeWeeks(), isValid = client.isValid, isVerifiedProteus = client.isVerified, - mlsPublicKeys = client.mlsPublicKeys, + e2eiCertificate = null, ) - fun updateE2EICertificateStatus(e2eiCertificateStatus: CertificateStatus): Device = copy( - e2eiCertificateStatus = e2eiCertificateStatus + fun updateE2EICertificate(e2eiCertificate: E2eiCertificate): Device = copy( + e2eiCertificate = e2eiCertificate ) } diff --git a/app/src/main/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsScreen.kt b/app/src/main/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsScreen.kt index 1e9a71c9e19..a907d318d85 100644 --- a/app/src/main/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsScreen.kt @@ -90,8 +90,11 @@ import com.wire.android.util.deviceDateTimeFormat import com.wire.android.util.ui.UIText import com.wire.kalium.logic.CoreFailure import com.wire.kalium.logic.data.conversation.ClientId +import com.wire.kalium.logic.feature.e2ei.CertificateStatus +import com.wire.kalium.logic.feature.e2ei.E2eiCertificate import com.wire.kalium.logic.feature.e2ei.usecase.E2EIEnrollmentResult import com.wire.kalium.logic.functional.Either +import kotlinx.datetime.Instant @RootNavGraph @Destination( @@ -126,6 +129,7 @@ fun DeviceDetailsScreen( } } +@Suppress("ComplexMethod") @Composable fun DeviceDetailsContent( state: DeviceDetailsState, @@ -185,9 +189,9 @@ fun DeviceDetailsContent( .background(MaterialTheme.wireColorScheme.surface) ) { - state.device.mlsPublicKeys?.forEach { (mlsProtocolType, mlsThumbprint) -> + state.device.e2eiCertificate?.let { certificate -> item { - DeviceMLSSignatureItem(mlsThumbprint, mlsProtocolType, screenState::copyMessage) + DeviceMLSSignatureItem(certificate.thumbprint, screenState::copyMessage) HorizontalDivider(color = MaterialTheme.wireColorScheme.background) } } @@ -321,7 +325,7 @@ private fun DeviceDetailsTopBar( ) if (shouldShowE2EIInfo) { - MLSVerificationIcon(device.e2eiCertificateStatus) + MLSVerificationIcon(device.e2eiCertificate?.status) } if (!isCurrentDevice && device.isVerifiedProteus) { @@ -371,17 +375,9 @@ fun DeviceKeyFingerprintItem( @Composable fun DeviceMLSSignatureItem( mlsThumbprint: String, - mlsProtocolType: String, onCopy: (String) -> Unit ) { - FolderHeader( - name = stringResource(id = R.string.label_mls_signature, mlsProtocolType).uppercase(), - modifier = Modifier - .background(MaterialTheme.wireColorScheme.background) - .fillMaxWidth() - ) - DeviceDetailSectionContent( stringResource(id = R.string.label_mls_thumbprint), sectionText = mlsThumbprint.formatAsFingerPrint(), @@ -576,7 +572,14 @@ fun PreviewDeviceDetailsScreen() { clientId = ClientId(""), name = UIText.DynamicString("My Device"), registrationTime = "2022-03-24T18:02:30.360Z", - mlsPublicKeys = mapOf("Ed25519" to "lekvmrlkgvnrelkmvrlgkvlknrgb0348gi34t09gj34v034ithjoievw") + e2eiCertificate = E2eiCertificate( + "handler", + CertificateStatus.VALID, + "serial", + "Details", + "Thumbprint", + Instant.DISTANT_FUTURE + ) ), isCurrentDevice = false ), diff --git a/app/src/main/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsViewModel.kt index 84ff017311e..d47412c14d3 100644 --- a/app/src/main/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsViewModel.kt @@ -119,7 +119,7 @@ class DeviceDetailsViewModel @Inject constructor( isE2eiCertificateActivated = true, e2eiCertificate = certificate.certificate, isLoadingCertificate = false, - device = state.device.updateE2EICertificateStatus(certificate.certificate.status) + device = state.device.updateE2EICertificate(certificate.certificate) ) } else { state.copy(isE2eiCertificateActivated = false, isLoadingCertificate = false) diff --git a/app/src/main/kotlin/com/wire/android/ui/settings/devices/SelfDevicesViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/settings/devices/SelfDevicesViewModel.kt index 6a57ced5b92..572d963cde7 100644 --- a/app/src/main/kotlin/com/wire/android/ui/settings/devices/SelfDevicesViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/settings/devices/SelfDevicesViewModel.kt @@ -70,10 +70,10 @@ class SelfDevicesViewModel @Inject constructor( isLoadingClientsList = false, currentDevice = result.clients .firstOrNull { it.id == currentClientId } - ?.let { Device(it, e2eiCertificates[it.id.value]?.status) }, + ?.let { Device(it, e2eiCertificates[it.id.value]) }, deviceList = result.clients .filter { it.id != currentClientId } - .map { Device(it, e2eiCertificates[it.id.value]?.status) } + .map { Device(it, e2eiCertificates[it.id.value]) } ) } } diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserDevicesScreen.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserDevicesScreen.kt index d79962556a7..5fb689a69e3 100644 --- a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserDevicesScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserDevicesScreen.kt @@ -124,7 +124,7 @@ private fun OtherUserDevicesContent( onClickAction = onDeviceClick, icon = Icons.Filled.ChevronRight.Icon(), shouldShowVerifyLabel = true, - shouldShowE2EIInfo = item.e2eiCertificateStatus != null + shouldShowE2EIInfo = item.e2eiCertificate != null ) if (index < otherUserDevices.lastIndex) WireDivider() } diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt index 6ee3e4ab374..46b45d282d2 100644 --- a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt @@ -167,7 +167,7 @@ class OtherUserProfileScreenViewModel @Inject constructor( is ObserveClientsByUserIdUseCase.Result.Success -> { state = state.copy(otherUserDevices = it.clients.map { item -> - Device(item, e2eiCertificates[item.id.value]?.status) + Device(item, e2eiCertificates[item.id.value]) }) } } diff --git a/app/src/test/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsViewModelTest.kt index 38b7d5ceaf6..652a9d5962c 100644 --- a/app/src/test/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/settings/devices/DeviceDetailsViewModelTest.kt @@ -37,12 +37,15 @@ import com.wire.kalium.logic.feature.client.GetClientDetailsResult import com.wire.kalium.logic.feature.client.ObserveClientDetailsUseCase import com.wire.kalium.logic.feature.client.Result import com.wire.kalium.logic.feature.client.UpdateClientVerificationStatusUseCase +import com.wire.kalium.logic.feature.e2ei.CertificateStatus +import com.wire.kalium.logic.feature.e2ei.E2eiCertificate import com.wire.kalium.logic.feature.e2ei.usecase.GetE2EICertificateUseCaseResult import com.wire.kalium.logic.feature.e2ei.usecase.GetE2eiCertificateUseCase import com.wire.kalium.logic.feature.user.GetUserInfoResult import com.wire.kalium.logic.feature.user.IsE2EIEnabledUseCase import com.wire.kalium.logic.feature.user.IsPasswordRequiredUseCase import com.wire.kalium.logic.feature.user.ObserveUserInfoUseCase +import com.wire.kalium.util.DateTimeUtil import io.mockk.Called import io.mockk.MockKAnnotations import io.mockk.coEvery @@ -60,6 +63,7 @@ import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import kotlin.time.Duration.Companion.days @OptIn(ExperimentalCoroutinesApi::class) @ExtendWith(CoroutineTestExtension::class) @@ -281,6 +285,29 @@ class DeviceDetailsViewModelTest { assertTrue(viewModel.state.startGettingE2EICertificate) } + @Test + fun `given a client with E2EI certificate, when fetching details, then returns device information`() { + val certificate = E2eiCertificate( + userHandle = "userHandle", + serialNumber = "serialNumber", + certificateDetail = "certificateDetail", + status = CertificateStatus.VALID, + thumbprint = "thumbprint", + endAt = DateTimeUtil.currentInstant().plus(1.days) + ) + runTest { + // given + val (_, viewModel) = Arrangement() + .withRequiredMockSetup() + .withClientDetailsResult(GetClientDetailsResult.Success(TestClient.CLIENT, true)) + .withE2eiCertificate(GetE2EICertificateUseCaseResult.Success(certificate)) + .arrange() + + // then + assertEquals(certificate, viewModel.state.device.e2eiCertificate) + } + } + private class Arrangement { @MockK @@ -370,6 +397,10 @@ class DeviceDetailsViewModelTest { ) } + fun withE2eiCertificate(result: GetE2EICertificateUseCaseResult) = apply { + coEvery { getE2eiCertificate(any()) } returns result + } + fun arrange() = this to viewModel companion object {