Skip to content

Commit

Permalink
tests: final testing of multiple verification cases
Browse files Browse the repository at this point in the history
  • Loading branch information
cristianIOHK committed May 6, 2024
1 parent f032e6a commit 1821879
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,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.CredentialType
import io.iohk.atala.prism.walletsdk.domain.models.Message
import io.iohk.atala.prism.walletsdk.pollux.models.JWTCredential
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.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json

class MessagesAdapter(private var data: MutableList<Message> = mutableListOf()) :
RecyclerView.Adapter<MessagesAdapter.MessageHolder>() {
class MessagesAdapter(
private var data: MutableList<UiMessage> = mutableListOf(),
private val validateListener: MessagesFragment.ValidateMessageListener
) : RecyclerView.Adapter<MessagesAdapter.MessageHolder>() {

fun updateMessages(updatedMessages: List<Message>) {
fun updateMessages(updatedMessages: List<UiMessage>) {
val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return data.size
Expand All @@ -37,18 +28,25 @@ class MessagesAdapter(private var data: MutableList<Message> = mutableListOf())
}

override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return data[oldItemPosition].id == updatedMessages[newItemPosition].id
return data[oldItemPosition].id == updatedMessages[newItemPosition].id && data[oldItemPosition].status == updatedMessages[newItemPosition].status
}

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return data[oldItemPosition] == updatedMessages[newItemPosition]
return data[oldItemPosition] == updatedMessages[newItemPosition] && data[oldItemPosition].status == updatedMessages[newItemPosition].status
}
})
data.clear()
data.addAll(updatedMessages)
diffResult.dispatchUpdatesTo(this)
}

fun updateMessageStatus(updatedMessage: UiMessage) {
val message = data.find { it.id == updatedMessage.id }
val index = data.indexOf(message)
data[index] = updatedMessage
notifyItemChanged(index)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.placeholder_message, parent, false)
Expand All @@ -57,7 +55,7 @@ class MessagesAdapter(private var data: MutableList<Message> = mutableListOf())

override fun onBindViewHolder(holder: MessageHolder, position: Int) {
// Bind data to the views
holder.bind(data[position])
holder.bind(data[position], validateListener)
}

override fun getItemCount(): Int {
Expand All @@ -69,42 +67,48 @@ 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)
private val validate: Button = itemView.findViewById(R.id.validate)
private val validationError: TextView = itemView.findViewById(R.id.validation_error)

