Updated on 2026-08-14

This commit is contained in:
Tangem 2021-09-11 22:16:58 +03:00
parent 53b89d7ff1
commit 4aa1a23229
3 changed files with 45 additions and 19 deletions

View file

@ -1,9 +1,6 @@
package com.tangem.tap.domain.twins
import com.tangem.CardSession
import com.tangem.CardSessionRunnable
import com.tangem.Message
import com.tangem.TangemSdkError
import com.tangem.*
import com.tangem.commands.wallet.CreateWalletResponse
import com.tangem.commands.wallet.PurgeWalletCommand
import com.tangem.common.CompletionResult
@ -14,10 +11,11 @@ import com.tangem.tap.domain.extensions.getSingleWallet
import com.tangem.tasks.CreateWalletTask
class CreateSecondTwinWalletTask(
private val firstPublicKey: String,
private val firstCardId: String,
private val preparingMessage: Message,
private val creatingWalletMessage: Message
private val firstPublicKey: String,
private val firstCardId: String,
private val issuerKeys: KeyPair,
private val preparingMessage: Message,
private val creatingWalletMessage: Message
) : CardSessionRunnable<CreateWalletResponse> {
override val requiresPin2 = true

View file

@ -1,5 +1,8 @@
package com.tangem.tap.domain.twins
import android.content.Context
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Types
import com.tangem.KeyPair
import com.tangem.Message
import com.tangem.blockchain.extensions.Result
@ -8,16 +11,22 @@ import com.tangem.common.CompletionResult
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toHexString
import com.tangem.crypto.CryptoUtils
import com.tangem.tap.common.extensions.readAssetAsString
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.network.createMoshi
import com.tangem.tap.tangemSdkManager
class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse) {
class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse, context: Context) {
private val currentCardId: String = scanNoteResponse.card.cardId
private var currentCardPublicKey: String? = null
private var secondCardPublicKey: String? = null
private val issuerKeyPair: KeyPair = getIssuerKeys(
context, scanNoteResponse.card.issuerPublicKey!!.toHexString()
)
suspend fun createFirstWallet(message: Message): SimpleResult {
val response = tangemSdkManager.runTaskAsync(
CreateFirstTwinWalletTask(), currentCardId, message
@ -41,6 +50,7 @@ class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse) {
val task = CreateSecondTwinWalletTask(
firstPublicKey = currentCardPublicKey!!,
firstCardId = currentCardId,
issuerKeys = issuerKeyPair,
preparingMessage = preparingMessage,
creatingWalletMessage = creatingWalletMessage
)
@ -59,7 +69,7 @@ class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse) {
suspend fun complete(message: Message): Result<ScanNoteResponse> {
val response = tangemSdkManager.runTaskAsync(
FinalizeTwinTask(secondCardPublicKey!!.hexToBytes(), issuerKeys),
FinalizeTwinTask(secondCardPublicKey!!.hexToBytes(), issuerKeyPair),
currentCardId, message
)
return when (response) {
@ -69,13 +79,6 @@ class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse) {
}
companion object {
val issuerKeys = KeyPair(
privateKey = "F9F4C50636C9E6FC65F92655BD5C21C85A5F6A34DCD0F1E75FCEA1980FE242F5".hexToBytes(),
publicKey = ("048196AA4B410AC44A3B9CCE18E7BE226AEA070ACC83A9CF67540F" +
"AC49AF25129F6A538A28AD6341358E3C4F9963064F" +
"7E365372A651D374E5C23CDD37FD099BF2").hexToBytes()
)
fun verifyTwinPublicKey(issuerData: ByteArray, cardWalletPublicKey: ByteArray?): Boolean {
if (issuerData.size < 65) return false
val publicKey = issuerData.sliceArray(0 until 65)
@ -83,5 +86,30 @@ class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse) {
return (cardWalletPublicKey != null &&
CryptoUtils.verify(cardWalletPublicKey, publicKey, signedKey))
}
private fun getIssuerKeys(context: Context, publicKey: String): KeyPair {
val issuer = getIssuers(context).first { it.publicKey == publicKey }
return KeyPair(
publicKey = issuer.publicKey.hexToBytes(),
privateKey = issuer.privateKey.hexToBytes()
)
}
private fun getAdapter(): JsonAdapter<List<Issuer>> {
return createMoshi().adapter(
Types.newParameterizedType(List::class.java, Issuer::class.java)
)
}
private fun getIssuers(context: Context): List<Issuer> {
val file = context.readAssetAsString("tangem-app-config/issuers")
return getAdapter().fromJson(file)!!
}
}
}
}
private class Issuer(
val id: String,
val privateKey: String,
val publicKey: String,
)