Skip to content

Commit

Permalink
chore: update sample app to showcase sdk verification
Browse files Browse the repository at this point in the history
  • Loading branch information
cristianIOHK committed May 6, 2024
1 parent ce3772f commit 989438e
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ import com.nimbusds.jwt.JWTClaimsSet
import com.nimbusds.jwt.SignedJWT
import io.iohk.atala.prism.apollo.base64.base64UrlDecoded
import io.iohk.atala.prism.apollo.utils.KMMEllipticCurve
import io.iohk.atala.prism.walletsdk.apollo.utils.Ed25519PublicKey
import io.iohk.atala.prism.walletsdk.apollo.utils.Secp256k1PrivateKey
import io.iohk.atala.prism.walletsdk.apollo.utils.Secp256k1PublicKey
import io.iohk.atala.prism.walletsdk.apollo.utils.X25519PrivateKey
import io.iohk.atala.prism.walletsdk.apollo.utils.X25519PublicKey
import io.iohk.atala.prism.walletsdk.domain.buildingblocks.Castor
import io.iohk.atala.prism.walletsdk.domain.buildingblocks.Pollux
import io.iohk.atala.prism.walletsdk.domain.models.Api
Expand Down Expand Up @@ -693,6 +697,7 @@ class PolluxImpl(
property::class == DIDDocument.Authentication::class
} as DIDDocument.Authentication


