Skip to content
This repository has been archived by the owner on Jan 9, 2024. It is now read-only.

Commit

Permalink
Add disclosure selection and map VPSession attributes outside of open…
Browse files Browse the repository at this point in the history
…id4vc lib for now
  • Loading branch information
waltkb committed Nov 22, 2023
1 parent a3bb7b1 commit 329bbc2
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 29 deletions.
8 changes: 7 additions & 1 deletion src/main/kotlin/id/walt/service/SSIKit2WalletService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -178,18 +178,24 @@ class SSIKit2WalletService(accountId: UUID, walletId: UUID) : WalletService(acco
) : IllegalArgumentException(message)




/**
* @return redirect uri
*/
override suspend fun usePresentationRequest(request: String, did: String, selectedCredentialIds: List<String>): Result<String?> {
override suspend fun usePresentationRequest(request: String, did: String, selectedCredentialIds: List<String>, disclosures: Map<String, List<String>>): Result<String?> {
val credentialWallet = getCredentialWallet(did)

val authReq = AuthorizationRequest.fromHttpQueryString(Url(request).encodedQuery)
println("Auth req: $authReq")

println("USING PRESENTATION REQUEST, SELECTED CREDENTIALS: $selectedCredentialIds")

SessionAttributes.HACK_outsideMappedSelectedCredentialsPerSession[authReq.state + authReq.presentationDefinition] = selectedCredentialIds
SessionAttributes.HACK_outsideMappedSelectedDisclosuresPerSession[authReq.state + authReq.presentationDefinition] = disclosures

val presentationSession = credentialWallet.initializeAuthorization(authReq, 60.seconds, selectedCredentialIds.toSet())
println("Initialized authorization (VPPresentationSession): $presentationSession")

println("Resolved presentation definition: ${presentationSession.authorizationRequest!!.presentationDefinition!!.toJSONString()}")

Expand Down
10 changes: 10 additions & 0 deletions src/main/kotlin/id/walt/service/SessionAttributes.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package id.walt.service

object SessionAttributes {

// TODO FIXME: openid4vc lib drops VPresentationSession attributes
val HACK_outsideMappedSelectedCredentialsPerSession = HashMap<String, List<String>>()
// TODO FIXME: openid4vc lib drops VPresentationSession attributes
val HACK_outsideMappedSelectedDisclosuresPerSession = HashMap<String, Map<String, List<String>>>()

}
2 changes: 1 addition & 1 deletion src/main/kotlin/id/walt/service/WalletKitWalletService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ class WalletKitWalletService(accountId: UUID, walletId: UUID) : WalletService(ac
val state: String?
)

override suspend fun usePresentationRequest(request: String, did: String, selectedCredentialIds: List<String>): Result<String?> {
override suspend fun usePresentationRequest(request: String, did: String, selectedCredentialIds: List<String>, disclosures: Map<String, List<String>>): Result<String?> {
val decoded = URLDecoder.decode(request, Charset.defaultCharset())
val queryParams = getQueryParams(decoded)
val redirectUri = queryParams["redirect_uri"]?.first()
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/id/walt/service/WalletService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ abstract class WalletService(val accountId: UUID, val walletId: UUID) {
abstract fun matchCredentialsByPresentationDefinition(presentationDefinition: PresentationDefinition): List<WalletCredential>

// SIOP
abstract suspend fun usePresentationRequest(request: String, did: String, selectedCredentialIds: List<String>): Result<String?>
abstract suspend fun usePresentationRequest(request: String, did: String, selectedCredentialIds: List<String>, disclosures: Map<String, List<String>>): Result<String?>
abstract suspend fun resolvePresentationRequest(request: String): String
abstract suspend fun useOfferRequest(offer: String, did: String)

Expand Down
10 changes: 8 additions & 2 deletions src/main/kotlin/id/walt/service/oidc4vc/TestCredentialWallet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import id.walt.oid4vc.providers.TokenTarget
import id.walt.oid4vc.requests.AuthorizationRequest
import id.walt.oid4vc.requests.TokenRequest
import id.walt.service.SSIKit2WalletService
import id.walt.service.SessionAttributes.HACK_outsideMappedSelectedCredentialsPerSession
import id.walt.service.SessionAttributes.HACK_outsideMappedSelectedDisclosuresPerSession
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.*
Expand Down Expand Up @@ -105,9 +107,13 @@ class TestCredentialWallet(

override fun generatePresentationForVPToken(session: VPresentationSession, tokenRequest: TokenRequest): PresentationResult {
println("=== GENERATING PRESENTATION FOR VP TOKEN - Session: $session")
val selectedCredential = session.selectedCredentialIds.toList()

val matchedCredentials = walletService.getCredentialsByIds(selectedCredential)
val selectedCredentials =
HACK_outsideMappedSelectedCredentialsPerSession[session.authorizationRequest!!.state + session.authorizationRequest.presentationDefinition]!!
val selectedDisclosures =
HACK_outsideMappedSelectedDisclosuresPerSession[session.authorizationRequest!!.state + session.authorizationRequest.presentationDefinition]!!

val matchedCredentials = walletService.getCredentialsByIds(selectedCredentials)

val vp = Json.encodeToString(
mapOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ fun Application.exchange() = walletRoute {
// TODO -> ?: auto matching


val result = wallet.usePresentationRequest(request, did, selectedCredentialIds)
val result = wallet.usePresentationRequest(request, did, selectedCredentialIds, emptyMap()) // TODO add disclosures here

if (result.isSuccess) {
wallet.addOperationHistory(
Expand Down
6 changes: 5 additions & 1 deletion web/src/composables/disclosures.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { decodeBase64ToUtf8 } from "~/composables/base64";
import { decodeBase64ToUtf8, encodeUtf8ToBase64 } from "~/composables/base64";

export function parseDisclosures(disclosureString: string) {
try {
Expand All @@ -8,3 +8,7 @@ export function parseDisclosures(disclosureString: string) {
return [];
}
}

export function encodeDisclosure(disclosure: any[]): string {
return encodeUtf8ToBase64(JSON.stringify(disclosure))
}
4 changes: 2 additions & 2 deletions web/src/pages/wallet/[wallet]/credentials/[credentialId].vue
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,14 @@

<div v-if="disclosures">
<hr class="my-5" />
<div class="text-gray-500 mb-4 font-bold">Selectively disclosure-able attributes</div>
<div class="text-gray-500 mb-4 font-bold">Selectively disclosable attributes</div>
<ul v-if="disclosures.length > 0">
<li class="md:flex text-gray-500 mb-3 md:mb-1" v-for="disclosure in disclosures">
<div class="min-w-[19vw]">Attribute "{{ disclosure[1] }}"</div>
<div class="font-bold">{{ disclosure[2] }}</div>
</li>
</ul>
<div v-else>No disclosure-able attributes!</div>
<div v-else>No disclosable attributes!</div>
</div>

<hr class="mt-5 mb-3" />
Expand Down
89 changes: 69 additions & 20 deletions web/src/pages/wallet/[wallet]/exchange/presentation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,33 +60,68 @@
>
<div class="mr-3 pt-2 flex h-6 items-center">
<input :id="`credential-${credential.id}`" v-model="selection[credential.id]"
:name="`credential-${credential.id}`" class="h-6 w-6 rounded border-gray-300 text-primary-400 focus:ring-primary-400"
:name="`credential-${credential.id}`"
class="h-6 w-6 rounded border-gray-300 text-primary-400 focus:ring-primary-400"
type="checkbox"
/>
</div>

<div class="min-w-0 flex-1 text-sm leading-6">
<label :for="`credential-${credential.id}`" class="select-none font-medium text-gray-900">

<!-- <div class="flex items-center gap-1">-->
<!-- <CredentialIcon :credentialType="credential.parsedDocument.type.at(-1)" class="h-6 w-6 flex-none rounded-full bg-gray-50"></CredentialIcon>-->
<!-- {{ credential.parsedDocument.type.at(-1) }}-->
<!-- </div>-->

<!-- <div class="min-w-0 items-center">-->
<!-- <p class="text-lg font-semibold leading-6 text-gray-900">{{ credential?.parsedDocument?.name }}</p>-->
<!-- <p class="ml-1 truncate text-sm leading-5 text-gray-800">{{ credential.id }}</p>-->
<!-- </div>-->

<VerifiableCredentialCard
:class="[selection[credential.id] == true ? 'shadow-xl shadow-primary-400' : 'shadow-2xl']"
:credential="credential.parsedDocument"
:show-id="true"
/>
<div class="font-medium select-none text-gray-900">
<label :for="`credential-${credential.id}`">

<!-- <div class="flex items-center gap-1">-->
<!-- <CredentialIcon :credentialType="credential.parsedDocument.type.at(-1)" class="h-6 w-6 flex-none rounded-full bg-gray-50"></CredentialIcon>-->
<!-- {{ credential.parsedDocument.type.at(-1) }}-->
<!-- </div>-->

<!-- <div class="min-w-0 items-center">-->
<!-- <p class="text-lg font-semibold leading-6 text-gray-900">{{ credential?.parsedDocument?.name }}</p>-->
<!-- <p class="ml-1 truncate text-sm leading-5 text-gray-800">{{ credential.id }}</p>-->
<!-- </div>-->

<VerifiableCredentialCard
:class="[selection[credential.id] == true ? 'shadow-xl shadow-primary-400' : 'shadow-2xl']"
:credential="credential.parsedDocument"
:show-id="true"
/>

</label>
</div>
<div v-if="credential.disclosures" class="mt-3">
<fieldset>
<legend class="text-base font-semibold leading-6 text-gray-900">Selectively disclosable attributes
</legend>
<div class="mt-1 divide-y divide-gray-200 border-b border-t border-gray-200">
<div v-for="(disclosure, disclosureIdx) in parseDisclosures(credential.disclosures)"
:key="disclosureIdx" class="relative flex items-start py-1"
>
<div class="min-w-0 flex-1 text-sm leading-6">
<label :for="`disclosure-${credential.id}-${disclosure[0]}`"
class="select-none font-medium text-gray-900"
>
<div class="md:flex text-gray-500 mb-3 md:mb-1">
<div class="min-w-[19vw]">{{ disclosureIdx + 1 }}. <span class="font-semibold">{{ disclosure[1] }}</span></div>
<div class="grow-0">
{{ disclosure[2] }}
</div>
</div>
</label>
</div>
<div class="ml-3 flex h-6 items-center">
<input :id="`disclosure-${credential.id}-${disclosure[0]}`"
:name="`disclosure-${disclosure[0]}`"
class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600"
type="checkbox"
@click="$event.target.checked ? addDisclosure(credential.id, disclosure) : removeDisclosure(credential.id, disclosure) "
/>
</div>
</div>
</div>
</fieldset>

<div v-if="credential.disclosures">Debug: SD Disclosures = {{ parseDisclosures(credential.disclosures) }}</div>
</div>

</label>
</div>
</div>
</div>
Expand Down Expand Up @@ -207,6 +242,20 @@ const selectedCredentialIds = computed(() => {
return _selectedCredentialIds;
});
const disclosures = ref({});
function addDisclosure(credentialId: string, disclosure: string) {
if (disclosures.value[credentialId] === undefined) {
disclosures.value[credentialId] = []
}
disclosures.value[credentialId].push(disclosure)
}
function removeDisclosure(credentialId: string, disclosure: string) {
disclosures.value[credentialId] = disclosures.value[credentialId].filter((elem) => elem[0] != disclosure[0])
}
async function acceptPresentation() {
const req = {
//did: String,
Expand Down

0 comments on commit 329bbc2

Please sign in to comment.