Updated on 2026-08-14
This commit is contained in:
parent
6b7a309a37
commit
e00f5390d2
8 changed files with 92 additions and 62 deletions
|
|
@ -8,6 +8,7 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.common.map
|
||||
import com.tangem.common.timemeasure.RealtimeMonotonicTimeSource
|
||||
import com.tangem.crypto.CryptoUtils
|
||||
import com.tangem.datasource.local.visa.VisaAuthTokenStorage
|
||||
import com.tangem.datasource.local.visa.VisaOTPStorage
|
||||
|
|
@ -29,6 +30,7 @@ import kotlinx.coroutines.*
|
|||
import timber.log.Timber
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.jvm.Throws
|
||||
import kotlin.time.measureTimedValue
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
class VisaCardActivationTask @AssistedInject constructor(
|
||||
|
|
@ -69,31 +71,38 @@ class VisaCardActivationTask @AssistedInject constructor(
|
|||
session = session,
|
||||
)
|
||||
|
||||
return if (challengeToSign != null) {
|
||||
context.signAuthorizationChallenge(challengeToSign)
|
||||
} else {
|
||||
val activationOrder = runCatching { visaActivationRepository.getActivationOrderToSign() }
|
||||
.getOrElse {
|
||||
return CompletionResult.Failure(TangemSdkError.Underlying(it.message ?: ""))
|
||||
}
|
||||
val timedResult = RealtimeMonotonicTimeSource.measureTimedValue {
|
||||
if (challengeToSign != null) {
|
||||
context.signAuthorizationChallenge(challengeToSign)
|
||||
} else {
|
||||
val activationOrder = runCatching { visaActivationRepository.getActivationOrderToSign() }
|
||||
.getOrElse {
|
||||
return CompletionResult.Failure(TangemSdkError.Underlying(it.message ?: ""))
|
||||
}
|
||||
|
||||
context.signOrder(activationOrder)
|
||||
context.signOrder(activationOrder)
|
||||
}
|
||||
}
|
||||
Timber.i("VisaCardActivationTask all time: ${timedResult.duration}")
|
||||
return timedResult.value
|
||||
}
|
||||
|
||||
private suspend fun SessionContext.signAuthorizationChallenge(
|
||||
challengeToSign: VisaAuthChallenge.Card,
|
||||
): CompletionResult<VisaCardActivationResponse> {
|
||||
val attestationCommand = AttestCardKeyCommand(challenge = CryptoUtils.generateRandomBytes(length = 16))
|
||||
val result = suspendCancellableCoroutine { continuation ->
|
||||
attestationCommand.run(session = session) { attestationResponse ->
|
||||
continuation.resume(attestationResponse)
|
||||
val timedResult = RealtimeMonotonicTimeSource.measureTimedValue {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
attestationCommand.run(session = session) { attestationResponse ->
|
||||
continuation.resume(attestationResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
Timber.i("AttestCardKeyCommand time: ${timedResult.duration}")
|
||||
|
||||
return when (result) {
|
||||
return when (val result = timedResult.value) {
|
||||
is CompletionResult.Success -> {
|
||||
Timber.tag("ASDASD").e("AttestCardKeyCommand success")
|
||||
Timber.i("AttestCardKeyCommand success")
|
||||
processSignedAuthorizationChallenge(
|
||||
signedChallenge = challengeToSign.toSignedChallenge(
|
||||
signedChallenge = result.data.cardSignature.toHexString(),
|
||||
|
|
@ -102,7 +111,7 @@ class VisaCardActivationTask @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
Timber.tag("ASDASD").e("AttestCardKeyCommand failure ${result.error}")
|
||||
Timber.e("AttestCardKeyCommand failure ${result.error}")
|
||||
CompletionResult.Failure(result.error)
|
||||
}
|
||||
}
|
||||
|
|
@ -153,19 +162,24 @@ class VisaCardActivationTask @AssistedInject constructor(
|
|||
createOTP(session)
|
||||
} else {
|
||||
val createWalletTask = CreateWalletTask(VisaUtilities.mandatoryCurve)
|
||||
val result = suspendCancellableCoroutine { continuation ->
|
||||
createWalletTask.run(session) { createWalletResult ->
|
||||
continuation.resume(createWalletResult)
|
||||
|
||||
val timedResult = RealtimeMonotonicTimeSource.measureTimedValue {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
createWalletTask.run(session) { createWalletResult ->
|
||||
continuation.resume(createWalletResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (result) {
|
||||
Timber.i("CreateWalletTask time: ${timedResult.duration}")
|
||||
|
||||
when (val result = timedResult.value) {
|
||||
is CompletionResult.Success -> {
|
||||
Timber.tag("ASDASD").e("CreateWalletTask success")
|
||||
Timber.i("CreateWalletTask success")
|
||||
createOTP(session)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
Timber.tag("ASDASD").e("CreateWalletTask failure ${result.error}")
|
||||
Timber.e("CreateWalletTask failure ${result.error}")
|
||||
CompletionResult.Failure(result.error)
|
||||
}
|
||||
}
|
||||
|
|
@ -179,20 +193,24 @@ class VisaCardActivationTask @AssistedInject constructor(
|
|||
CompletionResult.Success(Unit)
|
||||
} else {
|
||||
val otpCommand = GenerateOTPCommand()
|
||||
val result = suspendCancellableCoroutine { continuation ->
|
||||
otpCommand.run(session) { otpResult ->
|
||||
continuation.resume(otpResult)
|
||||
val timedResult = RealtimeMonotonicTimeSource.measureTimedValue {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
otpCommand.run(session) { otpResult ->
|
||||
continuation.resume(otpResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (result) {
|
||||
Timber.i("GenerateOTPCommand time: ${timedResult.duration}")
|
||||
|
||||
when (val result = timedResult.value) {
|
||||
is CompletionResult.Success -> {
|
||||
Timber.tag("ASDASD").e("GenerateOTPCommand success")
|
||||
Timber.i("GenerateOTPCommand success")
|
||||
otpStorage.saveOTP(cardId, result.data.rootOTP)
|
||||
CompletionResult.Success(Unit)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
Timber.tag("ASDASD").e("GenerateOTPCommand failure ${result.error}")
|
||||
Timber.e("GenerateOTPCommand failure ${result.error}")
|
||||
CompletionResult.Failure(result.error)
|
||||
}
|
||||
}
|
||||
|
|
@ -212,22 +230,26 @@ class VisaCardActivationTask @AssistedInject constructor(
|
|||
derivationPath = VisaUtilities.visaDefaultDerivationPath,
|
||||
)
|
||||
|
||||
val result = suspendCancellableCoroutine { continuation ->
|
||||
task.run(session) { signResult ->
|
||||
continuation.resume(signResult)
|
||||
val timedResult = RealtimeMonotonicTimeSource.measureTimedValue {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
task.run(session) { signResult ->
|
||||
continuation.resume(signResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return when (result) {
|
||||
Timber.i("SignHashCommand time: ${timedResult.duration}")
|
||||
|
||||
return when (val result = timedResult.value) {
|
||||
is CompletionResult.Success -> {
|
||||
Timber.tag("ASDASD").e("SignHashCommand success")
|
||||
Timber.i("SignHashCommand success")
|
||||
handleSignedOrder(
|
||||
activationOrder = order,
|
||||
response = result.data,
|
||||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
Timber.tag("ASDASD").e("SignHashCommand failure ${result.error}")
|
||||
Timber.e("SignHashCommand failure ${result.error}")
|
||||
CompletionResult.Failure(result.error)
|
||||
}
|
||||
}
|
||||
|
|
@ -261,22 +283,27 @@ class VisaCardActivationTask @AssistedInject constructor(
|
|||
return CompletionResult.Success(Unit)
|
||||
}
|
||||
|
||||
Timber.tag("ASDASD").e("Setting access code: $accessCode")
|
||||
Timber.i("Setting access code")
|
||||
|
||||
val task = SetUserCodeCommand.changeAccessCode(accessCode)
|
||||
val result = suspendCancellableCoroutine { continuation ->
|
||||
task.run(session) { setAccessCodeResult ->
|
||||
continuation.resume(setAccessCodeResult)
|
||||
|
||||
val timedResult = RealtimeMonotonicTimeSource.measureTimedValue {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
task.run(session) { setAccessCodeResult ->
|
||||
continuation.resume(setAccessCodeResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return when (result) {
|
||||
Timber.i("SetUserCodeCommand time: ${timedResult.duration}")
|
||||
|
||||
return when (val result = timedResult.value) {
|
||||
is CompletionResult.Success -> {
|
||||
Timber.tag("ASDASD").e("SetUserCodeCommand success")
|
||||
Timber.i("SetUserCodeCommand success")
|
||||
CompletionResult.Success(Unit)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
Timber.tag("ASDASD").e("SetUserCodeCommand failure ${result.error}")
|
||||
Timber.i("SetUserCodeCommand failure ${result.error}")
|
||||
CompletionResult.Failure(result.error)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package com.tangem.tap.domain.visa
|
||||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.card.CardWallet
|
||||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
|
|
@ -258,33 +258,26 @@ internal class VisaCardScanHandler @Inject constructor(
|
|||
derivationPath: DerivationPath,
|
||||
nonce: String,
|
||||
): CompletionResult<SignHashResponse> {
|
||||
val signHashCommand = SignHashCommand(publicKey, nonce.toByteArray(), derivationPath)
|
||||
val result = suspendCancellableCoroutine {
|
||||
val signHashCommand = SignHashCommand(
|
||||
hash = nonce.hexToBytes(),
|
||||
walletPublicKey = publicKey,
|
||||
derivationPath = derivationPath,
|
||||
)
|
||||
return suspendCancellableCoroutine {
|
||||
signHashCommand.run(session) { result ->
|
||||
it.resume(result)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private suspend fun SessionContext.signChallengeWithCard(
|
||||
challenge: String,
|
||||
): CompletionResult<AttestCardKeyResponse> {
|
||||
val signHashCommand = AttestCardKeyCommand(challenge = challenge.toByteArray())
|
||||
val result = suspendCancellableCoroutine { continuation ->
|
||||
val signHashCommand = AttestCardKeyCommand(challenge = challenge.hexToBytes())
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
signHashCommand.run(session) { result ->
|
||||
continuation.resume(result)
|
||||
}
|
||||
}
|
||||
|
||||
return when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
CompletionResult.Success(result.data)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
CompletionResult.Failure(result.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.common.timemeasure
|
||||
|
||||
import android.os.SystemClock
|
||||
import kotlin.time.AbstractLongTimeSource
|
||||
import kotlin.time.DurationUnit
|
||||
|
||||
object RealtimeMonotonicTimeSource : AbstractLongTimeSource(DurationUnit.NANOSECONDS) {
|
||||
override fun read(): Long = SystemClock.elapsedRealtimeNanos()
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ import dagger.assisted.AssistedFactory
|
|||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
internal class DefaultVisaActivationRepository @AssistedInject constructor(
|
||||
@Assisted private val cardId: String,
|
||||
private val visaApi: TangemVisaApi,
|
||||
|
|
@ -38,7 +39,7 @@ internal class DefaultVisaActivationRepository @AssistedInject constructor(
|
|||
}
|
||||
|
||||
override suspend fun getActivationOrderToSign(): ActivationOrder = withContext(dispatcherProvider.io) {
|
||||
ActivationOrder(CryptoUtils.generateRandomBytes(32).toHexString())
|
||||
ActivationOrder(CryptoUtils.generateRandomBytes(length = 32).toHexString())
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
internal class DefaultVisaAuthRepository @Inject constructor(
|
||||
private val visaAuthApi: TangemVisaAuthApi,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
|
|
@ -30,7 +31,7 @@ internal class DefaultVisaAuthRepository @Inject constructor(
|
|||
// )
|
||||
|
||||
VisaAuthChallenge.Card(
|
||||
challenge = CryptoUtils.generateRandomBytes(16).toHexString(),
|
||||
challenge = CryptoUtils.generateRandomBytes(length = 16).toHexString(),
|
||||
session = VisaAuthSession("session"),
|
||||
)
|
||||
}
|
||||
|
|
@ -49,7 +50,7 @@ internal class DefaultVisaAuthRepository @Inject constructor(
|
|||
// session = VisaAuthSession(response.sessionId),
|
||||
// )
|
||||
VisaAuthChallenge.Wallet(
|
||||
challenge = CryptoUtils.generateRandomBytes(32).toHexString(),
|
||||
challenge = CryptoUtils.generateRandomBytes(length = 32).toHexString(),
|
||||
session = VisaAuthSession("session"),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ object VisaUtilities {
|
|||
|
||||
val visaBlockchain = Blockchain.Polygon
|
||||
|
||||
val visaDefaultDerivationPath = visaBlockchain.derivationPath(DerivationStyle.V3)
|
||||
val visaDefaultDerivationPath
|
||||
get() = visaBlockchain.derivationPath(DerivationStyle.V3)
|
||||
|
||||
fun visaDefaultDerivationPath(style: DerivationStyle) = visaBlockchain.derivationPath(style)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.security.DisableScreenshotsDisposableEffect
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.features.onboarding.v2.visa.impl.DefaultOnboardingVisaComponent
|
||||
|
|
@ -44,7 +43,7 @@ internal class OnboardingVisaAccessCodeComponent(
|
|||
|
||||
BackHandler(onBack = model::onBack)
|
||||
|
||||
DisableScreenshotsDisposableEffect()
|
||||
// DisableScreenshotsDisposableEffect()
|
||||
|
||||
OnboardingVisaAccessCode(state, modifier)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.tan
|
||||
|
||||
@Stable
|
||||
@ComponentScoped
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue