Skip to content

Commit

Permalink
Updates to MDL Presentation to Match New Rust API (#32)
Browse files Browse the repository at this point in the history
* Modify MDL presentation implementation and related example app code to reflect changes to rust library APIs

* Bump mobile-sdk-rs dependency version
  • Loading branch information
rschulman authored Sep 30, 2024
1 parent 968f87b commit 0090888
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 65 deletions.
2 changes: 1 addition & 1 deletion MobileSdk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ android {
}

dependencies {
api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.0.31")
api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.0.32")
//noinspection GradleCompatible
implementation("com.android.support:appcompat-v7:28.0.0")
/* Begin UI dependencies */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ package com.spruceid.mobile.sdk
import android.bluetooth.BluetoothManager
import android.util.Log
import androidx.lifecycle.ViewModel
import com.spruceid.mobile.sdk.rs.RequestData
import com.spruceid.mobile.sdk.rs.SessionData
import com.spruceid.mobile.sdk.rs.handleRequest
import com.spruceid.mobile.sdk.rs.initialiseSession
import com.spruceid.mobile.sdk.rs.submitResponse
import com.spruceid.mobile.sdk.rs.submitSignature
import com.spruceid.mobile.sdk.rs.ItemsRequest
import com.spruceid.mobile.sdk.rs.MdlPresentationSession
import com.spruceid.mobile.sdk.rs.initializeMdlPresentationFromBytes
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import java.security.KeyStore
Expand All @@ -23,15 +20,15 @@ class CredentialsViewModel : ViewModel() {
private val _currState = MutableStateFlow(PresentmentState.UNINITIALIZED)
val currState = _currState.asStateFlow()

private val _requestData = MutableStateFlow<RequestData?>(null)
val requestData = _requestData.asStateFlow()

private val _session = MutableStateFlow<SessionData?>(null)
private val _session = MutableStateFlow<MdlPresentationSession?>(null)
val session = _session.asStateFlow()

private val _error = MutableStateFlow<Error?>(null)
val error = _error.asStateFlow()

private val _itemsRequests = MutableStateFlow<List<ItemsRequest>>(listOf())
val itemsRequest = _itemsRequests.asStateFlow()

private val _allowedNamespaces =
MutableStateFlow<Map<String, Map<String, List<String>>>>(mapOf())
val allowedNamespaces = _allowedNamespaces.asStateFlow()
Expand Down Expand Up @@ -68,21 +65,21 @@ class CredentialsViewModel : ViewModel() {
}

private fun updateRequestData(data: ByteArray) {
_requestData.value = handleRequest(_session.value!!.state, data)
_itemsRequests.value = _session.value!!.handleRequest(data)
val namespaces =
requestData.value!!.itemsRequests.map { itemsRequest -> itemsRequest.namespaces }
_itemsRequests.value.map { itemsRequest -> itemsRequest.namespaces }
Log.d(
"CredentialsViewModel.updateRequestData",
"Updating requestData: \nitemRequests ${requestData.value!!.itemsRequests.map { itemsRequest -> itemsRequest.docType }} namespaces: $namespaces"
"Updating requestData: \nitemRequests ${_itemsRequests.value.map { itemsRequest -> itemsRequest.docType }} namespaces: $namespaces"
)
_currState.value = PresentmentState.SELECT_NAMESPACES
}

fun present(bluetoothManager: BluetoothManager) {
suspend fun present(bluetoothManager: BluetoothManager) {
Log.d("CredentialsViewModel.present", "Credentials: ${_credentials.value}")
_uuid.value = UUID.randomUUID()
val first: MDoc = _credentials.value.first() as MDoc
_session.value = initialiseSession(first.inner, _uuid.value.toString())
_session.value = initializeMdlPresentationFromBytes(first.inner, _uuid.value.toString())
_currState.value = PresentmentState.ENGAGING_QR_CODE
_transport.value = Transport(bluetoothManager)
_transport.value!!
Expand All @@ -91,7 +88,7 @@ class CredentialsViewModel : ViewModel() {
_uuid.value,
"BLE",
"Central",
_session.value!!.bleIdent,
_session.value!!.getBleIdent(),
::updateRequestData,
null
)
Expand All @@ -113,8 +110,7 @@ class CredentialsViewModel : ViewModel() {
_error.value = e
throw e
}
val payload = submitResponse(
_requestData.value!!.sessionManager,
val payload = _session.value!!.generateResponse(
allowedNamespaces
)

Expand All @@ -136,7 +132,7 @@ class CredentialsViewModel : ViewModel() {
signer.initSign(entry.privateKey)
signer.update(payload)
val signature = signer.sign()
val response = submitSignature(_requestData.value!!.sessionManager, signature)
val response = _session.value!!.submitResponse(signature)
_transport.value!!.send(response)
_currState.value = PresentmentState.SUCCESS
} catch (e: Error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,67 +3,51 @@ package com.spruceid.mobile.sdk
import android.bluetooth.BluetoothManager
import android.util.Log
import com.spruceid.mobile.sdk.rs.ItemsRequest
import com.spruceid.mobile.sdk.rs.SessionManager
import com.spruceid.mobile.sdk.rs.SessionManagerEngaged
import com.spruceid.mobile.sdk.rs.initialiseSession
import com.spruceid.mobile.sdk.rs.handleRequest
import com.spruceid.mobile.sdk.rs.submitResponse
import com.spruceid.mobile.sdk.rs.submitSignature
import com.spruceid.mobile.sdk.rs.MdlPresentationSession
import com.spruceid.mobile.sdk.rs.RequestException
import com.spruceid.mobile.sdk.rs.initializeMdlPresentationFromBytes
import java.security.KeyStore
import java.security.Signature
import java.util.UUID

abstract class BLESessionStateDelegate {
abstract fun update(state: Map<String, Any>)
abstract fun error(error: Exception)
}

public class BLESessionManager {

class IsoMdlPresentation(
val mdoc: MDoc,
val keyAlias: String,
val bluetoothManager: BluetoothManager,
val callback: BLESessionStateDelegate
val uuid: UUID
var state: SessionManagerEngaged? = null
var sessionManager: SessionManager? = null
) {
val uuid: UUID = UUID.randomUUID()
var session: MdlPresentationSession? = null
var itemsRequests: List<ItemsRequest> = listOf()
val mdoc: MDoc
var bleManager: Transport? = null

constructor(
mdoc: MDoc,
bluetoothManager: BluetoothManager,
callback: BLESessionStateDelegate,
) {
this.callback = callback
this.uuid = UUID.randomUUID()
this.mdoc = mdoc
suspend fun initialize() {
try {
val sessionData = initialiseSession(mdoc.inner, uuid.toString())
this.state = sessionData.state
this.bleManager = Transport(bluetoothManager)
session = initializeMdlPresentationFromBytes(this.mdoc.inner, uuid.toString())
this.bleManager = Transport(this.bluetoothManager)
this.bleManager!!
.initialize(
"Holder",
this.uuid,
"BLE",
"Central",
sessionData.bleIdent,
session!!.getBleIdent(),
::updateRequestData,
callback
)
this.callback.update(mapOf(Pair("engagingQRCode", sessionData.qrCodeUri)))
this.callback.update(mapOf(Pair("engagingQRCode", session!!.getQrCodeUri())))
} catch (e: Error) {
Log.e("BleSessionManager.constructor", e.toString())
}
}

fun cancel() {
this.bleManager?.terminate()
}

fun submitNamespaces(items: Map<String, Map<String, List<String>>>) {
val payload = submitResponse(
this.sessionManager!!,
items
)
val payload = session!!.generateResponse(items)

val ks: KeyStore = KeyStore.getInstance(
"AndroidKeyStore"
Expand All @@ -73,9 +57,9 @@ public class BLESessionManager {
null
)

val entry = ks.getEntry(this.mdoc.keyAlias, null)
val entry = ks.getEntry(this.keyAlias, null)
if (entry !is KeyStore.PrivateKeyEntry) {
throw IllegalStateException("No such private key under the alias <${this.mdoc.keyAlias}>")
throw IllegalStateException("No such private key under the alias <${this.keyAlias}>")
}

try {
Expand All @@ -85,7 +69,7 @@ public class BLESessionManager {
signer.update(payload)

val signature = signer.sign()
val response = submitSignature(this.sessionManager!!, signature)
val response = session!!.submitResponse(signature)
this.bleManager!!.send(response)
} catch (e: Error) {
Log.e("CredentialsViewModel.submitNamespaces", e.toString())
Expand All @@ -95,9 +79,11 @@ public class BLESessionManager {
}

fun updateRequestData(data: ByteArray) {
val requestData = handleRequest(this.state!!, data)
this.sessionManager = requestData.sessionManager
this.itemsRequests = requestData.itemsRequests
this.callback.update(mapOf(Pair("selectNamespaces", requestData.itemsRequests)))
try {
this.itemsRequests = session!!.handleRequest(data)
this.callback.update(mapOf(Pair("selectNamespaces", this.itemsRequests)))
} catch (e: RequestException) {
this.callback.error(e)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fun SelectiveDisclosureView(
onCancel: () -> Unit
) {

val requestData by credentialViewModel.requestData.collectAsState()
val itemsRequests by credentialViewModel.itemsRequest.collectAsState()
val allowedNamespaces by credentialViewModel.allowedNamespaces.collectAsState()

val selectNamespacesSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
Expand All @@ -56,7 +56,7 @@ fun SelectiveDisclosureView(
.padding(all = 12.dp)
.verticalScroll(rememberScrollState())
) {
requestData!!.itemsRequests.map { itemsRequest ->
itemsRequests.map { itemsRequest ->
Column {
Text(
text = "Document being requested:\n\t\t${itemsRequest.docType}\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ fun ShareView(
}
}
PresentmentState.ENGAGING_QR_CODE -> {
if (session!!.qrCodeUri.isNotEmpty()) {
if (session!!.getQrCodeUri().isNotEmpty()) {
Image(
painter = rememberQrBitmapPainter(
session!!.qrCodeUri,
session!!.getQrCodeUri(),
300.dp,
),
contentDescription = "Share QRCode",
Expand Down

0 comments on commit 0090888

Please sign in to comment.