val proof = Proof(
type = "EcdsaSecp256k1Signature2019",
created = dateFormat.format(getTimeMillis() * 1000L),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,8 @@ class PrismAgent {
attachments = arrayOf(attachmentDescriptor),
thid = UUID.randomUUID().toString(),
from = newPeerDID,
to = toDID
to = toDID,
direction = Message.Direction.SENT
)

connectionManager.sendMessage(presentationRequest.makeMessage())
Expand Down Expand Up @@ -1084,8 +1085,6 @@ class PrismAgent {
suspend fun handlePresentationSubmission(msg: Message): Boolean {
val presentation = Presentation.fromMessage(msg)
val fromDID = presentation.from
val didDoc = this.castor.resolveDID(fromDID.toString())
val publicKeys = CastorShared.getKeyPairFromCoreProperties(didDoc.coreProperties)

val msgAttachmentDescriptor =
presentation.attachments.find { it.data::class == AttachmentBase64::class }
Expand All @@ -1102,7 +1101,7 @@ class PrismAgent {
}

val isProofVerified = presentation.thid?.let { thid ->
pluto.getMessageByThidAndPiuri(thid, presentation.type).firstOrNull()
pluto.getMessageByThidAndPiuri(thid, ProtocolType.DidcommRequestPresentation.value).firstOrNull()
?.let { message ->
val requestPresentation = RequestPresentation.fromMessage(message)
val challenge = requestPresentation.body.goalCode
Expand All @@ -1115,9 +1114,13 @@ class PrismAgent {
}
}
} ?: false

val isJWTVerified = proof.jws?.let { jws ->
val jwt = JWTCredential(proof.jws)
val diddoc = castor.resolveDID(jwt.jwtPayload.iss)
val publicKeysIssuer = CastorShared.getKeyPairFromCoreProperties(diddoc.coreProperties)
// In this first version we expect only one public key
val publicKey = publicKeys.first()
val publicKey = publicKeysIssuer.first()
pollux.verifyPresentationSubmissionJWT(jws, publicKey)
} ?: false
return isProofVerified && isJWTVerified
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ data class RequestPresentation(
val attachments: Array<AttachmentDescriptor>,
val thid: String? = null,
val from: DID,
val to: DID
val to: DID,
val direction: Message.Direction = Message.Direction.RECEIVED
) {

val type = ProtocolType.DidcommRequestPresentation.value
Expand All @@ -53,7 +54,8 @@ data class RequestPresentation(
to = this.to,
body = Json.encodeToString(this.body),
attachments = this.attachments,
thid = this.thid
thid = this.thid,
direction = direction
)
}

Expand Down Expand Up @@ -129,7 +131,8 @@ data class RequestPresentation(
attachments = fromMessage.attachments,
thid = fromMessage.thid,
from = fromMessage.from,
to = fromMessage.to
to = fromMessage.to,
direction = fromMessage.direction
)
} else {
throw PrismAgentError.InvalidMessageType(
Expand Down Expand Up @@ -161,7 +164,8 @@ data class RequestPresentation(
attachments = request.attachments,
thid = msg.id,
from = request.to,
to = request.from
to = request.from,
direction = msg.direction
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,5 @@ fetchMessageByThidAndPiuri:
SELECT *
FROM Message
WHERE `thid` = :thid
AND `type` = :piuri;

AND `type` = :piuri
AND `isReceived` = 0;
6 changes: 5 additions & 1 deletion sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/Sdk.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import io.iohk.atala.prism.walletsdk.apollo.ApolloImpl
import io.iohk.atala.prism.walletsdk.castor.CastorImpl
import io.iohk.atala.prism.walletsdk.castor.resolvers.PrismDIDApiResolver
import io.iohk.atala.prism.walletsdk.domain.buildingblocks.Apollo
import io.iohk.atala.prism.walletsdk.domain.buildingblocks.Castor
import io.iohk.atala.prism.walletsdk.domain.buildingblocks.Mercury
Expand Down Expand Up @@ -81,7 +82,10 @@ class Sdk {
}

private fun createCastor(): Castor {
return CastorImpl(apollo)
val castor = CastorImpl(apollo)
val prismDIDApiResolver = PrismDIDApiResolver(this.apollo, "http://192.168.68.103:8000/prism-agent")
castor.addResolver(prismDIDApiResolver)
return castor
}

private fun createMercury(): MercuryImpl {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.iohk.atala.prism.sampleapp.ui.messages

import android.app.AlertDialog
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.EditText
import android.widget.Spinner
import androidx.fragment.app.DialogFragment
import io.iohk.atala.prism.sampleapp.R
import io.iohk.atala.prism.walletsdk.domain.models.DID

class InitiateVerificationDialogFragment(
private val viewModel: MessagesViewModel
) : DialogFragment() {

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(activity)
// Inflate and set the layout for the dialog
val inflater = requireActivity().layoutInflater
val view = inflater.inflate(R.layout.dialog_initiate_verification, null)

// Set up EditText
val toDID = view.findViewById<EditText>(R.id.to)

// Set up the buttons
builder.setView(view)
.setPositiveButton("Accept") { _, _ ->
if (toDID.text.isNotBlank()) {
// viewModel.sendMessage(DID(toDID.text.toString()))
viewModel.sendVerificationRequest(toDID.text.toString())
}
}
.setNegativeButton("Cancel") { _, _ ->
this.dismiss()
}

return builder.create()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@ import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import io.iohk.atala.prism.sampleapp.R
import io.iohk.atala.prism.sampleapp.Sdk
import io.iohk.atala.prism.walletsdk.domain.models.AttachmentBase64
import io.iohk.atala.prism.walletsdk.domain.models.Message
import io.iohk.atala.prism.walletsdk.prismagent.protocols.ProtocolType
import io.iohk.atala.prism.walletsdk.prismagent.protocols.proofOfPresentation.PresentationSubmission
import io.ktor.util.decodeBase64String
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json

class MessagesAdapter(private var data: MutableList<Message> = mutableListOf()) :
RecyclerView.Adapter<MessagesAdapter.MessageHolder>() {
Expand Down Expand Up @@ -55,9 +64,28 @@ class MessagesAdapter(private var data: MutableList<Message> = mutableListOf())
private val type: TextView = itemView.findViewById(R.id.message_type)
private val body: TextView = itemView.findViewById(R.id.message)

@OptIn(DelicateCoroutinesApi::class)
fun bind(message: Message) {
type.text = message.piuri
this.body.text = message.body
if (message.piuri == ProtocolType.DidcommPresentation.value) {
GlobalScope.launch {
val sdk = Sdk.getInstance()
if (sdk.agent.handlePresentationSubmission(message)) {
val attachmentData = message.attachments.first().data
if (attachmentData::class == AttachmentBase64::class) {
attachmentData as AttachmentBase64
val decoded = attachmentData.base64.decodeBase64String()
val presentationSubmission = Json.decodeFromString<PresentationSubmission>(decoded)
presentationSubmission.verifiableCredential.forEach {
println("stop")
}
}
} else {
// TODO: Change UI body to say invalid presentation
}
}
this.body.text = message.body
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.iohk.atala.prism.sampleapp.ui.messages

import android.app.AlertDialog
import android.content.DialogInterface
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
Expand Down Expand Up @@ -36,6 +37,12 @@ class MessagesFragment : Fragment() {
binding.sendMessage.setOnClickListener {
viewModel.sendMessage()
}
binding.sendVerification.setOnClickListener {
InitiateVerificationDialogFragment(viewModel).show(
parentFragmentManager,
"InitiateVerificationDialogFragment"
)
}
setupStreamObservers()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import io.iohk.atala.prism.sampleapp.Sdk
import io.iohk.atala.prism.sampleapp.db.AppDatabase
import io.iohk.atala.prism.sampleapp.db.DatabaseClient
import io.iohk.atala.prism.walletsdk.domain.models.Credential
import io.iohk.atala.prism.walletsdk.domain.models.CredentialType
import io.iohk.atala.prism.walletsdk.domain.models.DID
import io.iohk.atala.prism.walletsdk.domain.models.DIDDocument
import io.iohk.atala.prism.walletsdk.domain.models.Message
import io.iohk.atala.prism.walletsdk.prismagent.DIDCOMM1
import io.iohk.atala.prism.walletsdk.prismagent.DIDCOMM_MESSAGING
import io.iohk.atala.prism.walletsdk.prismagent.protocols.ProtocolType
import io.iohk.atala.prism.walletsdk.prismagent.protocols.issueCredential.IssueCredential
import io.iohk.atala.prism.walletsdk.prismagent.protocols.issueCredential.OfferCredential
import io.iohk.atala.prism.walletsdk.prismagent.protocols.proofOfPresentation.ProofTypes
import io.iohk.atala.prism.walletsdk.prismagent.protocols.proofOfPresentation.RequestPresentation
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -28,7 +31,6 @@ class MessagesViewModel(application: Application) : AndroidViewModel(application
private var messages: MutableLiveData<List<Message>> = MutableLiveData()
private var proofRequestToProcess: MutableLiveData<Pair<Message, List<Credential>>> =
MutableLiveData()
private var presentationDone = false
private val issuedCredentials: ArrayList<String> = arrayListOf()
private val processedOffers: ArrayList<String> = arrayListOf()
private val db: AppDatabase = DatabaseClient.getInstance()
Expand Down Expand Up @@ -61,7 +63,7 @@ class MessagesViewModel(application: Application) : AndroidViewModel(application
return messages
}

fun sendMessage() {
fun sendMessage(toDID: DID? = null) {
CoroutineScope(Dispatchers.Default).launch {
val sdk = Sdk.getInstance()
val did = sdk.agent.createNewPeerDID(
Expand All @@ -79,13 +81,30 @@ class MessagesViewModel(application: Application) : AndroidViewModel(application
// TODO: This should be on ProtocolTypes as an enum
piuri = "https://didcomm.org/basicmessage/2.0/message",
from = did,
to = did,
to = toDID ?: did,
body = "{\"msg\":\"This is a new test message ${time}\"}"
)
sdk.mercury.sendMessage(message)
}
}

fun sendVerificationRequest(toDID: String) {
CoroutineScope(Dispatchers.Default).launch {
val sdk = Sdk.getInstance()
sdk.agent.initiatePresentationRequest(
type = CredentialType.JWT,
toDID = DID(toDID),
proofTypes = arrayOf(
ProofTypes(
schema = "",
requiredFields = emptyArray(),
trustIssuers = emptyArray()
)
)
)
}
}

fun proofRequestToProcess(): LiveData<Pair<Message, List<Credential>>> {
return proofRequestToProcess
}
Expand Down Expand Up @@ -173,23 +192,17 @@ class MessagesViewModel(application: Application) : AndroidViewModel(application
}
}

if (message.piuri == ProtocolType.DidcommRequestPresentation.value && !presentationDone) {
if (message.piuri == ProtocolType.DidcommRequestPresentation.value && message.direction == Message.Direction.RECEIVED) {
viewModelScope.launch {
agent.getAllCredentials().collect {
proofRequestToProcess.postValue(Pair(message, it))
// // TODO: Show dialog and wait for the selected credential to prepare the presentation proof
// val credential = it.first()
// val presentation = agent.preparePresentationForRequestProof(
// RequestPresentation.fromMessage(message),
// credential
// )
// mercury.sendMessage(presentation.makeMessage())
}
}
}
db.messageDao()
.updateMessage(MessageEntity(messageId = message.id, isRead = true))
}

db.messageDao()
.updateMessage(MessageEntity(messageId = message.id, isRead = true))
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions sampleapp/src/main/res/layout/dialog_initiate_verification.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:padding="16dp">

<EditText
android:id="@+id/to"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="To DID"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
12 changes: 12 additions & 0 deletions sampleapp/src/main/res/layout/fragment_messages.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,17 @@
app:layout_constraintEnd_toEndOf="parent"
android:contentDescription="@string/todo"/>

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/send_verification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:visibility="visible"
android:src="?android:attr/fingerprintAuthDrawable"
app:tint="@color/white"
app:layout_constraintBottom_toTopOf="@id/send_message"
app:layout_constraintEnd_toEndOf="parent"
android:contentDescription="@string/todo"/>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
3 changes: 2 additions & 1 deletion sampleapp/src/main/res/layout/placeholder_did.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/cardview_dark_background"
android:background="#B9B7B7"
android:orientation="vertical"
android:padding="8dp">

<TextView
android:id="@+id/did"
android:textIsSelectable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

Expand Down
2 changes: 1 addition & 1 deletion sampleapp/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<string name="mediator_did">Mediator DID:</string>
<string name="agent_status_label">Agent status:</string>
<string name="mediator_did_value">
did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHBzOi8vc2l0LXByaXNtLW1lZGlhdG9yLmF0YWxhcHJpc20uaW8iLCJhIjpbImRpZGNvbW0vdjIiXX19.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzczovL3NpdC1wcmlzbS1tZWRpYXRvci5hdGFsYXByaXNtLmlvL3dzIiwiYSI6WyJkaWRjb21tL3YyIl19fQ
did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjoiaHR0cDovLzE5Mi4xNjguNjguMTAzOjgwODAiLCJyIjpbXSwiYSI6WyJkaWRjb21tL3YyIl19
</string>
<string name="credentials_label">Credentials</string>
<string name="host_label">Host:</string>
Expand Down

0 comments on commit 989438e

Please sign in to comment.