Skip to content

Commit

Permalink
Merge branch 'release/candidate' into end-sft-one-on-one-call-proteus…
Browse files Browse the repository at this point in the history
…-cherry-pick
  • Loading branch information
ohassine authored Aug 9, 2024
2 parents 868e5ec + 20e5b85 commit 25c8721
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.wire.kalium.logic.StorageFailure
import com.wire.kalium.logic.data.client.MLSClientProvider
import com.wire.kalium.logic.data.conversation.Conversation.ProtocolInfo.MLSCapable.GroupState
import com.wire.kalium.logic.data.conversation.mls.EpochChangesData
import com.wire.kalium.logic.data.conversation.mls.NameAndHandle
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.id.GroupID
import com.wire.kalium.logic.data.id.IdMapper
Expand Down Expand Up @@ -57,8 +58,6 @@ import com.wire.kalium.logic.kaliumLogger
import com.wire.kalium.logic.wrapApiRequest
import com.wire.kalium.logic.wrapMLSRequest
import com.wire.kalium.logic.wrapStorageRequest
import com.wire.kalium.network.api.base.authenticated.client.ClientApi
import com.wire.kalium.network.api.base.authenticated.conversation.ConversationApi
import com.wire.kalium.network.api.authenticated.conversation.ConversationMemberDTO
import com.wire.kalium.network.api.authenticated.conversation.ConversationRenameResponse
import com.wire.kalium.network.api.authenticated.conversation.ConversationResponse
Expand All @@ -67,6 +66,8 @@ import com.wire.kalium.network.api.authenticated.conversation.UpdateConversation
import com.wire.kalium.network.api.authenticated.conversation.UpdateConversationReceiptModeResponse
import com.wire.kalium.network.api.authenticated.conversation.model.ConversationMemberRoleDTO
import com.wire.kalium.network.api.authenticated.conversation.model.ConversationReceiptModeDTO
import com.wire.kalium.network.api.base.authenticated.client.ClientApi
import com.wire.kalium.network.api.base.authenticated.conversation.ConversationApi
import com.wire.kalium.persistence.dao.QualifiedIDEntity
import com.wire.kalium.persistence.dao.client.ClientDAO
import com.wire.kalium.persistence.dao.conversation.ConversationDAO
Expand Down Expand Up @@ -300,6 +301,7 @@ interface ConversationRepository {
suspend fun observeLegalHoldStatusChangeNotified(conversationId: ConversationId): Flow<Either<StorageFailure, Boolean>>

suspend fun getGroupStatusMembersNamesAndHandles(groupID: GroupID): Either<StorageFailure, EpochChangesData>
suspend fun selectMembersNameAndHandle(conversationId: ConversationId): Either<StorageFailure, Map<UserId, NameAndHandle>>
}

@Suppress("LongParameterList", "TooManyFunctions", "LargeClass")
Expand Down Expand Up @@ -1124,6 +1126,13 @@ internal class ConversationDataSource internal constructor(
conversationDAO.selectGroupStatusMembersNamesAndHandles(groupID.value)
}.map { EpochChangesData.fromEntity(it) }

override suspend fun selectMembersNameAndHandle(conversationId: ConversationId): Either<StorageFailure, Map<UserId, NameAndHandle>> =
wrapStorageRequest {
memberDAO.selectMembersNameAndHandle(conversationId.toDao())
.mapValues { NameAndHandle.fromEntity(it.value) }
.mapKeys { it.key.toModel() }
}