@OptIn(DelicateCoroutinesApi::class)
fun bind(message: Message) {
fun bind(message: UiMessage, validateListener: MessagesFragment.ValidateMessageListener) {
type.text = message.piuri
if (message.attachments.isNotEmpty()) {
val attachmentDescriptor = message.attachments.first()
if (message.piuri == ProtocolType.DidcommPresentation.value && attachmentDescriptor.format == CredentialType.PRESENTATION_EXCHANGE_SUBMISSION.type) {
validationError.visibility = View.GONE
validate.visibility = View.VISIBLE
validate.setOnClickListener {
GlobalScope.launch(Dispatchers.IO) {
val sdk = Sdk.getInstance()
if (sdk.agent.handlePresentation(message)) {
val attachmentData = attachmentDescriptor.data
if (attachmentData::class == AttachmentBase64::class) {
attachmentData as AttachmentBase64
val decoded = attachmentData.base64.decodeBase64String()
val presentationSubmission =
Json.decodeFromString<PresentationSubmission>(decoded)
presentationSubmission.verifiablePresentation.forEach { jwt ->
val jwtCredential = JWTCredential.fromJwtString(jwt)
// TODO: Extract fields to display
}
}
withContext(Dispatchers.Main) {
validate.text = "Valid presentation"
validate.isEnabled = false
}
} else {
// TODO: Change UI body to say invalid presentation
}
}
validate.setOnClickListener { validateListener.validateMessage(message) }
message.status?.let { status ->
validationError.text = status
validationError.visibility = View.VISIBLE
validate.visibility = View.GONE
}
this.body.text = message.body
} else {
validate.visibility = View.GONE
// CoroutineScope(Dispatchers.IO).launch(handler) {
// val sdk = Sdk.getInstance()
// validationError.visibility = View.GONE
// if (sdk.agent.handlePresentation(message)) {
// val attachmentData = attachmentDescriptor.data
// if (attachmentData::class == AttachmentBase64::class) {
// attachmentData as AttachmentBase64
// val decoded = attachmentData.base64.decodeBase64String()
// val presentationSubmission =
// Json.decodeFromString<PresentationSubmission>(decoded)
// presentationSubmission.verifiablePresentation.forEach { jwt ->
// val jwtCredential = JWTCredential.fromJwtString(jwt)
// // TODO: Extract fields to display
// }
// }
// withContext(Dispatchers.Main) {
// validate.text = "Valid presentation"
// validate.isEnabled = false
// }
// } else {
// // TODO: Change UI body to say invalid presentation
// }
// }
}
} else {
validate.visibility = View.GONE
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ class MessagesFragment : Fragment() {
private val viewModel: MessagesViewModel by viewModels()

private val binding get() = _binding!!
private val adapter = MessagesAdapter()

interface ValidateMessageListener {
fun validateMessage(message: UiMessage)
}

private lateinit var adapter: MessagesAdapter

override fun onCreateView(
inflater: LayoutInflater,
Expand All @@ -32,7 +37,6 @@ class MessagesFragment : Fragment() {

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.list.adapter = adapter
binding.sendMessage.setOnClickListener {
viewModel.sendMessage(DID("did:peer:2.Ez6LSkjhgJcoGRTSTpjN5XBSKGpNtDSa55qidsahb1s3ucWkJ.Vz6MkgG8bJA2P2HNhCwh4DGHmBtUbKiCafYwBtDMjKnAihaE9.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6ImRpZDpwZWVyOjIuRXo2TFNnaHdTRTQzN3duREUxcHQzWDZoVkRVUXpTanNIemlucFgzWEZ2TWpSQW03eS5WejZNa2hoMWU1Q0VZWXE2SkJVY1RaNkNwMnJhbkNXUnJ2N1lheDNMZTRONTlSNmRkLlNleUowSWpvaVpHMGlMQ0p6SWpwN0luVnlhU0k2SW1oMGRIQnpPaTh2WTNKcGMzUnBZVzR0YldWa2FXRjBiM0l1YW5KcFltOHVhMmwzYVNJc0ltRWlPbHNpWkdsa1kyOXRiUzkyTWlKZGZYMC5TZXlKMElqb2laRzBpTENKeklqcDdJblZ5YVNJNkluZHpjem92TDJOeWFYTjBhV0Z1TFcxbFpHbGhkRzl5TG1weWFXSnZMbXRwZDJrdmQzTWlMQ0poSWpwYkltUnBaR052YlcwdmRqSWlYWDE5IiwiciI6W10sImEiOltdfX0"))
}
Expand All @@ -42,6 +46,26 @@ class MessagesFragment : Fragment() {
"InitiateVerificationDialogFragment"
)
}

adapter = MessagesAdapter(
validateListener = object : ValidateMessageListener {
override fun validateMessage(message: UiMessage) {
viewModel.handlePresentation(message).observe(viewLifecycleOwner) { status ->
adapter.updateMessageStatus(
UiMessage(
id = message.id,
piuri = message.piuri,
from = message.from,
to = message.to,
attachments = message.attachments,
status = status
)
)
}
}
}
)
binding.list.adapter = adapter
setupStreamObservers()
}

Expand Down Expand Up @@ -80,7 +104,16 @@ class MessagesFragment : Fragment() {

private fun setupStreamObservers() {
viewModel.messagesStream().observe(this.viewLifecycleOwner) { messages ->
adapter.updateMessages(messages)
val uiMessages = messages.map { message ->
UiMessage(
id = message.id,
piuri = message.piuri,
from = message.from?.toString() ?: "NA",
to = message.to?.toString() ?: "NA",
attachments = message.attachments
)
}
adapter.updateMessages(uiMessages)
}
viewModel.proofRequestToProcess().observe(this.viewLifecycleOwner) { proofRequest ->
val message = proofRequest.first
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ 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.RequestPresentation
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -97,16 +98,12 @@ class MessagesViewModel(application: Application) : AndroidViewModel(application
toDID = DID(toDID),
presentationClaims = PresentationClaims(
claims = mapOf(
// "$.issuer" to InputFieldFilter(
// type = "string",
// value = "did:prism:8b5321c004d4a11e87ef3601350eaa8b472a546d11677c9c6845c55a490f02f4"
// ),
"emailAddress" to InputFieldFilter(
type = "string",
pattern = "corporate@tomate.domain.com"
pattern = "cristian.castro@iohk.io"
)
),
issuer = "did:prism:8b5321c004d4a11e87ef3601350eaa8b472a546d11677c9c6845c55a490f02f4"
issuer = "did:prism:e02e8099d50351345c5dd831a9e9112b394a85d0064a2eb59429080734a159b6:CrkBCrYBEjoKBmF1dGgtMRAESi4KCXNlY3AyNTZrMRIhAuVYcorfWnL0fYtA5vgJK4_-ob3bUDc-w2UOHdO3QEvqEjsKB2lzc3VlLTEQAkouCglzZWNwMjU2azESIQLCu9NntqupBj-0NCdMA75zReBeyaCJO1aGYeP4BMQHVBI7CgdtYXN0ZXIwEAFKLgoJc2VjcDI1NmsxEiEDOWgvQx6vRu6wUb4FYcJuaECj9BjPMJvRp8LwM61hET4"
),
domain = "domain",
challenge = "challenge"
Expand Down Expand Up @@ -154,6 +151,25 @@ class MessagesViewModel(application: Application) : AndroidViewModel(application
return revokedCredentials
}

fun handlePresentation(uiMessage: UiMessage): LiveData<String> {
val liveData = MutableLiveData<String>()
val handler = CoroutineExceptionHandler { _, exception ->
liveData.postValue(exception.message)
}
viewModelScope.launch(handler) {
messages.value?.find { it.id == uiMessage.id }?.let { message ->
val sdk = Sdk.getInstance()
val valid = sdk.agent.handlePresentation(message)
if (valid) {
liveData.postValue("Valid!")
} else {
liveData.postValue("Not valid!")
}
}
}
return liveData
}

private suspend fun processMessages(messages: List<Message>) {
val sdk = Sdk.getInstance()
val messageIds: List<String> = messages.map { it.id }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.iohk.atala.prism.sampleapp.ui.messages

import io.iohk.atala.prism.walletsdk.domain.models.AttachmentDescriptor

data class UiMessage(
val id: String,
val piuri: String,
val from: String,
val to: String,
val status: String? = null,
val attachments: Array<AttachmentDescriptor>
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false

other as UiMessage

if (id != other.id) return false
if (piuri != other.piuri) return false
if (from != other.from) return false
if (to != other.to) return false
if (status != other.status) return false
return attachments.contentEquals(other.attachments)
}

override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + piuri.hashCode()
result = 31 * result + from.hashCode()
result = 31 * result + to.hashCode()
result = 31 * result + (status?.hashCode() ?: 0)
result = 31 * result + attachments.contentHashCode()
return result
}
}
7 changes: 7 additions & 0 deletions sampleapp/src/main/res/layout/placeholder_message.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@
android:layout_gravity="end"
android:text="Validate"
android:visibility="gone" />

<TextView
android:id="@+id/validation_error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
/>
</LinearLayout>

</androidx.cardview.widget.CardView>
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.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHBzOi8vY3Jpc3RpYW4tbWVkaWF0b3IuanJpYm8ua2l3aSIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzczovL2NyaXN0aWFuLW1lZGlhdG9yLmpyaWJvLmtpd2kvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19
did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHBzOi8vc2l0LXByaXNtLW1lZGlhdG9yLmF0YWxhcHJpc20uaW8iLCJhIjpbImRpZGNvbW0vdjIiXX19.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzczovL3NpdC1wcmlzbS1tZWRpYXRvci5hdGFsYXByaXNtLmlvL3dzIiwiYSI6WyJkaWRjb21tL3YyIl19fQ
</string>
<string name="credentials_label">Credentials</string>
<string name="host_label">Host:</string>
Expand Down

0 comments on commit 1821879

Please sign in to comment.