add tap prompt

This commit is contained in:
Michele Balistreri 2019-11-04 15:07:31 +03:00
parent fe4af3e5d8
commit 9c1f4fb612
No known key found for this signature in database
GPG Key ID: E9567DA33A4F791A
10 changed files with 93 additions and 21 deletions

View File

@ -25,12 +25,12 @@ object Registry {
lateinit var nfcAdapter: NfcAdapter
private set
fun init(activity: Activity) {
fun init(activity: Activity, listener: ScriptListener) {
pairingManager = PairingManager(activity)
pinCache = PINCache()
nfcAdapter = NfcAdapter.getDefaultAdapter(activity)
scriptExecutor = CardScriptExecutor(activity)
scriptExecutor = CardScriptExecutor(activity, listener)
cardManager = NFCCardManager()
cardManager.setCardListener(scriptExecutor)

View File

@ -6,7 +6,7 @@ import im.status.keycard.applet.KeycardCommandSet
import im.status.keycard.io.CardChannel
import im.status.keycard.io.CardListener
class CardScriptExecutor(private val activity: Activity) : CardListener {
class CardScriptExecutor(private val activity: Activity, private val listener: ScriptListener) : CardListener {
class ScriptContext(val activity: Activity, val cmdSet: KeycardCommandSet)
enum class State {
@ -23,24 +23,25 @@ class CardScriptExecutor(private val activity: Activity) : CardListener {
val executionContext = ScriptContext(activity, KeycardCommandSet(channel))
if (state == State.READY) {
state = State.RUNNING
startScript()
} else if (state == State.UX_ONGOING) {
return
}
val runningScript = script ?: defaultScript ?: return
var success = true
script@for (cmd in runningScript) {
when (cmd.run(executionContext)) {
CardCommand.Result.OK -> {}
CardCommand.Result.CANCEL -> { break@script}
CardCommand.Result.CANCEL -> { success = false; break@script}
CardCommand.Result.UX_ONGOING -> { waitingCmd = cmd; return }
CardCommand.Result.RETRY -> { return }
}
}
script = null
state = State.READY
finishScript(if (success) CardCommand.Result.OK else CardCommand.Result.CANCEL)
}
override fun onDisconnected() {
@ -52,22 +53,30 @@ class CardScriptExecutor(private val activity: Activity) : CardListener {
waitingCmd?.onDataReceived(data)
state = State.RUNNING
} else {
script = null
state = State.READY
cancelScript()
}
}
fun runScript(script: List<CardCommand>): Boolean {
if (state == State.READY) {
this.script = script
startScript()
return true
}
return false
}
fun cancelScript() {
fun cancelScript() = finishScript(CardCommand.Result.CANCEL)
private fun finishScript(result: CardCommand.Result) {
script = null
state = State.READY
listener.onScriptFinished(result)
}
private fun startScript() {
state = State.RUNNING
listener.onScriptStarted()
}
}

View File

@ -25,16 +25,16 @@ class InitCommand : CardCommand {
}
if (initPIN != null && initPUK != null && initPairing != null) {
try {
return try {
context.cmdSet.init(initPIN, initPUK, initPairing).checkOK()
context.cmdSet.select().checkOK()
context.cmdSet.autoPair(initPairing)
Registry.pairingManager.putPairing(context.cmdSet.applicationInfo.instanceUID, context.cmdSet.pairing)
return CardCommand.Result.OK
CardCommand.Result.OK
} catch (e: IOException) {
return CardCommand.Result.RETRY
CardCommand.Result.RETRY
} catch (e: APDUException) {
return CardCommand.Result.CANCEL
CardCommand.Result.CANCEL
} finally {
initPIN = null
initPUK = null

View File

@ -0,0 +1,6 @@
package im.status.keycard.connect.card
interface ScriptListener {
fun onScriptStarted()
fun onScriptFinished(result: CardCommand.Result)
}

View File

@ -48,7 +48,7 @@ class InitActivity : AppCompatActivity() {
finish()
}
fun randomToken(length: Int): String {
private fun randomToken(length: Int): String {
return Base64.encodeToString(Crypto.randomBytes(length), NO_PADDING or NO_WRAP)
}
}

View File

@ -5,18 +5,28 @@ import android.nfc.NfcAdapter
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.widget.ViewSwitcher
import im.status.keycard.connect.R
import im.status.keycard.connect.Registry
import im.status.keycard.connect.card.*
import im.status.keycard.connect.data.REQ_INTERACTIVE_SCRIPT
import kotlin.reflect.KClass
class MainActivity : AppCompatActivity() {
class MainActivity : AppCompatActivity(), ScriptListener {
private lateinit var viewSwitcher: ViewSwitcher
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Registry.init(this)
viewSwitcher = ViewSwitcher(this)
val inflater = LayoutInflater.from(this)
inflater.inflate(R.layout.activity_main, viewSwitcher)
inflater.inflate(R.layout.activity_nfc, viewSwitcher)
setContentView(viewSwitcher)
Registry.init(this, this)
Registry.scriptExecutor.defaultScript = cardCheckupScript()
}
@ -38,6 +48,22 @@ class MainActivity : AppCompatActivity() {
}
}
override fun onScriptStarted() {
this.runOnUiThread {
viewSwitcher.showNext()
}
}
override fun onScriptFinished(result: CardCommand.Result) {
this.runOnUiThread {
viewSwitcher.showNext()
}
}
fun cancelNFC(@Suppress("UNUSED_PARAMETER") view: View) {
Registry.scriptExecutor.cancelScript()
}
fun changePIN(@Suppress("UNUSED_PARAMETER") view: View) {
startCommand(ChangePINActivity::class)
}

View File

@ -8,7 +8,6 @@ import android.widget.EditText
import android.widget.TextView
import im.status.keycard.connect.R
import im.status.keycard.connect.Registry
import im.status.keycard.connect.data.PINCache
import im.status.keycard.connect.data.PIN_ACTIVITY_ATTEMPTS
import im.status.keycard.connect.data.PIN_ACTIVITY_CARD_UID

View File

@ -8,8 +8,6 @@ import android.widget.EditText
import android.widget.TextView
import im.status.keycard.connect.R
import im.status.keycard.connect.Registry
import im.status.keycard.connect.data.PIN_ACTIVITY_ATTEMPTS
import im.status.keycard.connect.data.PIN_ACTIVITY_CARD_UID
import im.status.keycard.connect.data.PUK_ACTIVITY_ATTEMPTS
class PUKActivity : AppCompatActivity() {

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?attr/actionBarSize"
tools:context=".ui.MainActivity">
<TextView
android:id="@+id/nfcPrompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nfc_prompt"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2" />
<Button
android:id="@+id/cancelButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="128dp"
android:onClick="cancelNFC"
android:text="@android:string/cancel"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -11,4 +11,5 @@
<string name="change_pin_prompt">New PIN</string>
<string name="change_pin">Change PIN</string>
<string name="puk_prompt" >Insert your PUK</string>
<string name="nfc_prompt">Tap your card</string>
</resources>