diff --git a/tangem-card-old/tangem-card-old.iml b/tangem-card-old/tangem-card-old.iml
deleted file mode 100644
index 3571291374..0000000000
--- a/tangem-card-old/tangem-card-old.iml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/CardEnvironment.kt b/tangem-core/src/main/java/com/tangem/CardEnvironment.kt
index e4fdb8ec16..8c32ac506f 100644
--- a/tangem-core/src/main/java/com/tangem/CardEnvironment.kt
+++ b/tangem-core/src/main/java/com/tangem/CardEnvironment.kt
@@ -1,6 +1,10 @@
package com.tangem
+/**
+ * Contains data relating to a Tangem card. It is used in constructing all the commands,
+ * and commands can return modified [CardEnvironment].
+ */
data class CardEnvironment(
val pin1: String = DEFAULT_PIN,
val pin2: String = DEFAULT_PIN2,
diff --git a/tangem-core/src/main/java/com/tangem/CardManager.kt b/tangem-core/src/main/java/com/tangem/CardManager.kt
index d0efa5a194..f8ac316151 100644
--- a/tangem-core/src/main/java/com/tangem/CardManager.kt
+++ b/tangem-core/src/main/java/com/tangem/CardManager.kt
@@ -8,6 +8,15 @@ import com.tangem.crypto.CryptoUtils
import com.tangem.tasks.*
import java.util.concurrent.Executors
+/**
+ * The main interface of Tangem SDK that allows your app to communicate with Tangem cards.
+ *
+ * @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 An interface that allows interaction with users and shows relevant UI.
+ * Its default implementation, DefaultCardManagerDelegate, is in our tangem-sdk module.
+ */
class CardManager(
private val reader: CardReader,
private val cardManagerDelegate: CardManagerDelegate? = null) {
@@ -20,11 +29,41 @@ class CardManager(
CryptoUtils.initCrypto()
}
+ /**
+ * 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]
+ * [TaskEvent.Completion] with an error field null after successful completion of a task or
+ * [TaskEvent.Completion] with a [TaskError] if some error occurs.
+ */
fun scanCard(callback: (result: TaskEvent) -> Unit) {
val task = ScanTask()
runTask(task, callback = callback)
}
+ /**
+ * 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]
+ * [TaskEvent.Completion] with an error field null after successful completion of a task or
+ * [TaskEvent.Completion] with a [TaskError] if some error occurs.
+ * 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 from one or up to ten hashes of the same length.
+ * @param cardId CID, Unique Tangem card ID number
+ * @param callback
+ *
+ */
fun sign(hashes: Array, cardId: String,
callback: (result: TaskEvent) -> Unit) {
val signCommand: SignCommand
@@ -42,6 +81,9 @@ class CardManager(
runTask(task, cardId, callback)
}
+ /**
+
+ */
fun runTask(task: Task, cardId: String? = null,
callback: (result: TaskEvent) -> Unit) {
if (isBusy) {
@@ -63,6 +105,9 @@ class CardManager(
}
}
+ /**
+
+ */
fun runCommand(command: CommandSerializer,
cardId: String? = null,
callback: (result: TaskEvent) -> Unit) {
diff --git a/tangem-core/src/main/java/com/tangem/CardManagerDelegate.kt b/tangem-core/src/main/java/com/tangem/CardManagerDelegate.kt
index 124d8e9d01..52f30a5e91 100644
--- a/tangem-core/src/main/java/com/tangem/CardManagerDelegate.kt
+++ b/tangem-core/src/main/java/com/tangem/CardManagerDelegate.kt
@@ -3,14 +3,43 @@ package com.tangem
import com.tangem.common.CompletionResult
import com.tangem.tasks.TaskError
+/**
+ * Allows interaction with users and shows visual elements.
+ *
+ * Its default implementation, DefaultCardManagerDelegate, is in our tangem-sdk module.
+ */
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) -> Unit)
+ /**
+ * It is called when a user is expected to enter pin code.
+ */
+ fun onPinRequested(callback: (result: CompletionResult) -> Unit)
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/CardReader.kt b/tangem-core/src/main/java/com/tangem/CardReader.kt
index 4b4d00769f..2327e13fe6 100644
--- a/tangem-core/src/main/java/com/tangem/CardReader.kt
+++ b/tangem-core/src/main/java/com/tangem/CardReader.kt
@@ -4,9 +4,29 @@ import com.tangem.common.CompletionResult
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.ResponseApdu
+/**
+ * Allows interaction between the phone or any other terminal and Tangem card.
+ *
+ * Its default implementation, NfcCardReader, is in our tangem-sdk module.
+ */
interface CardReader {
- 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]
+ */
fun transceiveApdu(apdu: CommandApdu, callback: (response: CompletionResult) -> Unit)
- fun startNfcSession()
+
+ /**
+ * Signals to [CardReader] to become ready to transceive data.
+ */
+ fun openSession()
+
+ /**
+ * Signals to [CardReader] that no further NFC transition is expected.
+ */
fun closeSession()
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/Log.kt b/tangem-core/src/main/java/com/tangem/Log.kt
index 8f77c9a854..b03303b1a5 100644
--- a/tangem-core/src/main/java/com/tangem/Log.kt
+++ b/tangem-core/src/main/java/com/tangem/Log.kt
@@ -22,6 +22,11 @@ object Log {
}
}
+/**
+ * Interface for logging events within the SDK.
+ *
+ * It allows to use Android logger or to choose another.
+ */
interface LoggerInterface {
fun i(logTag: String, message: String)
fun e(logTag: String, message: String)
diff --git a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt
index b581bc36ce..32ba138970 100644
--- a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt
@@ -11,13 +11,27 @@ import com.tangem.common.tlv.TlvMapper
import com.tangem.common.tlv.TlvTag
import com.tangem.tasks.TaskError
+/**
+ * Deserialized response from the Tangem card after [CheckWalletCommand].
+ *
+ * @property cardId Unique Tangem card ID number
+ * @property salt Random salt generated by the card
+ * @property walletSignature Challenge and salt signed with the wallet private key.
+ */
class CheckWalletResponse(
val cardId: String,
val salt: ByteArray,
val walletSignature: ByteArray
) : CommandResponse
-
+/**
+ * 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’.
+ * @property cardId Unique Tangem card ID number
+ * @property challenge Random challenge generated by application
+ */
class CheckWalletCommand(
private val pin1: String,
private val cardId: String,
diff --git a/tangem-core/src/main/java/com/tangem/commands/CommandSerializer.kt b/tangem-core/src/main/java/com/tangem/commands/CommandSerializer.kt
index a5c7db90a4..0835cff543 100644
--- a/tangem-core/src/main/java/com/tangem/commands/CommandSerializer.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/CommandSerializer.kt
@@ -2,22 +2,41 @@ package com.tangem.commands
import com.tangem.CardEnvironment
import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.extentions.toInt
import com.tangem.common.tlv.TlvTag
+/**
+ * Simple interface for responses received after sending commands to Tangem cards.
+ */
interface CommandResponse
-
+/**
+ * Abstract class for all Tangem card commands.
+ */
abstract class CommandSerializer {
- abstract val instruction: Instruction
- abstract val instructionCode: Int
-
+ /**
+ * 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].
+ */
abstract fun serialize(cardEnvironment: CardEnvironment): CommandApdu
+
+ /**
+ * 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].
+ */
abstract fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): T?
+ /**
+ * Helper method to parse security delay information received from a card.
+ *
+ * @return Remaining security delay in milliseconds.
+ */
fun deserializeSecurityDelay(responseApdu: ResponseApdu, cardEnvironment: CardEnvironment): Int? {
val tlv = responseApdu.getTlvData(cardEnvironment.encryptionKey)
return tlv?.find { it.tag == TlvTag.Pause }?.value?.toInt()
diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt
index f4eb833de6..ff8ad89e43 100644
--- a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt
@@ -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) {
@@ -152,7 +152,6 @@ class Card(
/**
* This command receives from the Tangem Card all the data about the card and the wallet,
* including unique card number (CID or cardId) that has to be submitted while calling all other commands.
- *
*/
class ReadCommand : CommandSerializer() {
diff --git a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt
index df7a61c2ff..23b021fef9 100644
--- a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt
@@ -12,6 +12,13 @@ import com.tangem.common.tlv.TlvTag
import com.tangem.crypto.sign
import com.tangem.tasks.TaskError
+/**
+ * @param cardId CID, Unique Tangem card ID number
+ * @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
+ */
class SignResponse(
val cardId: String,
val signature: ByteArray,
@@ -19,7 +26,12 @@ class SignResponse(
val signedHashes: Int
) : CommandResponse
-
+/**
+ * Signs transaction hashes using a wallet private key, stored on the card.
+ *
+ * @property hashes Array of transaction hashes.
+ * @property cardId CID, Unique Tangem card ID number
+ */
class SignCommand(private val hashes: Array, private val cardId: String)
: CommandSerializer() {
@@ -51,6 +63,14 @@ class SignCommand(private val hashes: Array, private val cardId: Stri
return CommandApdu(Instruction.Sign, tlvData)
}
+ /**
+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) {
cardEnvironment.terminalKeys?.let { terminalKeyPair ->
val signedData = dataToSign.sign(terminalKeyPair.privateKey)
diff --git a/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt b/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt
index aac64bbc28..afd76a39e8 100644
--- a/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt
+++ b/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt
@@ -1,7 +1,12 @@
package com.tangem.common
+import com.tangem.common.CompletionResult.Success
import com.tangem.tasks.TaskError
+/**
+ * Response class encapsulating successful and failed results.
+ * @param T Type of data that is returned in [Success].
+ */
sealed class CompletionResult {
class Success(val data: T) : CompletionResult()
class Failure(val error: TaskError) : CompletionResult()
diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt b/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt
index 86a706bd3e..f72fa4d0ae 100644
--- a/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt
+++ b/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt
@@ -5,6 +5,13 @@ import com.tangem.common.tlv.Tlv
import com.tangem.common.tlv.toBytes
import java.io.ByteArrayOutputStream
+/**
+ * Class that provides conversion of serialized request and Instruction code
+ * 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 A list of TLVs that are to be sent to the card
+ */
class CommandApdu(
private val ins: Int,
@@ -31,6 +38,10 @@ class CommandApdu(
encryptionKey = encryptionKey
)
+
+ /**
+ * Request converted to a raw data
+ */
val apduData: ByteArray
init {
diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/Instruction.kt b/tangem-core/src/main/java/com/tangem/common/apdu/Instruction.kt
index e4669e620b..904c5437bd 100644
--- a/tangem-core/src/main/java/com/tangem/common/apdu/Instruction.kt
+++ b/tangem-core/src/main/java/com/tangem/common/apdu/Instruction.kt
@@ -1,5 +1,9 @@
package com.tangem.common.apdu
+/**
+ * Instruction code that determines the type of the command that is sent to the Tangem card.
+ * It is used in the construction of [com.tangem.common.apdu.CommandApdu].
+ */
enum class Instruction(var code: Int) {
Unknown(0x00),
Read(0xF2),
diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt b/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt
index 9eecdc4448..6141512855 100644
--- a/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt
+++ b/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt
@@ -2,6 +2,13 @@ package com.tangem.common.apdu
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 sw Status word code, reflecting the status of the response.
+ * @property statusWord Parsed status word.
+ */
class ResponseApdu(val data: ByteArray) {
private val sw1: Int = 0x00FF and data[data.size - 2].toInt()
@@ -11,6 +18,12 @@ class ResponseApdu(val data: ByteArray) {
val statusWord: StatusWord = StatusWord.byCode(sw)
+ /**
+ * Converts raw response data to the list of TLVs.
+ *
+ * @param encryptionKey key to decrypt response.
+ * (Encryption / decryption functionality is not implemented yet.)
+ */
fun getTlvData(encryptionKey: ByteArray? = null): List? {
return when {
data.size < 2 -> null
diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt b/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt
index c346fe1e71..a43cfbe969 100644
--- a/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt
+++ b/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt
@@ -1,6 +1,9 @@
package com.tangem.common.apdu
-enum class StatusWord (val code: Int, val description: String){
+/**
+ * Part of a response from the card, shows the status of the operation
+ */
+enum class StatusWord(val code: Int, val description: String) {
ProcessCompleted(0x9000, "SW_PROCESS_COMPLETED"),
InvalidParams(0x6A86, "SW_INVALID_PARAMS"),
diff --git a/tangem-core/src/main/java/com/tangem/common/extentions/ByteArray.kt b/tangem-core/src/main/java/com/tangem/common/extentions/ByteArray.kt
index db25eeaadd..cfc35a118b 100644
--- a/tangem-core/src/main/java/com/tangem/common/extentions/ByteArray.kt
+++ b/tangem-core/src/main/java/com/tangem/common/extentions/ByteArray.kt
@@ -5,6 +5,9 @@ import java.security.MessageDigest
import java.util.*
import kotlin.experimental.and
+/**
+ * Extension functions for [ByteArray].
+ */
fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
diff --git a/tangem-core/src/main/java/com/tangem/common/extentions/String.kt b/tangem-core/src/main/java/com/tangem/common/extentions/String.kt
index 656d46bd9e..06a4f1a26e 100644
--- a/tangem-core/src/main/java/com/tangem/common/extentions/String.kt
+++ b/tangem-core/src/main/java/com/tangem/common/extentions/String.kt
@@ -3,7 +3,9 @@ package com.tangem.common.extentions
import java.nio.charset.Charset
import java.security.MessageDigest
-
+/**
+ * Extension functions for [String].
+ */
fun String.calculateSha256(): ByteArray {
val sha256 = MessageDigest.getInstance("SHA-256")
val data = this.toByteArray(Charset.forName("UTF-8"))
diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/Tlv.kt b/tangem-core/src/main/java/com/tangem/common/tlv/Tlv.kt
index b1b2c3b5fa..68063c8d07 100644
--- a/tangem-core/src/main/java/com/tangem/common/tlv/Tlv.kt
+++ b/tangem-core/src/main/java/com/tangem/common/tlv/Tlv.kt
@@ -3,6 +3,9 @@ package com.tangem.common.tlv
import java.io.ByteArrayInputStream
import java.io.IOException
+/**
+ * The data converted to the Tag Length Value protocol.
+ */
class Tlv {
val tag: TlvTag
diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvMapper.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvMapper.kt
index bec99188c8..5829f0600a 100644
--- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvMapper.kt
+++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvMapper.kt
@@ -14,8 +14,22 @@ class MissingTagException(message: String? = null) : TlvMapperException(message)
class WrongTypeException(message: String? = null) : TlvMapperException(message)
class ConversionException(message: String? = null) : TlvMapperException(message)
+/**
+ * Maps value fields in [Tlv] from raw [ByteArray] to concrete classes
+ * according to their [TlvTag] and corresponding [TlvValueType].
+ *
+ * @property tlvList List of TLVs, which values are to be converted to particular classes.
+ */
class TlvMapper(val tlvList: List) {
+ /**
+ * Finds [Tlv] by its [TlvTag].
+ * Returns null if [Tlv] is not found, otherwise converts its value to [T].
+ *
+ * @param tag [TlvTag] of a [Tlv] which value is to be returned.
+ *
+ * @return Value converted to a nullable type [T].
+ */
inline fun mapOptional(tag: TlvTag): T? =
try {
map(tag)
@@ -23,6 +37,17 @@ class TlvMapper(val tlvList: List) {
null
}
+ /**
+ * Finds [Tlv] by its [TlvTag].
+ * Throws [MissingTagException] if [Tlv] is not found,
+ * otherwise converts [Tlv] value to [T].
+ *
+ * @param tag [TlvTag] of a [Tlv] which value is to be returned.
+ *
+ * @return [Tlv] value converted to a nullable type [T].
+ *
+ * @throws [MissingTagException] if no [Tlv] is found by the Tag.
+ */
inline fun map(tag: TlvTag): T {
val tlvValue: ByteArray = tlvList.find { it.tag == tag }?.value
?: if (tag.valueType() == TlvValueType.BoolValue && T::class == Boolean::class) {
diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt
index aa0e0036f8..0b6933f175 100644
--- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt
+++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt
@@ -1,5 +1,8 @@
package com.tangem.common.tlv
+/**
+ * Contains all possible value types that value for [TlvTag] can contain.
+ */
enum class TlvValueType {
HexString,
Utf8String,
@@ -14,6 +17,9 @@ enum class TlvValueType {
SigningMethod
}
+/**
+ * Contains all TLV tags, with their code and descriptive name.
+ */
enum class TlvTag(val code: Int) {
Unknown(0x00),
CardId(0x01),
@@ -97,13 +103,9 @@ enum class TlvTag(val code: Int) {
TerminalPublicKey(0x5C),
TerminalTransactionSignature(0x57);
- fun hasNestedTlv(): Boolean {
- return when (this) {
- TlvTag.CardData -> true
- else -> false
- }
- }
-
+ /**
+ * @return [TlvValueType] associated with a [TlvTag]
+ */
fun valueType(): TlvValueType {
return when (this) {
CardId, Pin, Batch -> TlvValueType.HexString
diff --git a/tangem-core/src/main/java/com/tangem/crypto/CryptoUtils.kt b/tangem-core/src/main/java/com/tangem/crypto/CryptoUtils.kt
index 1dc0d2bc82..32742a3076 100644
--- a/tangem-core/src/main/java/com/tangem/crypto/CryptoUtils.kt
+++ b/tangem-core/src/main/java/com/tangem/crypto/CryptoUtils.kt
@@ -13,21 +13,65 @@ object CryptoUtils {
Security.addProvider(EdDSASecurityProvider())
}
+ /**
+ * Generates ByteArray of random bytes.
+ * It is used, among other things, to generate helper private keys
+ * (not the one for the blockchains, that one is generated on the card and does not leave the card).
+ *
+ * @param length length of the ByteArray that is to be generated.
+ */
fun generateRandomBytes(length: Int): ByteArray {
val bytes = ByteArray(length)
SecureRandom().nextBytes(bytes)
return bytes
}
+ /**
+ * Helper function to verify that the data was signed with a private key that corresponds
+ * to the provided public key.
+ *
+ * @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
+ */
fun verify(publicKey: ByteArray, message: ByteArray, signature: ByteArray,
curve: EllipticCurve = EllipticCurve.Secp256k1): Boolean {
return when (curve) {
- EllipticCurve.Secp256k1 -> verifySecp256k1(publicKey, message, signature)
- EllipticCurve.Ed25519 -> verifyEd25519(publicKey, message, signature)
+ EllipticCurve.Secp256k1 -> Sepc256k1.verify(publicKey, message, signature)
+ EllipticCurve.Ed25519 -> Ed25519.verify(publicKey, message, signature)
+ }
+ }
+
+ /**
+ * 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
+ *
+ * @return Public key [ByteArray]
+ */
+ fun generatePublicKey(
+ privateKeyArray: ByteArray,
+ curve: EllipticCurve = EllipticCurve.Secp256k1
+ ): ByteArray {
+ return when (curve) {
+ EllipticCurve.Secp256k1 -> Sepc256k1.generatePublicKey(privateKeyArray)
+ EllipticCurve.Ed25519 -> Ed25519.generatePublicKey(privateKeyArray)
}
}
}
+/**
+ * Extension function to sign a ByteArray with an elliptic curve cryptography.
+ *
+ * @param privateKeyArray Key to sign data
+ * @param curve Elliptic curve that is used to sign data
+ *
+ * @return Signed data
+ */
fun ByteArray.sign(privateKeyArray: ByteArray, curve: EllipticCurve = EllipticCurve.Secp256k1): ByteArray {
return when (curve) {
EllipticCurve.Secp256k1 -> signSecp256k1(this, privateKeyArray)
diff --git a/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt b/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt
index 4bd9194dc9..10625f335d 100644
--- a/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt
+++ b/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt
@@ -7,12 +7,27 @@ import com.tangem.commands.ReadCommand
import com.tangem.common.CompletionResult
import com.tangem.crypto.CryptoUtils
+/**
+ * Events that [ScanTask] returns on completion of its commands.
+ */
sealed class ScanEvent {
+
+ /**
+ * Contains data from a Tangem card after successful completion of [ReadCommand].
+ */
data class OnReadEvent(val card: Card) : ScanEvent()
+
+ /**
+ * Shows whether the Tangem card was verified on completion of [CheckWalletCommand].
+ */
data class OnVerifyEvent(val isGenuine: Boolean) : ScanEvent()
}
-
+/**
+ * Task that allows to read Tangem card and verify its private key.
+ *
+ * It performs two commands, [ReadCommand] and [CheckWalletCommand], subsequently.
+ */
internal class ScanTask : Task() {
override fun onRun(cardEnvironment: CardEnvironment,
diff --git a/tangem-core/src/main/java/com/tangem/tasks/SingleCommandTask.kt b/tangem-core/src/main/java/com/tangem/tasks/SingleCommandTask.kt
index 96176afdc6..34ed9b0a69 100644
--- a/tangem-core/src/main/java/com/tangem/tasks/SingleCommandTask.kt
+++ b/tangem-core/src/main/java/com/tangem/tasks/SingleCommandTask.kt
@@ -5,6 +5,11 @@ import com.tangem.commands.CommandResponse
import com.tangem.commands.CommandSerializer
import com.tangem.common.CompletionResult
+/**
+ * Allows to perform a single command.
+ *
+ * @property command A command that will be performed.
+ */
class SingleCommandTask(
private val command: CommandSerializer
) : Task() {
diff --git a/tangem-core/src/main/java/com/tangem/tasks/Task.kt b/tangem-core/src/main/java/com/tangem/tasks/Task.kt
index b866f6ad47..3998586946 100644
--- a/tangem-core/src/main/java/com/tangem/tasks/Task.kt
+++ b/tangem-core/src/main/java/com/tangem/tasks/Task.kt
@@ -10,6 +10,10 @@ import com.tangem.common.CompletionResult
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.StatusWord
+/**
+ * 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 TaskError(description: String? = null) : Exception(description) {
class UnknownStatus(sw: Int) : TaskError("Unknown StatusWord: $sw")
class MappingError : TaskError()
@@ -36,24 +40,54 @@ sealed class TaskError(description: String? = null) : Exception(description) {
class HashSizeMustBeEqual() : TaskError()
}
+/**
+ * Events that are are sent in callbacks from [Task].
+ */
sealed class TaskEvent {
+
+ /**
+ * A callback that is triggered by a Task.
+ */
class Event(val data: T) : TaskEvent()
+
+ /**
+ * A callback that is triggered when a [Task] is completed.
+ *
+ * @param error is null if it's a successful completion of a [Task]
+ */
class Completion(val error: TaskError? = null) : TaskEvent()
}
+/**
+ * Allows to perform a group of commands interacting between the card and the application.
+ * A task opens an NFC session, sends commands to the card and receives its responses,
+ * repeats the commands if needed, and closes session after receiving the last answer.
+ */
abstract class Task {
var delegate: CardManagerDelegate? = null
var reader: CardReader? = null
+ /**
+ * This method should be called to run the [Task] and perform all its operations.
+ *
+ * @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) -> Unit) {
delegate?.onNfcSessionStarted()
- reader?.startNfcSession()
+ reader?.openSession()
Log.i(this::class.simpleName!!, "Nfc task is started")
onRun(cardEnvironment, callback)
}
+ /**
+ * Should be called on [Task] completion, whether it was successful or with failure.
+ *
+ * @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()
if (withError) {
@@ -63,9 +97,16 @@ abstract class Task {
}
}
+ /**
+ * In this method the individual Tasks' logic should be implemented.
+ */
protected abstract fun onRun(cardEnvironment: CardEnvironment,
callback: (result: TaskEvent) -> Unit)
+ /**
+ * This method should be called by Tasks in their [onRun] method wherever
+ * they need to communicate with the Tangem Card by launching commands.
+ */
protected fun sendCommand(
command: CommandSerializer,
cardEnvironment: CardEnvironment,
@@ -116,10 +157,10 @@ abstract class Task {
}
is CompletionResult.Failure ->
if (result.error is TaskError.TagLost) {
- delegate?.hideSecurityDelay()
+ delegate?.onTagLost()
} else if (result.error is TaskError.UserCancelledError) {
callback(CompletionResult.Failure(TaskError.UserCancelledError()))
- reader?.readingActive = false
+ reader?.closeSession()
}
}
}
diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultCardManagerDelegate.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultCardManagerDelegate.kt
index e2a6e984f6..4985b73cec 100644
--- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultCardManagerDelegate.kt
+++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultCardManagerDelegate.kt
@@ -14,7 +14,10 @@ import com.tangem.tasks.TaskError
import kotlinx.android.synthetic.main.layout_touch_card.*
import kotlinx.android.synthetic.main.nfc_bottom_sheet.*
-
+/**
+ * Default implementation of [CardManagerDelegate].
+ * If no customisation is required, this is the preferred way to use Tangem SDK.
+ */
class DefaultCardManagerDelegate(private val reader: NfcReader) : CardManagerDelegate {
lateinit var activity: FragmentActivity
diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/NfcLifecycleObserver.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/NfcLifecycleObserver.kt
index f8caac7feb..2406b5c123 100644
--- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/NfcLifecycleObserver.kt
+++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/NfcLifecycleObserver.kt
@@ -6,7 +6,9 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import com.tangem.tangem_sdk_new.nfc.NfcManager
-
+/**
+ * [LifecycleObserver] for [NfcManager], helps to coordinate NFC modes with Activity lifecycle.
+ */
class NfcLifecycleObserver(private var nfcManager: NfcManager) : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcManager.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcManager.kt
index b6e29e445a..cdcb94c1c3 100644
--- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcManager.kt
+++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcManager.kt
@@ -12,6 +12,11 @@ import android.os.Build
import android.os.Bundle
import com.tangem.Log
+/**
+ * Helps use of NFC, leveraging Android NFC functionality.
+ * Launches [NfcAdapter], manages it with [Activity] lifecycle,
+ * enables and disables Nfc Reading Mode, receives NFC [Tag].
+ */
class NfcManager : NfcAdapter.ReaderCallback {
val reader = NfcReader()
diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt
index 713e232cdf..d80afe9c5e 100644
--- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt
+++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt
@@ -10,6 +10,9 @@ import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.ResponseApdu
import com.tangem.tasks.TaskError
+/**
+ * Provides NFC communication between an Android application and Tangem card.
+ */
class NfcReader : CardReader {
override var readingActive = false