Updated on 2026-08-14
This commit is contained in:
parent
f89ab30e5a
commit
64fda96648
9 changed files with 56 additions and 23 deletions
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.balancehiding.UpdateBalanceHidingSettingsUseCase
|
|||
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
||||
import com.tangem.domain.settings.*
|
||||
import com.tangem.domain.settings.repositories.AppRatingRepository
|
||||
import com.tangem.domain.settings.repositories.LegacySettingsRepository
|
||||
import com.tangem.domain.settings.repositories.PermissionRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase
|
||||
|
|
@ -68,10 +69,14 @@ internal object SettingsDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesCanUseBiometryUseCase(tangemSdkManager: TangemSdkManager): CanUseBiometryUseCase {
|
||||
return CanUseBiometryUseCase(
|
||||
legacySettingsRepository = DefaultLegacySettingsRepository(tangemSdkManager = tangemSdkManager),
|
||||
)
|
||||
fun provideLegacySettingsRepository(tangemSdkManager: TangemSdkManager): LegacySettingsRepository {
|
||||
return DefaultLegacySettingsRepository(tangemSdkManager = tangemSdkManager)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesCanUseBiometryUseCase(legacySettingsRepository: LegacySettingsRepository): CanUseBiometryUseCase {
|
||||
return CanUseBiometryUseCase(legacySettingsRepository = legacySettingsRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -8,4 +8,8 @@ internal class DefaultLegacySettingsRepository(
|
|||
) : LegacySettingsRepository {
|
||||
|
||||
override suspend fun canUseBiometry(): Boolean = tangemSdkManager.checkCanUseBiometry()
|
||||
|
||||
override suspend fun canUseBiometryStrict(): Boolean {
|
||||
return tangemSdkManager.checkCanUseBiometry() && tangemSdkManager.checkNeedEnrollBiometrics().not()
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ dependencies {
|
|||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.settings)
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.android)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.settings.repositories.LegacySettingsRepository
|
||||
import com.tangem.domain.wallets.hot.HotWalletAccessor
|
||||
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
|
|
@ -17,18 +18,21 @@ import kotlinx.coroutines.SupervisorJob
|
|||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class DefaultHotWalletAccessor @Inject constructor(
|
||||
private val tangemHotSdk: TangemHotSdk,
|
||||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val hotWalletPasswordRequester: HotWalletPasswordRequester,
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val legacySettingsRepository: LegacySettingsRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
) : HotWalletAccessor {
|
||||
|
||||
private val scope = CoroutineScope(context = SupervisorJob() + dispatchers.io)
|
||||
|
||||
private var contextualUnlockHotWallet: ConcurrentHashMap<HotWalletId, UnlockHotWallet?> = ConcurrentHashMap()
|
||||
private val contextualUnlockHotWallet: ConcurrentHashMap<HotWalletId, UnlockHotWallet?> = ConcurrentHashMap()
|
||||
|
||||
override suspend fun signHashes(hotWalletId: HotWalletId, dataToSign: List<DataToSign>): List<SignedData> =
|
||||
hotSdkRequest(hotWalletId) { unlock ->
|
||||
|
|
@ -82,7 +86,7 @@ class DefaultHotWalletAccessor @Inject constructor(
|
|||
}
|
||||
|
||||
private suspend fun <T> hotSdkRequest(hotWalletId: HotWalletId, block: suspend (unlock: UnlockHotWallet) -> T): T {
|
||||
val isAccessCodeRequired = walletsRepository.requireAccessCode()
|
||||
val isAccessCodeRequired = isAccessCodeRequired()
|
||||
|
||||
val auth = when (hotWalletId.authType) {
|
||||
HotWalletId.AuthType.NoPassword -> HotAuth.NoAuth
|
||||
|
|
@ -134,7 +138,7 @@ class DefaultHotWalletAccessor @Inject constructor(
|
|||
}
|
||||
|
||||
private suspend fun updateBiometryAuthIfNeeded(hotWalletId: HotWalletId, originalAuth: HotAuth) {
|
||||
val isAccessCodeRequired = walletsRepository.requireAccessCode()
|
||||
val isAccessCodeRequired = isAccessCodeRequired()
|
||||
val isUseBiometricAuthenticationEnabled = walletsRepository.useBiometricAuthentication()
|
||||
|
||||
if (originalAuth is HotAuth.Password && isUseBiometricAuthenticationEnabled && isAccessCodeRequired.not()) {
|
||||
|
|
@ -167,7 +171,7 @@ class DefaultHotWalletAccessor @Inject constructor(
|
|||
): T = runSuspendCatching {
|
||||
block(auth)
|
||||
}.getOrElse { exception ->
|
||||
if (auth is HotAuth.Biometry && exception.isBiometryError()) {
|
||||
if (auth is HotAuth.Biometry && (exception.isBiometryError() || exception.isBiometryReset())) {
|
||||
val shouldRetryBiometry = exception is TangemSdkError.AuthenticationCanceled
|
||||
|
||||
// fallback to password if biometry fails
|
||||
|
|
@ -215,6 +219,14 @@ class DefaultHotWalletAccessor @Inject constructor(
|
|||
?: throw TangemSdkError.UserCancelled()
|
||||
}
|
||||
|
||||
private suspend fun isAccessCodeRequired(): Boolean {
|
||||
return walletsRepository.requireAccessCode() || legacySettingsRepository.canUseBiometryStrict().not()
|
||||
}
|
||||
|
||||
private fun Throwable.isBiometryReset(): Boolean {
|
||||
return this is IllegalStateException
|
||||
}
|
||||
|
||||
private fun Throwable.isBiometryError(): Boolean {
|
||||
return this is TangemSdkError.AuthenticationFailed ||
|
||||
this is TangemSdkError.AuthenticationCanceled ||
|
||||
|
|
|
|||
|
|
@ -4,5 +4,8 @@ import com.tangem.domain.settings.repositories.LegacySettingsRepository
|
|||
|
||||
class CanUseBiometryUseCase(private val legacySettingsRepository: LegacySettingsRepository) {
|
||||
|
||||
@Deprecated("You probably want to use strict() instead. Check implementation", ReplaceWith("strict()"))
|
||||
suspend operator fun invoke(): Boolean = legacySettingsRepository.canUseBiometry()
|
||||
|
||||
suspend fun strict(): Boolean = legacySettingsRepository.canUseBiometryStrict()
|
||||
}
|
||||
|
|
@ -3,4 +3,6 @@ package com.tangem.domain.settings.repositories
|
|||
interface LegacySettingsRepository {
|
||||
|
||||
suspend fun canUseBiometry(): Boolean
|
||||
|
||||
suspend fun canUseBiometryStrict(): Boolean
|
||||
}
|
||||
|
|
@ -31,6 +31,8 @@ import com.tangem.hot.sdk.TangemHotSdk
|
|||
import com.tangem.hot.sdk.model.HotAuth
|
||||
import com.tangem.hot.sdk.model.HotWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
|
@ -63,6 +65,8 @@ internal class AccessCodeModel @Inject constructor(
|
|||
|
||||
private val params = paramsContainer.require<AccessCodeComponent.Params>()
|
||||
|
||||
private val settingCodeJobHolder = JobHolder()
|
||||
|
||||
internal val uiState: StateFlow<AccessCodeUM>
|
||||
field = MutableStateFlow(getInitialState())
|
||||
|
||||
|
|
@ -197,23 +201,25 @@ internal class AccessCodeModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun setCode(userWalletId: UserWalletId, accessCode: String) {
|
||||
private suspend fun setCode(userWalletId: UserWalletId, accessCode: String) = coroutineScope {
|
||||
if (settingCodeJobHolder.isActive) {
|
||||
return@coroutineScope
|
||||
}
|
||||
|
||||
params.callbacks.onAccessCodeUpdateStarted(params.userWalletId)
|
||||
|
||||
modelScope.launch {
|
||||
val userWallet = getUserWalletUseCase(userWalletId)
|
||||
.getOrElse { error("User wallet with id $userWalletId not found") }
|
||||
.requireHotWallet()
|
||||
val userWallet = getUserWalletUseCase(userWalletId)
|
||||
.getOrElse { error("User wallet with id $userWalletId not found") }
|
||||
.requireHotWallet()
|
||||
|
||||
tryToAskForBiometry()
|
||||
tryToAskForBiometry()
|
||||
|
||||
val settingCodeJob = launch(dispatchers.main) {
|
||||
setCodeOperation(userWallet, accessCode)
|
||||
params.callbacks.onAccessCodeUpdated(params.userWalletId)
|
||||
}
|
||||
val settingCodeJob = launch(dispatchers.main) {
|
||||
setCodeOperation(userWallet, accessCode)
|
||||
params.callbacks.onAccessCodeUpdated(params.userWalletId)
|
||||
}.saveIn(settingCodeJobHolder)
|
||||
|
||||
setLoadingIfLongJob(settingCodeJob)
|
||||
}
|
||||
setLoadingIfLongJob(settingCodeJob)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -246,7 +252,7 @@ internal class AccessCodeModel @Inject constructor(
|
|||
lockMethod = UserWalletsListRepository.LockMethod.AccessCode(accessCode.toCharArray()),
|
||||
)
|
||||
|
||||
if (walletsRepository.requireAccessCode().not() && canUseBiometryUseCase()) {
|
||||
if (walletsRepository.requireAccessCode().not() && canUseBiometryUseCase.strict()) {
|
||||
val newHotWalletIdWithBiometry = tangemHotSdk.changeAuth(
|
||||
unlockHotWallet = unlockHotWallet,
|
||||
auth = HotAuth.Biometry,
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ internal class HotAccessCodeRequestModel @Inject constructor(
|
|||
}
|
||||
|
||||
private suspend fun HotWalletPasswordRequester.AttemptRequest.isBiometryButtonVisible(): Boolean =
|
||||
hasBiometry && canUseBiometryUseCase()
|
||||
hasBiometry && canUseBiometryUseCase.strict()
|
||||
|
||||
private fun dismissState() {
|
||||
uiState.update {
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ internal class WelcomeModel @Inject constructor(
|
|||
}
|
||||
|
||||
private suspend fun canUnlockWithBiometrics(): Boolean {
|
||||
return canUseBiometryUseCase() && walletsRepository.useBiometricAuthentication()
|
||||
return canUseBiometryUseCase.strict() && walletsRepository.useBiometricAuthentication()
|
||||
}
|
||||
|
||||
suspend fun nonBiometricUnlockWallet(userWalletId: UserWalletId) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue