Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-19 13:17:04 +03:00
parent bb95420224
commit 143dcc5a62
34 changed files with 632 additions and 114 deletions

View file

@ -17,6 +17,7 @@ import com.tangem.datasource.local.preferences.PreferencesKeys.SEED_FIRST_NOTIFI
import com.tangem.datasource.local.preferences.utils.get
import com.tangem.datasource.local.preferences.utils.getObjectMap
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
import com.tangem.datasource.local.preferences.utils.getSyncOrNull
import com.tangem.datasource.local.preferences.utils.store
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.models.wallet.UserWallet
@ -47,14 +48,78 @@ internal class DefaultWalletsRepository(
return appPreferencesStore.getSyncOrDefault(key = PreferencesKeys.SAVE_USER_WALLETS_KEY, default = false)
}
@Deprecated("Hot wallet feature makes app always save user wallets. Do not use this method")
override fun shouldSaveUserWallets(): Flow<Boolean> {
return appPreferencesStore.get(key = PreferencesKeys.SAVE_USER_WALLETS_KEY, default = false)
}
@Deprecated("Hot wallet feature makes app always save user wallets. Do not use this method")
override suspend fun saveShouldSaveUserWallets(item: Boolean) {
appPreferencesStore.store(key = PreferencesKeys.SAVE_USER_WALLETS_KEY, value = item)
}
override suspend fun useBiometricAuthentication(): Boolean {
val useBiometricAuthentication = appPreferencesStore.getSyncOrNull(
key = PreferencesKeys.USE_BIOMETRIC_AUTHENTICATION_KEY,
)
if (useBiometricAuthentication != null) {
return useBiometricAuthentication
}
val legacySaveWalletsInTheApp = appPreferencesStore.getSyncOrNull(
key = PreferencesKeys.SAVE_USER_WALLETS_KEY,
)
if (legacySaveWalletsInTheApp != null) {
// Migrate legacy setting to new one
appPreferencesStore.store(
key = PreferencesKeys.USE_BIOMETRIC_AUTHENTICATION_KEY,
value = legacySaveWalletsInTheApp,
)
return legacySaveWalletsInTheApp
} else {
// Default value for new users
setUseBiometricAuthentication(false)
return false
}
}
override suspend fun setUseBiometricAuthentication(value: Boolean) {
appPreferencesStore.store(key = PreferencesKeys.USE_BIOMETRIC_AUTHENTICATION_KEY, value = value)
}
override suspend fun requireAccessCode(): Boolean {
val requireAccessCode = appPreferencesStore.getSyncOrNull(
key = PreferencesKeys.REQUIRE_ACCESS_CODE_KEY,
)
if (requireAccessCode != null) {
return requireAccessCode
}
val legacyShouldSaveAccessCode = appPreferencesStore.getSyncOrNull(
key = PreferencesKeys.SHOULD_SAVE_ACCESS_CODES_KEY,
)
if (legacyShouldSaveAccessCode != null) {
// Migrate legacy setting to new one
appPreferencesStore.store(
key = PreferencesKeys.REQUIRE_ACCESS_CODE_KEY,
value = legacyShouldSaveAccessCode.not(),
)
return legacyShouldSaveAccessCode.not()
} else {
// Default value for new users
setRequireAccessCode(true)
return true
}
}
override suspend fun setRequireAccessCode(value: Boolean) {
appPreferencesStore.store(key = PreferencesKeys.REQUIRE_ACCESS_CODE_KEY, value = value)
}
override suspend fun isWalletWithRing(userWalletId: UserWalletId): Boolean {
return appPreferencesStore
.getSyncOrDefault(key = PreferencesKeys.ADDED_WALLETS_WITH_RING_KEY, default = emptySet())

View file

@ -1,7 +1,11 @@
package com.tangem.data.wallets.hot
import com.tangem.common.core.TangemSdkError
import com.tangem.domain.core.wallets.UserWalletsListRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.copy
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.hot.sdk.TangemHotSdk
import com.tangem.hot.sdk.exception.WrongPasswordException
import com.tangem.hot.sdk.model.*
@ -9,7 +13,9 @@ import javax.inject.Inject
class HotWalletAccessor @Inject constructor(
private val tangemHotSdk: TangemHotSdk,
private val userWalletsListRepository: UserWalletsListRepository,
private val hotWalletPasswordRequester: HotWalletPasswordRequester,
private val walletsRepository: WalletsRepository,
) {
suspend fun signHashes(hotWalletId: HotWalletId, dataToSign: List<DataToSign>): List<SignedData> =
@ -23,10 +29,18 @@ class HotWalletAccessor @Inject constructor(
}
private suspend fun <T> hotSdkRequest(hotWalletId: HotWalletId, block: suspend (unlock: UnlockHotWallet) -> T): T {
val isAccessCodeRequired = walletsRepository.requireAccessCode()
val auth = when (hotWalletId.authType) {
HotWalletId.AuthType.NoPassword -> HotAuth.NoAuth
HotWalletId.AuthType.Password -> requestPassword(false)
HotWalletId.AuthType.Biometry -> HotAuth.Biometry
HotWalletId.AuthType.Biometry -> {
if (isAccessCodeRequired) {
requestPassword(false)
} else {
HotAuth.Biometry
}
}
}
return runCatchingSdkErrors(hotWalletId, auth) {
@ -47,20 +61,41 @@ class HotWalletAccessor @Inject constructor(
block = { blockAuth ->
block(blockAuth).also {
// Update biometry auth if the original auth was password
if (blockAuth is HotAuth.Password) {
tangemHotSdk.changeAuth(
unlockHotWallet = UnlockHotWallet(
walletId = hotWalletId,
auth = blockAuth,
),
auth = HotAuth.Biometry,
)
}
updateBiometryAuthIfNeeded(
hotWalletId = hotWalletId,
originalAuth = blockAuth,
)
}
},
)
}
private suspend fun updateBiometryAuthIfNeeded(hotWalletId: HotWalletId, originalAuth: HotAuth) {
val isAccessCodeRequired = walletsRepository.requireAccessCode()
if (originalAuth is HotAuth.Password && isAccessCodeRequired.not()) {
val userWallet = userWalletsListRepository.userWalletsSync()
.find { it is UserWallet.Hot && it.hotWalletId == hotWalletId }
as? UserWallet.Hot
?: return
val newHotWalletId = tangemHotSdk.changeAuth(
unlockHotWallet = UnlockHotWallet(
walletId = hotWalletId,
auth = originalAuth,
),
auth = HotAuth.Biometry,
)
userWalletsListRepository.saveWithoutLock(
userWallet = userWallet.copy(
hotWalletId = newHotWalletId,
),
canOverride = true,
)
}
}
private suspend fun <T> runCatchingWrongPassInternal(
originalAuth: HotAuth,
auth: HotAuth,