Updated on 2026-08-14

This commit is contained in:
Tangem 2022-12-13 18:43:54 +03:00
parent 77f097766d
commit bf9dbc3535
4 changed files with 25 additions and 67 deletions

View file

@ -14,10 +14,13 @@ import com.tangem.tap.domain.userWalletList.repository.implementation.BiometricU
import com.tangem.tap.domain.userWalletList.repository.implementation.DefaultSelectedUserWalletRepository
import com.tangem.tap.domain.userWalletList.repository.implementation.DefaultUserWalletsPublicInformationRepository
import com.tangem.tap.domain.userWalletList.repository.implementation.DefaultUserWalletsSensitiveInformationRepository
import com.tangem.tap.domain.userWalletList.utils.json.*
import com.tangem.tap.domain.userWalletList.utils.json.ByteArrayKeyAdapter
import com.tangem.tap.domain.userWalletList.utils.json.CardBackupStatusAdapter
import com.tangem.tap.domain.userWalletList.utils.json.ExtendedPublicKeysMapAdapter
import com.tangem.tap.domain.userWalletList.utils.json.ScanResponseDerivedKeysMapAdapter
import com.tangem.tap.domain.userWalletList.utils.json.WalletDerivedKeysMapAdapter
const val USER_WALLETS_STORAGE_NAME = "user_wallets_storage"
const val USER_WALLETS_BIOMETRIC_KEY_NAME = "user_wallets"
private const val USER_WALLETS_STORAGE_NAME = "user_wallets_storage"
fun UserWalletsListManager.Companion.provideBiometricImplementation(
context: Context,
@ -43,7 +46,6 @@ fun UserWalletsListManager.Companion.provideBiometricImplementation(
)
val keysRepository = BiometricUserWalletsKeysRepository(
biometricKeyName = USER_WALLETS_BIOMETRIC_KEY_NAME,
moshi = moshi,
secureStorage = secureStorage,
biometricManager = tangemSdkManager.biometricManager,
@ -61,7 +63,6 @@ fun UserWalletsListManager.Companion.provideBiometricImplementation(
)
return BiometricUserWalletsListManager(
tangemSdkManager = tangemSdkManager,
keysRepository = keysRepository,
publicInformationRepository = publicInformationRepository,
sensitiveInformationRepository = sensitiveInformationRepository,

View file

@ -3,7 +3,6 @@ package com.tangem.tap.domain.userWalletList.implementation
import com.tangem.common.*
import com.tangem.domain.common.util.UserWalletId
import com.tangem.domain.common.util.encryptionKey
import com.tangem.tap.domain.TangemSdkManager
import com.tangem.tap.domain.model.UserWallet
import com.tangem.tap.domain.userWalletList.UserWalletListError
import com.tangem.tap.domain.userWalletList.UserWalletsListManager
@ -20,7 +19,6 @@ import timber.log.Timber
@OptIn(ExperimentalCoroutinesApi::class)
internal class BiometricUserWalletsListManager(
private val tangemSdkManager: TangemSdkManager,
private val keysRepository: UserWalletsKeysRepository,
private val publicInformationRepository: UserWalletsPublicInformationRepository,
private val sensitiveInformationRepository: UserWalletsSensitiveInformationRepository,
@ -83,7 +81,6 @@ internal class BiometricUserWalletsListManager(
}
override fun lock() {
tangemSdkManager.biometricManager.unauthenticate()
state.update { prevState ->
prevState.copy(
encryptionKeys = emptyList(),
@ -122,14 +119,15 @@ internal class BiometricUserWalletsListManager(
if (isWalletSaved && !canOverride) {
CompletionResult.Failure(UserWalletListError.WalletAlreadySaved)
} else {
keysRepository.save(
walletId = userWallet.walletId,
encryptionKey = userWallet.scanResponse.card.encryptionKey,
)
.doOnSuccess { keys ->
val newEncryptionKeys = state.value.encryptionKeys
.plus(UserWalletEncryptionKey(userWallet.walletId, userWallet.scanResponse.card.encryptionKey))
.distinctBy { it.walletId }
keysRepository.store(newEncryptionKeys)
.doOnSuccess {
state.update { prevState ->
prevState.copy(
encryptionKeys = (keys + prevState.encryptionKeys).distinctBy { it.walletId },
encryptionKeys = newEncryptionKeys,
)
}
}
@ -146,21 +144,22 @@ internal class BiometricUserWalletsListManager(
val walletIdsToRemove = state.value.wallets
.map { it.walletId }
.filter { it in walletIds }
val remainingEncryptionKeys = state.value.encryptionKeys
.filter { it.walletId !in walletIdsToRemove }
changeSelectedWalletIfNeeded(walletIdsToRemove)
return sensitiveInformationRepository.delete(walletIdsToRemove)
.flatMap { publicInformationRepository.delete(walletIdsToRemove) }
.flatMap { keysRepository.delete(walletIdsToRemove) }
.map { keys ->
.flatMap { keysRepository.store(remainingEncryptionKeys) }
.map {
state.update { prevState ->
prevState.copy(
encryptionKeys = keys,
encryptionKeys = remainingEncryptionKeys,
wallets = prevState.wallets.filter { it.walletId !in walletIdsToRemove },
)
}
}
.flatMap { loadModels() }
}
override suspend fun clear(): CompletionResult<Unit> {
@ -171,12 +170,11 @@ internal class BiometricUserWalletsListManager(
.flatMap { keysRepository.clear() }
.map {
selectedUserWalletRepository.set(null)
tangemSdkManager.biometricManager.unauthenticate()
state.update { State() }
}
}
override suspend fun get(walletId: UserWalletId): CompletionResult<UserWallet> = withUnlock {
override suspend fun get(walletId: UserWalletId): CompletionResult<UserWallet> {
return catching {
state.value.wallets.first { it.walletId == walletId }
}

View file

@ -1,12 +1,10 @@
package com.tangem.tap.domain.userWalletList.repository
import com.tangem.common.CompletionResult
import com.tangem.domain.common.util.UserWalletId
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
internal interface UserWalletsKeysRepository {
suspend fun getAll(): CompletionResult<List<UserWalletEncryptionKey>>
suspend fun save(walletId: UserWalletId, encryptionKey: ByteArray): CompletionResult<List<UserWalletEncryptionKey>>
suspend fun delete(walletIds: List<UserWalletId>): CompletionResult<List<UserWalletEncryptionKey>>
suspend fun store(encryptionKeys: List<UserWalletEncryptionKey>): CompletionResult<Unit>
suspend fun clear(): CompletionResult<Unit>
}

View file

@ -6,24 +6,19 @@ import com.squareup.moshi.Types
import com.tangem.common.CompletionResult
import com.tangem.common.biometric.BiometricManager
import com.tangem.common.biometric.BiometricStorage
import com.tangem.common.flatMap
import com.tangem.common.map
import com.tangem.common.mapFailure
import com.tangem.common.services.secure.SecureStorage
import com.tangem.domain.common.util.UserWalletId
import com.tangem.tap.common.extensions.replaceByOrAdd
import com.tangem.tap.domain.userWalletList.UserWalletListError
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository
internal class BiometricUserWalletsKeysRepository(
biometricKeyName: String,
moshi: Moshi,
secureStorage: SecureStorage,
biometricManager: BiometricManager,
) : UserWalletsKeysRepository {
private val biometricStorage = BiometricStorage(
biometricKeyName = biometricKeyName,
biometricManager = biometricManager,
secureStorage = secureStorage,
)
@ -41,50 +36,16 @@ internal class BiometricUserWalletsKeysRepository(
}
}
override suspend fun save(
walletId: UserWalletId,
encryptionKey: ByteArray,
): CompletionResult<List<UserWalletEncryptionKey>> {
return getAll()
.flatMap { keys ->
if (keys.any { it.walletId == walletId }) {
return@flatMap CompletionResult.Success(Unit)
}
val encodedKeys = keys.toMutableList()
.apply {
replaceByOrAdd(UserWalletEncryptionKey(walletId, encryptionKey)) {
it.walletId == walletId
}
}
.encode()
biometricStorage.store(
key = StorageKey.WalletEncryptionKeys.name,
data = encodedKeys,
)
}
.flatMap { getAll() }
override suspend fun store(encryptionKeys: List<UserWalletEncryptionKey>): CompletionResult<Unit> {
return biometricStorage.store(
key = StorageKey.WalletEncryptionKeys.name,
data = encryptionKeys.encode(),
)
.mapFailure { error ->
UserWalletListError.SaveEncryptionKeysError(error.cause ?: error)
}
}
override suspend fun delete(walletIds: List<UserWalletId>): CompletionResult<List<UserWalletEncryptionKey>> {
return getAll()
.map { keys ->
val keysToRemove = keys.filter { it.walletId in walletIds }.toSet()
(keys - keysToRemove).encode()
}
.flatMap { encodedKeys ->
biometricStorage.store(
key = StorageKey.WalletEncryptionKeys.name,
data = encodedKeys,
)
}
.flatMap { getAll() }
}
override suspend fun clear(): CompletionResult<Unit> {
return biometricStorage.delete(key = StorageKey.WalletEncryptionKeys.name)
}