Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Display e2ei status of all devices #2584

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.wire.kalium.logic.feature.e2ei.usecase.EnrollE2EIUseCase
import com.wire.kalium.logic.feature.e2ei.usecase.GetE2eiCertificateUseCase
import com.wire.kalium.logic.feature.e2ei.usecase.GetMembersE2EICertificateStatusesUseCase
import com.wire.kalium.logic.feature.e2ei.usecase.GetUserE2eiCertificateStatusUseCase
import com.wire.kalium.logic.feature.e2ei.usecase.GetUserE2eiCertificatesUseCase
import com.wire.kalium.logic.feature.publicuser.GetAllContactsUseCase
import com.wire.kalium.logic.feature.publicuser.GetKnownUserUseCase
import com.wire.kalium.logic.feature.publicuser.RefreshUsersWithoutMetadataUseCase
Expand Down Expand Up @@ -236,4 +237,9 @@ class UserModule {
@Provides
fun provideGetMembersE2EICertificateStatusesUseCase(userScope: UserScope): GetMembersE2EICertificateStatusesUseCase =
userScope.getMembersE2EICertificateStatuses

@ViewModelScoped
@Provides
fun provideGetUserE2eiCertificates(userScope: UserScope): GetUserE2eiCertificatesUseCase =
userScope.getUserE2eiCertificates
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import com.wire.android.BuildConfig
import com.wire.android.R
import com.wire.android.ui.authentication.devices.model.Device
import com.wire.android.ui.authentication.devices.model.lastActiveDescription
import com.wire.android.ui.common.MLSVerificationIcon
import com.wire.android.ui.common.ProteusVerifiedIcon
import com.wire.android.ui.common.button.WireSecondaryButton
import com.wire.android.ui.common.button.getMinTouchMargins
Expand Down Expand Up @@ -179,9 +180,9 @@ private fun DeviceItemTexts(
.wrapContentWidth()
.shimmerPlaceholder(visible = placeholder)
)
MLSVerificationIcon(device.e2eiCertificateStatus)
if (shouldShowVerifyLabel) {
Spacer(modifier = Modifier.width(MaterialTheme.wireDimensions.spacing8x))
// TODO MLS icons here
if (device.isVerifiedProteus) ProteusVerifiedIcon(Modifier.wrapContentWidth().align(Alignment.CenterVertically))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +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.util.inWholeWeeks
import com.wire.kalium.util.DateTimeUtil.toIsoDateTimeString
import kotlinx.datetime.Clock
Expand All @@ -37,16 +38,18 @@ data class Device(
val lastActiveInWholeWeeks: Int? = null,
val isValid: Boolean = true,
val isVerifiedProteus: Boolean = false,
val mlsPublicKeys: Map<String, String>? = null
val mlsPublicKeys: Map<String, String>? = null,
val e2eiCertificateStatus: CertificateStatus? = null
) {
constructor(client: Client) : this(
constructor(client: Client, e2eiCertificateStatus: CertificateStatus? = null) : this(
name = client.displayName(),
clientId = client.id,
registrationTime = client.registrationTime?.toIsoDateTimeString(),
lastActiveInWholeWeeks = client.lastActiveInWholeWeeks(),
isValid = client.isValid,
isVerifiedProteus = client.isVerified,
mlsPublicKeys = client.mlsPublicKeys
mlsPublicKeys = client.mlsPublicKeys,
e2eiCertificateStatus = e2eiCertificateStatus
)
}

Expand Down
48 changes: 48 additions & 0 deletions app/src/main/kotlin/com/wire/android/ui/common/VerifiedIcons.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.wire.android.R
import com.wire.kalium.logic.data.conversation.Conversation
import com.wire.kalium.logic.feature.e2ei.CertificateStatus

@Composable
fun RowScope.ConversationVerificationIcons(
Expand Down Expand Up @@ -66,6 +67,29 @@ fun RowScope.ConversationVerificationIcons(
}
}

@Composable
fun RowScope.MLSVerificationIcon(mlsVerificationStatus: CertificateStatus?) {
val mlsIconModifier = Modifier
.wrapContentWidth()
.align(Alignment.CenterVertically)

when (mlsVerificationStatus) {
CertificateStatus.VALID -> MLSVerifiedIcon(
contentDescriptionId = R.string.e2ei_certificat_status_valid,
modifier = mlsIconModifier
)

CertificateStatus.REVOKED -> MLSRevokedIcon(modifier = mlsIconModifier)

CertificateStatus.EXPIRED -> MLSNotVerifiedIcon(
contentDescriptionId = R.string.e2ei_certificat_status_expired,
modifier = mlsIconModifier
)

null -> MLSNotVerifiedIcon(modifier = mlsIconModifier)
}
}

@Composable
fun ProteusVerifiedIcon(
modifier: Modifier = Modifier,
Expand All @@ -89,3 +113,27 @@ fun MLSVerifiedIcon(
contentDescription = stringResource(contentDescriptionId)
)
}

@Composable
fun MLSRevokedIcon(
modifier: Modifier = Modifier,
@StringRes contentDescriptionId: Int = R.string.e2ei_certificat_status_revoked
) {
Image(
modifier = modifier.padding(start = dimensions().spacing4x),
painter = painterResource(id = R.drawable.ic_certificate_revoked_mls),
contentDescription = stringResource(contentDescriptionId)
)
}

@Composable
fun MLSNotVerifiedIcon(
modifier: Modifier = Modifier,
@StringRes contentDescriptionId: Int = R.string.e2ei_certificat_status_not_activated
) {
Image(
modifier = modifier.padding(start = dimensions().spacing4x),
painter = painterResource(id = R.drawable.ic_certificate_not_activated_mls),
contentDescription = stringResource(contentDescriptionId)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import com.wire.android.ui.authentication.devices.remove.RemoveDeviceDialog
import com.wire.android.ui.authentication.devices.remove.RemoveDeviceDialogState
import com.wire.android.ui.authentication.devices.remove.RemoveDeviceError
import com.wire.android.ui.common.CopyButton
import com.wire.android.ui.common.MLSVerificationIcon
import com.wire.android.ui.common.ProteusVerifiedIcon
import com.wire.android.ui.common.WireDialog
import com.wire.android.ui.common.WireDialogButtonProperties
Expand Down Expand Up @@ -304,6 +305,9 @@ private fun DeviceDetailsTopBar(
style = MaterialTheme.wireTypography.title01,
maxLines = 2
)

MLSVerificationIcon(device.e2eiCertificateStatus)

if (!isCurrentDevice && device.isVerifiedProteus) {
ProteusVerifiedIcon(Modifier.align(Alignment.CenterVertically))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.feature.client.FetchSelfClientsFromRemoteUseCase
import com.wire.kalium.logic.feature.client.ObserveClientsByUserIdUseCase
import com.wire.kalium.logic.feature.client.ObserveCurrentClientIdUseCase
import com.wire.kalium.logic.feature.e2ei.usecase.GetUserE2eiCertificatesUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
Expand All @@ -40,7 +41,8 @@ class SelfDevicesViewModel @Inject constructor(
@CurrentAccount val currentAccountId: UserId,
private val fetchSelfClientsFromRemote: FetchSelfClientsFromRemoteUseCase,
private val observeClientList: ObserveClientsByUserIdUseCase,
private val currentClientIdUseCase: ObserveCurrentClientIdUseCase
private val currentClientIdUseCase: ObserveCurrentClientIdUseCase,
private val getUserE2eiCertificates: GetUserE2eiCertificatesUseCase,
) : ViewModel() {

var state: SelfDevicesState by mutableStateOf(
Expand All @@ -61,13 +63,14 @@ class SelfDevicesViewModel @Inject constructor(
is ObserveClientsByUserIdUseCase.Result.Failure -> state.copy(isLoadingClientsList = false)
is ObserveClientsByUserIdUseCase.Result.Success -> {
val currentClientId = currentClientIdUseCase().firstOrNull()
val e2eiCertificates = getUserE2eiCertificates(currentAccountId)
state.copy(
isLoadingClientsList = false,
currentDevice = result.clients
.firstOrNull { it.id == currentClientId }?.let { Device(it) },
.firstOrNull { it.id == currentClientId }?.let { Device(it, e2eiCertificates[it.id.value]?.status) },
deviceList = result.clients
.filter { it.id != currentClientId }
.map { Device(it) }
.map { Device(it, e2eiCertificates[it.id.value]?.status) }
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import com.wire.kalium.logic.feature.conversation.UpdateConversationMutedStatusU
import com.wire.kalium.logic.feature.e2ei.CertificateStatus
import com.wire.kalium.logic.feature.e2ei.usecase.GetUserE2eiCertificateStatusResult
import com.wire.kalium.logic.feature.e2ei.usecase.GetUserE2eiCertificateStatusUseCase
import com.wire.kalium.logic.feature.e2ei.usecase.GetUserE2eiCertificatesUseCase
import com.wire.kalium.logic.feature.user.GetUserInfoResult
import com.wire.kalium.logic.feature.user.ObserveUserInfoUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
Expand Down Expand Up @@ -105,6 +106,7 @@ class OtherUserProfileScreenViewModel @Inject constructor(
private val clearConversationContentUseCase: ClearConversationContentUseCase,
private val updateConversationArchivedStatus: UpdateConversationArchivedStatusUseCase,
private val getUserE2eiCertificateStatus: GetUserE2eiCertificateStatusUseCase,
private val getUserE2eiCertificates: GetUserE2eiCertificatesUseCase,
savedStateHandle: SavedStateHandle
) : ViewModel(), OtherUserProfileEventsHandler, OtherUserProfileBottomSheetEventsHandler {

Expand Down Expand Up @@ -144,17 +146,18 @@ class OtherUserProfileScreenViewModel @Inject constructor(
}

override fun observeClientList() {
viewModelScope.launch {
viewModelScope.launch(dispatchers.io()) {
observeClientList(userId)
.collect {
val e2eiCertificates = getUserE2eiCertificates(userId)
when (it) {
is ObserveClientsByUserIdUseCase.Result.Failure -> {
/* no-op */
}

is ObserveClientsByUserIdUseCase.Result.Success -> {
state = state.copy(otherUserDevices = it.clients.map { item ->
Device(item)
Device(item, e2eiCertificates[item.id.value]?.status)
})
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.wire.kalium.logic.feature.client.FetchSelfClientsFromRemoteUseCase
import com.wire.kalium.logic.feature.client.ObserveClientsByUserIdUseCase
import com.wire.kalium.logic.feature.client.ObserveCurrentClientIdUseCase
import com.wire.kalium.logic.feature.client.SelfClientsResult
import com.wire.kalium.logic.feature.e2ei.usecase.GetUserE2eiCertificatesUseCase
import io.mockk.coEvery
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
Expand Down Expand Up @@ -66,14 +67,18 @@ class SelfDevicesViewModelTest {
@MockK
lateinit var fetchSelfClientsFromRemote: FetchSelfClientsFromRemoteUseCase

@MockK
lateinit var getUserE2eiCertificates: GetUserE2eiCertificatesUseCase

val selfId = UserId("selfId", "domain")

private val viewModel by lazy {
SelfDevicesViewModel(
observeClientList = observeClientsByUserId,
currentAccountId = selfId,
currentClientIdUseCase = currentClientId,
fetchSelfClientsFromRemote = fetchSelfClientsFromRemote
fetchSelfClientsFromRemote = fetchSelfClientsFromRemote,
getUserE2eiCertificates = getUserE2eiCertificates
)
}

Expand All @@ -89,6 +94,7 @@ class SelfDevicesViewModelTest {
)
)
)
coEvery { getUserE2eiCertificates.invoke(any()) } returns mapOf()
}

fun arrange() = this to viewModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import com.wire.kalium.logic.feature.conversation.UpdateConversationMutedStatusU
import com.wire.kalium.logic.feature.e2ei.CertificateStatus
import com.wire.kalium.logic.feature.e2ei.usecase.GetUserE2eiCertificateStatusResult
import com.wire.kalium.logic.feature.e2ei.usecase.GetUserE2eiCertificateStatusUseCase
import com.wire.kalium.logic.feature.e2ei.usecase.GetUserE2eiCertificatesUseCase
import com.wire.kalium.logic.feature.user.GetSelfUserUseCase
import com.wire.kalium.logic.feature.user.GetUserInfoResult
import com.wire.kalium.logic.feature.user.ObserveUserInfoUseCase
Expand Down Expand Up @@ -108,6 +109,9 @@ internal class OtherUserProfileViewModelArrangement {
@MockK
lateinit var getUserE2eiCertificateStatus: GetUserE2eiCertificateStatusUseCase

@MockK
lateinit var getUserE2eiCertificates: GetUserE2eiCertificatesUseCase

private val viewModel by lazy {
OtherUserProfileScreenViewModel(
TestDispatcherProvider(),
Expand All @@ -126,7 +130,8 @@ internal class OtherUserProfileViewModelArrangement {
clearConversationContent,
updateConversationArchivedStatus,
getUserE2eiCertificateStatus,
savedStateHandle
getUserE2eiCertificates,
savedStateHandle,
)
}

Expand Down Expand Up @@ -155,6 +160,7 @@ internal class OtherUserProfileViewModelArrangement {
GetOneToOneConversationUseCase.Result.Success(OtherUserProfileScreenViewModelTest.CONVERSATION)
)
coEvery { getUserE2eiCertificateStatus.invoke(any()) } returns GetUserE2eiCertificateStatusResult.Success(CertificateStatus.VALID)
coEvery { getUserE2eiCertificates.invoke(any()) } returns mapOf()
}

suspend fun withBlockUserResult(result: BlockUserResult) = apply {
Expand Down
2 changes: 1 addition & 1 deletion kalium
Submodule kalium updated 19 files
+23 −2 logic/src/commonMain/kotlin/com/wire/kalium/logic/data/message/ProtoContentMapper.kt
+49 −0 logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/e2ei/usecase/GetUserE2EIAllCertificatesUseCase.kt
+12 −1 logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/message/MessageScope.kt
+110 −0 logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/message/SendLocationUseCase.kt
+7 −0 logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/UserScope.kt
+4 −5 logic/src/commonTest/kotlin/com/wire/kalium/logic/data/asset/AssetRepositoryTest.kt
+23 −0 logic/src/commonTest/kotlin/com/wire/kalium/logic/data/message/ProtoContentMapperTest.kt
+0 −16 logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/e2ei/EnrollE2EICertificateUseCaseTest.kt
+104 −0 logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/e2ei/GetUserE2eiAllCertificateStatusesUseCaseTest.kt
+2 −5 logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/PersistMigratedMessagesUseCaseTest.kt
+4 −5 logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/SendEditTextMessageUseCaseTest.kt
+5 −5 logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/SendKnockUserCaseTest.kt
+221 −0 logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/SendLocationUseCaseTest.kt
+4 −5 logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/SendTextMessageCaseTest.kt
+20 −4 logic/src/commonTest/kotlin/com/wire/kalium/logic/util/EitherAssertions.kt
+1 −1 persistence/src/commonMain/db_user/com/wire/kalium/persistence/Conversations.sq
+21 −2 testservice/src/main/kotlin/com/wire/kalium/testservice/api/v1/ConversationResources.kt
+36 −0 testservice/src/main/kotlin/com/wire/kalium/testservice/managed/ConversationRepository.kt
+28 −0 testservice/src/main/kotlin/com/wire/kalium/testservice/models/SendLocationRequest.kt
Loading