Updated on 2026-08-14

This commit is contained in:
Tangem 2019-10-22 10:59:05 +03:00
parent 7e3841c4ef
commit 698575606f
3 changed files with 94 additions and 96 deletions

View file

@ -3,7 +3,11 @@ package com.tangem
import com.tangem.commands.CommandResponse
import com.tangem.commands.CommandSerializer
import com.tangem.commands.SignCommandData
import com.tangem.tasks.*
import com.tangem.crypto.initCrypto
import com.tangem.tasks.ScanEvent
import com.tangem.tasks.ScanTask
import com.tangem.tasks.Task
import com.tangem.tasks.TaskResult
class CardManager(
private val reader: CardReader,
@ -12,30 +16,30 @@ class CardManager(
private val cardEnvironmentRepository = CardEnvironmentRepository(dataStorage)
fun scanCard(callback: (result: TaskResult) -> Unit) {
init {
initCrypto()
}
fun scanCard(callback: (result: ScanEvent, cardEnvironment: CardEnvironment) -> Unit) {
val task = ScanTask(cardManagerDelegate, reader)
runTask(task, cardEnvironmentRepository.cardEnvironment, callback)
}
fun sign(signCommandData: SignCommandData,
callback: (result: TaskResult) -> Unit) {
val task = SignTask(signCommandData, cardManagerDelegate, reader)
runTask(task, cardEnvironmentRepository.cardEnvironment, callback)
// val task = SignTask<SignEvent>(signCommandData, cardManagerDelegate, reader)
// runTask(task, cardEnvironmentRepository.cardEnvironment, callback)
}
fun runTask(task: Task, environment: CardEnvironment? = null,
callback: (result: TaskResult) -> Unit) {
task.run(environment ?: cardEnvironmentRepository.cardEnvironment) {result, returnedEnvironment ->
//TODO: environment is kept in Repository
cardEnvironmentRepository.cardEnvironment = returnedEnvironment
callback.invoke(result)
}
fun <TaskEvent>runTask(task: Task<TaskEvent>, environment: CardEnvironment? = null,
callback: (result: TaskEvent, cardEnvironment: CardEnvironment) -> Unit) {
task.run(environment ?: cardEnvironmentRepository.cardEnvironment, callback)
}
fun runCommand(commandSerializer: CommandSerializer<CommandResponse>,
environment: CardEnvironment? = null,
callback: (result: TaskResult) -> Unit) {
val task = BasicTask<CommandResponse>(commandSerializer, cardManagerDelegate, reader)
runTask(task, environment, callback)
// val task = BasicTask<CommandResponse>(commandSerializer, cardManagerDelegate, reader)
// runTask(task, environment, callback)
}
}

View file

@ -10,20 +10,12 @@ import com.tangem.crypto.verify
sealed class ScanEvent {
data class OnReadEvent(val result: ReadCardResponse) : ScanEvent()
data class OnVerifyEvent(val verified: Boolean) : ScanEvent()
class OnUserCancelledEvent() : ScanEvent()
object OnUserCancelledEvent : ScanEvent()
data class Failure(val error: TaskError) : ScanEvent()
data class Succcess(val result: Any) : ScanEvent()
}
//
//sealed class ScanResult {
// data class ReadResult(val card: Card) : ScanResult()
// data class VerifyResult(val verified: Boolean) : ScanResult()
// data class Failure(val error: TaskError) : ScanResult()
//}
class ScanTask<out: ScanEvent>(delegate: CardManagerDelegate? = null, reader: CardReader) : Task<ScanEvent>(delegate, reader) {
class ScanTask(delegate: CardManagerDelegate? = null, reader: CardReader) : Task<ScanEvent>(delegate, reader) {
private lateinit var readCardData: ReadCardResponse
private lateinit var challenge: ByteArray
@ -34,42 +26,52 @@ class ScanTask<out: ScanEvent>(delegate: CardManagerDelegate? = null, reader: Ca
callback: (result: ScanEvent, cardEnvironment: CardEnvironment) -> Unit) {
val readCommand = ReadCardCommand(cardEnvironment.pin1)
sendCommand(readCommand, cardEnvironment) {
sendCommand(readCommand, cardEnvironment) { readCommandEvent ->
if (it is CommandEvent.Success) {
readCardData = it.response as ReadCardResponse
when (readCommandEvent) {
is CommandEvent.Success -> {
readCardData = readCommandEvent.response as ReadCardResponse
callback(ScanEvent.OnReadEvent(readCardData), cardEnvironment)
callback(ScanEvent.OnReadEvent(readCardData), cardEnvironment)
if (readCardData.curve != null && readCardData.walletPublicKey != null) {
curve = readCardData.curve!!
walletPublickKey = readCardData.walletPublicKey!!
} else {
callback(ScanEvent.Failure(TaskError.CardError()), cardEnvironment)
}
val checkWalletCommand = prepareCheckWalletCommand(cardEnvironment)
sendCommand(checkWalletCommand, cardEnvironment) { checkWalletResult ->
delegate?.closeNfcPopup()
if (checkWalletResult is CommandEvent.Success) {
val checkWalletResponse = checkWalletResult.response as CheckWalletResponse
val verified = verify(walletPublickKey,
challenge + checkWalletResponse.salt,
checkWalletResponse.walletSignature,
curve)
if (verified) {
callback(ScanEvent.OnVerifyEvent(true), cardEnvironment)
} else {
callback(ScanEvent.Failure(TaskError.VefificationFailed()), cardEnvironment)
}
if (readCardData.curve != null && readCardData.walletPublicKey != null) {
curve = readCardData.curve!!
walletPublickKey = readCardData.walletPublicKey!!
} else {
delegate?.closeNfcPopup()
callback(ScanEvent.Failure(TaskError.CardError()), cardEnvironment)
}
val checkWalletCommand = prepareCheckWalletCommand(cardEnvironment)
sendCommand(checkWalletCommand, cardEnvironment) { checkWalletEvent ->
delegate?.closeNfcPopup()
when (checkWalletEvent) {
is CommandEvent.Success -> {
val checkWalletResponse = checkWalletEvent.response as CheckWalletResponse
val verified = verify(walletPublickKey,
challenge + checkWalletResponse.salt,
checkWalletResponse.walletSignature,
curve)
if (verified) {
callback(ScanEvent.OnVerifyEvent(true), cardEnvironment)
} else {
callback(ScanEvent.Failure(TaskError.VefificationFailed()), cardEnvironment)
}
}
is CommandEvent.Failure ->
callback(ScanEvent.Failure(checkWalletEvent.taskError), cardEnvironment)
is CommandEvent.UserCancellation ->
callback(ScanEvent.OnUserCancelledEvent, cardEnvironment)
}
}
}
} else {
//TODO: Handle error
is CommandEvent.Failure ->
callback(ScanEvent.Failure(readCommandEvent.taskError), cardEnvironment)
is CommandEvent.UserCancellation ->
callback(ScanEvent.OnUserCancelledEvent, cardEnvironment)
}
}
}

View file

@ -21,8 +21,8 @@ abstract class Task<T>(protected val delegate: CardManagerDelegate? = null, priv
abstract fun onRun(cardEnvironment: CardEnvironment,
callback: (result: T, cardEnvironment: CardEnvironment) -> Unit)
protected fun <T: CommandResponse>sendCommand(commandSerializer: CommandSerializer<T>, cardEnvironment: CardEnvironment,
callback: (result: CommandEvent) -> Unit) {
protected fun <T : CommandResponse> sendCommand(commandSerializer: CommandSerializer<T>, cardEnvironment: CardEnvironment,
callback: (result: CommandEvent) -> Unit) {
reader.sendApdu(
commandSerializer.serialize(cardEnvironment).toBytes()) { responseApdu ->
@ -30,34 +30,21 @@ abstract class Task<T>(protected val delegate: CardManagerDelegate? = null, priv
when (responseApdu.status) {
Status.ProcessCompleted, Status.Pin1Changed, Status.Pin2Changed, Status.PinsChanged
-> {
val responseData = commandSerializer.deserialize(cardEnvironment, responseApdu)
if (responseData == null) {
} else {
callback(
CommandEvent.Success(responseData)
)
try {
val responseData = commandSerializer.deserialize(cardEnvironment, responseApdu)
callback(CommandEvent.Success(responseData as T))
} catch (error: TaskError) {
callback(CommandEvent.Failure(error))
}
}
Status.InvalidParams -> TODO()
Status.ErrorProcessingCommand -> TODO()
Status.InvalidState -> TODO()
Status.InvalidParams -> callback(CommandEvent.Failure(TaskError.InvalidParams()))
Status.ErrorProcessingCommand -> callback(CommandEvent.Failure(TaskError.ErrorProcessingCommand()))
Status.InvalidState -> callback(CommandEvent.Failure(TaskError.InvalidState()))
Status.InsNotSupported -> TODO()
Status.NeedEnctryption -> TODO()
Status.NeedPause -> TODO()
Status.InsNotSupported -> callback(CommandEvent.Failure(TaskError.InsNotSupported()))
Status.NeedEncryption -> callback(CommandEvent.Failure(TaskError.NeedEncryption()))
Status.NeedPause -> callback(CommandEvent.Failure(TaskError.NeedPause()))
}
// val parsedApdu = responseApdu.getTlvData()
// if (parsedApdu == null) callback.invoke(TaskResult.Error(CardError()))
// else if (!parsedApdu.statusCompleted()) {
// callback.invoke(TaskResult.Error(CardError(parsedApdu.status.code)))
// } else {
// val response = commandSerializer.deserialize(parsedApdu)
// callback.invoke(response)
// }
}
}
}
@ -65,12 +52,18 @@ abstract class Task<T>(protected val delegate: CardManagerDelegate? = null, priv
sealed class TaskError : Exception() {
class UnknownStatus(sw: Int) : TaskError()
class MappingError : TaskError()
class ErrorProcessingCommand : TaskError()
class InvalidState : TaskError()
class InsNotSupported : TaskError()
class InvalidParams : TaskError()
class NeedEncryption : TaskError()
class NeedPause : TaskError()
class VefificationFailed : TaskError()
class CardError : TaskError()
class ReaderError() : TaskError()
class SerializeCommandError() : TaskError()
}
sealed class TaskResult {
@ -80,23 +73,22 @@ sealed class TaskResult {
}
class BasicTask<T: CommandResponse>(
private val commandSerializer: CommandSerializer<CommandResponse>,
delegate: CardManagerDelegate? = null,
reader: CardReader) : Task(delegate, reader) {
override fun onRun(cardEnvironment: CardEnvironment,
callback: (result: TaskResult, cardEnvironment: CardEnvironment) -> Unit) {
sendCommand(commandSerializer, cardEnvironment) {
callback.invoke(it, updateEnvironment())
}
}
private fun updateEnvironment(): CardEnvironment {
//TODO: set logic of changing CardEnvironment when needed
return CardEnvironment()
}
}
//class BasicTask<T: CommandResponse>(
// private val commandSerializer: CommandSerializer<CommandResponse>,
// delegate: CardManagerDelegate? = null,
// reader: CardReader) : Task(delegate, reader) {
//
// override fun onRun(cardEnvironment: CardEnvironment,
// callback: (result: TaskResult, cardEnvironment: CardEnvironment) -> Unit) {
// sendCommand(commandSerializer, cardEnvironment) {
// callback.invoke(it, updateEnvironment())
// }
// }
//
// private fun updateEnvironment(): CardEnvironment {
// //TODO: set logic of changing CardEnvironment when needed
// return CardEnvironment()
// }
//}