Updated on 2026-08-14
This commit is contained in:
commit
0d4fd5874e
5 changed files with 71 additions and 16 deletions
|
|
@ -0,0 +1,31 @@
|
|||
package com.tangem.core.ui.security
|
||||
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
|
||||
/**
|
||||
* Disables autofill for the current Compose view hierarchy.
|
||||
*
|
||||
* This prevents password managers and other autofill services from accessing
|
||||
* sensitive content (e.g., seed phrases, private keys) entered in text fields.
|
||||
*
|
||||
* Must be called within a Composable scope before the text fields that need protection.
|
||||
*
|
||||
* The original autofill setting is restored when this composable leaves the composition.
|
||||
*/
|
||||
@Composable
|
||||
fun DisableAutofillEffect() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val view = LocalView.current
|
||||
DisposableEffect(view) {
|
||||
val previousValue = view.importantForAutofill
|
||||
view.importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
|
||||
onDispose {
|
||||
view.importantForAutofill = previousValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -84,7 +84,7 @@ class ManageCryptoCurrenciesUseCase(
|
|||
withContext(NonCancellable) {
|
||||
val accountStatus = getAccountStatus(accountId = accountId)
|
||||
|
||||
val modifiedCurrencyList = accountStatus.tokenList.flattenCurrencies()
|
||||
var modifiedCurrencyList = accountStatus.tokenList.flattenCurrencies()
|
||||
.modify(add = add, remove = remove)
|
||||
|
||||
if (!modifiedCurrencyList.hasChanges) {
|
||||
|
|
@ -92,12 +92,21 @@ class ManageCryptoCurrenciesUseCase(
|
|||
return@withContext
|
||||
}
|
||||
|
||||
val derivingResult = derivePublicKeys(userWalletId = userWalletId, currencies = modifiedCurrencyList.added)
|
||||
|
||||
if (!skipDerivationErrors && derivingResult.isLeft()) {
|
||||
modifiedCurrencyList = accountStatus.tokenList.flattenCurrencies()
|
||||
.modify(add = emptyList(), remove = remove)
|
||||
|
||||
if (!modifiedCurrencyList.hasChanges) {
|
||||
derivingResult.bind()
|
||||
}
|
||||
}
|
||||
|
||||
saveAccount(
|
||||
account = accountStatus.account.copy(cryptoCurrencies = modifiedCurrencyList.total),
|
||||
)
|
||||
|
||||
val result = derivePublicKeys(userWalletId = userWalletId, currencies = modifiedCurrencyList.added)
|
||||
|
||||
parallelUpdatingScope.launch {
|
||||
syncTokens(userWalletId, modifiedCurrencyList)
|
||||
|
||||
|
|
@ -107,7 +116,7 @@ class ManageCryptoCurrenciesUseCase(
|
|||
}
|
||||
|
||||
if (!skipDerivationErrors) {
|
||||
result.bind()
|
||||
derivingResult.bind()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.managetokens.model
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
|
|
@ -8,6 +9,7 @@ import com.tangem.core.decompose.model.ParamsContainer
|
|||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.domain.managetokens.CreateCryptoCurrencyUseCase
|
||||
import com.tangem.domain.managetokens.FindTokenUseCase
|
||||
|
|
@ -146,7 +148,7 @@ internal class CustomTokenFormModel @Inject constructor(
|
|||
is CustomCurrencyValidator.Status.Validating,
|
||||
-> Unit
|
||||
is CustomCurrencyValidator.Status.SearchingToken -> updateStateWithProgress()
|
||||
is CustomCurrencyValidator.Status.UnexpectedException -> showErrorDialog()
|
||||
is CustomCurrencyValidator.Status.UnexpectedException -> showErrorDialog(validatorState.cause)
|
||||
is CustomCurrencyValidator.Status.FormValidationException -> updateStateWithExceptions(
|
||||
exceptions = validatorState.exceptions,
|
||||
)
|
||||
|
|
@ -236,9 +238,17 @@ internal class CustomTokenFormModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun showErrorDialog() {
|
||||
private fun showErrorDialog(throwable: Throwable) {
|
||||
Timber.e(throwable)
|
||||
val message = when (throwable) {
|
||||
is TangemSdkError -> resourceReference(
|
||||
R.string.generic_error_code,
|
||||
wrappedList(throwable.code.toString()),
|
||||
)
|
||||
else -> resourceReference(R.string.common_unknown_error)
|
||||
}
|
||||
val dialog = DialogMessage(
|
||||
message = resourceReference(R.string.common_unknown_error),
|
||||
message = message,
|
||||
)
|
||||
|
||||
messageSender.send(dialog)
|
||||
|
|
@ -341,8 +351,12 @@ internal class CustomTokenFormModel @Inject constructor(
|
|||
) {
|
||||
val currency = createdCurrency
|
||||
if (currency == null) {
|
||||
Timber.e("Trying to add currency without validation")
|
||||
showErrorDialog()
|
||||
showErrorDialog(IllegalStateException("Trying to add currency without validation"))
|
||||
return@resource
|
||||
}
|
||||
|
||||
useCasesFacade.addCryptoCurrenciesUseCase(currency).getOrElse { throwable ->
|
||||
showErrorDialog(throwable)
|
||||
return@resource
|
||||
}
|
||||
|
||||
|
|
@ -353,12 +367,6 @@ internal class CustomTokenFormModel @Inject constructor(
|
|||
)
|
||||
analyticsEventHandler.send(event)
|
||||
|
||||
useCasesFacade.addCryptoCurrenciesUseCase(currency).getOrElse { throwable ->
|
||||
Timber.e(throwable, "Failed to add currency")
|
||||
showErrorDialog()
|
||||
return@resource
|
||||
}
|
||||
|
||||
params.onCurrencyAdded(currency)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,11 @@ internal class CustomTokenFormUseCasesFacade @AssistedInject constructor(
|
|||
return either {
|
||||
val accountId = getAccountId(currency)
|
||||
|
||||
manageCryptoCurrenciesUseCase(accountId = accountId, add = currency).bind()
|
||||
manageCryptoCurrenciesUseCase(
|
||||
accountId = accountId,
|
||||
add = currency,
|
||||
skipDerivationErrors = false,
|
||||
).bind()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.security.DisableAutofillEffect
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.state.MultiWalletSeedPhraseUM
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.utils.InvalidWordsColorTransformation
|
||||
|
|
@ -53,6 +54,8 @@ internal fun MultiWalletSeedPhraseImport(state: MultiWalletSeedPhraseUM.Import,
|
|||
)
|
||||
}
|
||||
|
||||
DisableAutofillEffect()
|
||||
|
||||
Box(modifier.fillMaxSize()) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue