diff --git a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt index 0534f85d0a..c2b744d811 100644 --- a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt +++ b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt @@ -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 diff --git a/tangem-core/src/main/java/com/tangem/commands/Command.kt b/tangem-core/src/main/java/com/tangem/commands/Command.kt index 57cc3dd0a2..2c7263ca52 100644 --- a/tangem-core/src/main/java/com/tangem/commands/Command.kt +++ b/tangem-core/src/main/java/com/tangem/commands/Command.kt @@ -41,7 +41,18 @@ abstract class Command : ApduSerializable, CardSessionRu override fun run(session: CardSession, callback: (result: CompletionResult) -> 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 : ApduSerializable, CardSessionRu } } } + + private fun handlePin2( + session: CardSession, + callback: (result: CompletionResult) -> 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) + } + } + } + } } \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/SetPinCommand.kt b/tangem-core/src/main/java/com/tangem/commands/SetPinCommand.kt new file mode 100644 index 0000000000..e079f82786 --- /dev/null +++ b/tangem-core/src/main/java/com/tangem/commands/SetPinCommand.kt @@ -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() { + + 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 + ) + } +} \ No newline at end of file