From 6111adf5b0ae9895661bf2d1eb38fca92f7ef82e Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 7 May 2020 14:28:49 +0300 Subject: [PATCH 1/8] Updated on 2026-08-14 --- .../tangem/devkit/ucase/ui/ActionViewModel.kt | 3 --- .../responses/converter/BaseResponseConverter.kt | 2 +- .../variants/responses/ui/ResponseFragment.kt | 4 ++-- tangem-sdk/build.gradle | 4 +++- .../converter/ResponseConverter.kt | 6 +++--- .../com/tangem/tangem_sdk_new/extensions/List.kt | 16 ++++++++++++++++ 6 files changed, 25 insertions(+), 10 deletions(-) rename tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/responses/ResponseJsonConverter.kt => tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/converter/ResponseConverter.kt (97%) create mode 100644 tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/List.kt diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/ui/ActionViewModel.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/ui/ActionViewModel.kt index 3c04d86d59..8ba6cf2f72 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/ui/ActionViewModel.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/ui/ActionViewModel.kt @@ -3,7 +3,6 @@ package com.tangem.devkit.ucase.ui import android.view.View import androidx.annotation.UiThread import androidx.lifecycle.* -import com.google.gson.Gson import com.tangem.SessionError import com.tangem.TangemSdk import com.tangem.commands.Card @@ -16,7 +15,6 @@ import com.tangem.devkit._arch.structure.Payload import com.tangem.devkit._arch.structure.abstraction.Item import com.tangem.devkit._arch.structure.abstraction.iterate import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager -import com.tangem.devkit.ucase.domain.responses.ResponseJsonConverter import com.tangem.devkit.ucase.resources.ActionType import com.tangem.devkit.ucase.tunnel.ViewScreen import com.tangem.devkit.ucase.variants.personalize.converter.ItemTypes @@ -134,7 +132,6 @@ class ActionViewModel(private val itemsManager: ItemsManager) : ViewModel(), Lif internal class Notifier(private val vm: ActionViewModel) { private var notShowedError: SessionError? = null - private val gson: Gson = ResponseJsonConverter().gson fun handleActionResult(result: CompletionResult<*>, list: List) { if (list.isNotEmpty()) notifyItemsChanged(list) diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/responses/converter/BaseResponseConverter.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/responses/converter/BaseResponseConverter.kt index c1eded3858..34ead3b362 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/responses/converter/BaseResponseConverter.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/responses/converter/BaseResponseConverter.kt @@ -2,8 +2,8 @@ package com.tangem.devkit.ucase.variants.responses.converter import com.tangem.devkit._arch.structure.Id import com.tangem.devkit._arch.structure.abstraction.* -import com.tangem.devkit.ucase.domain.responses.ResponseFieldConverter import com.tangem.devkit.ucase.variants.responses.item.TextHeaderItem +import com.tangem.tangem_sdk_new.converter.ResponseFieldConverter import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf /** diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/responses/ui/ResponseFragment.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/responses/ui/ResponseFragment.kt index 0dcb15e807..ea236daef2 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/responses/ui/ResponseFragment.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/responses/ui/ResponseFragment.kt @@ -12,10 +12,10 @@ import com.tangem.devkit.R import com.tangem.devkit._arch.widget.WidgetBuilder import com.tangem.devkit._main.MainViewModel import com.tangem.devkit.extensions.shareText -import com.tangem.devkit.ucase.domain.responses.ResponseJsonConverter import com.tangem.devkit.ucase.ui.BaseFragment import com.tangem.devkit.ucase.variants.responses.ResponseViewModel import com.tangem.devkit.ucase.variants.responses.ui.widget.ResponseItemBuilder +import com.tangem.tangem_sdk_new.converter.ResponseConverter /** [REDACTED_AUTHOR] @@ -68,7 +68,7 @@ open class ResponseFragment : BaseFragment() { override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.action_share -> { - shareText(ResponseJsonConverter().convertResponse(mainActivityVM.commandResponse)) + shareText(ResponseConverter().convertResponse(mainActivityVM.commandResponse)) } } return super.onOptionsItemSelected(item) diff --git a/tangem-sdk/build.gradle b/tangem-sdk/build.gradle index 14d86acb0d..9c2742da98 100644 --- a/tangem-sdk/build.gradle +++ b/tangem-sdk/build.gradle @@ -58,4 +58,6 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' -} + + implementation 'com.google.code.gson:gson:2.8.6' +} \ No newline at end of file diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/responses/ResponseJsonConverter.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/converter/ResponseConverter.kt similarity index 97% rename from tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/responses/ResponseJsonConverter.kt rename to tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/converter/ResponseConverter.kt index 4c6148b6f9..392bdc9f96 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/responses/ResponseJsonConverter.kt +++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/converter/ResponseConverter.kt @@ -1,9 +1,9 @@ -package com.tangem.devkit.ucase.domain.responses +package com.tangem.tangem_sdk_new.converter import com.google.gson.* import com.tangem.commands.* import com.tangem.common.extensions.toHexString -import com.tangem.devkit.extensions.print +import com.tangem.tangem_sdk_new.extensions.print import java.lang.reflect.Type import java.text.DateFormat import java.util.* @@ -11,7 +11,7 @@ import java.util.* /** [REDACTED_AUTHOR] */ -class ResponseJsonConverter { +class ResponseConverter { val gson: Gson by lazy { init() } diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/List.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/List.kt new file mode 100644 index 0000000000..4f261d8ab5 --- /dev/null +++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/List.kt @@ -0,0 +1,16 @@ +package com.tangem.tangem_sdk_new.extensions + +/** +[REDACTED_AUTHOR] + */ +fun List.print(delimiter: String = ", ", wrap: Boolean = true): String { + val builder = StringBuilder() + forEach { builder.append(it).append(delimiter) } + val length = builder.length + if (length > delimiter.length) { + builder.delete(length - delimiter.length, length) + } + val result = builder.toString() + + return if (wrap) "[$result]" else result +} \ No newline at end of file From ba856fbb6de3359c9092eac963c52b8ad0017038 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 7 May 2020 14:30:05 +0300 Subject: [PATCH 2/8] Updated on 2026-08-14 --- .../src/main/java/com/tangem/tangem_sdk_new/extensions/List.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/List.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/List.kt index 4f261d8ab5..a86c326453 100644 --- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/List.kt +++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/List.kt @@ -1,8 +1,5 @@ package com.tangem.tangem_sdk_new.extensions -/** -[REDACTED_AUTHOR] - */ fun List.print(delimiter: String = ", ", wrap: Boolean = true): String { val builder = StringBuilder() forEach { builder.append(it).append(delimiter) } From 3be1a1e694768a486100e672c3bdef4622e56407 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 7 May 2020 15:32:17 +0300 Subject: [PATCH 3/8] Updated on 2026-08-14 --- .../blockchain_demo/BlockchainDemoActivity.kt | 4 +- .../src/main/java/com/tangem/CardSession.kt | 30 +-- .../src/main/java/com/tangem/Config.kt | 5 +- .../java/com/tangem/SessionEnvironment.kt | 3 +- .../src/main/java/com/tangem/TangemSdk.kt | 33 ++-- .../{SessionError.kt => TangemSdkError.kt} | 176 ++++++++++-------- .../com/tangem/commands/CheckWalletCommand.kt | 23 ++- .../main/java/com/tangem/commands/Command.kt | 33 +++- .../tangem/commands/CreateWalletCommand.kt | 41 +++- .../com/tangem/commands/OpenSessionCommand.kt | 4 +- .../com/tangem/commands/PurgeWalletCommand.kt | 37 +++- .../java/com/tangem/commands/ReadCommand.kt | 6 +- .../tangem/commands/ReadIssuerDataCommand.kt | 18 +- .../commands/ReadIssuerExtraDataCommand.kt | 14 +- .../tangem/commands/ReadUserDataCommand.kt | 102 +++++----- .../java/com/tangem/commands/SignCommand.kt | 63 ++++++- .../tangem/commands/WriteIssuerDataCommand.kt | 65 +++++-- .../commands/WriteIssuerExtraDataCommand.kt | 65 ++++++- .../tangem/commands/WriteUserDataCommand.kt | 42 ++++- .../personalization/DepersonalizeCommand.kt | 16 ++ .../personalization/PersonalizeCommand.kt | 17 +- .../entities/CardConfigExtensions.kt | 2 +- .../com/tangem/common/CompletionResult.kt | 4 +- .../java/com/tangem/common/apdu/StatusWord.kt | 16 +- .../java/com/tangem/common/tlv/TlvDecoder.kt | 20 +- .../java/com/tangem/common/tlv/TlvEncoder.kt | 6 +- .../java/com/tangem/tasks/CreateWalletTask.kt | 6 +- .../main/java/com/tangem/tasks/ScanTask.kt | 6 +- .../com/tangem/common/tlv/TlvDecoderTest.kt | 14 +- .../com/tangem/devkit/TestUserDataActivity.kt | 6 +- .../tangem/devkit/ucase/ui/ActionViewModel.kt | 8 +- tangem-sdk-android-config/README.md | 32 ++-- .../tangem/tangem_sdk_new/nfc/NfcReader.kt | 10 +- 33 files changed, 638 insertions(+), 289 deletions(-) rename tangem-core/src/main/java/com/tangem/{SessionError.kt => TangemSdkError.kt} (55%) diff --git a/blockchain-demo/src/main/java/com/tangem/blockchain_demo/BlockchainDemoActivity.kt b/blockchain-demo/src/main/java/com/tangem/blockchain_demo/BlockchainDemoActivity.kt index 809eb2e976..038c0ea66c 100644 --- a/blockchain-demo/src/main/java/com/tangem/blockchain_demo/BlockchainDemoActivity.kt +++ b/blockchain-demo/src/main/java/com/tangem/blockchain_demo/BlockchainDemoActivity.kt @@ -4,8 +4,8 @@ import android.os.Bundle import android.text.Editable import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import com.tangem.SessionError import com.tangem.TangemSdk +import com.tangem.TangemSdkError import com.tangem.blockchain.common.* import com.tangem.blockchain.extensions.Result import com.tangem.blockchain.extensions.Signer @@ -65,7 +65,7 @@ class BlockchainDemoActivity : AppCompatActivity() { getInfo() } is CompletionResult.Failure -> { - if (result.error !is SessionError.UserCancelled) { + if (result.error !is TangemSdkError.UserCancelled) { handleError(result.error.toString()) } } diff --git a/tangem-core/src/main/java/com/tangem/CardSession.kt b/tangem-core/src/main/java/com/tangem/CardSession.kt index e2cbafb179..34f243fc4f 100644 --- a/tangem-core/src/main/java/com/tangem/CardSession.kt +++ b/tangem-core/src/main/java/com/tangem/CardSession.kt @@ -37,7 +37,7 @@ interface CardSessionRunnable { * @property viewDelegate is an interface that allows interaction with users and shows relevant UI. * @property cardId ID, Unique Tangem card ID number. If not null, the SDK will check that you the card * with which you tapped a phone has this [cardId] and SDK will return - * the [SessionError.WrongCard] otherwise. + * the [TangemSdkError.WrongCard] otherwise. * @property initialMessage A custom description that will be shown at the beginning of the NFC session. * If null, a default header and text body will be used. */ @@ -86,12 +86,12 @@ class CardSession( /** * Starts a card session and performs preflight [ReadCommand]. - * @param callback: callback with the card session. Can contain [SessionError] if something goes wrong. + * @param callback: callback with the card session. Can contain [TangemSdkError] if something goes wrong. */ - fun start(callback: (session: CardSession, error: SessionError?) -> Unit) { + fun start(callback: (session: CardSession, error: TangemSdkError?) -> Unit) { try { startSession() - } catch (error: SessionError) { + } catch (error: TangemSdkError) { callback(this, error) } @@ -109,7 +109,7 @@ class CardSession( } private fun startSession() { - if (isBusy) throw SessionError.Busy() + if (isBusy) throw TangemSdkError.Busy() isBusy = true viewDelegate.onNfcSessionStarted(cardId, initialMessage) reader.openSession() @@ -133,14 +133,14 @@ class CardSession( is CompletionResult.Success -> { val receivedCardId = result.data.cardId if (cardId != null && receivedCardId != cardId) { - stopWithError(SessionError.WrongCard()) - callback(CompletionResult.Failure(SessionError.WrongCard())) + stopWithError(TangemSdkError.WrongCard()) + callback(CompletionResult.Failure(TangemSdkError.WrongCard())) return@run } val allowedCardTypes = environment.cardFilter.allowedCardTypes if (!allowedCardTypes.contains(result.data.getType())) { - stopWithError(SessionError.WrongCardType()) - callback(CompletionResult.Failure(SessionError.WrongCardType())) + stopWithError(TangemSdkError.WrongCardType()) + callback(CompletionResult.Failure(TangemSdkError.WrongCardType())) return@run } environment.card = result.data @@ -169,12 +169,12 @@ class CardSession( reader.closeSession() isBusy = false - val errorMessage = if (error is SessionError) { + val errorMessage = if (error is TangemSdkError) { "${error::class.simpleName}: ${error.code}" } else { error.localizedMessage } - if (error !is SessionError.UserCancelled) { + if (error !is TangemSdkError.UserCancelled) { Log.e("tag", "Finishing with error: $errorMessage") viewDelegate.onError(errorMessage) } @@ -185,10 +185,10 @@ class CardSession( } private fun tryHandleError( - error: SessionError, callback: (result: CompletionResult) -> Unit) { + error: TangemSdkError, callback: (result: CompletionResult) -> Unit) { when (error) { - is SessionError.NeedEncryption -> { + is TangemSdkError.NeedEncryption -> { Log.i(tag, "Establishing encryption") when (environment.encryptionMode) { EncryptionMode.NONE -> { @@ -201,12 +201,12 @@ class CardSession( } EncryptionMode.STRONG -> { Log.e(tag, "Encryption doesn't work") - callback(CompletionResult.Failure(SessionError.NeedEncryption())) + callback(CompletionResult.Failure(TangemSdkError.NeedEncryption())) } } return establishEncryption(callback) } - else -> callback(CompletionResult.Failure(SessionError.UnknownError())) + else -> callback(CompletionResult.Failure(TangemSdkError.UnknownError())) } } diff --git a/tangem-core/src/main/java/com/tangem/Config.kt b/tangem-core/src/main/java/com/tangem/Config.kt index 20c5c849bd..45da4b6912 100644 --- a/tangem-core/src/main/java/com/tangem/Config.kt +++ b/tangem-core/src/main/java/com/tangem/Config.kt @@ -34,5 +34,8 @@ class Config( /** * Filter that can be used to limit cards that can be interacted with in TangemSdk. */ - val cardFilter: CardFilter = CardFilter() + val cardFilter: CardFilter = CardFilter(), + + var handleErrors: Boolean = true + ) \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt index c1c9a296b2..790a1f7881 100644 --- a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt +++ b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt @@ -21,7 +21,8 @@ data class SessionEnvironment( var encryptionMode: EncryptionMode = EncryptionMode.NONE, var encryptionKey: ByteArray? = null, val cvc: ByteArray? = null, - var cardFilter: CardFilter = CardFilter() + var cardFilter: CardFilter = CardFilter(), + val handleErrors: Boolean ) { fun setPin1(pin1: String) { diff --git a/tangem-core/src/main/java/com/tangem/TangemSdk.kt b/tangem-core/src/main/java/com/tangem/TangemSdk.kt index a5f90dc0ca..8fc1fb4e2e 100644 --- a/tangem-core/src/main/java/com/tangem/TangemSdk.kt +++ b/tangem-core/src/main/java/com/tangem/TangemSdk.kt @@ -46,7 +46,7 @@ class TangemSdk( * it proves that the wallet owns a private key that corresponds to a public one. * * @param callback is triggered on the completion of the [ScanTask] and provides card response - * in the form of [Card] if the task was performed successfully or [SessionError] in case of an error. + * in the form of [Card] if the task was performed successfully or [TangemSdkError] in case of an error. */ fun scanCard(initialMessage: Message? = null, callback: (result: CompletionResult) -> Unit) { startSessionWithRunnable(ScanTask(), null, initialMessage, callback) @@ -68,7 +68,7 @@ class TangemSdk( * @param cardId CID, Unique Tangem card ID number * @param callback is triggered on the completion of the [SignCommand] and provides card response * in the form of [SignResponse] if the task was performed successfully - * or [SessionError] in case of an error. + * or [TangemSdkError] in case of an error. */ fun sign(hashes: Array, cardId: String, initialMessage: Message? = null, callback: (result: CompletionResult) -> Unit) { @@ -86,7 +86,7 @@ class TangemSdk( * @param cardId CID, Unique Tangem card ID number. * @param callback is triggered on the completion of the [ReadIssuerDataCommand] and provides * card response in the form of [ReadIssuerDataResponse] if the task was performed successfully - * or [SessionError] in case of an error. + * or [TangemSdkError] in case of an error. */ fun readIssuerData(cardId: String, initialMessage: Message? = null, callback: (result: CompletionResult) -> Unit) { @@ -105,7 +105,7 @@ class TangemSdk( * @param cardId CID, Unique Tangem card ID number. * @param callback is triggered on the completion of the [ReadIssuerExtraDataCommand] and provides * card response in the form of [ReadIssuerExtraDataResponse] if the task was performed successfully - * or [SessionError] in case of an error. + * or [TangemSdkError] in case of an error. */ fun readIssuerExtraData(cardId: String, callback: (result: CompletionResult) -> Unit) { @@ -126,7 +126,7 @@ class TangemSdk( * @param issuerDataCounter An optional counter that protect issuer data against replay attack. * @param callback is triggered on the completion of the [WriteIssuerDataCommand] and provides * card response in the form of [WriteIssuerDataResponse] if the task was performed successfully - * or [SessionError] in case of an error. + * or [TangemSdkError] in case of an error. */ fun writeIssuerData(cardId: String, issuerData: ByteArray, @@ -164,7 +164,7 @@ class TangemSdk( * @param issuerDataCounter An optional counter that protect issuer data against replay attack. * @param callback is triggered on the completion of the [WriteIssuerExtraDataCommand] and provides * card response in the form of [WriteIssuerDataResponse] if the task was performed successfully - * or [SessionError] in case of an error. + * or [TangemSdkError] in case of an error. */ fun writeIssuerExtraData(cardId: String, issuerData: ByteArray, @@ -224,7 +224,7 @@ class TangemSdk( * @param cardId CID, Unique Tangem card ID number. * @param callback is triggered on the completion of the [ReadUserDataCommand] and provides * card response in the form of [ReadUserDataResponse] if the task was performed successfully - * or [SessionError] in case of an error. + * or [TangemSdkError] in case of an error. */ fun readUserData(cardId: String, initialMessage: Message? = null, callback: (result: CompletionResult) -> Unit) { @@ -246,7 +246,7 @@ class TangemSdk( * @param cardId CID, Unique Tangem card ID number. * @param callback is triggered on the completion of the [CreateWalletTask] and provides * card response in the form of [CreateWalletResponse] if the task was performed successfully - * or [SessionError] in case of an error. + * or [TangemSdkError] in case of an error. */ fun createWallet(cardId: String, initialMessage: Message? = null, callback: (result: CompletionResult) -> Unit) { @@ -265,7 +265,7 @@ class TangemSdk( * @param cardId CID, Unique Tangem card ID number. * @param callback is triggered on the completion of the [PurgeWalletCommand] and provides * card response in the form of [PurgeWalletResponse] if the task was performed successfully - * or [SessionError] in case of an error. + * or [TangemSdkError] in case of an error. */ fun purgeWallet(cardId: String, initialMessage: Message? = null, callback: (result: CompletionResult) -> Unit) { @@ -283,7 +283,7 @@ class TangemSdk( * @param cardId CID, Unique Tangem card ID number. * @param callback is triggered on the completion of the [DepersonalizeCommand] and provides * card response in the form of [DepersonalizeResponse] if the task was performed successfully - * or [SessionError] in case of an error. + * or [TangemSdkError] in case of an error. * */ fun depersonalize(cardId: String, initialMessage: Message? = null, callback: (result: CompletionResult) -> Unit) { @@ -306,7 +306,7 @@ class TangemSdk( * (non-EMV) POS terminal infrastructure and transaction processing back-end. * @param callback is triggered on the completion of the [PersonalizeCommand] and provides * card response in the form of [Card] if the command was performed successfully - * or [SessionError] in case of an error. + * or [TangemSdkError] in case of an error. */ fun personalize(config: CardConfig, issuer: Issuer, manufacturer: Manufacturer, acquirer: Acquirer? = null, @@ -325,7 +325,7 @@ class TangemSdk( * @runnable: A custom task, adopting [CardSessionRunnable] protocol * @cardId: CID, Unique Tangem card ID number. If not null, the SDK will check that you the card * with which you tapped a phone has this [cardId] and SDK will return - * the [SessionError.WrongCard] otherwise. + * the [TangemSdkError.WrongCard] otherwise. * @initialMessage: A custom description that shows at the beginning of the NFC session. * If null, default message will be used. * @callback: Standard [TangemSdk] callback. @@ -343,14 +343,14 @@ class TangemSdk( * @cardId: CID, Unique Tangem card ID number. If not null, the SDK will check that you the card * with which you tapped a phone has this [cardId] and SDK will return - * the [SessionError.WrongCard] otherwise. + * the [TangemSdkError.WrongCard] otherwise. * @initialMessage: A custom description that shows at the beginning of the NFC session. * If null, default message will be used. - * @callback: At first, you should check that the [SessionError] is not null, + * @callback: At first, you should check that the [TangemSdkError] is not null, * then you can use the [CardSession] to interact with a card. */ fun startSession(cardId: String? = null, initialMessage: Message? = null, - callback: (session: CardSession, error: SessionError?) -> Unit) { + callback: (session: CardSession, error: TangemSdkError?) -> Unit) { val cardSession = CardSession(buildEnvironment(), reader, viewDelegate, cardId, initialMessage) Thread().run { cardSession.start(callback) } } @@ -367,7 +367,8 @@ class TangemSdk( val terminalKeys = if (config.linkedTerminal) terminalKeysService?.getKeys() else null return SessionEnvironment( terminalKeys = terminalKeys, - cardFilter = config.cardFilter + cardFilter = config.cardFilter, + handleErrors = config.handleErrors ) } diff --git a/tangem-core/src/main/java/com/tangem/SessionError.kt b/tangem-core/src/main/java/com/tangem/TangemSdkError.kt similarity index 55% rename from tangem-core/src/main/java/com/tangem/SessionError.kt rename to tangem-core/src/main/java/com/tangem/TangemSdkError.kt index b5f702ceb2..5167aff71f 100644 --- a/tangem-core/src/main/java/com/tangem/SessionError.kt +++ b/tangem-core/src/main/java/com/tangem/TangemSdkError.kt @@ -9,52 +9,42 @@ import com.tangem.tasks.ScanTask * An error class that represent typical errors that may occur when performing Tangem SDK tasks. * Errors are propagated back to the caller in callbacks. */ -sealed class SessionError(val code: Int) : Exception() { +sealed class TangemSdkError(val code: Int) : Exception(code.toString()) { - //Errors in serializing APDU /** - * This error is returned when there [CommandSerializer] cannot deserialize [com.tangem.common.tlv.Tlv] - * (this error is a wrapper around internal [com.tangem.common.tlv.TlvDecoder] errors). + * This error is returned when Android NFC reader loses a tag + * (e.g. a user detaches card from the phone's NFC module) while the NFC session is in progress. */ - class SerializeCommandError : SessionError(1000) + class TagLost : TangemSdkError(10001) - class DeserializeApduFailed : SessionError(1001) - class EncodingFailedTypeMismatch : SessionError(1002) - class EncodingFailed : SessionError(1003) - class DecodingFailedMissingTag : SessionError(1004) - class DecodingFailedTypeMismatch : SessionError(1005) - class DecodingFailed : SessionError(1005) + class SerializeCommandError : TangemSdkError(20001) + class DeserializeApduFailed : TangemSdkError(20002) + class EncodingFailedTypeMismatch : TangemSdkError(20003) + class EncodingFailed : TangemSdkError(20004) + class DecodingFailedMissingTag : TangemSdkError(20005) + class DecodingFailedTypeMismatch : TangemSdkError(20006) + class DecodingFailed : TangemSdkError(20007) /** * This error is returned when unknown [StatusWord] is received from a card. */ - class UnknownStatus : SessionError(2001) - + class UnknownStatus : TangemSdkError(30001) /** * This error is returned when a card's reply is [StatusWord.ErrorProcessingCommand]. * The card sends this status in case of internal card error. */ - class ErrorProcessingCommand : SessionError(2002) - - /** - * This error is returned when a task (such as [ScanTask]) requires that [ReadCommand] - * is executed before performing other commands. - */ - class MissingPreflightRead : SessionError(2003) - + class ErrorProcessingCommand : TangemSdkError(30002) /** * This error is returned when a card's reply is [StatusWord.InvalidState]. * The card sends this status when command can not be executed in the current state of a card. */ - class InvalidState : SessionError(2004) - + class InvalidState : TangemSdkError(30003) /** * This error is returned when a card's reply is [StatusWord.InsNotSupported]. * The card sends this status when the card cannot process the [com.tangem.common.apdu.Instruction]. */ - class InsNotSupported : SessionError(2005) - + class InsNotSupported : TangemSdkError(30004) /** * This error is returned when a card's reply is [StatusWord.InvalidParams]. * The card sends this status when there are wrong or not sufficient parameters in TLV request, @@ -62,85 +52,113 @@ sealed class SessionError(val code: Int) : Exception() { * The error may be caused, for example, by wrong parameters of the [Task], [CommandSerializer], * mapping or serialization errors. */ - class InvalidParams : SessionError(2006) - + class InvalidParams : TangemSdkError(30005) /** * This error is returned when a card's reply is [StatusWord.NeedEncryption] * and the encryption was not established by TangemSdk. */ - class NeedEncryption : SessionError(2007) + class NeedEncryption : TangemSdkError(30006) - //Scan errors - /** - * This error is returned when a [Task] checks unsuccessfully either - * a card's ability to sign with its private key, or the validity of issuer data. - */ - class VerificationFailed : SessionError(3000) + class Pin1Changed : TangemSdkError(30007) - /** - * This error is returned when a [ScanTask] returns a [Card] without some of the essential fields. - */ - class CardError : SessionError(3001) + class Pin2Changed : TangemSdkError(30008) + class PinsChanged : TangemSdkError(30009) + + + + //Personalization Errors + class AlreadyPersonalized : TangemSdkError(40101) + + //Depersonalization Errors + class CannotBeDepersonalized : TangemSdkError(40201) + + //Read Errors + class Pin1Required : TangemSdkError(40401) /** * This error is returned when a [Task] expects a user to use a particular card, * and a user tries to use a different card. */ - class WrongCard : SessionError(3002) - - /** - * Tangem cards can sign currently up to 10 hashes during one [com.tangem.commands.SignCommand]. - * This error is returned when a [com.tangem.commands.SignCommand] receives more than 10 hashes to sign. - */ - class TooMuchHashesInOneTransaction : SessionError(3003) - - /** - * This error is returned when a [com.tangem.commands.SignCommand] - * receives only empty hashes for signature. - */ - class EmptyHashes : SessionError(3004) - - /** - * This error is returned when a [com.tangem.commands.SignCommand] - * receives hashes of different lengths for signature. - */ - class HashSizeMustBeEqual : SessionError(3005) - - + class WrongCard : TangemSdkError(40403) /** * This error is returned when a user scans a card of a [com.tangem.common.extensions.CardType] * that is not specified in [Config.allowedCards]. */ - class WrongCardType : SessionError(3006) + class WrongCardType : TangemSdkError(40404) + //CreateWallet Errors + class AlreadyCreated : TangemSdkError(40501) + + //PurgeWallet Errors + class PurgeWalletProhibited : TangemSdkError(40601) + + //SetPin Errors + class Pin1CannotBeChanged : TangemSdkError(40801) + class Pin2CannotBeChanged : TangemSdkError(40802) + class Pin1CannotBeDefault : TangemSdkError(40803) + + //Sign Errors + class NoRemainingSignatures : TangemSdkError(40901) /** - * This error is returned when [com.tangem.TangemSdk] was called with a new [Task], - * while a previous [Task] is still in progress. + * This error is returned when a [com.tangem.commands.SignCommand] + * receives only empty hashes for signature. */ - class Busy : SessionError(4000) - + class EmptyHashes : TangemSdkError(40902) /** - * This error is returned when a user manually closes NFC Reading Bottom Sheet Dialog. + * This error is returned when a [com.tangem.commands.SignCommand] + * receives hashes of different lengths for signature. */ - class UserCancelled : SessionError(4001) - - //NFC errors - class NfcReaderError : SessionError(5002) - + class HashSizeMustBeEqual : TangemSdkError(40903) + class CardIsEmpty : TangemSdkError(40904) + class SignHashesNotAvailable : TangemSdkError(40905) /** - * This error is returned when Android NFC reader loses a tag - * (e.g. a user detaches card from the phone's NFC module) while the NFC session is in progress. + * Tangem cards can sign currently up to 10 hashes during one [com.tangem.commands.SignCommand]. + * This error is returned when a [com.tangem.commands.SignCommand] receives more than 10 hashes to sign. */ - class TagLost : SessionError(5003) + class TooManyhHashesInOneTransaction : TangemSdkError(40906) - class UnknownError : SessionError(6000) - - //Specific Command Errors + //General Errors + class NotPersonalized() : TangemSdkError(40001) + class NotActivated : TangemSdkError(40002) + class CardIsPurged : TangemSdkError(40003) + class Pin2OrCvcRequired : TangemSdkError(40004) + /** + * This error is returned when a [Task] checks unsuccessfully either + * a card's ability to sign with its private key, or the validity of issuer data. + */ + class VerificationFailed : TangemSdkError(40005) + class DataSizeTooLarge : TangemSdkError(40006) /** * This error is returned when [ReadIssuerDataTask] or [ReadIssuerExtraDataTask] expects a counter * (when the card's requires it), but the counter is missing. */ - class MissingCounter : SessionError(7001) + class MissingCounter : TangemSdkError(40007) + class OverwritingDataIsProhibited : TangemSdkError(40008) + class DataCannotBeWritten : TangemSdkError(40009) + class MissingIssuerPubicKey : TangemSdkError(40010) + /** + * This error is returned when a [ScanTask] returns a [Card] without some of the essential fields. + */ + class CardError : TangemSdkError(40011) + + + //SDK Errors + class UnknownError: TangemSdkError(50001) + /** + * This error is returned when a user manually closes NFC Reading Bottom Sheet Dialog. + */ + class UserCancelled: TangemSdkError(50002) + /** + * This error is returned when [com.tangem.TangemSdk] was called with a new [Task], + * while a previous [Task] is still in progress. + */ + class Busy : TangemSdkError(50003) + /** + * This error is returned when a task (such as [ScanTask]) requires that [ReadCommand] + * is executed before performing other commands. + */ + class MissingPreflightRead : TangemSdkError(50004) + + +} - class MissingIssuerPubicKey : SessionError(7002) -} \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt index 4d9c3a53ff..ab33a2cc3c 100644 --- a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt @@ -2,7 +2,7 @@ package com.tangem.commands import com.tangem.CardSession import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction @@ -49,7 +49,7 @@ class CheckWalletCommand( private val challenge = CryptoUtils.generateRandomBytes(16) override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { - transceive(session) { result -> + super.run(session) { result -> when (result) { is CompletionResult.Failure -> { callback(CompletionResult.Failure(result.error)) @@ -63,13 +63,28 @@ class CheckWalletCommand( if (verified) { callback(CompletionResult.Success(result.data)) } else { - callback(CompletionResult.Failure(SessionError.VerificationFailed())) + callback(CompletionResult.Failure(TangemSdkError.VerificationFailed())) } } } } } + override fun handlePreRunErrors( + session: CardSession, + callback: (result: CompletionResult) -> Unit + ): Boolean { + if (session.environment.card?.status == CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) + return true + } + if (session.environment.card?.isActivated == true) { + callback(CompletionResult.Failure(TangemSdkError.NotActivated())) + return true + } + return false + } + override fun serialize(environment: SessionEnvironment): CommandApdu { val tlvBuilder = TlvBuilder() tlvBuilder.append(TlvTag.Pin, environment.pin1) @@ -83,7 +98,7 @@ class CheckWalletCommand( override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): CheckWalletResponse { val tlvData = apdu.getTlvData(environment.encryptionKey) - ?: throw SessionError.DeserializeApduFailed() + ?: throw TangemSdkError.DeserializeApduFailed() val decoder = TlvDecoder(tlvData) return CheckWalletResponse( 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 225fa97430..a0c28b2ba6 100644 --- a/tangem-core/src/main/java/com/tangem/commands/Command.kt +++ b/tangem-core/src/main/java/com/tangem/commands/Command.kt @@ -5,7 +5,7 @@ import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.ResponseApdu import com.tangem.common.apdu.StatusWord -import com.tangem.common.apdu.toSessionError +import com.tangem.common.apdu.toTangemSdkError import com.tangem.common.extensions.toInt import com.tangem.common.tlv.TlvTag @@ -39,7 +39,26 @@ abstract class Command : CardSessionRunnable { override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { Log.i("Command", "Sending ${this::class.java.simpleName}") - transceive(session, callback) + if (session.environment.handleErrors) { + if (handlePreRunErrors(session, callback)) return + } + transceive(session) { result -> + if (session.environment.handleErrors) { + if (handleResponseErrors(session, result, callback)) return@transceive + } + callback(result) + } + } + + open fun handlePreRunErrors(session: CardSession, + callback: (result: CompletionResult) -> Unit): Boolean { + return false + } + + open fun handleResponseErrors(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit): Boolean { + return false } fun transceive(session: CardSession, callback: (result: CompletionResult) -> Unit) { @@ -54,7 +73,7 @@ abstract class Command : CardSessionRunnable { } } } - } catch (error: SessionError) { + } catch (error: TangemSdkError) { callback(CompletionResult.Failure(error)) } } @@ -81,17 +100,17 @@ abstract class Command : CardSessionRunnable { transceiveApdu(apdu, session, callback) } else -> { - val error = responseApdu.statusWord.toSessionError() + val error = responseApdu.statusWord.toTangemSdkError() if (error != null && !tryHandleError(error)) { callback(CompletionResult.Failure(error)) } else { - callback(CompletionResult.Failure(SessionError.UnknownError())) + callback(CompletionResult.Failure(TangemSdkError.UnknownError())) } } } } is CompletionResult.Failure -> - if (result.error is SessionError.TagLost) { + if (result.error is TangemSdkError.TagLost) { session.viewDelegate.onTagLost() } else { callback(CompletionResult.Failure(result.error)) @@ -110,7 +129,7 @@ abstract class Command : CardSessionRunnable { return tlv?.find { it.tag == TlvTag.Pause }?.value?.toInt() } - private fun tryHandleError(error: SessionError): Boolean { + private fun tryHandleError(error: TangemSdkError): Boolean { return false } diff --git a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt index 089a134702..b5563bd747 100644 --- a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt @@ -1,7 +1,9 @@ package com.tangem.commands +import com.tangem.CardSession import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError +import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu @@ -37,6 +39,41 @@ class CreateWalletResponse( */ class CreateWalletCommand : Command() { + override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + if (session.environment.card?.status == CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) + return true + } + if (session.environment.card?.isActivated == true) { + callback(CompletionResult.Failure(TangemSdkError.NotActivated())) + return true + } + if (session.environment.card?.status == CardStatus.Purged) { + callback(CompletionResult.Failure(TangemSdkError.CardIsPurged())) + return true + } + if (session.environment.card?.status == CardStatus.Loaded) { + callback(CompletionResult.Failure(TangemSdkError.AlreadyCreated())) + return true + } + return false + } + + override fun handleResponseErrors(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit): Boolean { + when (result) { + is CompletionResult.Failure -> { + if (result.error is TangemSdkError.InvalidParams) { + callback(CompletionResult.Failure(TangemSdkError.Pin2OrCvcRequired())) + return true + } + return false + } + else -> return false + } + } + override fun serialize(environment: SessionEnvironment): CommandApdu { val tlvBuilder = TlvBuilder() tlvBuilder.append(TlvTag.Pin, environment.pin1) @@ -51,7 +88,7 @@ class CreateWalletCommand : Command() { override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): CreateWalletResponse { val tlvData = apdu.getTlvData(environment.encryptionKey) - ?: throw SessionError.DeserializeApduFailed() + ?: throw TangemSdkError.DeserializeApduFailed() val decoder = TlvDecoder(tlvData) return CreateWalletResponse( diff --git a/tangem-core/src/main/java/com/tangem/commands/OpenSessionCommand.kt b/tangem-core/src/main/java/com/tangem/commands/OpenSessionCommand.kt index 7484f9d48b..891e28f3c1 100644 --- a/tangem-core/src/main/java/com/tangem/commands/OpenSessionCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/OpenSessionCommand.kt @@ -1,7 +1,7 @@ package com.tangem.commands import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu @@ -32,7 +32,7 @@ class OpenSessionCommand(private val sessionKeyA: ByteArray) : Command() { + override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + if (session.environment.card?.status == CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) + return true + } + if (session.environment.card?.isActivated == true) { + callback(CompletionResult.Failure(TangemSdkError.NotActivated())) + return true + } + if (session.environment.card?.settingsMask?.contains(Settings.ProhibitPurgeWallet) == true) { + callback(CompletionResult.Failure(TangemSdkError.PurgeWalletProhibited())) + return true + } + return false + } + + override fun handleResponseErrors(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit): Boolean { + when (result) { + is CompletionResult.Failure -> { + if (result.error is TangemSdkError.InvalidParams) { + callback(CompletionResult.Failure(TangemSdkError.Pin2OrCvcRequired())) + return true + } + return false + } + else -> return false + } + } + override fun serialize(environment: SessionEnvironment): CommandApdu { val tlvBuilder = TlvBuilder() tlvBuilder.append(TlvTag.Pin, environment.pin1) @@ -42,7 +75,7 @@ class PurgeWalletCommand : Command() { override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): PurgeWalletResponse { val tlvData = apdu.getTlvData(environment.encryptionKey) - ?: throw SessionError.DeserializeApduFailed() + ?: throw TangemSdkError.DeserializeApduFailed() val decoder = TlvDecoder(tlvData) return PurgeWalletResponse( diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt index e3b5d4ccee..d94ba5de4c 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt @@ -1,7 +1,7 @@ package com.tangem.commands import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu @@ -132,7 +132,7 @@ data class SettingsMask(val rawValue: Int) { enum class Settings(val code: Int) { IsReusable(0x0001), UseActivation(0x0002), - ForbidPurgeWallet(0x0004), + ProhibitPurgeWallet(0x0004), UseBlock(0x0008), AllowSwapPIN(0x0010), @@ -384,7 +384,7 @@ class ReadCommand : Command() { override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): Card { val tlvData = apdu.getTlvData(environment.encryptionKey) - ?: throw SessionError.DeserializeApduFailed() + ?: throw TangemSdkError.DeserializeApduFailed() val decoder = TlvDecoder(tlvData) diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt index 7055bc403f..9b1600c5a7 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt @@ -2,7 +2,7 @@ package com.tangem.commands import com.tangem.CardSession import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.commands.common.DefaultIssuerDataVerifier import com.tangem.commands.common.IssuerDataMode import com.tangem.commands.common.IssuerDataToVerify @@ -61,12 +61,12 @@ class ReadIssuerDataCommand( override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { val card = session.environment.card if (card == null) { - callback(CompletionResult.Failure(SessionError.MissingPreflightRead())) + callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead())) return } val publicKey = issuerPublicKey ?: card.issuerPublicKey if (publicKey == null) { - callback(CompletionResult.Failure(SessionError.MissingIssuerPubicKey())) + callback(CompletionResult.Failure(TangemSdkError.MissingIssuerPubicKey())) return } super.run(session) { result -> @@ -83,13 +83,21 @@ class ReadIssuerDataCommand( if (verify(publicKey, result.data.issuerDataSignature, issuerDataToVerify)) { callback(result) } else { - callback(CompletionResult.Failure(SessionError.VerificationFailed())) + callback(CompletionResult.Failure(TangemSdkError.VerificationFailed())) } } } } } + override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + if (session.environment.card?.status == CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) + return true + } + return false + } + override fun serialize(environment: SessionEnvironment): CommandApdu { val tlvBuilder = TlvBuilder() tlvBuilder.append(TlvTag.Pin, environment.pin1) @@ -103,7 +111,7 @@ class ReadIssuerDataCommand( override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): ReadIssuerDataResponse { val tlvData = apdu.getTlvData(environment.encryptionKey) - ?: throw SessionError.DeserializeApduFailed() + ?: throw TangemSdkError.DeserializeApduFailed() val decoder = TlvDecoder(tlvData) return ReadIssuerDataResponse( diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt index db748d8ec5..82e148a05d 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt @@ -2,7 +2,7 @@ package com.tangem.commands import com.tangem.CardSession import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.commands.common.DefaultIssuerDataVerifier import com.tangem.commands.common.IssuerDataMode import com.tangem.commands.common.IssuerDataToVerify @@ -71,12 +71,16 @@ class ReadIssuerExtraDataCommand( override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { val card = session.environment.card if (card == null) { - callback(CompletionResult.Failure(SessionError.MissingPreflightRead())) + callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead())) return } val publicKey = issuerPublicKey ?: card.issuerPublicKey if (publicKey == null) { - callback(CompletionResult.Failure(SessionError.MissingIssuerPubicKey())) + callback(CompletionResult.Failure(TangemSdkError.MissingIssuerPubicKey())) + return + } + if (session.environment.card?.status == CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) return } @@ -138,7 +142,7 @@ class ReadIssuerExtraDataCommand( ) callback(CompletionResult.Success(finalResult)) } else { - callback(CompletionResult.Failure(SessionError.VerificationFailed())) + callback(CompletionResult.Failure(TangemSdkError.VerificationFailed())) } } @@ -156,7 +160,7 @@ class ReadIssuerExtraDataCommand( override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): ReadIssuerExtraDataResponse { val tlvData = apdu.getTlvData(environment.encryptionKey) - ?: throw SessionError.DeserializeApduFailed() + ?: throw TangemSdkError.DeserializeApduFailed() val decoder = TlvDecoder(tlvData) diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt index 528ba98fb0..e3cf00b130 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt @@ -1,7 +1,9 @@ package com.tangem.commands +import com.tangem.CardSession import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError +import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu @@ -10,32 +12,32 @@ import com.tangem.common.tlv.TlvDecoder import com.tangem.common.tlv.TlvTag class ReadUserDataResponse( - /** - * CID, Unique Tangem card ID number. - */ - val cardId: String, + /** + * CID, Unique Tangem card ID number. + */ + val cardId: String, - /** - * Data defined by user's App. - */ - val userData: ByteArray, + /** + * Data defined by user's App. + */ + val userData: ByteArray, - /** - * Data defined by user's App (confirmed by PIN2). - */ - val userProtectedData: ByteArray, + /** + * Data defined by user's App (confirmed by PIN2). + */ + val userProtectedData: ByteArray, - /** - * Counter initialized by user's App and increased on every signing of new transaction - */ - val userCounter: Int, + /** + * Counter initialized by user's App and increased on every signing of new transaction + */ + val userCounter: Int, - /** - * Counter initialized by user's App (confirmed by PIN2) and increased on every signing of new transaction - */ - val userProtectedCounter: Int + /** + * Counter initialized by user's App (confirmed by PIN2) and increased on every signing of new transaction + */ + val userProtectedCounter: Int -): CommandResponse +) : CommandResponse /** * This command returns two up to 512-byte User_Data, User_Protected_Data and two counters User_Counter and @@ -47,30 +49,42 @@ class ReadUserDataResponse( * of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use. * For example, this fields may contain blockchain nonce value. */ -class ReadUserDataCommand: Command() { +class ReadUserDataCommand : Command() { - override fun serialize(environment: SessionEnvironment): CommandApdu { - val builder = TlvBuilder() - builder.append(TlvTag.CardId, environment.card?.cardId) - builder.append(TlvTag.Pin, environment.pin1) + override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + if (session.environment.card?.status == CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) + return true + } + if (session.environment.card?.isActivated == true) { + callback(CompletionResult.Failure(TangemSdkError.NotActivated())) + return true + } + return false + } - return CommandApdu( - Instruction.ReadUserData, builder.serialize(), - environment.encryptionMode, environment.encryptionKey - ) - } + override fun serialize(environment: SessionEnvironment): CommandApdu { + val builder = TlvBuilder() + builder.append(TlvTag.CardId, environment.card?.cardId) + builder.append(TlvTag.Pin, environment.pin1) - override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): ReadUserDataResponse { - val tlvData = apdu.getTlvData(environment.encryptionKey) - ?: throw SessionError.DeserializeApduFailed() + return CommandApdu( + Instruction.ReadUserData, builder.serialize(), + environment.encryptionMode, environment.encryptionKey + ) + } - val decoder = TlvDecoder(tlvData) - return ReadUserDataResponse( - cardId = decoder.decode(TlvTag.CardId), - userData = decoder.decode(TlvTag.UserData), - userProtectedData = decoder.decode(TlvTag.UserProtectedData), - userCounter = decoder.decode(TlvTag.UserCounter), - userProtectedCounter = decoder.decode(TlvTag.UserProtectedCounter) - ) - } + override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): ReadUserDataResponse { + val tlvData = apdu.getTlvData(environment.encryptionKey) + ?: throw TangemSdkError.DeserializeApduFailed() + + val decoder = TlvDecoder(tlvData) + return ReadUserDataResponse( + cardId = decoder.decode(TlvTag.CardId), + userData = decoder.decode(TlvTag.UserData), + userProtectedData = decoder.decode(TlvTag.UserProtectedData), + userCounter = decoder.decode(TlvTag.UserCounter), + userProtectedCounter = decoder.decode(TlvTag.UserProtectedCounter) + ) + } } \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt index 7707f82197..5c0c5bea32 100644 --- a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt @@ -1,7 +1,9 @@ package com.tangem.commands +import com.tangem.CardSession import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError +import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu @@ -35,6 +37,57 @@ class SignCommand(private val hashes: Array) private val hashSizes = if (hashes.isNotEmpty()) hashes.first().size else 0 + override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + if (session.environment.card?.status == CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) + return true + } + if (session.environment.card?.isActivated == true) { + callback(CompletionResult.Failure(TangemSdkError.NotActivated())) + return true + } + if (session.environment.card?.status == CardStatus.Purged) { + callback(CompletionResult.Failure(TangemSdkError.CardIsPurged())) + return true + } + if (session.environment.card?.status == CardStatus.Empty) { + callback(CompletionResult.Failure(TangemSdkError.CardIsEmpty())) + return true + } + if (session.environment.card?.walletRemainingSignatures == 0) { + callback(CompletionResult.Failure(TangemSdkError.NoRemainingSignatures())) + return true + } + if (session.environment.card?.signingMethods?.contains(SigningMethod.SignHash) != true) { + callback(CompletionResult.Failure(TangemSdkError.SignHashesNotAvailable())) + return true + } + if (hashSizes == 0) { + callback(CompletionResult.Failure(TangemSdkError.EmptyHashes())) + return true + } + if (hashes.any { it.size != hashSizes }) { + callback(CompletionResult.Failure(TangemSdkError.HashSizeMustBeEqual())) + return true + } + return false + } + + override fun handleResponseErrors(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit): Boolean { + when (result) { + is CompletionResult.Failure -> { + if (result.error is TangemSdkError.InvalidParams) { + callback(CompletionResult.Failure(TangemSdkError.Pin2OrCvcRequired())) + return true + } + return false + } + else -> return false + } + } + override fun serialize(environment: SessionEnvironment): CommandApdu { val dataToSign = flattenHashes() val tlvBuilder = TlvBuilder() @@ -58,9 +111,9 @@ class SignCommand(private val hashes: Array) } private fun checkForErrors() { - if (hashes.isEmpty()) throw SessionError.EmptyHashes() - if (hashes.size > 10) throw SessionError.TooMuchHashesInOneTransaction() - if (hashes.any { it.size != hashSizes }) throw SessionError.HashSizeMustBeEqual() + if (hashes.isEmpty()) throw TangemSdkError.EmptyHashes() + if (hashes.size > 10) throw TangemSdkError.TooManyhHashesInOneTransaction() + if (hashes.any { it.size != hashSizes }) throw TangemSdkError.HashSizeMustBeEqual() } /** @@ -81,7 +134,7 @@ class SignCommand(private val hashes: Array) override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): SignResponse { val tlvData = apdu.getTlvData(environment.encryptionKey) - ?: throw SessionError.DeserializeApduFailed() + ?: throw TangemSdkError.DeserializeApduFailed() val decoder = TlvDecoder(tlvData) return SignResponse( diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt index a425f5a740..fa817fd392 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt @@ -2,7 +2,7 @@ package com.tangem.commands import com.tangem.CardSession import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.commands.common.DefaultIssuerDataVerifier import com.tangem.commands.common.IssuerDataMode import com.tangem.commands.common.IssuerDataToVerify @@ -40,33 +40,62 @@ class WriteIssuerDataCommand( verifier: IssuerDataVerifier = DefaultIssuerDataVerifier() ) : Command(), IssuerDataVerifier by verifier { - override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { - + override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { val card = session.environment.card if (card == null) { - callback(CompletionResult.Failure(SessionError.MissingPreflightRead())) - return + callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead())) + return true } val publicKey = issuerPublicKey ?: card.issuerPublicKey if (publicKey == null) { - callback(CompletionResult.Failure(SessionError.MissingIssuerPubicKey())) - return + callback(CompletionResult.Failure(TangemSdkError.MissingIssuerPubicKey())) + return true + } + if (session.environment.card?.status == CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) + return true + } + if (session.environment.card?.isActivated == true) { + callback(CompletionResult.Failure(TangemSdkError.NotActivated())) + return true + } + if (issuerData.size > MAX_SIZE) { + callback(CompletionResult.Failure(TangemSdkError.DataSizeTooLarge())) + return true } - if (!isCounterValid(issuerDataCounter, card)) { - callback(CompletionResult.Failure(SessionError.MissingCounter())) - } else if (!verifySignature(publicKey, card.cardId)) { - callback(CompletionResult.Failure(SessionError.VerificationFailed())) - } else { - super.run(session, callback) + callback(CompletionResult.Failure(TangemSdkError.MissingCounter())) + return true + } + if (!verifySignature(publicKey, card.cardId)) { + callback(CompletionResult.Failure(TangemSdkError.VerificationFailed())) + return true + } + return false + } + + override fun handleResponseErrors(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit + ): Boolean { + when (result) { + is CompletionResult.Failure -> { + if (result.error is TangemSdkError.InvalidParams && + isCounterRequired(session.environment.card)) { + callback(CompletionResult.Failure(TangemSdkError.DataCannotBeWritten())) + return true + } + return false + } + else -> return false } } private fun isCounterValid(issuerDataCounter: Int?, card: Card): Boolean = if (isCounterRequired(card)) issuerDataCounter != null else true - private fun isCounterRequired(card: Card): Boolean = - card.settingsMask?.contains(Settings.ProtectIssuerDataAgainstReplay) != false + private fun isCounterRequired(card: Card?): Boolean = + card?.settingsMask?.contains(Settings.ProtectIssuerDataAgainstReplay) != false private fun verifySignature(publicKey: ByteArray, cardId: String): Boolean { return verify( @@ -93,11 +122,15 @@ class WriteIssuerDataCommand( override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): WriteIssuerDataResponse { val tlvData = apdu.getTlvData(environment.encryptionKey) - ?: throw SessionError.DeserializeApduFailed() + ?: throw TangemSdkError.DeserializeApduFailed() val decoder = TlvDecoder(tlvData) return WriteIssuerDataResponse( cardId = decoder.decode(TlvTag.CardId) ) } + + companion object { + const val MAX_SIZE = 512 + } } \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt index 4a93ebd734..188273730c 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt @@ -2,7 +2,7 @@ package com.tangem.commands import com.tangem.CardSession import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.commands.common.DefaultIssuerDataVerifier import com.tangem.commands.common.IssuerDataMode import com.tangem.commands.common.IssuerDataToVerify @@ -46,24 +46,68 @@ class WriteIssuerExtraDataCommand( override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { val card = session.environment.card if (card == null) { - callback(CompletionResult.Failure(SessionError.MissingPreflightRead())) + callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead())) return } val publicKey = issuerPublicKey ?: card.issuerPublicKey if (publicKey == null) { - callback(CompletionResult.Failure(SessionError.MissingIssuerPubicKey())) + callback(CompletionResult.Failure(TangemSdkError.MissingIssuerPubicKey())) return } - if (!isCounterValid(issuerDataCounter, card)) { - callback(CompletionResult.Failure(SessionError.MissingCounter())) - } else if (!verifySignatures(card.cardId, publicKey)) { - callback(CompletionResult.Failure(SessionError.VerificationFailed())) - } else { - writeIssuerData(session, card.cardId, publicKey, callback) + writeIssuerData(session, card.cardId, publicKey) { response -> + when (response) { + is CompletionResult.Success -> callback(response) + is CompletionResult.Failure -> { + if (response.error is TangemSdkError.InvalidParams && isCounterRequired(card)) { + callback(CompletionResult.Failure(TangemSdkError.DataCannotBeWritten())) + return@writeIssuerData + } + if (response.error is TangemSdkError.InvalidState && + card.settingsMask?.contains(Settings.ProtectIssuerDataAgainstReplay) != false) { + callback(CompletionResult.Failure(TangemSdkError.OverwritingDataIsProhibited())) + return@writeIssuerData + } + } + } } } + override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + val card = session.environment.card + if (card == null) { + callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead())) + return true + } + val publicKey = issuerPublicKey ?: card.issuerPublicKey + if (publicKey == null) { + callback(CompletionResult.Failure(TangemSdkError.MissingIssuerPubicKey())) + return true + } + + if (session.environment.card?.status == CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) + return true + } + if (session.environment.card?.isActivated == true) { + callback(CompletionResult.Failure(TangemSdkError.NotActivated())) + return true + } + if (issuerData.size > MAX_SIZE) { + callback(CompletionResult.Failure(TangemSdkError.DataSizeTooLarge())) + return true + } + if (!isCounterValid(issuerDataCounter, card)) { + callback(CompletionResult.Failure(TangemSdkError.MissingCounter())) + return true + } + if (!verifySignatures(card.cardId, publicKey)) { + callback(CompletionResult.Failure(TangemSdkError.VerificationFailed())) + return true + } + return false + } + private fun isCounterValid(issuerDataCounter: Int?, card: Card): Boolean = if (isCounterRequired(card)) issuerDataCounter != null else true @@ -156,7 +200,7 @@ class WriteIssuerExtraDataCommand( override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): WriteIssuerDataResponse { val tlvData = apdu.getTlvData(environment.encryptionKey) - ?: throw SessionError.DeserializeApduFailed() + ?: throw TangemSdkError.DeserializeApduFailed() return WriteIssuerDataResponse(cardId = TlvDecoder(tlvData).decode(TlvTag.CardId) ) @@ -164,5 +208,6 @@ class WriteIssuerExtraDataCommand( companion object { const val SINGLE_WRITE_SIZE = 1524 + const val MAX_SIZE = 32 * 1024 } } \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt index 7b43e879e7..8e965cded3 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt @@ -1,7 +1,9 @@ package com.tangem.commands +import com.tangem.CardSession import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError +import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu @@ -32,6 +34,38 @@ class WriteUserDataCommand(private val userData: ByteArray? = null, private val private val userCounter: Int? = null, private val userProtectedCounter: Int? = null) : Command() { + override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + if (session.environment.card?.status == CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) + return true + } + if (session.environment.card?.isActivated == true) { + callback(CompletionResult.Failure(TangemSdkError.NotActivated())) + return true + } + if (userData?.size ?: 0 > MAX_SIZE || userProtectedData?.size ?: 0 > MAX_SIZE) { + callback(CompletionResult.Failure(TangemSdkError.DataSizeTooLarge())) + return true + } + return false + } + + override fun handleResponseErrors(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit + ): Boolean { + when (result) { + is CompletionResult.Failure -> { + if (result.error is TangemSdkError.InvalidParams) { + callback(CompletionResult.Failure(TangemSdkError.Pin2OrCvcRequired())) + return true + } + return false + } + else -> return false + } + } + override fun serialize(environment: SessionEnvironment): CommandApdu { val builder = TlvBuilder() builder.append(TlvTag.CardId, environment.card?.cardId) @@ -51,7 +85,11 @@ class WriteUserDataCommand(private val userData: ByteArray? = null, private val override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): WriteUserDataResponse { val tlvData = apdu.getTlvData(environment.encryptionKey) - ?: throw SessionError.DeserializeApduFailed() + ?: throw TangemSdkError.DeserializeApduFailed() return WriteUserDataResponse(TlvDecoder(tlvData).decode(TlvTag.CardId)) } + + companion object{ + const val MAX_SIZE = 512 + } } \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt index 2ed9366331..ac47de6c75 100644 --- a/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt @@ -1,8 +1,12 @@ package com.tangem.commands.personalization +import com.tangem.CardSession import com.tangem.SessionEnvironment +import com.tangem.TangemSdkError +import com.tangem.commands.CardStatus import com.tangem.commands.Command import com.tangem.commands.CommandResponse +import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu @@ -17,6 +21,18 @@ data class DepersonalizeResponse(val success: Boolean) : CommandResponse */ class DepersonalizeCommand : Command() { + override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + if (session.environment.card?.status == CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) + return true + } + if (session.environment.card?.firmwareVersion?.contains("SDK") == false) { + callback(CompletionResult.Failure(TangemSdkError.CannotBeDepersonalized())) + return true + } + return false + } + override fun serialize(environment: SessionEnvironment): CommandApdu { return CommandApdu( Instruction.Depersonalize, byteArrayOf() diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt index e4fe1a8b15..b7f2c7c9dc 100644 --- a/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt @@ -1,11 +1,14 @@ package com.tangem.commands.personalization +import com.tangem.CardSession import com.tangem.SessionEnvironment -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.commands.Card import com.tangem.commands.CardData +import com.tangem.commands.CardStatus import com.tangem.commands.Command import com.tangem.commands.personalization.entities.* +import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu @@ -36,6 +39,14 @@ class PersonalizeCommand( private val acquirer: Acquirer? = null ) : Command() { + override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + if (session.environment.card?.status != CardStatus.NotPersonalized) { + callback(CompletionResult.Failure(TangemSdkError.AlreadyPersonalized())) + return true + } + return false + } + override fun serialize(environment: SessionEnvironment): CommandApdu { return CommandApdu( Instruction.Personalize, @@ -46,7 +57,7 @@ class PersonalizeCommand( override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): Card { val tlvData = apdu.getTlvData(devPersonalizationKey) - ?: throw SessionError.DeserializeApduFailed() + ?: throw TangemSdkError.DeserializeApduFailed() val decoder = TlvDecoder(tlvData) return Card( @@ -99,7 +110,7 @@ class PersonalizeCommand( } private fun serializePersonalizationData(config: CardConfig): ByteArray { - val cardId = config.createCardId() ?: throw SessionError.SerializeCommandError() + val cardId = config.createCardId() ?: throw TangemSdkError.SerializeCommandError() val tlvBuilder = TlvBuilder() tlvBuilder.append(TlvTag.CardId, cardId) diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/CardConfigExtensions.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/CardConfigExtensions.kt index 4d7895f3c4..78e5709596 100644 --- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/CardConfigExtensions.kt +++ b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/CardConfigExtensions.kt @@ -29,7 +29,7 @@ internal fun CardConfig.createSettingsMask(): SettingsMask { if (protectIssuerDataAgainstReplay) builder.add(Settings.ProtectIssuerDataAgainstReplay) - if (forbidPurgeWallet) builder.add(Settings.ForbidPurgeWallet) + if (forbidPurgeWallet) builder.add(Settings.ProhibitPurgeWallet) if (allowSelectBlockchain) builder.add(Settings.AllowSelectBlockchain) if (skipCheckPIN2andCVCIfValidatedByIssuer) builder.add(Settings.SkipCheckPin2andCvcIfValidatedByIssuer) diff --git a/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt b/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt index 71f460c7d7..52bf7a9351 100644 --- a/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt +++ b/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt @@ -1,6 +1,6 @@ package com.tangem.common -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.common.CompletionResult.Success /** @@ -9,5 +9,5 @@ import com.tangem.common.CompletionResult.Success */ sealed class CompletionResult { class Success(val data: T) : CompletionResult() - class Failure(val error: SessionError) : CompletionResult() + class Failure(val error: TangemSdkError) : CompletionResult() } \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt b/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt index 3938cee65f..96daaa2826 100644 --- a/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt +++ b/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt @@ -1,6 +1,6 @@ package com.tangem.common.apdu -import com.tangem.SessionError +import com.tangem.TangemSdkError /** * Part of a response from the card, shows the status of the operation @@ -25,16 +25,16 @@ enum class StatusWord(val code: Int, val description: String) { } } -fun StatusWord.toSessionError(): SessionError? { +fun StatusWord.toTangemSdkError(): TangemSdkError? { return when (this) { StatusWord.ProcessCompleted, StatusWord.Pin1Changed, StatusWord.Pin2Changed, StatusWord.PinsChanged -> null StatusWord.NeedPause -> null - StatusWord.InvalidParams -> SessionError.InvalidParams() - StatusWord.ErrorProcessingCommand -> SessionError.ErrorProcessingCommand() - StatusWord.InvalidState -> SessionError.InvalidState() - StatusWord.InsNotSupported -> SessionError.InsNotSupported() - StatusWord.NeedEncryption -> SessionError.NeedEncryption() - StatusWord.Unknown -> SessionError.UnknownStatus() + StatusWord.InvalidParams -> TangemSdkError.InvalidParams() + StatusWord.ErrorProcessingCommand -> TangemSdkError.ErrorProcessingCommand() + StatusWord.InvalidState -> TangemSdkError.InvalidState() + StatusWord.InsNotSupported -> TangemSdkError.InsNotSupported() + StatusWord.NeedEncryption -> TangemSdkError.NeedEncryption() + StatusWord.Unknown -> TangemSdkError.UnknownStatus() } } diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt index 4954c38c46..2b9bd3520c 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt @@ -1,7 +1,7 @@ package com.tangem.common.tlv import com.tangem.Log -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.commands.* import com.tangem.commands.common.IssuerDataMode import com.tangem.common.extensions.toDate @@ -34,7 +34,7 @@ class TlvDecoder(val tlvList: List) { inline fun decodeOptional(tag: TlvTag): T? = try { decode(tag) - } catch (exception: SessionError.DecodingFailedMissingTag) { + } catch (exception: TangemSdkError.DecodingFailedMissingTag) { null } @@ -55,7 +55,7 @@ class TlvDecoder(val tlvList: List) { return false as T } else { Log.e(this::class.simpleName!!, "Tag $tag not found") - throw SessionError.DecodingFailedMissingTag() + throw TangemSdkError.DecodingFailedMissingTag() } return when (tag.valueType()) { @@ -73,7 +73,7 @@ class TlvDecoder(val tlvList: List) { tlvValue.toInt() as T } catch (exception: IllegalArgumentException) { Log.e(this::class.simpleName!!, exception.message ?: "") - throw SessionError.DecodingFailed() + throw TangemSdkError.DecodingFailed() } } TlvValueType.BoolValue -> { @@ -90,7 +90,7 @@ class TlvDecoder(val tlvList: List) { EllipticCurve.byName(tlvValue.toUtf8()) as T } catch (exception: Exception) { logException(tag, tlvValue.toUtf8(), exception) - throw SessionError.DecodingFailed() + throw TangemSdkError.DecodingFailed() } @@ -101,7 +101,7 @@ class TlvDecoder(val tlvList: List) { tlvValue.toDate() as T } catch (exception: Exception) { logException(tag, tlvValue.toHexString(), exception) - throw SessionError.DecodingFailed() + throw TangemSdkError.DecodingFailed() } } TlvValueType.ProductMask -> { @@ -118,7 +118,7 @@ class TlvDecoder(val tlvList: List) { CardStatus.byCode(tlvValue.toInt()) as T } catch (exception: Exception) { logException(tag, tlvValue.toInt().toString(), exception) - throw SessionError.DecodingFailed() + throw TangemSdkError.DecodingFailed() } } TlvValueType.SigningMethod -> { @@ -127,7 +127,7 @@ class TlvDecoder(val tlvList: List) { SigningMethodMask(tlvValue.toInt()) as T } catch (exception: Exception) { logException(tag, tlvValue.toInt().toString(), exception) - throw SessionError.DecodingFailed() + throw TangemSdkError.DecodingFailed() } } TlvValueType.IssuerDataMode -> { @@ -136,7 +136,7 @@ class TlvDecoder(val tlvList: List) { IssuerDataMode.byCode(tlvValue.toInt().toByte()) as T } catch (exception: Exception) { logException(tag, tlvValue.toInt().toString(), exception) - throw SessionError.DecodingFailed() + throw TangemSdkError.DecodingFailed() } } } @@ -151,7 +151,7 @@ class TlvDecoder(val tlvList: List) { if (T::class != ExpectedT::class) { Log.e(this::class.simpleName!!, "Mapping error. Type for tag: $tag must be ${tag.valueType()}. It is ${T::class}") - throw SessionError.DecodingFailedTypeMismatch() + throw TangemSdkError.DecodingFailedTypeMismatch() } } diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt index 057b0807e8..99589b7d40 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt @@ -1,7 +1,7 @@ package com.tangem.common.tlv import com.tangem.Log -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.commands.* import com.tangem.commands.common.IssuerDataMode import com.tangem.common.extensions.calculateSha256 @@ -24,7 +24,7 @@ class TlvEncoder { return Tlv(tag, encodeValue(tag, value)) } else { Log.e(this::class.simpleName!!, "Encoding error. Value for tag $tag is null") - throw SessionError.EncodingFailed() + throw TangemSdkError.EncodingFailed() } } @@ -106,7 +106,7 @@ class TlvEncoder { if (T::class != ExpectedT::class) { Log.e(this::class.simpleName!!, "Mapping error. Type for tag: $tag must be ${tag.valueType()}. It is ${T::class}") - throw SessionError.EncodingFailedTypeMismatch() + throw TangemSdkError.EncodingFailedTypeMismatch() } } } \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/tasks/CreateWalletTask.kt b/tangem-core/src/main/java/com/tangem/tasks/CreateWalletTask.kt index 6b21be102c..c9b87b4da2 100644 --- a/tangem-core/src/main/java/com/tangem/tasks/CreateWalletTask.kt +++ b/tangem-core/src/main/java/com/tangem/tasks/CreateWalletTask.kt @@ -2,7 +2,7 @@ package com.tangem.tasks import com.tangem.CardSession import com.tangem.CardSessionRunnable -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.commands.CardStatus import com.tangem.commands.CheckWalletCommand import com.tangem.commands.CreateWalletCommand @@ -14,7 +14,7 @@ class CreateWalletTask : CardSessionRunnable { override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { val curve = session.environment.card?.curve if (curve == null) { - callback(CompletionResult.Failure(SessionError.CardError())) + callback(CompletionResult.Failure(TangemSdkError.CardError())) return } @@ -24,7 +24,7 @@ class CreateWalletTask : CardSessionRunnable { is CompletionResult.Failure -> callback(createWalletResult) is CompletionResult.Success -> { if (createWalletResult.data.status != CardStatus.Loaded) { - callback(CompletionResult.Failure(SessionError.UnknownError())) + callback(CompletionResult.Failure(TangemSdkError.UnknownError())) } else { val checkWalletCommand = CheckWalletCommand( curve, createWalletResult.data.walletPublicKey diff --git a/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt b/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt index 39dea59f0b..db78568806 100644 --- a/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt +++ b/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt @@ -2,7 +2,7 @@ package com.tangem.tasks import com.tangem.CardSession import com.tangem.CardSessionRunnable -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.commands.* import com.tangem.common.CompletionResult @@ -18,7 +18,7 @@ internal class ScanTask : CardSessionRunnable { val card = session.environment.card if (card == null) { - callback(CompletionResult.Failure(SessionError.MissingPreflightRead())) + callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead())) } else if (card.cardData?.productMask?.contains(Product.Tag) != false) { callback(CompletionResult.Success(card)) @@ -27,7 +27,7 @@ internal class ScanTask : CardSessionRunnable { callback(CompletionResult.Success(card)) } else if (card.curve == null || card.walletPublicKey == null) { - callback(CompletionResult.Failure(SessionError.CardError())) + callback(CompletionResult.Failure(TangemSdkError.CardError())) } else { val checkWalletCommand = CheckWalletCommand(card.curve, card.walletPublicKey) diff --git a/tangem-core/src/test/java/com/tangem/common/tlv/TlvDecoderTest.kt b/tangem-core/src/test/java/com/tangem/common/tlv/TlvDecoderTest.kt index fbd4514c11..8f7bd0b91e 100644 --- a/tangem-core/src/test/java/com/tangem/common/tlv/TlvDecoderTest.kt +++ b/tangem-core/src/test/java/com/tangem/common/tlv/TlvDecoderTest.kt @@ -1,7 +1,7 @@ package com.tangem.common.tlv import com.google.common.truth.Truth.assertThat -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.commands.* import com.tangem.common.extensions.hexToBytes import org.junit.Test @@ -35,21 +35,21 @@ class TlvDecoderTest { @Test fun `map when value is null throws MissingTagException`() { - assertThrows { + assertThrows { tlvMapper.decode(TlvTag.TokenSymbol) } } @Test fun `map optional to wrong type throws WrongTypeException`() { - assertThrows { + assertThrows { tlvMapper.decodeOptional(TlvTag.CardData) } } @Test fun `map to wrong type throws WrongTypeException`() { - assertThrows { + assertThrows { tlvMapper.decode(TlvTag.CardData) } } @@ -76,7 +76,7 @@ class TlvDecoderTest { .isTrue() assertThat(settingsMask.contains(Settings.UseDynamicNdef)) .isTrue() - assertThat(settingsMask.contains(Settings.ForbidPurgeWallet)) + assertThat(settingsMask.contains(Settings.ProhibitPurgeWallet)) .isFalse() } @@ -134,7 +134,7 @@ class TlvDecoderTest { @Test fun `map Enum with unknown code throws ConversionException error`() { val localMapper = TlvDecoder(listOf(Tlv(TlvTag.CurveId, "test".toByteArray()))) - assertThrows { + assertThrows { localMapper.decode(TlvTag.CurveId) } } @@ -171,7 +171,7 @@ class TlvDecoderTest { @Test fun `map Int with wrong value throws ConversionException`() { val localMapper = TlvDecoder(listOf(Tlv(TlvTag.SignedHashes, byteArrayOf(1, 2, 3, 4, 5)))) - assertThrows { + assertThrows { localMapper.decode(TlvTag.SignedHashes) } } diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt b/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt index c6124d542f..1fd9eeedb6 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt @@ -6,8 +6,8 @@ import android.widget.CompoundButton import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import com.tangem.SessionEnvironment -import com.tangem.SessionError import com.tangem.TangemSdk +import com.tangem.TangemSdkError import com.tangem.common.CompletionResult import com.tangem.tangem_sdk_new.extensions.init import kotlinx.android.synthetic.main.activity_test_user_data.* @@ -92,8 +92,8 @@ class TestUserDataActivity : AppCompatActivity() { } } - private fun handleError(tv: TextView, error: SessionError) { - if (error is SessionError.UserCancelled) return + private fun handleError(tv: TextView, error: TangemSdkError) { + if (error is TangemSdkError.UserCancelled) return runOnUiThread { tv.text = error::class.simpleName } } diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/ui/ActionViewModel.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/ui/ActionViewModel.kt index 3c04d86d59..7604a2dd9a 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/ui/ActionViewModel.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/ui/ActionViewModel.kt @@ -4,8 +4,8 @@ import android.view.View import androidx.annotation.UiThread import androidx.lifecycle.* import com.google.gson.Gson -import com.tangem.SessionError import com.tangem.TangemSdk +import com.tangem.TangemSdkError import com.tangem.commands.Card import com.tangem.commands.CommandResponse import com.tangem.common.CompletionResult @@ -133,7 +133,7 @@ class ActionViewModel(private val itemsManager: ItemsManager) : ViewModel(), Lif internal class Notifier(private val vm: ActionViewModel) { - private var notShowedError: SessionError? = null + private var notShowedError: TangemSdkError? = null private val gson: Gson = ResponseJsonConverter().gson fun handleActionResult(result: CompletionResult<*>, list: List) { @@ -163,10 +163,10 @@ internal class Notifier(private val vm: ActionViewModel) { } } - private fun handleError(error: SessionError) { + private fun handleError(error: TangemSdkError) { Log.d(this, "error = $error") when (error) { - is SessionError.UserCancelled -> { + is TangemSdkError.UserCancelled -> { if (notShowedError == null) { vm.seError.postValue("User canceled the action") } else { diff --git a/tangem-sdk-android-config/README.md b/tangem-sdk-android-config/README.md index 5acf8ff48f..9a9fc5efc4 100644 --- a/tangem-sdk-android-config/README.md +++ b/tangem-sdk-android-config/README.md @@ -117,7 +117,7 @@ tangemSdk.scanCard { result -> } } is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -132,7 +132,7 @@ Communication with the card is an asynchronous operation. In order to get a resu `CompletionResult` – this is the sealed class for the results of `CardSessionRunnable`. `Success(val data: T)` is triggered after successful operation and contains a `CommandResponse`. -`Failure(val error: SessionError)` is triggered on error. +`Failure(val error: TangemSdkError)` is triggered on error. #### Sign This method allows you to sign one or multiple hashes. Simultaneous signing of array of hashes in a single SIGN command is required to support Bitcoin-type multi-input blockchains (UTXO). The SIGN command will return a corresponding array of signatures. @@ -143,7 +143,7 @@ tangemSdk.sign( cardId) { result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -164,7 +164,7 @@ An example of usage (description is available at documentation for `TangemSdk.re tangemSdk.readIssuerData(cardId) { result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -184,7 +184,7 @@ An example of usage (description is available at documentation for `TangemSdk.re tangemSdk.readIssuerExtraData(cardId) { result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -204,7 +204,7 @@ An example of usage (description is available at documentation for `TangemSdk.wr tangemSdk.writeIssuerData(cardId, issuerData, issuerDataSignature, issuerDataCounter) { result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -225,7 +225,7 @@ An example of usage (description is available at documentation for `TangemSdk.wr ) { result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -246,7 +246,7 @@ An example of usage (description is available at documentation for `TangemSdk.wr ) { result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -265,7 +265,7 @@ An example of usage (description is available at documentation for `TangemSdk.re tangemSdk.readUserData(cardId) { result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -284,7 +284,7 @@ An example of usage (description is available at documentation for `TangemSdk.cr tangemSdk.createWallet(cardId) { result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -303,7 +303,7 @@ An example of usage (description is available at documentation for `TangemSdk.pu tangemSdk.purgeWallet(cardId) { result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -323,7 +323,7 @@ An example of usage (description is available at documentation for `TangemSdk.de tangemSdk.depersonalize(cardId) { result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -342,7 +342,7 @@ An example of usage (description is available at documentation for `TangemSdk.pe tangemSdk.personalize(config, issuer, manufacturer, acquirer) { result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -383,7 +383,7 @@ To do this, you need to call `tangemSdk.startSession()` method and get a `CardSe SignCommand(createSampleHashes())) {result -> when (result) { is CompletionResult.Failure -> { - if (result.error is SessionError.UserCancelledError) { + if (result.error is TangemSdkError.UserCancelledError) { // Handle case when user cancelled manually } // Handle other errors @@ -410,7 +410,7 @@ class OneTapSignTask(private val hashesToSign: Array) : CardSessionRu val card = session.environment.card if (card == null) { - callback(CompletionResult.Failure(SessionError.MissingPreflightRead())) + callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead())) } else if (card.cardData?.productMask?.contains(Product.Tag) != false) { callback(CompletionResult.Success(card)) @@ -419,7 +419,7 @@ class OneTapSignTask(private val hashesToSign: Array) : CardSessionRu callback(CompletionResult.Success(card)) } else if (card.curve == null || card.walletPublicKey == null) { - callback(CompletionResult.Failure(SessionError.CardError())) + callback(CompletionResult.Failure(TangemSdkError.CardError())) } else { val signCommand = SignCommand(hashesToSign) diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt index 845dbb2abd..002bf20104 100644 --- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt +++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt @@ -6,7 +6,7 @@ import android.nfc.tech.IsoDep import android.nfc.tech.NfcV import com.tangem.CardReader import com.tangem.Log -import com.tangem.SessionError +import com.tangem.TangemSdkError import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.ResponseApdu @@ -38,7 +38,7 @@ class NfcReader : CardReader { // Stops reading and sends failure callback to a task // if reading is cancelled (when user closes nfc bottom sheet dialog). closeSession() - callback?.invoke(CompletionResult.Failure(SessionError.UserCancelled())) + callback?.invoke(CompletionResult.Failure(TangemSdkError.UserCancelled())) } } @@ -67,7 +67,7 @@ class NfcReader : CardReader { private fun transceiveData() { if (readingCancelled) { - callback?.invoke(CompletionResult.Failure(SessionError.UserCancelled())) + callback?.invoke(CompletionResult.Failure(TangemSdkError.UserCancelled())) return } if (data == null) return @@ -76,7 +76,7 @@ class NfcReader : CardReader { try { rawResponse = isoDep?.transceive(data) } catch (exception: TagLostException) { - callback?.invoke(CompletionResult.Failure(SessionError.TagLost())) + callback?.invoke(CompletionResult.Failure(TangemSdkError.TagLost())) isoDep = null return } catch (exception: Exception) { @@ -110,7 +110,7 @@ class NfcReader : CardReader { when (response) { is SlixReadResult.Failure -> { Log.e(this::class.simpleName!!, "${response.exception.message}") - callback?.invoke(CompletionResult.Failure(SessionError.ErrorProcessingCommand())) + callback?.invoke(CompletionResult.Failure(TangemSdkError.ErrorProcessingCommand())) } is SlixReadResult.Success -> { callback?.invoke(CompletionResult.Success(ResponseApdu(response.data))) From aef46280e09fc54774a6654a0cc028fc6eb7ae39 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 7 May 2020 17:35:45 +0300 Subject: [PATCH 4/8] Updated on 2026-08-14 --- tangem-sdk/src/main/res/drawable/pb_circle.xml | 6 +++--- .../src/main/res/layout/layout_touch_card.xml | 2 +- .../src/main/res/layout/nfc_bottom_sheet.xml | 17 +++++++++++------ tangem-sdk/src/main/res/values/colors.xml | 5 ++++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/tangem-sdk/src/main/res/drawable/pb_circle.xml b/tangem-sdk/src/main/res/drawable/pb_circle.xml index a3e74eb416..cf65fbe9d4 100644 --- a/tangem-sdk/src/main/res/drawable/pb_circle.xml +++ b/tangem-sdk/src/main/res/drawable/pb_circle.xml @@ -34,9 +34,9 @@ android:toDegrees="360" /> diff --git a/tangem-sdk/src/main/res/layout/layout_touch_card.xml b/tangem-sdk/src/main/res/layout/layout_touch_card.xml index c8f66c0bc4..ba8e553180 100644 --- a/tangem-sdk/src/main/res/layout/layout_touch_card.xml +++ b/tangem-sdk/src/main/res/layout/layout_touch_card.xml @@ -34,7 +34,7 @@ android:id="@+id/rippleBackgroundNfc" android:layout_width="150dp" android:layout_height="150dp" - app:rb_color="@color/fab" + app:rb_color="@color/card_sdk_ripple" app:rb_duration="3000" app:rb_radius="16dp" app:rb_rippleAmount="4" diff --git a/tangem-sdk/src/main/res/layout/nfc_bottom_sheet.xml b/tangem-sdk/src/main/res/layout/nfc_bottom_sheet.xml index b077eb38ce..33bf9ad0a3 100644 --- a/tangem-sdk/src/main/res/layout/nfc_bottom_sheet.xml +++ b/tangem-sdk/src/main/res/layout/nfc_bottom_sheet.xml @@ -32,10 +32,11 @@ android:gravity="center" android:letterSpacing="0.02" android:text="@string/header_card" - android:textColor="#000000" + android:textColor="@color/card_sdk_text_color" android:textSize="15sp" android:textStyle="normal" - android:visibility="gone"/> + android:visibility="gone" + tools:visibility="visible"/> + android:visibility="gone" + tools:visibility="visible"/> @@ -63,6 +65,7 @@ android:layout_gravity="center" android:layout_marginTop="24dp" android:text="@string/dialog_ready_to_scan" + android:textColor="@color/card_sdk_text_color" android:textAppearance="@style/TextAppearance.AppCompat.Large" /> @@ -113,6 +116,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" + android:tint="@color/card_sdk_accent" android:src="@drawable/ic_done_135dp" /> + /> \ No newline at end of file diff --git a/tangem-sdk/src/main/res/values/colors.xml b/tangem-sdk/src/main/res/values/colors.xml index b154cb7818..ea2433c6ad 100644 --- a/tangem-sdk/src/main/res/values/colors.xml +++ b/tangem-sdk/src/main/res/values/colors.xml @@ -3,6 +3,9 @@ #027aff #027AFF #027AFF - #4f98c0 + + #266dd3 + #000000 + #2c5ac4 \ No newline at end of file From 6a259674f12707c9ce7b9203ec5d7427b72ff5df Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 7 May 2020 18:14:05 +0300 Subject: [PATCH 5/8] Updated on 2026-08-14 --- tangem-core/src/main/java/com/tangem/SessionEnvironment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt index 790a1f7881..e51d5e5d97 100644 --- a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt +++ b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt @@ -22,7 +22,7 @@ data class SessionEnvironment( var encryptionKey: ByteArray? = null, val cvc: ByteArray? = null, var cardFilter: CardFilter = CardFilter(), - val handleErrors: Boolean + val handleErrors: Boolean = true ) { fun setPin1(pin1: String) { From 7f29eea6299f90ed4a8fd22b4bb3d633c86f9a90 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 8 May 2020 10:37:04 +0300 Subject: [PATCH 6/8] Updated on 2026-08-14 --- .../src/main/java/com/tangem/TangemSdkError.kt | 12 ++---------- .../com/tangem/commands/CheckWalletCommand.kt | 2 +- .../src/main/java/com/tangem/commands/Command.kt | 14 +++++++------- .../com/tangem/commands/CreateWalletCommand.kt | 8 ++++---- .../com/tangem/commands/PurgeWalletCommand.kt | 8 ++++---- .../main/java/com/tangem/commands/ReadCommand.kt | 15 +++++++++++++++ .../com/tangem/commands/ReadIssuerDataCommand.kt | 2 +- .../com/tangem/commands/ReadUserDataCommand.kt | 2 +- .../main/java/com/tangem/commands/SignCommand.kt | 8 ++++---- .../com/tangem/commands/WriteIssuerDataCommand.kt | 8 ++++---- .../commands/WriteIssuerExtraDataCommand.kt | 2 +- .../com/tangem/commands/WriteUserDataCommand.kt | 8 ++++---- .../personalization/DepersonalizeCommand.kt | 2 +- .../personalization/PersonalizeCommand.kt | 2 +- .../main/java/com/tangem/common/tlv/TlvBuilder.kt | 2 +- .../main/java/com/tangem/common/tlv/TlvDecoder.kt | 2 +- tangem-devkit/build.gradle | 4 ++-- .../ucase/resources/initializers/TlvResources.kt | 2 +- .../com/tangem/tangem_sdk_new/nfc/NfcReader.kt | 1 + 19 files changed, 56 insertions(+), 48 deletions(-) diff --git a/tangem-core/src/main/java/com/tangem/TangemSdkError.kt b/tangem-core/src/main/java/com/tangem/TangemSdkError.kt index 5167aff71f..4ea2612c51 100644 --- a/tangem-core/src/main/java/com/tangem/TangemSdkError.kt +++ b/tangem-core/src/main/java/com/tangem/TangemSdkError.kt @@ -59,14 +59,6 @@ sealed class TangemSdkError(val code: Int) : Exception(code.toString()) { */ class NeedEncryption : TangemSdkError(30006) - class Pin1Changed : TangemSdkError(30007) - - class Pin2Changed : TangemSdkError(30008) - - class PinsChanged : TangemSdkError(30009) - - - //Personalization Errors class AlreadyPersonalized : TangemSdkError(40101) @@ -77,12 +69,12 @@ sealed class TangemSdkError(val code: Int) : Exception(code.toString()) { class Pin1Required : TangemSdkError(40401) /** * This error is returned when a [Task] expects a user to use a particular card, - * and a user tries to use a different card. + * but the user tries to use a different card. */ class WrongCard : TangemSdkError(40403) /** * This error is returned when a user scans a card of a [com.tangem.common.extensions.CardType] - * that is not specified in [Config.allowedCards]. + * that is not specified in [Config.cardFilter]. */ class WrongCardType : TangemSdkError(40404) diff --git a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt index ab33a2cc3c..e3cbdf970a 100644 --- a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt @@ -70,7 +70,7 @@ class CheckWalletCommand( } } - override fun handlePreRunErrors( + override fun performPreCheck( session: CardSession, callback: (result: CompletionResult) -> Unit ): Boolean { 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 a0c28b2ba6..fad1b0d025 100644 --- a/tangem-core/src/main/java/com/tangem/commands/Command.kt +++ b/tangem-core/src/main/java/com/tangem/commands/Command.kt @@ -40,24 +40,24 @@ abstract class Command : CardSessionRunnable { override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { Log.i("Command", "Sending ${this::class.java.simpleName}") if (session.environment.handleErrors) { - if (handlePreRunErrors(session, callback)) return + if (performPreCheck(session, callback)) return } transceive(session) { result -> if (session.environment.handleErrors) { - if (handleResponseErrors(session, result, callback)) return@transceive + if (performAfterCheck(session, result, callback)) return@transceive } callback(result) } } - open fun handlePreRunErrors(session: CardSession, - callback: (result: CompletionResult) -> Unit): Boolean { + open fun performPreCheck(session: CardSession, + callback: (result: CompletionResult) -> Unit): Boolean { return false } - open fun handleResponseErrors(session: CardSession, - result: CompletionResult, - callback: (result: CompletionResult) -> Unit): Boolean { + open fun performAfterCheck(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit): Boolean { return false } diff --git a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt index b5563bd747..e0bf433c99 100644 --- a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt @@ -39,7 +39,7 @@ class CreateWalletResponse( */ class CreateWalletCommand : Command() { - override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { if (session.environment.card?.status == CardStatus.NotPersonalized) { callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) return true @@ -59,9 +59,9 @@ class CreateWalletCommand : Command() { return false } - override fun handleResponseErrors(session: CardSession, - result: CompletionResult, - callback: (result: CompletionResult) -> Unit): Boolean { + override fun performAfterCheck(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit): Boolean { when (result) { is CompletionResult.Failure -> { if (result.error is TangemSdkError.InvalidParams) { diff --git a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt index 4a406e4c71..bbc3edfbb2 100644 --- a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt @@ -31,7 +31,7 @@ class PurgeWalletResponse( */ class PurgeWalletCommand : Command() { - override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { if (session.environment.card?.status == CardStatus.NotPersonalized) { callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) return true @@ -47,9 +47,9 @@ class PurgeWalletCommand : Command() { return false } - override fun handleResponseErrors(session: CardSession, - result: CompletionResult, - callback: (result: CompletionResult) -> Unit): Boolean { + override fun performAfterCheck(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit): Boolean { when (result) { is CompletionResult.Failure -> { if (result.error is TangemSdkError.InvalidParams) { diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt index d94ba5de4c..c8bbda44ff 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt @@ -1,7 +1,9 @@ package com.tangem.commands +import com.tangem.CardSession import com.tangem.SessionEnvironment import com.tangem.TangemSdkError +import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu @@ -366,6 +368,19 @@ class Card( */ class ReadCommand : Command() { + override fun performAfterCheck(session: CardSession, result: CompletionResult, callback: (result: CompletionResult) -> Unit): Boolean { + when (result) { + is CompletionResult.Failure -> { + if (result.error is TangemSdkError.InvalidParams) { + callback(CompletionResult.Failure(TangemSdkError.Pin1Required())) + return true + } + return false + } + else -> return false + } + } + override fun serialize(environment: SessionEnvironment): CommandApdu { val tlvBuilder = TlvBuilder() /** diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt index 9b1600c5a7..d01a3adbe8 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt @@ -90,7 +90,7 @@ class ReadIssuerDataCommand( } } - override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { if (session.environment.card?.status == CardStatus.NotPersonalized) { callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) return true diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt index e3cf00b130..b8ee2022d6 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt @@ -51,7 +51,7 @@ class ReadUserDataResponse( */ class ReadUserDataCommand : Command() { - override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { if (session.environment.card?.status == CardStatus.NotPersonalized) { callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) return true diff --git a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt index 5c0c5bea32..607ad41cd7 100644 --- a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt @@ -37,7 +37,7 @@ class SignCommand(private val hashes: Array) private val hashSizes = if (hashes.isNotEmpty()) hashes.first().size else 0 - override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { if (session.environment.card?.status == CardStatus.NotPersonalized) { callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) return true @@ -73,9 +73,9 @@ class SignCommand(private val hashes: Array) return false } - override fun handleResponseErrors(session: CardSession, - result: CompletionResult, - callback: (result: CompletionResult) -> Unit): Boolean { + override fun performAfterCheck(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit): Boolean { when (result) { is CompletionResult.Failure -> { if (result.error is TangemSdkError.InvalidParams) { diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt index fa817fd392..2574a2f4a6 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt @@ -40,7 +40,7 @@ class WriteIssuerDataCommand( verifier: IssuerDataVerifier = DefaultIssuerDataVerifier() ) : Command(), IssuerDataVerifier by verifier { - override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { val card = session.environment.card if (card == null) { callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead())) @@ -74,9 +74,9 @@ class WriteIssuerDataCommand( return false } - override fun handleResponseErrors(session: CardSession, - result: CompletionResult, - callback: (result: CompletionResult) -> Unit + override fun performAfterCheck(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit ): Boolean { when (result) { is CompletionResult.Failure -> { diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt index 188273730c..8cb0dfc949 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt @@ -73,7 +73,7 @@ class WriteIssuerExtraDataCommand( } } - override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { val card = session.environment.card if (card == null) { callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead())) diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt index 8e965cded3..fc0d0467ae 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt @@ -34,7 +34,7 @@ class WriteUserDataCommand(private val userData: ByteArray? = null, private val private val userCounter: Int? = null, private val userProtectedCounter: Int? = null) : Command() { - override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { if (session.environment.card?.status == CardStatus.NotPersonalized) { callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) return true @@ -50,9 +50,9 @@ class WriteUserDataCommand(private val userData: ByteArray? = null, private val return false } - override fun handleResponseErrors(session: CardSession, - result: CompletionResult, - callback: (result: CompletionResult) -> Unit + override fun performAfterCheck(session: CardSession, + result: CompletionResult, + callback: (result: CompletionResult) -> Unit ): Boolean { when (result) { is CompletionResult.Failure -> { diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt index ac47de6c75..c3bb2d4de8 100644 --- a/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt @@ -21,7 +21,7 @@ data class DepersonalizeResponse(val success: Boolean) : CommandResponse */ class DepersonalizeCommand : Command() { - override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { if (session.environment.card?.status == CardStatus.NotPersonalized) { callback(CompletionResult.Failure(TangemSdkError.NotPersonalized())) return true diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt index b7f2c7c9dc..52d85278fa 100644 --- a/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt @@ -39,7 +39,7 @@ class PersonalizeCommand( private val acquirer: Acquirer? = null ) : Command() { - override fun handlePreRunErrors(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { + override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean { if (session.environment.card?.status != CardStatus.NotPersonalized) { callback(CompletionResult.Failure(TangemSdkError.AlreadyPersonalized())) return true diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt index 3e3c8557f2..3cade3e92a 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt @@ -14,7 +14,7 @@ class TlvBuilder { fun serialize(): ByteArray { Log.v("TLV", - "List of TLV that are being sent to a card:\n${tlvs.joinToString("\n")}") + "List of encoded TLVs:\n${tlvs.joinToString("\n")}") return tlvs.serialize() } diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt index 2b9bd3520c..62c0899f2d 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt @@ -20,7 +20,7 @@ class TlvDecoder(val tlvList: List) { init { Log.v("TLV", - "List of TLV received from card:\n${tlvList.joinToString("\n")}") + "List of decoded TLVs:\n${tlvList.joinToString("\n")}") } /** diff --git a/tangem-devkit/build.gradle b/tangem-devkit/build.gradle index e692140432..266e0bf816 100644 --- a/tangem-devkit/build.gradle +++ b/tangem-devkit/build.gradle @@ -9,8 +9,8 @@ android { applicationId "com.tangem.devkit" minSdkVersion 21 targetSdkVersion 29 - versionCode 1 - versionName "1.0" + versionCode 3 + versionName "1.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/TlvResources.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/TlvResources.kt index 32bb68d840..c7527b36ed 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/TlvResources.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/TlvResources.kt @@ -18,7 +18,7 @@ class TlvResources { holder.register(TlvId.TransactionOutHash, Resources(R.string.tlv_transaction_out_hash, R.string.info_tlv_transaction_out_hash)) holder.register(TlvId.Counter, Resources(R.string.tlv_counter, R.string.info_tlv_counter)) holder.register(TlvId.IssuerData, Resources(R.string.tlv_issuer_data, R.string.info_tlv_issuer_data)) - holder.register(TlvId.UserData, Resources(R.string.tlv_issuer_data, R.string.info_tlv_user_data)) + holder.register(TlvId.UserData, Resources(R.string.tlv_user_data, R.string.info_tlv_user_data)) holder.register(TlvId.ProtectedUserData, Resources(R.string.tlv_user_protected_data, R.string.info_tlv_protected_user_data)) } } \ No newline at end of file diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt index 002bf20104..225edfb595 100644 --- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt +++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt @@ -80,6 +80,7 @@ class NfcReader : CardReader { isoDep = null return } catch (exception: Exception) { + Log.i(this::class.simpleName!!, exception.localizedMessage ?: "Error tranceiving data") isoDep = null return } From 878581ca8e677c0c4bfe8442869d8e0daac92e91 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 May 2020 10:04:22 +0300 Subject: [PATCH 7/8] Updated on 2026-08-14 --- .../src/main/java/com/tangem/TangemSdk.kt | 38 +++++++++++++++---- .../com/tangem/devkit/TestUserDataActivity.kt | 4 +- .../_main/entryPoint/ActionListFragment.kt | 3 +- .../domain/actions/WriteUserDataAction.kt | 5 +-- .../actions/WriteUserProtectedDataAction.kt | 29 ++++++++++++++ .../paramsManager/managers/SimpleManagers.kt | 15 ++++++-- .../com/tangem/devkit/ucase/resources/Ids.kt | 1 + .../resources/initializers/ActionResources.kt | 1 + .../ui/WriteProtectedUserDataFragment.kt | 10 +++++ .../src/main/res/navigation/navigation.xml | 9 +++++ .../src/main/res/values/strings_action.xml | 6 ++- 11 files changed, 100 insertions(+), 21 deletions(-) create mode 100644 tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserProtectedDataAction.kt create mode 100644 tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/userdata/ui/WriteProtectedUserDataFragment.kt diff --git a/tangem-core/src/main/java/com/tangem/TangemSdk.kt b/tangem-core/src/main/java/com/tangem/TangemSdk.kt index 8fc1fb4e2e..880796d9e7 100644 --- a/tangem-core/src/main/java/com/tangem/TangemSdk.kt +++ b/tangem-core/src/main/java/com/tangem/TangemSdk.kt @@ -183,29 +183,51 @@ class TangemSdk( } /** - * This method launches a [WriteUserDataCommand] on a new thread. + * This method launches a [WriteUserDataCommand] on a new thread, writing UserData and UserCounter fields. * - * This command writes some of UserData, UserProtectedData, UserCounter and UserProtectedCounter fields. - * User_Data and User_ProtectedData are never changed or parsed by the executable code the Tangem COS. - * The App defines purpose of use, format and it's payload. For example, this field may contain cashed information + * User_Data is never changed or parsed by the executable code the Tangem COS. + * The App defines purpose of use, format and its payload. For example, this field may contain cashed information * from blockchain to accelerate preparing new transaction. - * User_Counter and User_ProtectedCounter are counters, that initial values can be set by App and increased on every signing + * The initial value of User_Counter can be set by an App and increased on every signing * of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use. * For example, this fields may contain blockchain nonce value. * * Writing of UserCounter and UserData is protected only by PIN1. - * UserProtectedCounter and UserProtectedData need additionally PIN2 to confirmation. */ fun writeUserData( cardId: String, userData: ByteArray? = null, - userProtectedData: ByteArray? = null, userCounter: Int? = null, + initialMessage: Message? = null, + callback: (result: CompletionResult) -> Unit + ) { + val command = WriteUserDataCommand(userData = userData,userCounter = userCounter) + startSessionWithRunnable(command, cardId, initialMessage, callback) + } + + /** + * This method launches a [WriteUserDataCommand] on a new thread, + * writing UserProtectedData and UserProtectedCounter fields. + * + * User_ProtectedData is never changed or parsed by the executable code the Tangem COS. + * The App defines purpose of use, format and its payload. For example, this field may contain cashed information + * from blockchain to accelerate preparing new transaction. + * The initial value of User_ProtectedCounter can be set by an App and increased on every signing + * of a new transaction (on SIGN command that calculate new signatures). The App defines the purpose of use. + * For example, this fields may contain blockchain nonce value. + * + * UserProtectedCounter and UserProtectedData require PIN2 for confirmation. + */ + fun writeProtectedUserData( + cardId: String, + userProtectedData: ByteArray? = null, userProtectedCounter: Int? = null, initialMessage: Message? = null, callback: (result: CompletionResult) -> Unit ) { - val command = WriteUserDataCommand(userData, userProtectedData, userCounter, userProtectedCounter) + val command = WriteUserDataCommand( + userProtectedData = userProtectedData, userProtectedCounter = userProtectedCounter + ) startSessionWithRunnable(command, cardId, initialMessage, callback) } diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt b/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt index 1fd9eeedb6..5628c01f29 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt @@ -50,9 +50,7 @@ class TestUserDataActivity : AppCompatActivity() { tangemSdk.writeUserData( writeOptions.cardId!!, writeOptions.userData, - writeOptions.userProtectedData, - writeOptions.userCounter, - writeOptions.userProtectedCounter + writeOptions.userCounter ) { when (it) { is CompletionResult.Failure -> handleError(tv_write_result, it.error) diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/ActionListFragment.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/ActionListFragment.kt index 5a1008d717..2656204d6b 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/ActionListFragment.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/ActionListFragment.kt @@ -71,7 +71,8 @@ class ActionListFragment : BaseFragment() { ActionType.ReadIssuerExData, ActionType.WriteIssuerExData, ActionType.ReadUserData, - ActionType.WriteUserData + ActionType.WriteUserData, + ActionType.WriteProtectedUserData ) } } \ No newline at end of file diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserDataAction.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserDataAction.kt index d7d6da6107..7727546c05 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserDataAction.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserDataAction.kt @@ -11,12 +11,10 @@ class WriteUserDataAction : BaseAction() { override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) { val userData = (attrs.itemList.findItem(TlvId.UserData)?.getData() as? String)?.toByteArray() ?: return - val protectedUserData = (attrs.itemList.findItem(TlvId.ProtectedUserData)?.getData() as? String)?.toByteArray() - ?: return val cardId = attrs.itemList.findItem(TlvId.CardId)?.viewModel?.data ?: return val counter = (attrs.itemList.findItem(TlvId.Counter)?.viewModel?.data as? Int) ?: 1 - attrs.tangemSdk.writeUserData(stringOf(cardId), userData, protectedUserData, counter, counter) { + attrs.tangemSdk.writeUserData(stringOf(cardId), userData, counter) { handleResult(payload, it, null, attrs, callback) } } @@ -24,7 +22,6 @@ class WriteUserDataAction : BaseAction() { override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? { return when (id) { TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) } - TlvId.Counter -> { callback -> ReadUserDataAction().executeMainAction(payload, attrs, callback) } else -> null } } diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserProtectedDataAction.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserProtectedDataAction.kt new file mode 100644 index 0000000000..e315107b8b --- /dev/null +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserProtectedDataAction.kt @@ -0,0 +1,29 @@ +package com.tangem.devkit.ucase.domain.actions + +import com.tangem.devkit._arch.structure.Id +import com.tangem.devkit._arch.structure.PayloadHolder +import com.tangem.devkit._arch.structure.abstraction.findItem +import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback +import com.tangem.devkit.ucase.variants.TlvId +import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf + + +class WriteUserProtectedDataAction : BaseAction() { + override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) { + val protectedUserData = (attrs.itemList.findItem(TlvId.ProtectedUserData)?.getData() as? String)?.toByteArray() + ?: return + val cardId = attrs.itemList.findItem(TlvId.CardId)?.viewModel?.data ?: return + val counter = (attrs.itemList.findItem(TlvId.Counter)?.viewModel?.data as? Int) ?: 1 + + attrs.tangemSdk.writeProtectedUserData(stringOf(cardId), protectedUserData, counter) { + handleResult(payload, it, null, attrs, callback) + } + } + + override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? { + return when (id) { + TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) } + else -> null + } + } +} \ No newline at end of file diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/SimpleManagers.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/SimpleManagers.kt index a5085dccb2..bb6b16540e 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/SimpleManagers.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/SimpleManagers.kt @@ -96,9 +96,18 @@ class WriteUserDataItemsManager : BaseItemsManager(WriteUserDataAction()) { setItems(listOf( EditTextItem(TlvId.CardId, null), EditTextItem(TlvId.Counter, "1"), - EditTextItem(TlvId.UserData, "User data to be written on a card"), - EditTextItem(TlvId.ProtectedUserData, "Protected user data to be written on a card") - + EditTextItem(TlvId.UserData, "User data to be written on a card") )) } +} + + class WriteProtectedUserDataItemsManager : BaseItemsManager(WriteUserProtectedDataAction()) { + init { + setItemChangeConsequences(CardIdConsequence()) + setItems(listOf( + EditTextItem(TlvId.CardId, null), + EditTextItem(TlvId.Counter, "1"), + EditTextItem(TlvId.ProtectedUserData, "Protected user data to be written on a card") + )) + } } \ No newline at end of file diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/Ids.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/Ids.kt index 1daedb6326..90e2d54588 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/Ids.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/Ids.kt @@ -16,6 +16,7 @@ enum class ActionType : Id { WriteIssuerExData, ReadUserData, WriteUserData, + WriteProtectedUserData, Personalize, Depersonalize, Unknown, diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/ActionResources.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/ActionResources.kt index 2d7adcea1c..7ca4301b5f 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/ActionResources.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/ActionResources.kt @@ -24,6 +24,7 @@ class ActionResources { holder.register(ActionType.WriteIssuerExData, ActionRes(R.string.action_issuer_write_ex_data, R.string.info_action_issuer_write_ex_data, R.id.action_nav_entry_point_to_nav_issuer_write_ex_data)) holder.register(ActionType.ReadUserData, ActionRes(R.string.action_user_read_data, R.string.info_action_user_read_data, R.id.action_nav_entry_point_to_nav_user_read_data)) holder.register(ActionType.WriteUserData, ActionRes(R.string.action_user_write_data, R.string.info_action_user_write_data, R.id.action_nav_entry_point_to_nav_user_write_data)) + holder.register(ActionType.WriteProtectedUserData, ActionRes(R.string.action_user_write_protected_data, R.string.info_action_user_write_protected_data, R.id.action_nav_entry_point_to_nav_user_write_protected_data)) // holder.register(ActionType.Unknown, getIfNotContains()) } } \ No newline at end of file diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/userdata/ui/WriteProtectedUserDataFragment.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/userdata/ui/WriteProtectedUserDataFragment.kt new file mode 100644 index 0000000000..4962b4537a --- /dev/null +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/userdata/ui/WriteProtectedUserDataFragment.kt @@ -0,0 +1,10 @@ +package com.tangem.devkit.ucase.variants.userdata.ui + +import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager +import com.tangem.devkit.ucase.domain.paramsManager.managers.WriteProtectedUserDataItemsManager +import com.tangem.devkit.ucase.ui.BaseCardActionFragment + +class WriteProtectedUserDataFragment : BaseCardActionFragment() { + + override val itemsManager: ItemsManager by lazy { WriteProtectedUserDataItemsManager() } +} \ No newline at end of file diff --git a/tangem-devkit/src/main/res/navigation/navigation.xml b/tangem-devkit/src/main/res/navigation/navigation.xml index a08466aff6..f89849a75c 100644 --- a/tangem-devkit/src/main/res/navigation/navigation.xml +++ b/tangem-devkit/src/main/res/navigation/navigation.xml @@ -44,6 +44,9 @@ + @@ -119,6 +122,12 @@ android:label="@string/action_user_write_data" tools:layout="@layout/fg_base_action_layout" /> + + Write Issuer Extra Data Read User Data Write User Data + Write Protected User DataThis command returns all data about the card and the wallet, including unique card number (CID) that has to be submitted while calling all other commands Depending on Signing_Method parameter defined during personalization, this command signs data using Wallet_PrivateKey @@ -26,7 +27,8 @@ This command retrieves Issuer Extra Data field and its issuer’s signature. This command writes Issuer Extra Data field and its issuer’s signature to the card. This command returns User Data and User Protected Data (up to 512-byte each) and two counters: User Counter and User Protected Counter. - This command writes to the card any of User Data, User Protected Data, User Counter and User Protected Counter fields. - + This command writes to the card User Data and User Counter fields. + This command writes to the card User Protected Data and User Protected Counter fields. + \ No newline at end of file From 1c1e5230a5e662e1e3c36dd261203faa88da8880 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 May 2020 13:27:40 +0300 Subject: [PATCH 8/8] Updated on 2026-08-14 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 07bb7d859f..af2ce223fa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,7 +99,7 @@ dependencies { implementation 'com.google.dagger:dagger:2.24' kapt 'com.google.dagger:dagger-compiler:2.21' annotationProcessor 'com.google.dagger:dagger-compiler:2.21' - implementation 'com.google.zxing:core:3.4.0' + implementation 'com.google.zxing:core:3.3.3' // Do not update to 3.4.0, it requires minSdk 24 implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.madgag.spongycastle:core:1.56.0.0' implementation 'com.madgag.spongycastle:prov:1.56.0.0'