Updated on 2026-08-14
This commit is contained in:
commit
3103a1bc0e
40 changed files with 668 additions and 302 deletions
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ interface CardSessionRunnable<T : CommandResponse> {
|
|||
* @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<Boolean>) -> Unit) {
|
||||
error: TangemSdkError, callback: (result: CompletionResult<Boolean>) -> 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()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
)
|
||||
|
|
@ -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 = true
|
||||
) {
|
||||
|
||||
fun setPin1(pin1: String) {
|
||||
|
|
|
|||
|
|
@ -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<Card>) -> 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<ByteArray>, cardId: String, initialMessage: Message? = null,
|
||||
callback: (result: CompletionResult<SignResponse>) -> 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<ReadIssuerDataResponse>) -> 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<ReadIssuerExtraDataResponse>) -> 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<ReadUserDataResponse>) -> 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<CreateWalletResponse>) -> 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<PurgeWalletResponse>) -> 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<DepersonalizeResponse>) -> 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
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,105 @@ 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)
|
||||
//Personalization Errors
|
||||
class AlreadyPersonalized : TangemSdkError(40101)
|
||||
|
||||
/**
|
||||
* This error is returned when a [ScanTask] returns a [Card] without some of the essential fields.
|
||||
*/
|
||||
class CardError : SessionError(3001)
|
||||
//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.
|
||||
* but the user tries to use a different card.
|
||||
*/
|
||||
class WrongCard : SessionError(3002)
|
||||
|
||||
class WrongCard : TangemSdkError(40403)
|
||||
/**
|
||||
* 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.
|
||||
* This error is returned when a user scans a card of a [com.tangem.common.extensions.CardType]
|
||||
* that is not specified in [Config.cardFilter].
|
||||
*/
|
||||
class TooMuchHashesInOneTransaction : SessionError(3003)
|
||||
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 a [com.tangem.commands.SignCommand]
|
||||
* receives only empty hashes for signature.
|
||||
*/
|
||||
class EmptyHashes : SessionError(3004)
|
||||
|
||||
class EmptyHashes : TangemSdkError(40902)
|
||||
/**
|
||||
* This error is returned when a [com.tangem.commands.SignCommand]
|
||||
* receives hashes of different lengths for signature.
|
||||
*/
|
||||
class HashSizeMustBeEqual : SessionError(3005)
|
||||
|
||||
|
||||
class HashSizeMustBeEqual : TangemSdkError(40903)
|
||||
class CardIsEmpty : TangemSdkError(40904)
|
||||
class SignHashesNotAvailable : TangemSdkError(40905)
|
||||
/**
|
||||
* This error is returned when a user scans a card of a [com.tangem.common.extensions.CardType]
|
||||
* that is not specified in [Config.allowedCards].
|
||||
* 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 WrongCardType : SessionError(3006)
|
||||
class TooManyhHashesInOneTransaction : TangemSdkError(40906)
|
||||
|
||||
//General Errors
|
||||
class NotPersonalized() : TangemSdkError(40001)
|
||||
class NotActivated : TangemSdkError(40002)
|
||||
class CardIsPurged : TangemSdkError(40003)
|
||||
class Pin2OrCvcRequired : TangemSdkError(40004)
|
||||
/**
|
||||
* 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 [Task] checks unsuccessfully either
|
||||
* a card's ability to sign with its private key, or the validity of issuer data.
|
||||
*/
|
||||
class Busy : SessionError(4000)
|
||||
|
||||
/**
|
||||
* This error is returned when a user manually closes NFC Reading Bottom Sheet Dialog.
|
||||
*/
|
||||
class UserCancelled : SessionError(4001)
|
||||
|
||||
//NFC errors
|
||||
class NfcReaderError : SessionError(5002)
|
||||
|
||||
/**
|
||||
* 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 TagLost : SessionError(5003)
|
||||
|
||||
class UnknownError : SessionError(6000)
|
||||
|
||||
//Specific Command Errors
|
||||
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)
|
||||
}
|
||||
|
|
@ -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<CheckWalletResponse>) -> 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 performPreCheck(
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<CheckWalletResponse>) -> 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(
|
||||
|
|
|
|||
|
|
@ -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<T : CommandResponse> : CardSessionRunnable<T> {
|
|||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<T>) -> Unit) {
|
||||
Log.i("Command", "Sending ${this::class.java.simpleName}")
|
||||
transceive(session, callback)
|
||||
if (session.environment.handleErrors) {
|
||||
if (performPreCheck(session, callback)) return
|
||||
}
|
||||
transceive(session) { result ->
|
||||
if (session.environment.handleErrors) {
|
||||
if (performAfterCheck(session, result, callback)) return@transceive
|
||||
}
|
||||
callback(result)
|
||||
}
|
||||
}
|
||||
|
||||
open fun performPreCheck(session: CardSession,
|
||||
callback: (result: CompletionResult<T>) -> Unit): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
open fun performAfterCheck(session: CardSession,
|
||||
result: CompletionResult<T>,
|
||||
callback: (result: CompletionResult<T>) -> Unit): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
fun transceive(session: CardSession, callback: (result: CompletionResult<T>) -> Unit) {
|
||||
|
|
@ -54,7 +73,7 @@ abstract class Command<T : CommandResponse> : CardSessionRunnable<T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
} catch (error: SessionError) {
|
||||
} catch (error: TangemSdkError) {
|
||||
callback(CompletionResult.Failure(error))
|
||||
}
|
||||
}
|
||||
|
|
@ -81,17 +100,17 @@ abstract class Command<T : CommandResponse> : CardSessionRunnable<T> {
|
|||
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<T : CommandResponse> : CardSessionRunnable<T> {
|
|||
return tlv?.find { it.tag == TlvTag.Pause }?.value?.toInt()
|
||||
}
|
||||
|
||||
private fun tryHandleError(error: SessionError): Boolean {
|
||||
private fun tryHandleError(error: TangemSdkError): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<CreateWalletResponse>() {
|
||||
|
||||
override fun performPreCheck(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> 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 performAfterCheck(session: CardSession,
|
||||
result: CompletionResult<CreateWalletResponse>,
|
||||
callback: (result: CompletionResult<CreateWalletResponse>) -> 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<CreateWalletResponse>() {
|
|||
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -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<OpenSessi
|
|||
|
||||
override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): OpenSessionResponse {
|
||||
val tlvData = apdu.getTlvData()
|
||||
?: throw SessionError.DeserializeApduFailed()
|
||||
?: throw TangemSdkError.DeserializeApduFailed()
|
||||
|
||||
val decoder = TlvDecoder(tlvData)
|
||||
return OpenSessionResponse(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -29,6 +31,37 @@ class PurgeWalletResponse(
|
|||
*/
|
||||
class PurgeWalletCommand : Command<PurgeWalletResponse>() {
|
||||
|
||||
override fun performPreCheck(session: CardSession, callback: (result: CompletionResult<PurgeWalletResponse>) -> 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 performAfterCheck(session: CardSession,
|
||||
result: CompletionResult<PurgeWalletResponse>,
|
||||
callback: (result: CompletionResult<PurgeWalletResponse>) -> 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<PurgeWalletResponse>() {
|
|||
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -132,7 +134,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),
|
||||
|
|
@ -366,6 +368,19 @@ class Card(
|
|||
*/
|
||||
class ReadCommand : Command<Card>() {
|
||||
|
||||
override fun performAfterCheck(session: CardSession, result: CompletionResult<Card>, callback: (result: CompletionResult<Card>) -> 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()
|
||||
/**
|
||||
|
|
@ -384,7 +399,7 @@ class ReadCommand : Command<Card>() {
|
|||
|
||||
override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): Card {
|
||||
val tlvData = apdu.getTlvData(environment.encryptionKey)
|
||||
?: throw SessionError.DeserializeApduFailed()
|
||||
?: throw TangemSdkError.DeserializeApduFailed()
|
||||
|
||||
val decoder = TlvDecoder(tlvData)
|
||||
|
||||
|
|
|
|||
|
|
@ -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<ReadIssuerDataResponse>) -> 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 performPreCheck(session: CardSession, callback: (result: CompletionResult<ReadIssuerDataResponse>) -> 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(
|
||||
|
|
|
|||
|
|
@ -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<ReadIssuerExtraDataResponse>) -> 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)
|
||||
|
|
|
|||
|
|
@ -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<ReadUserDataResponse>() {
|
||||
class ReadUserDataCommand : Command<ReadUserDataResponse>() {
|
||||
|
||||
override fun serialize(environment: SessionEnvironment): CommandApdu {
|
||||
val builder = TlvBuilder()
|
||||
builder.append(TlvTag.CardId, environment.card?.cardId)
|
||||
builder.append(TlvTag.Pin, environment.pin1)
|
||||
override fun performPreCheck(session: CardSession, callback: (result: CompletionResult<ReadUserDataResponse>) -> 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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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<ByteArray>)
|
|||
|
||||
private val hashSizes = if (hashes.isNotEmpty()) hashes.first().size else 0
|
||||
|
||||
override fun performPreCheck(session: CardSession, callback: (result: CompletionResult<SignResponse>) -> 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 performAfterCheck(session: CardSession,
|
||||
result: CompletionResult<SignResponse>,
|
||||
callback: (result: CompletionResult<SignResponse>) -> 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<ByteArray>)
|
|||
}
|
||||
|
||||
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<ByteArray>)
|
|||
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -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<WriteIssuerDataResponse>(), IssuerDataVerifier by verifier {
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<WriteIssuerDataResponse>) -> Unit) {
|
||||
|
||||
override fun performPreCheck(session: CardSession, callback: (result: CompletionResult<WriteIssuerDataResponse>) -> 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 performAfterCheck(session: CardSession,
|
||||
result: CompletionResult<WriteIssuerDataResponse>,
|
||||
callback: (result: CompletionResult<WriteIssuerDataResponse>) -> 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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<WriteIssuerDataResponse>) -> 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 performPreCheck(session: CardSession, callback: (result: CompletionResult<WriteIssuerDataResponse>) -> 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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<WriteUserDataResponse>() {
|
||||
|
||||
override fun performPreCheck(session: CardSession, callback: (result: CompletionResult<WriteUserDataResponse>) -> 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 performAfterCheck(session: CardSession,
|
||||
result: CompletionResult<WriteUserDataResponse>,
|
||||
callback: (result: CompletionResult<WriteUserDataResponse>) -> 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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<DepersonalizeResponse>() {
|
||||
|
||||
override fun performPreCheck(session: CardSession, callback: (result: CompletionResult<DepersonalizeResponse>) -> 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()
|
||||
|
|
|
|||
|
|
@ -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<Card>() {
|
||||
|
||||
override fun performPreCheck(session: CardSession, callback: (result: CompletionResult<Card>) -> 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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<T> {
|
||||
class Success<T>(val data: T) : CompletionResult<T>()
|
||||
class Failure<T>(val error: SessionError) : CompletionResult<T>()
|
||||
class Failure<T>(val error: TangemSdkError) : CompletionResult<T>()
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -20,7 +20,7 @@ class TlvDecoder(val tlvList: List<Tlv>) {
|
|||
|
||||
init {
|
||||
Log.v("TLV",
|
||||
"List of TLV received from card:\n${tlvList.joinToString("\n")}")
|
||||
"List of decoded TLVs:\n${tlvList.joinToString("\n")}")
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -34,7 +34,7 @@ class TlvDecoder(val tlvList: List<Tlv>) {
|
|||
inline fun <reified T> decodeOptional(tag: TlvTag): T? =
|
||||
try {
|
||||
decode<T>(tag)
|
||||
} catch (exception: SessionError.DecodingFailedMissingTag) {
|
||||
} catch (exception: TangemSdkError.DecodingFailedMissingTag) {
|
||||
null
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ class TlvDecoder(val tlvList: List<Tlv>) {
|
|||
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<Tlv>) {
|
|||
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<Tlv>) {
|
|||
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<Tlv>) {
|
|||
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<Tlv>) {
|
|||
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<Tlv>) {
|
|||
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<Tlv>) {
|
|||
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<Tlv>) {
|
|||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<CreateWalletResponse> {
|
|||
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> 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<CreateWalletResponse> {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -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<Card> {
|
|||
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<Card> {
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -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<SessionError.DecodingFailedMissingTag> {
|
||||
assertThrows<TangemSdkError.DecodingFailedMissingTag> {
|
||||
tlvMapper.decode<String>(TlvTag.TokenSymbol)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `map optional to wrong type throws WrongTypeException`() {
|
||||
assertThrows<SessionError.DecodingFailedTypeMismatch> {
|
||||
assertThrows<TangemSdkError.DecodingFailedTypeMismatch> {
|
||||
tlvMapper.decodeOptional<String?>(TlvTag.CardData)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `map to wrong type throws WrongTypeException`() {
|
||||
assertThrows<SessionError.DecodingFailedTypeMismatch> {
|
||||
assertThrows<TangemSdkError.DecodingFailedTypeMismatch> {
|
||||
tlvMapper.decode<String>(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<SessionError.DecodingFailed> {
|
||||
assertThrows<TangemSdkError.DecodingFailed> {
|
||||
localMapper.decode<EllipticCurve>(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<SessionError.DecodingFailed> {
|
||||
assertThrows<TangemSdkError.DecodingFailed> {
|
||||
localMapper.decode<Int>(TlvTag.SignedHashes)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
@ -3,8 +3,9 @@ package com.tangem.devkit.ucase.ui
|
|||
import android.view.View
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.lifecycle.*
|
||||
import com.tangem.SessionError
|
||||
import com.google.gson.Gson
|
||||
import com.tangem.TangemSdk
|
||||
import com.tangem.TangemSdkError
|
||||
import com.tangem.commands.Card
|
||||
import com.tangem.commands.CommandResponse
|
||||
import com.tangem.common.CompletionResult
|
||||
|
|
@ -131,7 +132,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
|
||||
|
||||
fun handleActionResult(result: CompletionResult<*>, list: List<Item>) {
|
||||
if (list.isNotEmpty()) notifyItemsChanged(list)
|
||||
|
|
@ -160,10 +161,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 {
|
||||
|
|
|
|||
|
|
@ -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<T>` – this is the sealed class for the results of `CardSessionRunnable`.
|
||||
|
||||
`Success<T>(val data: T)` is triggered after successful operation and contains a `CommandResponse`.
|
||||
`Failure<T>(val error: SessionError)` is triggered on error.
|
||||
`Failure<T>(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<ByteArray>) : 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<ByteArray>) : 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)
|
||||
|
|
|
|||
|
|
@ -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,10 +76,11 @@ 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) {
|
||||
Log.i(this::class.simpleName!!, exception.localizedMessage ?: "Error tranceiving data")
|
||||
isoDep = null
|
||||
return
|
||||
}
|
||||
|
|
@ -110,7 +111,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)))
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@
|
|||
android:toDegrees="360" />
|
||||
|
||||
<gradient
|
||||
android:centerColor="@color/colorAccent"
|
||||
android:endColor="@color/colorAccent"
|
||||
android:startColor="@color/colorAccent"
|
||||
android:centerColor="@color/card_sdk_accent"
|
||||
android:endColor="@color/card_sdk_accent"
|
||||
android:startColor="@color/card_sdk_accent"
|
||||
android:type="sweep" />
|
||||
|
||||
</shape>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCardId"
|
||||
|
|
@ -47,11 +48,12 @@
|
|||
android:paddingStart="5dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/colorAccent"
|
||||
android:textColor="@color/card_sdk_accent"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="normal"
|
||||
tools:text="cb22000000027374"
|
||||
android:visibility="gone"/>
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
@ -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" />
|
||||
|
||||
<include
|
||||
|
|
@ -85,7 +88,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:textColor="@color/colorAccent"
|
||||
android:textColor="@color/card_sdk_accent"
|
||||
android:textSize="60dp"
|
||||
android:textStyle="normal" />
|
||||
|
||||
|
|
@ -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" />
|
||||
|
||||
<ProgressBar
|
||||
|
|
@ -166,8 +170,9 @@
|
|||
android:gravity="center"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:textColor="@color/card_sdk_text_color"
|
||||
android:text="@string/dialog_scan_text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
/>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -3,6 +3,9 @@
|
|||
<color name="colorPrimary">#027aff</color>
|
||||
<color name="colorPrimaryDark">#027AFF</color>
|
||||
<color name="colorAccent">#027AFF</color>
|
||||
<color name="fab">#4f98c0</color>
|
||||
|
||||
<color name="card_sdk_accent">#266dd3</color>
|
||||
<color name="card_sdk_text_color">#000000</color>
|
||||
<color name="card_sdk_ripple">#2c5ac4</color>
|
||||
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue