Updated on 2026-08-14

This commit is contained in:
Tangem 2020-06-18 13:19:18 +03:00
parent 077c4f5bf9
commit 58e6564cc8
3 changed files with 121 additions and 1 deletions

View file

@ -25,6 +25,7 @@ data class SessionEnvironment(
) {
var isDefaultPin1: Boolean = Companion.pin1.contentEquals(DEFAULT_PIN.calculateSha256())
var isDefaultPin2: Boolean = pin2.contentEquals(DEFAULT_PIN2.calculateSha256())
var pin1: ByteArray = SessionEnvironment.pin1
private set

View file

@ -41,7 +41,18 @@ abstract class Command<T : CommandResponse> : ApduSerializable<T>, CardSessionRu
override fun run(session: CardSession, callback: (result: CompletionResult<T>) -> Unit) {
Log.i("Command", "Initializing ${this::class.java.simpleName}")
transceive(session, callback)
if (requiresPin2() && session.environment.isDefaultPin2) {
handlePin2(session, callback)
} else {
transceive(session, callback)
}
}
private fun Command<*>.requiresPin2(): Boolean {
return this is SignCommand || this is PurgeWalletCommand ||
this is CreateWalletCommand || this is WriteUserDataCommand
}
open fun performPreCheck(card: Card): TangemSdkError? = null
@ -199,4 +210,29 @@ abstract class Command<T : CommandResponse> : ApduSerializable<T>, CardSessionRu
}
}
}
private fun handlePin2(
session: CardSession,
callback: (result: CompletionResult<T>) -> Unit
) {
val checkPinCommand = SetPinCommand(session.environment.pin1, session.environment.pin2)
checkPinCommand.run(session) { result ->
when (result) {
is CompletionResult.Failure -> {
session.viewDelegate.onPinRequested { pin2 ->
if (!pin2.isNullOrEmpty()) {
session.environment.setPin2(pin2)
transceive(session, callback)
} else {
session.environment.setPin2(SessionEnvironment.DEFAULT_PIN2)
transceive(session, callback)
}
}
}
is CompletionResult.Success -> {
transceive(session, callback)
}
}
}
}
}

View file

@ -0,0 +1,83 @@
package com.tangem.commands
import com.tangem.SessionEnvironment
import com.tangem.TangemSdkError
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.apdu.StatusWord
import com.tangem.common.extensions.calculateSha256
import com.tangem.common.tlv.TlvBuilder
import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
enum class SetPinStatus {
PinsNotChanged,
Pin1Changed,
Pin2Changed,
Pin3Changed,
Pins12Changed,
Pins13Changed,
Pins23Changed,
Pins123Changed,
;
companion object {
fun fromStatusWord(statusWord: StatusWord): SetPinStatus? {
return when (statusWord) {
StatusWord.ProcessCompleted -> PinsNotChanged
StatusWord.Pin1Changed -> Pin1Changed
StatusWord.Pin2Changed -> Pin2Changed
StatusWord.Pins12Changed -> Pins12Changed
StatusWord.Pin3Changed -> Pin3Changed
StatusWord.Pins13Changed -> Pins13Changed
StatusWord.Pins23Changed -> Pins23Changed
StatusWord.Pins123Changed -> Pins123Changed
else -> null
}
}
}
}
class SetPinResponse(
/**
* CID, Unique Tangem card ID number.
*/
val cardId: String,
/**
*
*/
val status: SetPinStatus
) : CommandResponse
class SetPinCommand(
private val newPin1: ByteArray = SessionEnvironment.DEFAULT_PIN.calculateSha256(),
private val newPin2: ByteArray = SessionEnvironment.DEFAULT_PIN2.calculateSha256(),
private val newPin3: ByteArray? = null
) : Command<SetPinResponse>() {
override fun serialize(environment: SessionEnvironment): CommandApdu {
val tlvBuilder = TlvBuilder()
tlvBuilder.append(TlvTag.Pin, environment.pin1)
tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
tlvBuilder.append(TlvTag.Pin2, environment.pin2)
tlvBuilder.append(TlvTag.Cvc, environment.cvc)
tlvBuilder.append(TlvTag.NewPin, newPin1)
tlvBuilder.append(TlvTag.NewPin2, newPin2)
tlvBuilder.append(TlvTag.NewPin3, newPin3)
return CommandApdu(Instruction.SwapPIN, tlvBuilder.serialize())
}
override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): SetPinResponse {
val tlvData = apdu.getTlvData() ?: throw TangemSdkError.DeserializeApduFailed()
val status = SetPinStatus.fromStatusWord(apdu.statusWord) ?: throw TangemSdkError.DecodingFailed()
val decoder = TlvDecoder(tlvData)
return SetPinResponse(
cardId = decoder.decode(TlvTag.CardId),
status = status
)
}
}