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

Merged
merged 15 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from 13 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 @@ -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,14 +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): 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 @@ -56,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()
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ private fun DeviceItemTexts(
)
if (shouldShowVerifyLabel) {
if (shouldShowE2EIInfo) {
MLSVerificationIcon(device.e2eiCertificate?.status)
MLSVerificationIcon(device.mlsClientIdentity?.e2eiStatus)
}
Spacer(modifier = Modifier.width(MaterialTheme.wireDimensions.spacing8x))
if (device.isVerifiedProteus && !isCurrentClient) ProteusVerifiedIcon(
Expand All @@ -205,15 +205,15 @@ private fun 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 @@ -30,7 +30,6 @@ 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 kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.drop
Expand All @@ -55,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 @@ -74,9 +73,9 @@ class ObserveParticipantsForConversationUseCase @Inject constructor(

ConversationParticipantsData(
admins = visibleAdminsWithoutServices
.map { uiParticipantMapper.toUIParticipant(it.user, mlsVerificationMap[it.user.id]) },
.map { uiParticipantMapper.toUIParticipant(it.user, mlsVerificationMap[it.user.id].let { false }) },
participants = visibleParticipants
.map { uiParticipantMapper.toUIParticipant(it.user, mlsVerificationMap[it.user.id]) },
.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 @@ -91,8 +91,13 @@ import com.wire.android.util.extension.formatAsString
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 @@ -136,7 +141,7 @@ fun DeviceDetailsContent(
state: DeviceDetailsState,
onDeleteDevice: () -> Unit = {},
onNavigateBack: () -> Unit = {},
onNavigateToE2eiCertificateDetailsScreen: (E2eiCertificate) -> Unit = {},
onNavigateToE2eiCertificateDetailsScreen: (MLSClientIdentity) -> Unit = {},
onPasswordChange: (TextFieldValue) -> Unit = {},
onRemoveConfirm: () -> Unit = {},
onDialogDismiss: () -> Unit = {},
Expand Down Expand Up @@ -189,10 +194,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)
Divider(color = MaterialTheme.wireColorScheme.background)
}
}
Expand All @@ -201,7 +205,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 @@ -291,9 +295,9 @@ fun DeviceDetailsContent(
)
}

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

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

if (!isCurrentDevice && device.isVerifiedProteus) {
Expand Down Expand Up @@ -573,14 +577,21 @@ fun PreviewDeviceDetailsScreen() {
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
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ 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.usecase.E2EIEnrollmentResult
import com.wire.kalium.logic.feature.e2ei.usecase.GetE2EICertificateUseCaseResult
import com.wire.kalium.logic.feature.e2ei.usecase.GetE2eiCertificateUseCase
import com.wire.kalium.logic.feature.e2ei.usecase.GetMLSClientIdentityUseCase
import com.wire.kalium.logic.feature.user.GetUserInfoResult
import com.wire.kalium.logic.feature.user.IsE2EIEnabledUseCase
import com.wire.kalium.logic.feature.user.IsPasswordRequiredUseCase
Expand All @@ -68,7 +67,7 @@ class DeviceDetailsViewModel @Inject constructor(
private val fingerprintUseCase: ClientFingerprintUseCase,
private val updateClientVerificationStatus: UpdateClientVerificationStatusUseCase,
private val observeUserInfo: ObserveUserInfoUseCase,
private val e2eiCertificate: GetE2eiCertificateUseCase,
private val e2eiCertificate: GetMLSClientIdentityUseCase,
isE2EIEnabledUseCase: IsE2EIEnabledUseCase
) : SavedStateViewModel(savedStateHandle) {

Expand Down Expand Up @@ -113,17 +112,16 @@ class DeviceDetailsViewModel @Inject constructor(

private fun getE2eiCertificate() {
viewModelScope.launch {
val certificate = e2eiCertificate(deviceId)
state = if (certificate is GetE2EICertificateUseCaseResult.Success) {
state = e2eiCertificate(deviceId).fold({
state.copy(isE2eiCertificateActivated = false, isLoadingCertificate = false)
}, { mlsClientIdentity ->
state.copy(
isE2eiCertificateActivated = true,
e2eiCertificate = certificate.certificate,
mlsClientIdentity = mlsClientIdentity,
isLoadingCertificate = false,
device = state.device.updateE2EICertificate(certificate.certificate)
device = state.device.updateE2EICertificate(mlsClientIdentity)
)
} else {
state.copy(isE2eiCertificateActivated = false, isLoadingCertificate = false)
}
})
}
}

Expand Down
Loading
Loading