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

chore(mls): unify MLS client identity models (WPB-9774) 🍒 #3107 #3233

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ import com.wire.kalium.logic.feature.asset.GetAvatarAssetUseCase
import com.wire.kalium.logic.feature.client.FinalizeMLSClientAfterE2EIEnrollment
import com.wire.kalium.logic.feature.conversation.GetAllContactsNotInConversationUseCase
import com.wire.kalium.logic.feature.e2ei.CertificateRevocationListCheckWorker
import com.wire.kalium.logic.feature.e2ei.usecase.GetE2eiCertificateUseCase
import com.wire.kalium.logic.feature.e2ei.usecase.GetMLSClientIdentityUseCase
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.IsOtherUserE2EIVerifiedUseCase
import com.wire.kalium.logic.feature.e2ei.usecase.GetUserE2eiCertificatesUseCase
import com.wire.kalium.logic.feature.e2ei.usecase.ObserveCertificateRevocationForSelfClientUseCase
import com.wire.kalium.logic.feature.featureConfig.FeatureFlagsSyncWorker
Expand Down Expand Up @@ -212,12 +212,12 @@ class UserModule {

@ViewModelScoped
@Provides
fun provideGetE2EICertificateUseCase(userScope: UserScope): GetE2eiCertificateUseCase =
fun provideGetE2EICertificateUseCase(userScope: UserScope): GetMLSClientIdentityUseCase =
userScope.getE2EICertificate

@ViewModelScoped
@Provides
fun provideGetUserE2eiCertificateStatusUseCase(userScope: UserScope): GetUserE2eiCertificateStatusUseCase =
fun provideGetUserE2eiCertificateStatusUseCase(userScope: UserScope): IsOtherUserE2EIVerifiedUseCase =
userScope.getUserE2eiCertificateStatus

@ViewModelScoped
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,13 @@ import com.wire.kalium.logic.data.user.OtherUser
import com.wire.kalium.logic.data.user.SelfUser
import com.wire.kalium.logic.data.user.User
import com.wire.kalium.logic.data.user.type.UserType
import com.wire.kalium.logic.feature.e2ei.CertificateStatus
import javax.inject.Inject

class UIParticipantMapper @Inject constructor(
private val userTypeMapper: UserTypeMapper,
private val wireSessionImageLoader: WireSessionImageLoader
) {
fun toUIParticipant(
user: User,
mlsCertificateStatus: CertificateStatus? = null,
isUnderLegalHold: Boolean = false,
): UIParticipant = with(user) {
fun toUIParticipant(user: User, isMLSVerified: Boolean = false): UIParticipant = with(user) {
val (userType, connectionState, unavailable) = when (this) {
is OtherUser -> Triple(this.userType, this.connectionStatus, this.isUnavailableUser)
// TODO(refactor): does self user need a type ? to false
Expand All @@ -60,7 +55,7 @@ class UIParticipantMapper @Inject constructor(
botService = (user as? OtherUser)?.botService,
isDefederated = (user is OtherUser && user.defederated),
isProteusVerified = (user is OtherUser && user.isProteusVerified),
isMLSVerified = mlsCertificateStatus == CertificateStatus.VALID,
isMLSVerified = isMLSVerified,
supportedProtocolList = supportedProtocols.orEmpty().toList(),
isUnderLegalHold = isUnderLegalHold,
)
Expand Down
11 changes: 10 additions & 1 deletion app/src/main/kotlin/com/wire/android/ui/WireActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ import com.wire.android.ui.legalhold.dialog.deactivated.LegalHoldDeactivatedView
import com.wire.android.ui.legalhold.dialog.requested.LegalHoldRequestedDialog
import com.wire.android.ui.legalhold.dialog.requested.LegalHoldRequestedState
import com.wire.android.ui.legalhold.dialog.requested.LegalHoldRequestedViewModel
import com.wire.android.ui.settings.devices.e2ei.E2EICertificateDetails
import com.wire.android.ui.theme.ThemeOption
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.userprofile.self.dialog.LogoutOptionsDialog
Expand Down Expand Up @@ -416,7 +417,15 @@ class WireActivity : AppCompatActivity() {
result = e2EIResult,
updateCertificate = featureFlagNotificationViewModel::enrollE2EICertificate,
snoozeDialog = featureFlagNotificationViewModel::snoozeE2EIdRequiredDialog,
openCertificateDetails = { navigate(NavigationCommand(E2eiCertificateDetailsScreenDestination(it))) },
openCertificateDetails = {
navigate(
NavigationCommand(
E2eiCertificateDetailsScreenDestination(
E2EICertificateDetails.DuringLoginCertificateDetails(it)
)
)
)
},
dismissSuccessDialog = featureFlagNotificationViewModel::dismissSuccessE2EIdDialog,
isE2EILoading = isE2EILoading
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ private fun ColumnScope.DeviceItemTexts(
)
if (shouldShowVerifyLabel) {
if (shouldShowE2EIInfo) {
MLSVerificationIcon(device.e2eiCertificate?.status)
MLSVerificationIcon(device.mlsClientIdentity?.e2eiStatus)
}
if (device.isVerifiedProteus && !isCurrentClient) {
ProteusVerifiedIcon(
Expand All @@ -216,15 +216,15 @@ private fun ColumnScope.DeviceItemTexts(

Spacer(modifier = Modifier.height(MaterialTheme.wireDimensions.removeDeviceItemTitleVerticalPadding))

device.e2eiCertificate?.let { certificate ->
device.mlsClientIdentity?.let { identity ->
Text(
style = MaterialTheme.wireTypography.subline01,
color = MaterialTheme.wireColorScheme.labelText,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
text = stringResource(
R.string.remove_device_mls_thumbprint_label,
certificate.thumbprint.formatAsFingerPrint()
identity.thumbprint.formatAsFingerPrint()
),
modifier = Modifier
.fillMaxWidth()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.E2eiCertificate
import com.wire.kalium.logic.feature.e2ei.MLSClientIdentity
import com.wire.kalium.logic.util.inWholeWeeks
import com.wire.kalium.util.DateTimeUtil.toIsoDateTimeString
import kotlinx.datetime.Clock
Expand All @@ -38,16 +38,16 @@ data class Device(
val lastActiveInWholeWeeks: Int? = null,
val isValid: Boolean = true,
val isVerifiedProteus: Boolean = false,
val e2eiCertificate: E2eiCertificate? = null
val mlsClientIdentity: MLSClientIdentity? = null
) {
constructor(client: Client, e2eiCertificate: E2eiCertificate? = null) : this(
constructor(client: Client, mlsClientIdentity: MLSClientIdentity? = null) : this(
name = client.displayName(),
clientId = client.id,
registrationTime = client.registrationTime?.toIsoDateTimeString(),
lastActiveInWholeWeeks = client.lastActiveInWholeWeeks(),
isValid = client.isValid,
isVerifiedProteus = client.isVerified,
e2eiCertificate = e2eiCertificate
mlsClientIdentity = mlsClientIdentity
)

fun updateFromClient(client: Client): Device = copy(
Expand All @@ -57,11 +57,11 @@ data class Device(
lastActiveInWholeWeeks = client.lastActiveInWholeWeeks(),
isValid = client.isValid,
isVerifiedProteus = client.isVerified,
e2eiCertificate = null,
mlsClientIdentity = null,
)

fun updateE2EICertificate(e2eiCertificate: E2eiCertificate): Device = copy(
e2eiCertificate = e2eiCertificate
fun updateE2EICertificate(mlsClientIdentity: MLSClientIdentity): Device = copy(
mlsClientIdentity = mlsClientIdentity
)
}

Expand Down
13 changes: 8 additions & 5 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,7 +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
import com.wire.kalium.logic.feature.e2ei.MLSClientE2EIStatus

@Composable
fun RowScope.ConversationVerificationIcons(
Expand Down Expand Up @@ -68,24 +68,27 @@ fun RowScope.ConversationVerificationIcons(
}

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

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

CertificateStatus.REVOKED -> MLSRevokedIcon(modifier = mlsIconModifier)
MLSClientE2EIStatus.REVOKED -> MLSRevokedIcon(modifier = mlsIconModifier)

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

MLSClientE2EIStatus.NOT_ACTIVATED -> MLSNotVerifiedIcon(modifier = mlsIconModifier)

null -> MLSNotVerifiedIcon(modifier = mlsIconModifier)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import com.wire.android.ui.destinations.InitialSyncScreenDestination
import com.wire.android.ui.home.E2EIEnrollmentErrorWithDismissDialog
import com.wire.android.ui.home.E2EISuccessDialog
import com.wire.android.ui.markdown.MarkdownConstants
import com.wire.android.ui.settings.devices.e2ei.E2EICertificateDetails
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.theme.wireTypography
Expand Down Expand Up @@ -85,7 +86,13 @@ fun E2EIEnrollmentScreen(
enrollE2EICertificate = viewModel::enrollE2EICertificate,
handleE2EIEnrollmentResult = viewModel::handleE2EIEnrollmentResult,
openCertificateDetails = {
navigator.navigate(NavigationCommand(E2eiCertificateDetailsScreenDestination(state.certificate)))
navigator.navigate(
NavigationCommand(
E2eiCertificateDetailsScreenDestination(
E2EICertificateDetails.DuringLoginCertificateDetails(state.certificate)
)
)
)
},
onBackButtonClicked = viewModel::onBackButtonClicked,
onCancelEnrollmentClicked = { viewModel.onCancelEnrollmentClicked(NavigationSwitchAccountActions(navigator::navigate)) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,13 @@ import com.wire.android.ui.home.conversations.name
import com.wire.android.ui.home.conversations.userId
import com.wire.android.util.dispatchers.DispatcherProvider
import com.wire.kalium.logic.data.conversation.Conversation.Member
import com.wire.kalium.logic.data.conversation.MemberDetails
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.user.OtherUser
import com.wire.kalium.logic.data.user.SelfUser
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.data.user.type.UserType
import com.wire.kalium.logic.feature.conversation.ObserveConversationMembersUseCase
import com.wire.kalium.logic.feature.e2ei.CertificateStatus
import com.wire.kalium.logic.feature.e2ei.usecase.GetMembersE2EICertificateStatusesUseCase
import com.wire.kalium.logic.feature.legalhold.MembersHavingLegalHoldClientUseCase
import com.wire.kalium.logic.functional.getOrElse
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.flowOn
Expand All @@ -45,7 +41,6 @@ import javax.inject.Inject
class ObserveParticipantsForConversationUseCase @Inject constructor(
private val observeConversationMembers: ObserveConversationMembersUseCase,
private val getMembersE2EICertificateStatuses: GetMembersE2EICertificateStatusesUseCase,
private val membersHavingLegalHoldClientUseCase: MembersHavingLegalHoldClientUseCase,
private val uiParticipantMapper: UIParticipantMapper,
private val dispatchers: DispatcherProvider
) {
Expand All @@ -59,7 +54,7 @@ class ObserveParticipantsForConversationUseCase @Inject constructor(
}
}
.scan(
ConversationParticipantsData() to emptyMap<UserId, CertificateStatus?>()
ConversationParticipantsData() to emptyMap<UserId, Boolean>()
) { (_, previousMlsVerificationMap), sortedMemberList ->
val allAdminsWithoutServices = sortedMemberList.getOrDefault(true, listOf())
val visibleAdminsWithoutServices = allAdminsWithoutServices.limit(limit)
Expand All @@ -78,16 +73,14 @@ class ObserveParticipantsForConversationUseCase @Inject constructor(
getMembersE2EICertificateStatuses(conversationId, newlyEmittedVisibleUserIds)
}
)
val legalHoldList = membersHavingLegalHoldClientUseCase(conversationId).getOrElse(emptyList())

fun List<MemberDetails>.toUIParticipants() = this.map {
uiParticipantMapper.toUIParticipant(it.user, mlsVerificationMap[it.userId], legalHoldList.contains(it.userId))
}
val selfUser = (allParticipants + allAdminsWithoutServices).firstOrNull { it.user is SelfUser }

ConversationParticipantsData(
admins = visibleAdminsWithoutServices.toUIParticipants(),
participants = visibleParticipants.toUIParticipants(),
admins = visibleAdminsWithoutServices
.map { uiParticipantMapper.toUIParticipant(it.user, mlsVerificationMap[it.user.id].let { false }) },
participants = visibleParticipants
.map { uiParticipantMapper.toUIParticipant(it.user, mlsVerificationMap[it.user.id].let { false }) },
allAdminsCount = allAdminsWithoutServices.size,
allParticipantsCount = allParticipants.size,
isSelfAnAdmin = allAdminsWithoutServices.any { it.user is SelfUser },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import com.wire.android.ui.e2eiEnrollment.GetE2EICertificateUI
import com.wire.android.ui.home.E2EISuccessDialog
import com.wire.android.ui.home.E2EIUpdateErrorWithDismissDialog
import com.wire.android.ui.home.conversationslist.common.FolderHeader
import com.wire.android.ui.settings.devices.e2ei.E2EICertificateDetails
import com.wire.android.ui.settings.devices.model.DeviceDetailsState
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireColorScheme
Expand All @@ -90,8 +91,13 @@ import com.wire.android.util.ui.PreviewMultipleThemes
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.data.id.QualifiedClientID
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.feature.e2ei.Handle
import com.wire.kalium.logic.feature.e2ei.MLSClientE2EIStatus
import com.wire.kalium.logic.feature.e2ei.MLSClientIdentity
import com.wire.kalium.logic.feature.e2ei.MLSCredentialsType
import com.wire.kalium.logic.feature.e2ei.X509Identity
import com.wire.kalium.logic.feature.e2ei.usecase.E2EIEnrollmentResult
import com.wire.kalium.logic.functional.Either
import kotlinx.datetime.Instant
Expand Down Expand Up @@ -120,7 +126,11 @@ fun DeviceDetailsScreen(
handleE2EIEnrollmentResult = viewModel::handleE2EIEnrollmentResult,
onNavigateToE2eiCertificateDetailsScreen = {
navigator.navigate(
NavigationCommand(E2eiCertificateDetailsScreenDestination(it))
NavigationCommand(
E2eiCertificateDetailsScreenDestination(
E2EICertificateDetails.AfterLoginCertificateDetails(it)
)
)
)
},
onEnrollE2EIErrorDismiss = viewModel::hideEnrollE2EICertificateError,
Expand All @@ -138,7 +148,7 @@ fun DeviceDetailsContent(
modifier: Modifier = Modifier,
onDeleteDevice: () -> Unit = {},
onNavigateBack: () -> Unit = {},
onNavigateToE2eiCertificateDetailsScreen: (String) -> Unit = {},
onNavigateToE2eiCertificateDetailsScreen: (MLSClientIdentity) -> Unit = {},
onRemoveConfirm: () -> Unit = {},
onDialogDismiss: () -> Unit = {},
onErrorDialogDismiss: () -> Unit = {},
Expand Down Expand Up @@ -190,10 +200,9 @@ fun DeviceDetailsContent(
.padding(internalPadding)
.background(MaterialTheme.wireColorScheme.surface)
) {

state.device.e2eiCertificate?.let { certificate ->
state.device.mlsClientIdentity?.let { identity ->
item {
DeviceMLSSignatureItem(certificate.thumbprint, screenState::copyMessage)
DeviceMLSSignatureItem(identity.thumbprint, screenState::copyMessage)
HorizontalDivider(color = MaterialTheme.wireColorScheme.background)
}
}
Expand All @@ -202,7 +211,7 @@ fun DeviceDetailsContent(
item {
EndToEndIdentityCertificateItem(
isE2eiCertificateActivated = state.isE2eiCertificateActivated,
certificate = state.e2eiCertificate,
mlsClientIdentity = state.mlsClientIdentity,
isCurrentDevice = state.isCurrentDevice,
isLoadingCertificate = state.isLoadingCertificate,
enrollE2eiCertificate = { enrollE2eiCertificate() },
Expand Down Expand Up @@ -292,9 +301,9 @@ fun DeviceDetailsContent(
)
}

if (state.isE2EICertificateEnrollSuccess) {
if (state.isE2EICertificateEnrollSuccess && state.mlsClientIdentity != null) {
E2EISuccessDialog(
openCertificateDetails = { onNavigateToE2eiCertificateDetailsScreen(state.e2eiCertificate.certificateDetail) },
openCertificateDetails = { onNavigateToE2eiCertificateDetailsScreen(state.mlsClientIdentity) },
dismissDialog = onEnrollE2EISuccessDismiss
)
}
Expand Down Expand Up @@ -327,7 +336,7 @@ private fun DeviceDetailsTopBar(
)

if (shouldShowE2EIInfo) {
MLSVerificationIcon(device.e2eiCertificate?.status)
MLSVerificationIcon(device.mlsClientIdentity?.e2eiStatus)
}

if (!isCurrentDevice && device.isVerifiedProteus) {
Expand Down Expand Up @@ -584,14 +593,21 @@ fun PreviewDeviceDetailsScreen() = WireTheme {
clientId = ClientId(""),
name = UIText.DynamicString("My Device"),
registrationTime = "2022-03-24T18:02:30.360Z",
e2eiCertificate = E2eiCertificate(
"handler",
CertificateStatus.VALID,
"serial",
"Details",
"Thumbprint",
Instant.DISTANT_FUTURE
)
mlsClientIdentity = MLSClientIdentity(
clientId = QualifiedClientID(ClientId(""), UserId("", "")),
e2eiStatus = MLSClientE2EIStatus.VALID,
thumbprint = "thumbprint",
credentialType = MLSCredentialsType.X509,
x509Identity = X509Identity(
handle = Handle("", "", ""),
displayName = "",
domain = "",
certificate = "",
serialNumber = "e5:d5:e6:75:7e:04:86:07:14:3c:a0:ed:9a:8d:e4:fd",
notBefore = Instant.DISTANT_PAST,
notAfter = Instant.DISTANT_FUTURE
)
),
),
isCurrentDevice = false
),
Expand Down
Loading
Loading