companion object {
const val DEFAULT_MEMBER_ROLE = "wire_member"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.wire.kalium.logic.NetworkFailure
import com.wire.kalium.logic.StorageFailure
import com.wire.kalium.logic.data.conversation.MemberMapper
import com.wire.kalium.logic.data.conversation.Recipient
import com.wire.kalium.logic.data.conversation.mls.NameAndHandle
import com.wire.kalium.logic.data.event.Event
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.id.IdMapper
Expand Down Expand Up @@ -161,6 +162,7 @@ interface UserRepository {
suspend fun fetchUsersLegalHoldConsent(userIds: Set<UserId>): Either<CoreFailure, ListUsersLegalHoldConsent>

suspend fun getOneOnOnConversationId(userId: QualifiedID): Either<StorageFailure, ConversationId>
suspend fun getNameAndHandle(userId: UserId): Either<StorageFailure, NameAndHandle>
}

@Suppress("LongParameterList", "TooManyFunctions")
Expand Down Expand Up @@ -634,6 +636,10 @@ internal class UserDataSource internal constructor(
userDAO.getOneOnOnConversationId(userId.toDao())?.toModel()
}

override suspend fun getNameAndHandle(userId: UserId): Either<StorageFailure, NameAndHandle> = wrapStorageRequest {
userDAO.getNameAndHandle(userId.toDao())
}.map { NameAndHandle.fromEntity(it) }

companion object {
internal const val SELF_USER_ID_KEY = "selfUserID"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1845,6 +1845,7 @@ class UserSessionScope internal constructor(
clientIdProvider,
e2eiRepository,
mlsConversationRepository,
conversationRepository,
team.isSelfATeamMember,
updateSupportedProtocols,
clientRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,13 @@ internal class FetchMLSVerificationStatusUseCaseImpl(
// check that all identities are valid and name and handle are matching
for ((userId, wireIdentity) in ccIdentity) {
val persistedMemberInfo = dbData.members[userId]
val isUserVerified = wireIdentity.firstOrNull {
val isUserVerified = wireIdentity.none {
it.status != CryptoCertificateStatus.VALID ||
it.credentialType != CredentialType.X509 ||
it.x509Identity == null ||
it.x509Identity?.displayName != persistedMemberInfo?.name ||
it.x509Identity?.handle?.handle != persistedMemberInfo?.handle
} == null
}
if (!isUserVerified) {
newStatus = VerificationStatus.NOT_VERIFIED
break
Expand All @@ -141,7 +141,7 @@ internal class FetchMLSVerificationStatusUseCaseImpl(
var dbData = epochChangesData

val missingUsers = missingUsers(
usersFromDB = epochChangesData.members.keys.map { it }.toSet(),
usersFromDB = epochChangesData.members.keys,
usersFromCC = ccIdentities.keys
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ package com.wire.kalium.logic.feature.e2ei.usecase
import com.wire.kalium.cryptography.CredentialType
import com.wire.kalium.cryptography.CryptoCertificateStatus
import com.wire.kalium.cryptography.WireIdentity
import com.wire.kalium.logic.data.conversation.ConversationRepository
import com.wire.kalium.logic.data.conversation.MLSConversationRepository
import com.wire.kalium.logic.data.conversation.mls.NameAndHandle
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.feature.e2ei.CertificateStatus
import com.wire.kalium.logic.functional.fold
import com.wire.kalium.logic.functional.getOrElse
import com.wire.kalium.logic.functional.map

/**
* This use case is used to get the e2ei certificates of all the users in Conversation.
Expand All @@ -35,23 +38,27 @@ interface GetMembersE2EICertificateStatusesUseCase {
}

class GetMembersE2EICertificateStatusesUseCaseImpl internal constructor(
private val mlsConversationRepository: MLSConversationRepository
private val mlsConversationRepository: MLSConversationRepository,
private val conversationRepository: ConversationRepository
) : GetMembersE2EICertificateStatusesUseCase {
override suspend operator fun invoke(conversationId: ConversationId, userIds: List<UserId>): Map<UserId, Boolean> =
mlsConversationRepository.getMembersIdentities(conversationId, userIds).fold(
{ mapOf() },
{
it.mapValues { (_, identities) ->
// todo: we need to check the user name and details!
identities.isUserMLSVerified()
mlsConversationRepository.getMembersIdentities(conversationId, userIds)
.map { identities ->
val usersNameAndHandle = conversationRepository.selectMembersNameAndHandle(conversationId).getOrElse(mapOf())

identities.mapValues { (userId, identities) ->
identities.isUserMLSVerified(usersNameAndHandle[userId])
}
}
)
}.getOrElse(mapOf())
}

/**
* @return if given user is verified or not
*/
fun List<WireIdentity>.isUserMLSVerified() = this.isNotEmpty() && this.all {
it.x509Identity != null && it.credentialType == CredentialType.X509 && it.status == CryptoCertificateStatus.VALID
fun List<WireIdentity>.isUserMLSVerified(nameAndHandle: NameAndHandle?) = this.isNotEmpty() && this.all {
it.x509Identity != null
&& it.credentialType == CredentialType.X509
&& it.status == CryptoCertificateStatus.VALID
&& it.x509Identity?.handle?.handle == nameAndHandle?.handle
&& it.x509Identity?.displayName == nameAndHandle?.name
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ package com.wire.kalium.logic.feature.e2ei.usecase

import com.wire.kalium.logic.data.conversation.MLSConversationRepository
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.data.user.UserRepository
import com.wire.kalium.logic.feature.user.IsE2EIEnabledUseCase
import com.wire.kalium.logic.functional.fold
import com.wire.kalium.logic.functional.getOrNull

/**
* This use case is used to get the e2ei certificate status of specific user
Expand All @@ -31,11 +33,14 @@ interface IsOtherUserE2EIVerifiedUseCase {

class IsOtherUserE2EIVerifiedUseCaseImpl internal constructor(
private val mlsConversationRepository: MLSConversationRepository,
private val isE2EIEnabledUseCase: IsE2EIEnabledUseCase
private val isE2EIEnabledUseCase: IsE2EIEnabledUseCase,
private val userRepository: UserRepository
) : IsOtherUserE2EIVerifiedUseCase {
override suspend operator fun invoke(userId: UserId): Boolean =
isE2EIEnabledUseCase() && mlsConversationRepository.getUserIdentity(userId).fold(
{ false },
{ it.isUserMLSVerified() }
)
if (isE2EIEnabledUseCase()) {
val nameHandle = userRepository.getNameAndHandle(userId).getOrNull()
mlsConversationRepository.getUserIdentity(userId).fold({ false }, { it.isUserMLSVerified(nameHandle) })
} else {
false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.wire.kalium.logic.configuration.UserConfigRepository
import com.wire.kalium.logic.configuration.server.ServerConfigRepository
import com.wire.kalium.logic.data.asset.AssetRepository
import com.wire.kalium.logic.data.client.ClientRepository
import com.wire.kalium.logic.data.conversation.ConversationRepository
import com.wire.kalium.logic.data.conversation.JoinExistingMLSConversationsUseCase
import com.wire.kalium.logic.data.conversation.MLSConversationRepository
import com.wire.kalium.logic.data.e2ei.CertificateRevocationListRepository
Expand Down Expand Up @@ -100,6 +101,7 @@ class UserScope internal constructor(
private val clientIdProvider: CurrentClientIdProvider,
private val e2EIRepository: E2EIRepository,
private val mlsConversationRepository: MLSConversationRepository,
private val conversationRepository: ConversationRepository,
private val isSelfATeamMember: IsSelfATeamMemberUseCase,
private val updateSelfUserSupportedProtocolsUseCase: UpdateSelfUserSupportedProtocolsUseCase,
private val clientRepository: ClientRepository,
Expand Down Expand Up @@ -133,7 +135,8 @@ class UserScope internal constructor(
val getUserE2eiCertificateStatus: IsOtherUserE2EIVerifiedUseCase
get() = IsOtherUserE2EIVerifiedUseCaseImpl(
mlsConversationRepository = mlsConversationRepository,
isE2EIEnabledUseCase = isE2EIEnabledUseCase
isE2EIEnabledUseCase = isE2EIEnabledUseCase,
userRepository = userRepository
)
val getUserE2eiCertificates: GetUserE2eiCertificatesUseCase
get() = GetUserE2eiCertificatesUseCaseImpl(
Expand All @@ -142,7 +145,8 @@ class UserScope internal constructor(
)
val getMembersE2EICertificateStatuses: GetMembersE2EICertificateStatusesUseCase
get() = GetMembersE2EICertificateStatusesUseCaseImpl(
mlsConversationRepository = mlsConversationRepository
mlsConversationRepository = mlsConversationRepository,
conversationRepository = conversationRepository
)
val deleteAsset: DeleteAssetUseCase get() = DeleteAssetUseCaseImpl(assetRepository)
val setUserHandle: SetUserHandleUseCase get() = SetUserHandleUseCase(accountRepository, validateUserHandleUseCase, syncManager)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ import com.wire.kalium.cryptography.CryptoCertificateStatus
import com.wire.kalium.cryptography.CryptoQualifiedClientId
import com.wire.kalium.cryptography.WireIdentity
import com.wire.kalium.logic.MLSFailure
import com.wire.kalium.logic.data.conversation.mls.NameAndHandle
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.id.toCrypto
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.feature.e2ei.usecase.GetMembersE2EICertificateStatusesUseCaseImpl
import com.wire.kalium.logic.functional.Either
import com.wire.kalium.logic.util.arrangement.mls.MLSConversationRepositoryArrangement
import com.wire.kalium.logic.util.arrangement.mls.MLSConversationRepositoryArrangementImpl
import io.mockative.matchers.EqualsMatcher
import com.wire.kalium.logic.util.arrangement.repository.ConversationRepositoryArrangement
import com.wire.kalium.logic.util.arrangement.repository.ConversationRepositoryArrangementImpl
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant
Expand All @@ -54,6 +56,7 @@ class GetMembersE2EICertificateStatusesUseCaseTest {
fun givenEmptyWireIdentityMap_whenRequestMembersStatuses_thenNotActivatedResult() = runTest {
val (_, getMembersE2EICertificateStatuses) = arrange {
withMembersIdentities(Either.Right(mapOf()))
withMembersNameAndHandle(Either.Right(mapOf()))
}

val result = getMembersE2EICertificateStatuses(CONVERSATION_ID, listOf())
Expand All @@ -65,6 +68,7 @@ class GetMembersE2EICertificateStatusesUseCaseTest {
fun givenOneWireIdentityExpiredForSomeUser_whenRequestMembersStatuses_thenResultUsersStatusIsExpired() =
runTest {
val (_, getMembersE2EICertificateStatuses) = arrange {
withMembersNameAndHandle(Either.Right(mapOf(USER_ID to NAME_AND_HANDLE)))
withMembersIdentities(
Either.Right(
mapOf(
Expand All @@ -87,6 +91,7 @@ class GetMembersE2EICertificateStatusesUseCaseTest {
runTest {
val userId2 = USER_ID.copy(value = "value_2")
val (_, getMembersE2EICertificateStatuses) = arrange {
withMembersNameAndHandle(Either.Right(mapOf(userId2 to NAME_AND_HANDLE)))
withMembersIdentities(
Either.Right(
mapOf(
Expand All @@ -108,12 +113,14 @@ class GetMembersE2EICertificateStatusesUseCaseTest {
}

private class Arrangement(private val block: suspend Arrangement.() -> Unit) :
MLSConversationRepositoryArrangement by MLSConversationRepositoryArrangementImpl() {
MLSConversationRepositoryArrangement by MLSConversationRepositoryArrangementImpl(),
ConversationRepositoryArrangement by ConversationRepositoryArrangementImpl() {

fun arrange() = run {
runBlocking { block() }
this@Arrangement to GetMembersE2EICertificateStatusesUseCaseImpl(
mlsConversationRepository = mlsConversationRepository
mlsConversationRepository = mlsConversationRepository,
conversationRepository = conversationRepository
)
}
}
Expand Down Expand Up @@ -145,5 +152,7 @@ class GetMembersE2EICertificateStatusesUseCaseTest {
notAfter = Instant.DISTANT_FUTURE.epochSeconds
)
)

private val NAME_AND_HANDLE = NameAndHandle(name = "user displayName", handle = "userHandle")
}
}
Loading

0 comments on commit 25c8721

Please sign in to comment.