add sign interface

This commit is contained in:
Michele Balistreri 2019-11-06 17:38:10 +03:00
parent aad3a2bf9a
commit 503743d527
No known key found for this signature in database
GPG Key ID: E9567DA33A4F791A
7 changed files with 128 additions and 8 deletions

View File

@ -10,13 +10,14 @@
android:required="true" /> android:required="true" />
<application <application
android:hardwareAccelerated="true"
android:allowBackup="true" android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<activity android:name=".ui.SignMessageActivity"></activity>
<activity android:name=".ui.PUKActivity" /> <activity android:name=".ui.PUKActivity" />
<activity android:name=".ui.ChangePINActivity" /> <activity android:name=".ui.ChangePINActivity" />
<activity android:name=".ui.InitActivity" /> <activity android:name=".ui.InitActivity" />

View File

@ -11,6 +11,9 @@ const val INIT_ACTIVITY_PIN = "initPIN"
const val INIT_ACTIVITY_PUK = "initPUK" const val INIT_ACTIVITY_PUK = "initPUK"
const val INIT_ACTIVITY_PAIRING = "initPairing" const val INIT_ACTIVITY_PAIRING = "initPairing"
const val SIGN_TEXT_MESSAGE = "signMessage"
const val REQ_INTERACTIVE_SCRIPT = 0x01 const val REQ_INTERACTIVE_SCRIPT = 0x01
const val REQ_WALLETCONNECT = 0x02
const val CACHE_VALIDITY = 15 * 60 * 1000 const val CACHE_VALIDITY = 15 * 60 * 1000

View File

@ -17,6 +17,7 @@ import kotlin.reflect.KClass
import androidx.core.app.ComponentActivity.ExtraData import androidx.core.app.ComponentActivity.ExtraData
import androidx.core.content.ContextCompat.getSystemService import androidx.core.content.ContextCompat.getSystemService
import com.google.zxing.client.android.Intents import com.google.zxing.client.android.Intents
import im.status.keycard.connect.data.REQ_WALLETCONNECT
class MainActivity : AppCompatActivity(), ScriptListener { class MainActivity : AppCompatActivity(), ScriptListener {
private lateinit var viewSwitcher: ViewSwitcher private lateinit var viewSwitcher: ViewSwitcher
@ -49,6 +50,7 @@ class MainActivity : AppCompatActivity(), ScriptListener {
when (requestCode) { when (requestCode) {
REQ_INTERACTIVE_SCRIPT -> Registry.scriptExecutor.onUserInteractionReturned(resultCode, data) REQ_INTERACTIVE_SCRIPT -> Registry.scriptExecutor.onUserInteractionReturned(resultCode, data)
REQ_WALLETCONNECT -> Registry.walletConnect.onUserInteractionReturned(resultCode, data)
IntentIntegrator.REQUEST_CODE -> qrCodeScanned(resultCode, data) IntentIntegrator.REQUEST_CODE -> qrCodeScanned(resultCode, data)
} }
} }

View File

@ -0,0 +1,29 @@
package im.status.keycard.connect.ui
import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.TextView
import im.status.keycard.connect.R
import im.status.keycard.connect.data.SIGN_TEXT_MESSAGE
class SignMessageActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign_message)
val signText = findViewById<TextView>(R.id.signText)
signText.text = intent.getStringExtra(SIGN_TEXT_MESSAGE)
}
fun sign(@Suppress("UNUSED_PARAMETER") view: View) {
setResult(Activity.RESULT_OK)
finish()
}
fun reject(@Suppress("UNUSED_PARAMETER") view: View) {
setResult(Activity.RESULT_CANCELED)
finish()
}
}

View File

