Updated on 2026-08-14
This commit is contained in:
parent
d6d7c292e7
commit
7db8aa448c
15 changed files with 77 additions and 90 deletions
|
|
@ -1,36 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":tangem-card-old" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":tangem-card-old" />
|
||||
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" />
|
||||
<option name="LAST_KNOWN_AGP_VERSION" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="java-gradle" name="Java-Gradle">
|
||||
<configuration>
|
||||
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
||||
<option name="BUILDABLE" value="true" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
|
||||
<output url="file://$MODULE_DIR$/build/classes/java/main" />
|
||||
<output-test url="file://$MODULE_DIR$/build/classes/java/test" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="Gradle: prov-1.56.0.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="Gradle: core-1.56.0.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="Gradle: eddsa-0.3.0" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -14,7 +14,7 @@ import java.util.concurrent.Executors
|
|||
* @property reader is an interface that is responsible for NFC connection and
|
||||
* transfer of data to and from the Tangem Card.
|
||||
* Its default implementation, NfcCardReader, is in our tangem-sdk module.
|
||||
* @property cardManagerDelegate is an interface that allows interaction with users and shows relevant UI.
|
||||
* @property cardManagerDelegate An interface that allows interaction with users and shows relevant UI.
|
||||
* Its default implementation, DefaultCardManagerDelegate, is in our tangem-sdk module.
|
||||
*/
|
||||
class CardManager(
|
||||
|
|
@ -30,7 +30,11 @@ class CardManager(
|
|||
}
|
||||
|
||||
/**
|
||||
* A method that allows to read a card and verify that its private key.
|
||||
* To start using any card, you first need to read it using the scanCard() method.
|
||||
* This method launches an NFC session, and once it’s connected with the card,
|
||||
* it obtains the card data. Optionally, if the card contains a wallet (private and public key pair),
|
||||
* it proves that the wallet owns a private key that corresponds to a public one.
|
||||
*
|
||||
* It launches on the new thread a [ScanTask] that will send the following events in a callback:
|
||||
* [ScanEvent.OnReadEvent] after completing [com.tangem.commands.ReadCommand]
|
||||
* [ScanEvent.OnVerifyEvent] after completing [com.tangem.commands.CheckWalletCommand]
|
||||
|
|
@ -43,8 +47,10 @@ class CardManager(
|
|||
}
|
||||
|
||||
/**
|
||||
* A method that allows to sign hashes (usually a blockchain transaction) with a private key
|
||||
* from a Tangem card. (Please note that the private key itself never leaves the Tangem card).
|
||||
* This method allows you to sign one or multiple hashes.
|
||||
* Simultaneous signing of array of hashes in a single [SignCommand] is required to support
|
||||
* Bitcoin-type multi-input blockchains (UTXO).
|
||||
* The [SignCommand] will return a corresponding array of signatures.
|
||||
*
|
||||
* This method launches on the new thread [SignCommand] that will send the following events in a callback:
|
||||
* [SignResponse] after completing [SignCommand]
|
||||
|
|
@ -53,7 +59,7 @@ class CardManager(
|
|||
* Please note that Tangem cards usually protect the signing with a security delay
|
||||
* that may last up to 90 seconds, depending on a card.
|
||||
* It is for [CardManagerDelegate] to notify users of security delay.
|
||||
* @param hashes Array of transaction hashes. It can be a single hash or several hashes of the same length.
|
||||
* @param hashes Array of transaction hashes. It can be from one or up to ten hashes of the same length.
|
||||
* @param cardId CID, Unique Tangem card ID number
|
||||
* @param callback
|
||||
*
|
||||
|
|
|
|||
|
|
@ -10,12 +10,36 @@ import com.tangem.tasks.TaskError
|
|||
*/
|
||||
interface CardManagerDelegate {
|
||||
|
||||
/**
|
||||
* It is called when user is expected to scan a Tangem Card with an Android device.
|
||||
*/
|
||||
fun onNfcSessionStarted()
|
||||
|
||||
/**
|
||||
* It is called when security delay is triggered by the card.
|
||||
* A user is expected to hold the card until the security delay is over.
|
||||
*/
|
||||
fun onSecurityDelay(ms: Int)
|
||||
|
||||
/**
|
||||
* It is called when user takes the card away from the Android device during the scanning
|
||||
* (for example when security delay is in progress) and the TagLostException is received.
|
||||
*/
|
||||
fun onTagLost()
|
||||
|
||||
/**
|
||||
* It is called when NFC session was completed and a user can take the card away from the Android device.
|
||||
*/
|
||||
fun onNfcSessionCompleted()
|
||||
|
||||
/**
|
||||
* It is called when some error occur during NFC session.
|
||||
*/
|
||||
fun onError(error: TaskError? = null)
|
||||
|
||||
fun requestPin(callback: (result: CompletionResult<String>) -> Unit)
|
||||
/**
|
||||
* It is called when a user is expected to enter pin code.
|
||||
*/
|
||||
fun onPinRequested(callback: (result: CompletionResult<String>) -> Unit)
|
||||
|
||||
}
|
||||
|
|
@ -11,25 +11,19 @@ import com.tangem.common.apdu.ResponseApdu
|
|||
*/
|
||||
interface CardReader {
|
||||
|
||||
/**
|
||||
* [com.tangem.tasks.Task] sets it to true before the first command,
|
||||
* and it should be set to false on completion of the task.
|
||||
*/
|
||||
var readingActive: Boolean
|
||||
|
||||
/**
|
||||
* Sends data to the card and receives the reply.
|
||||
*
|
||||
* @param apdu data to be sent. [CommandApdu] serializes it to a [ByteArray]
|
||||
* @param callback returns response from the card,
|
||||
* [ResponseApdu] allows to convert raw data to [Tlv]
|
||||
* @param apdu Data to be sent. [CommandApdu] serializes it to a [ByteArray]
|
||||
* @param callback Returns response from the card,
|
||||
* [ResponseApdu] Allows to convert raw data to [Tlv]
|
||||
*/
|
||||
fun transceiveApdu(apdu: CommandApdu, callback: (response: CompletionResult<ResponseApdu>) -> Unit)
|
||||
|
||||
/**
|
||||
* Signals to [CardReader] to become ready to transceive data.
|
||||
*/
|
||||
fun startNfcSession()
|
||||
fun openSession()
|
||||
|
||||
/**
|
||||
* Signals to [CardReader] that no further NFC transition is expected.
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ import com.tangem.tasks.TaskError
|
|||
*
|
||||
* @property cardId Unique Tangem card ID number
|
||||
* @property salt Random salt generated by the card
|
||||
* @property walletSignature Signature with wallet private key of challenge and salt.
|
||||
* It uses SHA256 for ‘secp256k1’ curve and SHA512 for ‘ed25519’ curve.
|
||||
* @property walletSignature Challenge and salt signed with the wallet private key.
|
||||
*/
|
||||
class CheckWalletResponse(
|
||||
val cardId: String,
|
||||
|
|
@ -29,8 +28,7 @@ class CheckWalletResponse(
|
|||
* This command proves that the wallet private key from the card corresponds to the wallet public key.
|
||||
* Standard challenge/response scheme is used.
|
||||
*
|
||||
* @property pin1 hashed user’s pin 1 code to access the card. Default unhashed value: ‘000000’.
|
||||
* Pin code should be taken from card environment.
|
||||
* @property pin1 Hashed user’s pin 1 code to access the card. Default unhashed value: ‘000000’.
|
||||
* @property cardId Unique Tangem card ID number
|
||||
* @property challenge Random challenge generated by application
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ abstract class CommandSerializer<T : CommandResponse> {
|
|||
* Serializes data into a [List] of [com.tangem.common.tlv.Tlv],
|
||||
* then creates [CommandApdu] with this data.
|
||||
*
|
||||
* @return command data that can be converted to raw bytes with a method [CommandApdu.toBytes].
|
||||
* @return Command data that can be converted to raw bytes with a method [CommandApdu.toBytes].
|
||||
*/
|
||||
abstract fun serialize(cardEnvironment: CardEnvironment): CommandApdu
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ abstract class CommandSerializer<T : CommandResponse> {
|
|||
* Deserializes data, received from a card and stored in [ResponseApdu],
|
||||
* into a [List] of [com.tangem.common.tlv.Tlv]. Then this method maps it into a [CommandResponse].
|
||||
*
|
||||
* @return card response, converted to a [CommandResponse] of a type [T].
|
||||
* @return Card response, converted to a [CommandResponse] of a type [T].
|
||||
*/
|
||||
abstract fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): T?
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ enum class ProductMask(val code: Byte) {
|
|||
/**
|
||||
* Stores and maps Tangem card settings.
|
||||
*
|
||||
* @property rawValue are card settings in a form of flags,
|
||||
* @property rawValue Card settings in a form of flags,
|
||||
* while flags definitions and values are in [SettingsMask.Companion] as constants.
|
||||
*/
|
||||
data class SettingsMask(val rawValue: Int) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import com.tangem.tasks.TaskError
|
|||
|
||||
/**
|
||||
* @param cardId CID, Unique Tangem card ID number
|
||||
* @param signature signed hashes (array of resulting signatures)
|
||||
* @param signature Signed hashes (array of resulting signatures)
|
||||
* @param remainingSignatures Remaining number of sign operations before the wallet will stop signing transactions.
|
||||
* @param signedHashes Total number of signed single hashes returned by the card in sign command responses.
|
||||
* Sums up array elements within all SIGN commands
|
||||
|
|
@ -64,10 +64,12 @@ class SignCommand(private val hashes: Array<ByteArray>, private val cardId: Stri
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds to the command data the terminal public key (generated by the application) and
|
||||
* transaction hashes signed by the terminal private key.
|
||||
* This allows to link the card to the Android device and skip security delay.
|
||||
* (as described in Linked Terminal section of the Tangem Card Manual).
|
||||
d
|
||||
* Application can optionally submit a public key Terminal_PublicKey in [SignCommand].
|
||||
* Submitted key is stored by the Tangem card if it differs from a previous submitted Terminal_PublicKey.
|
||||
* The Tangem card will not enforce security delay if [SignCommand] will be called with
|
||||
* TerminalTransactionSignature parameter containing a correct signature of raw data to be signed made with TerminalPrivateKey
|
||||
* (this key should be generated and securily stored by the application).
|
||||
*/
|
||||
private fun addTerminalSignature(cardEnvironment: CardEnvironment, tlvData: MutableList<Tlv>) {
|
||||
cardEnvironment.terminalKeys?.let { terminalKeyPair ->
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.tasks.TaskError
|
|||
|
||||
/**
|
||||
* Response class encapsulating successful and failed results.
|
||||
* [T] is a type of data that is returned in [Success].
|
||||
* @param T Type of data that is returned in [Success].
|
||||
*/
|
||||
sealed class CompletionResult<T> {
|
||||
class Success<T>(val data: T) : CompletionResult<T>()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import java.io.ByteArrayOutputStream
|
|||
* to a raw data that can be sent to the card.
|
||||
*
|
||||
* @property ins Instruction code that determines the type of request for the card.
|
||||
* @property tlvList list of TLVs that are to be sent to the card
|
||||
* @property tlvList A list of TLVs that are to be sent to the card
|
||||
*/
|
||||
class CommandApdu(
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import com.tangem.common.tlv.Tlv
|
|||
/**
|
||||
* Stores response data from the card and parses it to [Tlv] and [StatusWord].
|
||||
*
|
||||
* @property data raw response from the card.
|
||||
* @property data Raw response from the card.
|
||||
* @property sw Status word code, reflecting the status of the response.
|
||||
* @property statusWord parsed status word.
|
||||
* @property statusWord Parsed status word.
|
||||
*/
|
||||
class ResponseApdu(val data: ByteArray) {
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class TlvMapper(val tlvList: List<Tlv>) {
|
|||
*
|
||||
* @param tag [TlvTag] of a [Tlv] which value is to be returned.
|
||||
*
|
||||
* @return value converted to a nullable type [T].
|
||||
* @return Value converted to a nullable type [T].
|
||||
*/
|
||||
inline fun <reified T> mapOptional(tag: TlvTag): T? =
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -30,12 +30,12 @@ object CryptoUtils {
|
|||
* Helper function to verify that the data was signed with a private key that corresponds
|
||||
* to the provided public key.
|
||||
*
|
||||
* @param publicKey public key corresponding to the private key that was used to sing a message
|
||||
* @param message the data that was signed
|
||||
* @param signature signed data
|
||||
* @param curve elliptic curve used
|
||||
* @param publicKey Corresponding to the private key that was used to sing a message
|
||||
* @param message The data that was signed
|
||||
* @param signature Signed data
|
||||
* @param curve Elliptic curve used
|
||||
*
|
||||
* @return result of a verification
|
||||
* @return Result of a verification
|
||||
*/
|
||||
fun verify(publicKey: ByteArray, message: ByteArray, signature: ByteArray,
|
||||
curve: EllipticCurve = EllipticCurve.Secp256k1): Boolean {
|
||||
|
|
@ -48,10 +48,10 @@ object CryptoUtils {
|
|||
/**
|
||||
* Helper function that generates public key from a private key.
|
||||
*
|
||||
* @param privateKeyArray a private key from which a public key is generated
|
||||
* @param curve elliptic curve used
|
||||
* @param privateKeyArray A private key from which a public key is generated
|
||||
* @param curve Elliptic curve used
|
||||
*
|
||||
* @return public key [ByteArray]
|
||||
* @return Public key [ByteArray]
|
||||
*/
|
||||
fun generatePublicKey(
|
||||
privateKeyArray: ByteArray,
|
||||
|
|
@ -67,10 +67,10 @@ object CryptoUtils {
|
|||
/**
|
||||
* Extension function to sign a ByteArray with an elliptic curve cryptography.
|
||||
*
|
||||
* @param privateKeyArray key to sign data
|
||||
* @param curve curve that is used to sign data
|
||||
* @param privateKeyArray Key to sign data
|
||||
* @param curve Elliptic curve that is used to sign data
|
||||
*
|
||||
* @return signed data
|
||||
* @return Signed data
|
||||
*/
|
||||
fun ByteArray.sign(privateKeyArray: ByteArray, curve: EllipticCurve = EllipticCurve.Secp256k1): ByteArray {
|
||||
return when (curve) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.tangem.common.CompletionResult
|
|||
/**
|
||||
* Allows to perform a single command.
|
||||
*
|
||||
* @property command is a command that will be performed.
|
||||
* @property command A command that will be performed.
|
||||
*/
|
||||
class SingleCommandTask<Event : CommandResponse>(
|
||||
private val command: CommandSerializer<Event>
|
||||
|
|
|
|||
|
|
@ -41,13 +41,12 @@ sealed class TaskError(description: String? = null) : Exception(description) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Events that are are sent in callbacks from [Task] during [Task] and Commands completions.
|
||||
* Events that are are sent in callbacks from [Task].
|
||||
*/
|
||||
sealed class TaskEvent<T> {
|
||||
|
||||
/**
|
||||
* A callback that is triggered when a command returns response from a card
|
||||
* (on a completion of a [CommandSerializer]).
|
||||
* A callback that is triggered by a Task.
|
||||
*/
|
||||
class Event<T>(val data: T) : TaskEvent<T>()
|
||||
|
||||
|
|
@ -72,13 +71,13 @@ abstract class Task<T> {
|
|||
/**
|
||||
* This method should be called to run the [Task] and perform all its operations.
|
||||
*
|
||||
* @param cardEnvironment is a relevant current version of a card environment
|
||||
* @param callback is a callback that will be triggered during the performance of the [Task]
|
||||
* @param cardEnvironment Relevant current version of a card environment
|
||||
* @param callback It will be triggered during the performance of the [Task]
|
||||
*/
|
||||
fun run(cardEnvironment: CardEnvironment,
|
||||
callback: (result: TaskEvent<T>) -> Unit) {
|
||||
delegate?.onNfcSessionStarted()
|
||||
reader?.startNfcSession()
|
||||
reader?.openSession()
|
||||
Log.i(this::class.simpleName!!, "Nfc task is started")
|
||||
onRun(cardEnvironment, callback)
|
||||
}
|
||||
|
|
@ -86,8 +85,8 @@ abstract class Task<T> {
|
|||
/**
|
||||
* Should be called on [Task] completion, whether it was successful or with failure.
|
||||
*
|
||||
* @param withError is true when there is an error
|
||||
* @param taskError the error to be shown by [CardManagerDelegate]
|
||||
* @param withError True when there is an error
|
||||
* @param taskError The error to be shown by [CardManagerDelegate]
|
||||
*/
|
||||
protected fun completeNfcSession(withError: Boolean = false, taskError: TaskError? = null) {
|
||||
reader?.closeSession()
|
||||
|
|
@ -161,7 +160,7 @@ abstract class Task<T> {
|
|||
delegate?.onTagLost()
|
||||
} else if (result.error is TaskError.UserCancelledError) {
|
||||
callback(CompletionResult.Failure(TaskError.UserCancelledError()))
|
||||
reader?.readingActive = false
|
||||
reader?.closeSession()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue