From f4afb2a34db29d7d2915a2505533ff826cc7d5ff Mon Sep 17 00:00:00 2001 From: Mohamad Jaara Date: Wed, 29 Jan 2025 14:30:13 +0100 Subject: [PATCH 1/2] refactor: stop updating user info in the background [WPB-14826] (#3249) * refactor: stop updating user info in the background * detekt --- .../logic/data/logout/LogoutRepository.kt | 2 - .../kalium/logic/data/user/UserRepository.kt | 134 +----------- .../kalium/logic/feature/UserSessionScope.kt | 1 - .../logic/data/user/UserRepositoryTest.kt | 199 +----------------- 4 files changed, 11 insertions(+), 325 deletions(-) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/logout/LogoutRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/logout/LogoutRepository.kt index b898e922b4d..768abd7142c 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/logout/LogoutRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/logout/LogoutRepository.kt @@ -19,7 +19,6 @@ package com.wire.kalium.logic.data.logout import com.wire.kalium.logic.CoreFailure -import com.wire.kalium.logic.data.user.UserDataSource import com.wire.kalium.logic.functional.Either import com.wire.kalium.logic.wrapApiRequest import com.wire.kalium.logic.wrapStorageRequest @@ -75,7 +74,6 @@ internal class LogoutDataSource( metadataDAO.clear( keysToKeep = listOf( ClientRegistrationStorageImpl.RETAINED_CLIENT_ID_KEY, - UserDataSource.SELF_USER_ID_KEY ) ) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/user/UserRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/user/UserRepository.kt index 8b383d2b203..4deb535169d 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/user/UserRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/user/UserRepository.kt @@ -18,7 +18,6 @@ package com.wire.kalium.logic.data.user -import co.touchlab.stately.collections.ConcurrentMutableMap import com.wire.kalium.logger.obfuscateDomain import com.wire.kalium.logic.CoreFailure import com.wire.kalium.logic.NetworkFailure @@ -48,7 +47,6 @@ import com.wire.kalium.logic.failure.SelfUserDeleted import com.wire.kalium.logic.functional.Either import com.wire.kalium.logic.functional.flatMap import com.wire.kalium.logic.functional.flatMapLeft -import com.wire.kalium.logic.functional.fold import com.wire.kalium.logic.functional.foldToEitherWhileRight import com.wire.kalium.logic.functional.getOrNull import com.wire.kalium.logic.functional.map @@ -74,28 +72,13 @@ import com.wire.kalium.network.api.model.UserProfileDTO import com.wire.kalium.network.api.model.isTeamMember import com.wire.kalium.persistence.dao.ConnectionEntity import com.wire.kalium.persistence.dao.ConversationIDEntity -import com.wire.kalium.persistence.dao.MetadataDAO -import com.wire.kalium.persistence.dao.QualifiedIDEntity import com.wire.kalium.persistence.dao.UserDAO import com.wire.kalium.persistence.dao.UserIDEntity import com.wire.kalium.persistence.dao.UserTypeEntity import com.wire.kalium.persistence.dao.client.ClientDAO -import com.wire.kalium.util.DateTimeUtil -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.async -import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock -import kotlinx.datetime.Instant -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import kotlin.time.Duration.Companion.minutes @Suppress("TooManyFunctions") interface UserRepository { @@ -178,7 +161,6 @@ interface UserRepository { @Suppress("LongParameterList", "TooManyFunctions") internal class UserDataSource internal constructor( private val userDAO: UserDAO, - private val metadataDAO: MetadataDAO, private val clientDAO: ClientDAO, private val selfApi: SelfApi, private val userDetailsApi: UserDetailsApi, @@ -196,17 +178,6 @@ internal class UserDataSource internal constructor( private val memberMapper: MemberMapper = MapperProvider.memberMapper(), ) : UserRepository { - /** - * Stores the last time a user's details were fetched from remote. - * - * @see Event.User.Update - * @see USER_DETAILS_MAX_AGE - */ - private val userDetailsRefreshInstantCache = ConcurrentMutableMap() - - private var userRefresh: Deferred>? = null - private val userRefreshMutex: Mutex = Mutex() - override suspend fun fetchSelfUser(): Either = wrapApiRequest { selfApi.getSelfInfo() } .flatMap { selfUserDTO -> selfUserDTO.teamId.let { selfUserTeamId -> @@ -228,9 +199,6 @@ internal class UserDataSource internal constructor( } .flatMap { userEntity -> wrapStorageRequest { userDAO.upsertUser(userEntity) } - .flatMap { - wrapStorageRequest { metadataDAO.insertValue(Json.encodeToString(userEntity.id), SELF_USER_ID_KEY) } - } } } } @@ -242,10 +210,6 @@ internal class UserDataSource internal constructor( userDAO.observeUserDetailsByQualifiedID(qualifiedID = userId.toDao()) .map { userEntity -> userEntity?.let { userMapper.fromUserDetailsEntityToOtherUser(userEntity) } - }.onEach { otherUser -> - if (otherUser != null) { - refreshUserDetailsIfNeeded(userId) - } } override suspend fun getUsersWithOneOnOneConversation(): List { @@ -253,37 +217,6 @@ internal class UserDataSource internal constructor( .map(userMapper::fromUserEntityToOtherUser) } - private suspend fun refreshUserDetailsIfNeeded(userId: UserId): Either = coroutineScope { - userRefreshMutex.withLock { - val now = DateTimeUtil.currentInstant() - val wasFetchedRecently = userDetailsRefreshInstantCache[userId]?.let { now < it + USER_DETAILS_MAX_AGE } ?: false - - if (wasFetchedRecently) return@coroutineScope Either.Right(Unit) - - if (userRefresh?.isActive == true) return@coroutineScope userRefresh?.await() ?: error("") - - userRefresh = async { refreshUserDetails(userId) } - } - - userRefresh?.await() ?: error("") - } - - /** - * Only refresh user profiles if it wasn't fetched recently. - * - * @see userDetailsRefreshInstantCache - * @see USER_DETAILS_MAX_AGE - */ - private suspend fun refreshUserDetails(userId: UserId): Either { - return when (userId) { - selfUserId -> fetchSelfUser() - else -> fetchUserInfo(userId) - }.also { - kaliumLogger.d("Refreshing user info from API after $USER_DETAILS_MAX_AGE") - userDetailsRefreshInstantCache[userId] = DateTimeUtil.currentInstant() - } - } - override suspend fun fetchAllOtherUsers(): Either { val ids = userDAO.allOtherUsersId().map(UserIDEntity::toModel).toSet() return fetchUsersByIds(ids).map { } @@ -435,52 +368,15 @@ internal class UserDataSource internal constructor( } override suspend fun observeSelfUser(): Flow { - - val selfUser = getOrFetchSelfUserId() - - return if (selfUser != null) { - userDAO.observeUserDetailsByQualifiedID(selfUser).filterNotNull() - .map(userMapper::fromUserDetailsEntityToSelfUser) - } else { - emptyFlow() - } + return userDAO.observeUserDetailsByQualifiedID(selfUserId.toDao()).filterNotNull() + .map(userMapper::fromUserDetailsEntityToSelfUser) } - private suspend fun getOrFetchSelfUserId(): QualifiedIDEntity? { - - var userId = metadataDAO.valueByKey(SELF_USER_ID_KEY) - - if (userId == null) { - - val logPrefix = "Observing self user before insertion" - kaliumLogger.w("$logPrefix: Triggering a fetch.") - - fetchSelfUser().fold({ failure -> - kaliumLogger.e("""$logPrefix failed: {"failure":"$failure"}""") - }, { - kaliumLogger.i("$logPrefix: Succeeded") - userDetailsRefreshInstantCache[selfUserId] = DateTimeUtil.currentInstant() - }) - } else { - refreshUserDetailsIfNeeded(selfUserId) - } - - return metadataDAO.valueByKey(SELF_USER_ID_KEY)?.let { Json.decodeFromString(it) } - } - - @OptIn(ExperimentalCoroutinesApi::class) override suspend fun observeSelfUserWithTeam(): Flow> { - - val selfUser = getOrFetchSelfUserId() - - return if (selfUser != null) { - userDAO.getUserDetailsWithTeamByQualifiedID(selfUser).filterNotNull() - .map { (user, team) -> - userMapper.fromUserDetailsEntityToSelfUser(user) to team?.let { teamMapper.fromDaoModelToTeam(it) } - } - } else { - emptyFlow() - } + return userDAO.getUserDetailsWithTeamByQualifiedID(selfUserId.toDao()).filterNotNull() + .map { (user, team) -> + userMapper.fromUserDetailsEntityToSelfUser(user) to team?.let { teamMapper.fromDaoModelToTeam(it) } + } } @Deprecated( @@ -500,10 +396,8 @@ internal class UserDataSource internal constructor( } override suspend fun getSelfUser(): SelfUser? { - return getOrFetchSelfUserId()?.let { - userDAO.getUserDetailsByQualifiedID(it)?.let { - userMapper.fromUserDetailsEntityToSelfUser(it) - } + return userDAO.getUserDetailsByQualifiedID(selfUserId.toDao())?.let { + userMapper.fromUserDetailsEntityToSelfUser(it) } } @@ -709,17 +603,7 @@ internal class UserDataSource internal constructor( } companion object { - internal const val SELF_USER_ID_KEY = "selfUserID" - - /** - * Maximum age for user details. - * - * The USER_DETAILS_MAX_AGE constant represents the maximum age in minutes that user details can be considered valid. After - * this duration, the user details should be refreshed. - * - * This is needed because some users don't get `user.update` events, so we need to refresh their details every so often. - */ - internal val USER_DETAILS_MAX_AGE = 5.minutes + internal const val BATCH_SIZE = 500 } } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index ea26e771196..f37e1455f88 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -812,7 +812,6 @@ class UserSessionScope internal constructor( private val userRepository: UserRepository = UserDataSource( userDAO = userStorage.database.userDAO, - metadataDAO = userStorage.database.metadataDAO, clientDAO = userStorage.database.clientDAO, selfApi = authenticatedNetworkContainer.selfApi, userDetailsApi = authenticatedNetworkContainer.userDetailsApi, diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/user/UserRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/user/UserRepositoryTest.kt index 2d5fd672103..df81a5c27ae 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/user/UserRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/user/UserRepositoryTest.kt @@ -28,7 +28,6 @@ import com.wire.kalium.logic.data.id.toDao import com.wire.kalium.logic.data.legalhold.ListUsersLegalHoldConsent import com.wire.kalium.logic.data.session.SessionRepository import com.wire.kalium.logic.data.user.UserDataSource.Companion.BATCH_SIZE -import com.wire.kalium.logic.data.user.UserDataSource.Companion.SELF_USER_ID_KEY import com.wire.kalium.logic.failure.SelfUserDeleted import com.wire.kalium.logic.framework.TestConversation import com.wire.kalium.logic.framework.TestEvent @@ -58,7 +57,6 @@ import com.wire.kalium.network.api.base.authenticated.userDetails.UserDetailsApi import com.wire.kalium.network.api.model.LegalHoldStatusDTO import com.wire.kalium.network.api.model.UserProfileDTO import com.wire.kalium.network.utils.NetworkResponse -import com.wire.kalium.persistence.dao.MetadataDAO import com.wire.kalium.persistence.dao.PartialUserEntity import com.wire.kalium.persistence.dao.QualifiedIDEntity import com.wire.kalium.persistence.dao.UserDAO @@ -79,10 +77,6 @@ import io.mockative.mock import io.mockative.once import io.mockative.twice import io.mockative.verify -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.consumeAsFlow -import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest import kotlin.test.Test @@ -123,7 +117,7 @@ class UserRepositoryTest { val requestedUserIds = setOf(UserId(value = "id1", domain = "domain1"), missingUserId) val knownUserEntities = listOf(TestUser.DETAILS_ENTITY.copy(id = UserIDEntity(value = "id1", domain = "domain1"))) val (arrangement, userRepository) = Arrangement() - .withGetSelfUserId() +// .withGetSelfUserId() .withSuccessfulGetUsersByQualifiedIdList(knownUserEntities) .withSuccessfulGetMultipleUsersApiRequest(ListUsersDTO(usersFailed = emptyList(), listOf(TestUser.USER_PROFILE_DTO))) .arrange() @@ -298,153 +292,6 @@ class UserRepositoryTest { }.wasInvoked(exactly = once) } - @Test - fun givenSelfUserIsUnknown_whenObservingSelfUser_thenShouldAttemptToFetchIt() = runTest { - val selfUserIdChannel = Channel(Channel.UNLIMITED) - selfUserIdChannel.send(null) - selfUserIdChannel.send(TestUser.JSON_QUALIFIED_ID) - // given - val (arrangement, userRepository) = Arrangement() - .withSelfUserIdMetadataReturning(TestUser.JSON_QUALIFIED_ID) - .withSelfUserIdFlowMetadataReturning(selfUserIdChannel.consumeAsFlow()) - .withRemoteGetSelfReturningUser() - .arrange() - // when - userRepository.observeSelfUser().first() - // then - coVerify { - arrangement.selfApi.getSelfInfo() - }.wasInvoked(exactly = once) - } - - @Test - fun givenAKnownFederatedUser_whenGettingFromDbAndCacheExpiredOrNotPresent_thenShouldRefreshItsDataFromAPI() = runTest { - val (arrangement, userRepository) = Arrangement() - .withUserDaoReturning(TestUser.DETAILS_ENTITY.copy(userType = UserTypeEntity.FEDERATED)) - .withSuccessfulGetUsersInfo() - .arrange() - - val result = userRepository.getKnownUser(TestUser.OTHER_USER_ID) - - result.collect { - coVerify { - arrangement.userDetailsApi.getUserInfo(any()) - }.wasInvoked(exactly = once) - coVerify { - arrangement.userDAO.upsertUsers(any()) - }.wasInvoked() - } - } - - @Test - fun givenAKnownOtherUser_whenGettingFromDbAndCacheExpiredOrNotPresent_thenShouldRefreshItsDataFromAPI() = runTest { - val (arrangement, userRepository) = Arrangement() - .withUserDaoReturning(TestUser.DETAILS_ENTITY) - .withSuccessfulGetUsersInfo() - .arrange() - - val result = userRepository.getKnownUser(TestUser.OTHER_USER_ID) - - result.collect { - coVerify { - arrangement.userDetailsApi.getUserInfo(any()) - }.wasInvoked(exactly = once) - coVerify { - arrangement.userDAO.upsertUsers(any()) - }.wasInvoked(exactly = once) - } - } - - @Test - fun givenAKnownOtherUser_whenGettingFromDbAndCacheValid_thenShouldNOTRefreshItsDataFromAPI() = runTest { - val (arrangement, userRepository) = Arrangement() - .withUserDaoReturning(TestUser.DETAILS_ENTITY) - .withSuccessfulGetUsersInfo() - .arrange() - - val result = userRepository.getKnownUser(TestUser.OTHER_USER_ID) - - result.collect { - coVerify { - arrangement.userDetailsApi.getUserInfo(any()) - }.wasInvoked(exactly = once) - coVerify { - arrangement.userDAO.upsertUsers(any()) - }.wasInvoked(exactly = once) - } - - val resultSecondTime = userRepository.getKnownUser(TestUser.OTHER_USER_ID) - resultSecondTime.collect { - coVerify { - arrangement.userDetailsApi.getUserInfo(any()) - }.wasNotInvoked() - coVerify { - arrangement.userDAO.upsertUsers(any()) - }.wasNotInvoked() - } - } - - @Test - fun givenAKnownSelfUser_whenGettingFromDbAndCacheExpiredOrNotPresent_thenShouldRefreshItsDataFromAPI() = runTest { - val (arrangement, userRepository) = Arrangement() - .withSelfUserIdMetadataReturning(TestUser.JSON_QUALIFIED_ID) - .withSelfUserIdFlowMetadataReturning(flowOf(TestUser.JSON_QUALIFIED_ID)) - .withRemoteGetSelfReturningUser() - .withGetTeamMemberSuccess(TestTeam.memberDTO(TestUser.SELF.id.value)) - .arrange() - - val result = userRepository.observeSelfUser() - - result.collect { - coVerify { - arrangement.selfApi.getSelfInfo() - }.wasInvoked(exactly = once) - coVerify { - arrangement.teamsApi.getTeamMember(eq(TestTeam.TEAM_ID.value), any()) - }.wasInvoked(exactly = once) - coVerify { - arrangement.userDAO.upsertUser(any()) - }.wasInvoked(exactly = once) - } - } - - @Test - fun givenAKnownSelfUser_whenGettingFromDbAndCacheValid_thenShouldNOTRefreshItsDataFromAPI() = runTest { - val (arrangement, userRepository) = Arrangement() - .withSelfUserIdMetadataReturning(TestUser.JSON_QUALIFIED_ID) - .withSelfUserIdFlowMetadataReturning(flowOf(TestUser.JSON_QUALIFIED_ID)) - .withRemoteGetSelfReturningUser() - .withGetTeamMemberSuccess(TestTeam.memberDTO(TestUser.SELF.id.value)) - .arrange() - - val result = userRepository.observeSelfUser() - - result.collect { - coVerify { - arrangement.selfApi.getSelfInfo() - }.wasInvoked(exactly = once) - coVerify { - arrangement.teamsApi.getTeamMember(eq(TestTeam.TEAM_ID.value), any()) - }.wasInvoked(exactly = once) - coVerify { - arrangement.userDAO.upsertUser(any()) - }.wasInvoked(exactly = once) - } - - val resultSecondTime = userRepository.observeSelfUser() - resultSecondTime.collect { - coVerify { - arrangement.selfApi.getSelfInfo() - }.wasNotInvoked() - coVerify { - arrangement.teamsApi.getTeamMember(eq(TestTeam.TEAM_ID.value), any()) - }.wasNotInvoked() - coVerify { - arrangement.userDAO.upsertUser(any()) - }.wasNotInvoked() - } - } - @Test fun givenThereAreUsersWithoutMetadata_whenSyncingUsers_thenShouldUpdateThem() = runTest { // given @@ -509,7 +356,7 @@ class UserRepositoryTest { fun whenObservingKnowUsers_thenShouldReturnUsersThatHaveMetadata() = runTest { // Given val (arrangement, userRepository) = Arrangement() - .withGetSelfUserId() +// .withGetSelfUserId() .withDaoObservingByConnectionStatusReturning( listOf( TestUser.DETAILS_ENTITY.copy(id = QualifiedIDEntity("id-valid", "domain2"), hasIncompleteMetadata = false), @@ -538,7 +385,6 @@ class UserRepositoryTest { fun whenObservingKnowUsersNotInConversation_thenShouldReturnUsersThatHaveMetadata() = runTest { // Given val (arrangement, userRepository) = Arrangement() - .withGetSelfUserId() .withDaoObservingNotInConversationReturning( listOf( TestUser.DETAILS_ENTITY.copy(id = QualifiedIDEntity("id-valid", "domain2"), hasIncompleteMetadata = false), @@ -607,7 +453,6 @@ class UserRepositoryTest { fun givenANewSupportedProtocols_whenUpdatingOk_thenShouldSucceedAndPersistTheSupportedProtocolsLocally() = runTest { val successResponse = NetworkResponse.Success(Unit, mapOf(), HttpStatusCode.OK.value) val (arrangement, userRepository) = Arrangement() - .withGetSelfUserId() .withUpdateSupportedProtocolsApiRequestResponse(successResponse) .arrange() @@ -627,7 +472,6 @@ class UserRepositoryTest { @Test fun givenANewSupportedProtocols_whenUpdatingFails_thenShouldNotPersistSupportedProtocolsLocally() = runTest { val (arrangement, userRepository) = Arrangement() - .withGetSelfUserId() .withUpdateSupportedProtocolsApiRequestResponse(TestNetworkResponseError.genericResponseError()) .arrange() @@ -729,9 +573,6 @@ class UserRepositoryTest { coVerify { arrangement.userDetailsApi.getUserInfo(any()) }.wasInvoked(exactly = once) - coVerify { - arrangement.teamsApi.getTeamMembersByIds(any(), any()) - }.wasInvoked(exactly = once) coVerify { arrangement.userDAO.upsertUsers(any()) }.wasInvoked(exactly = once) @@ -841,9 +682,6 @@ class UserRepositoryTest { @Mock val userDAO = mock(UserDAO::class) - @Mock - val metadataDAO = mock(MetadataDAO::class) - @Mock val clientDAO = mock(ClientDAO::class) @@ -874,7 +712,6 @@ class UserRepositoryTest { val userRepository: UserRepository by lazy { UserDataSource( userDAO = userDAO, - metadataDAO = metadataDAO, clientDAO = clientDAO, selfApi = selfApi, userDetailsApi = userDetailsApi, @@ -893,18 +730,6 @@ class UserRepositoryTest { }.returns(value) } - suspend fun withSelfUserIdMetadataReturning(selfUserId: String?) = apply { - coEvery { - metadataDAO.valueByKey(eq(SELF_USER_ID_KEY)) - }.returns(selfUserId) - } - - suspend fun withSelfUserIdFlowMetadataReturning(selfUserIdStringFlow: Flow) = apply { - coEvery { - metadataDAO.valueByKeyFlow(eq(SELF_USER_ID_KEY)) - }.returns(selfUserIdStringFlow) - } - suspend fun withDaoObservingByConnectionStatusReturning(userEntities: List) = apply { coEvery { userDAO.observeAllUsersDetailsByConnectionStatus(any()) @@ -959,25 +784,6 @@ class UserRepositoryTest { }.returns(userEntity) } - suspend fun withGetSelfUserId() = apply { - coEvery { - metadataDAO.valueByKey(any()) - }.returns( - """ - { - "value" : "someValue", - "domain" : "someDomain" - } - """.trimIndent() - ) - } - - suspend fun withRemoteGetSelfReturningUser(): Arrangement = apply { - coEvery { - selfApi.getSelfInfo() - }.returns(NetworkResponse.Success(TestUser.SELF_USER_DTO.copy(teamId = TestTeam.TEAM_ID.value), mapOf(), 200)) - } - suspend fun withRemoteGetSelfReturningDeletedUser(): Arrangement = apply { coEvery { selfApi.getSelfInfo() @@ -1095,7 +901,6 @@ class UserRepositoryTest { } suspend inline fun arrange(block: (Arrangement.() -> Unit) = { }): Pair { - withSelfUserIdFlowMetadataReturning(flowOf(TestUser.JSON_QUALIFIED_ID)) coEvery { userDAO.observeUserDetailsByQualifiedID(any()) }.returns(flowOf(TestUser.DETAILS_ENTITY)) From 952e034c5d98d77dd5e95e3a3daa8659024fa706 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:57:16 +0000 Subject: [PATCH 2/2] chore: bump core crypto to 3.0.1 (#3256) (#3258) Co-authored-by: Mohamad Jaara Co-authored-by: Oussama Hassine --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3ea28e41e82..51c7a38b57a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ pbandk = "0.14.2" turbine = "1.1.0" avs = "10.0.1" jna = "5.14.0" -core-crypto = "3.0.0" +core-crypto = "3.0.1" core-crypto-multiplatform = "0.6.0-rc.3-multiplatform-pre1" completeKotlin = "1.1.0" desugar-jdk = "2.1.3"