@ -1,5 +1,7 @@
package im.status.keycard.connect.walletconnect package im.status.keycard.connect.walletconnect
import android.app.Activity
import android.content.Intent
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import im.status.keycard.applet.BIP32KeyPair import im.status.keycard.applet.BIP32KeyPair
@ -8,6 +10,9 @@ import im.status.keycard.connect.Registry
import im.status.keycard.connect.card.ExportKeyCommand import im.status.keycard.connect.card.ExportKeyCommand
import im.status.keycard.connect.card.SignCommand import im.status.keycard.connect.card.SignCommand
import im.status.keycard.connect.card.scriptWithAuthentication import im.status.keycard.connect.card.scriptWithAuthentication
import im.status.keycard.connect.data.REQ_WALLETCONNECT
import im.status.keycard.connect.data.SIGN_TEXT_MESSAGE
import im.status.keycard.connect.ui.SignMessageActivity
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -30,6 +35,7 @@ class WalletConnect : ExportKeyCommand.Listener, SignCommand.Listener {
private val sessionStore = FileWCSessionStore(File(Registry.mainActivity.filesDir, "wcSessions.json").apply { createNewFile() }, moshi) private val sessionStore = FileWCSessionStore(File(Registry.mainActivity.filesDir, "wcSessions.json").apply { createNewFile() }, moshi)
private var session: WCSession? = null private var session: WCSession? = null
private var requestId: Long = 0 private var requestId: Long = 0
private var action: (data: Intent?) -> Unit = this::nop
private val sessionCB = object : Session.Callback { private val sessionCB = object : Session.Callback {
override fun onStatus(status: Session.Status) { override fun onStatus(status: Session.Status) {
@ -69,6 +75,10 @@ class WalletConnect : ExportKeyCommand.Listener, SignCommand.Listener {
session?.rejectRequest(call.id, 1L, "Not implemented yet") session?.rejectRequest(call.id, 1L, "Not implemented yet")
} }
"eth_signTransaction" -> {
session?.rejectRequest(call.id, 1L, "Not implemented yet")
}
"eth_sendRawTransaction" -> { "eth_sendRawTransaction" -> {
session?.rejectRequest(call.id, 1L, "Not implemented yet") session?.rejectRequest(call.id, 1L, "Not implemented yet")
} }
@ -79,14 +89,36 @@ class WalletConnect : ExportKeyCommand.Listener, SignCommand.Listener {
} }
private fun signText(id: Long, message: String) { private fun signText(id: Long, message: String) {
requestId = id
val msg = Hex.decode(if (message.startsWith("0x", true)) message.drop(2) else message) val msg = Hex.decode(if (message.startsWith("0x", true)) message.drop(2) else message)
val keccak256 = Keccak.Digest256() val text = String(msg)
val hash = keccak256.digest(byteArrayOf(0x19) + "Ethereum Signed Message:\n${msg.size}".toByteArray() + msg)
Registry.scriptExecutor.runScript(scriptWithAuthentication().plus(SignCommand(Registry.walletConnect, hash))) requestId = id
action = {
val keccak256 = Keccak.Digest256()
val hash = keccak256.digest(byteArrayOf(0x19) + "Ethereum Signed Message:\n${msg.size}".toByteArray() + msg)
Registry.scriptExecutor.runScript(scriptWithAuthentication().plus(SignCommand(Registry.walletConnect, hash)))
}
val intent = Intent(Registry.mainActivity, SignMessageActivity::class.java).apply {
putExtra(SIGN_TEXT_MESSAGE, text)
}
Registry.mainActivity.startActivityForResult(intent, REQ_WALLETCONNECT)
} }
} }
private fun nop(@Suppress("UNUSED_PARAMETER") data: Intent?) { }
fun onUserInteractionReturned(resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK) {
action.invoke(data)
} else {
session?.rejectRequest(requestId, -1, "Rejected by user")
}
action = this::nop
}
fun connect(uri: String) { fun connect(uri: String) {
scope.launch { scope.launch {
session?.kill() session?.kill()
@ -114,7 +146,6 @@ class WalletConnect : ExportKeyCommand.Listener, SignCommand.Listener {
override fun onResponse(signature: RecoverableSignature) { override fun onResponse(signature: RecoverableSignature) {
scope.launch { scope.launch {
session?.approveRequest(requestId, "0x${toHexString(signature.r)}${toHexString(signature.s)}${toHexString(byteArrayOf(signature.recId.toByte()))}") session?.approveRequest(requestId, "0x${toHexString(signature.r)}${toHexString(signature.s)}${toHexString(byteArrayOf(signature.recId.toByte()))}")
//session?.rejectRequest(requestId, -1, "Rejected by user")
} }
} }
} }

View File

@ -0,0 +1,51 @@
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.SignMessageActivity">
<TextView
android:id="@+id/signTextLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="52dp"
android:text="@string/sign_text_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/signButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:layout_marginEnd="68dp"
android:onClick="sign"
android:text="@string/sign_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/signText" />
<Button
android:id="@+id/rejectButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="64dp"
android:layout_marginTop="80dp"
android:onClick="reject"
android:text="@string/reject_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/signText" />
<TextView
android:id="@+id/signText"
android:layout_width="306dp"
android:layout_height="389dp"
android:layout_marginTop="52dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/signTextLabel" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -10,7 +10,10 @@
<string name="title_activity_change_pin">ChangePINActivity</string> <string name="title_activity_change_pin">ChangePINActivity</string>
<string name="change_pin_prompt">New PIN</string> <string name="change_pin_prompt">New PIN</string>
<string name="change_pin">Change PIN</string> <string name="change_pin">Change PIN</string>
<string name="puk_prompt" >Insert your PUK</string> <string name="puk_prompt">Insert your PUK</string>
<string name="nfc_prompt">Tap your card</string> <string name="nfc_prompt">Tap your card</string>
<string name="connect_wallet" >Connect to WalletConnect</string> <string name="connect_wallet">Connect to WalletConnect</string>
<string name="sign_button">Sign</string>
<string name="reject_button">Reject</string>
<string name="sign_text_label">Sign a message</string>
</resources> </resources>