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

Commit

Permalink
Ise correct redirect URI and error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
waltkb authored and mikeplotean committed Nov 2, 2023
1 parent 937dfb3 commit 46996e4
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 41 deletions.
36 changes: 30 additions & 6 deletions src/main/kotlin/id/walt/service/SSIKit2WalletService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ class SSIKit2WalletService(accountId: UUID) : WalletService(accountId) {
followRedirects = false
}


data class PresentationError(
override val message: String,
val redirectUri: String?
) : IllegalArgumentException(message)

/**
* @return redirect uri
*/
Expand All @@ -178,15 +184,33 @@ class SSIKit2WalletService(accountId: UUID) : WalletService(accountId) {
entry.value.forEach { append(entry.key, it) }
}
})
println("HTTP Response: $resp, body: ${resp.bodyAsText()}")
val httpResponseBody = runCatching { resp.bodyAsText() }.getOrNull()
val isResponseRedirectUrl =
httpResponseBody != null && httpResponseBody.take(8).lowercase().let {
@Suppress("HttpUrlsUsage")
it.startsWith("http://") || it.startsWith("https://")
}
println("HTTP Response: $resp, body: $httpResponseBody")

return if (resp.status.isSuccess()) {
val redirectUri = resp.bodyAsText()
if (redirectUri.startsWith("http"))
Result.success(redirectUri)
else Result.success(null)
Result.success(if (isResponseRedirectUrl) httpResponseBody else null)
} else {
Result.failure(IllegalStateException("https://error.org/"))
if (isResponseRedirectUrl) {
Result.failure(
PresentationError(
message = "Presentation failed - redirecting to error page",
redirectUri = httpResponseBody
)
)
} else {
println("Response body: $httpResponseBody")
Result.failure(
PresentationError(
message = if (httpResponseBody != null) "Presentation failed:\n $httpResponseBody" else "Presentation failed",
redirectUri = ""
)
)
}
}
}

Expand Down
36 changes: 33 additions & 3 deletions src/main/kotlin/id/walt/web/controllers/ExchangeController.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package id.walt.web.controllers

import id.walt.service.SSIKit2WalletService
import id.walt.service.dto.WalletOperationHistory
import id.walt.web.getWalletService
import io.github.smiley4.ktorswaggerui.dsl.post
Expand Down Expand Up @@ -62,6 +63,12 @@ fun Application.exchange() = walletRoute {
description = """{"redirectUri": String}"""
}
}
HttpStatusCode.BadRequest to {
description = "Presentation was not accepted"
body<JsonObject> {
description = """{"redirectUri": String?, "errorMessage": String}"""
}
}
}
}) {
val wallet = getWalletService()
Expand All @@ -79,20 +86,43 @@ fun Application.exchange() = walletRoute {
wallet.addOperationHistory(
WalletOperationHistory.new(
wallet, "usePresentationRequest",
mapOf("did" to did, "request" to request, "success" to "true", "redirect" to result.getOrThrow()) // change string true to bool
mapOf(
"did" to did,
"request" to request,
"success" to "true",
"redirect" to result.getOrThrow()
) // change string true to bool
)
)

context.respond(HttpStatusCode.OK, mapOf("redirectUri" to result.getOrThrow()))
} else {
val err = result.exceptionOrNull()
println("Presentation failed: $err")

wallet.addOperationHistory(
WalletOperationHistory.new(
wallet, "usePresentationRequest",
mapOf("did" to did, "request" to request, "success" to "false", "redirect" to result.getOrThrow()) // change string true to bool
mapOf(
"did" to did,
"request" to request,
"success" to "false",
//"redirect" to ""
) // change string false to bool
)
)
when (err) {
is SSIKit2WalletService.PresentationError -> {
context.respond(
HttpStatusCode.BadRequest, mapOf(
"redirectUri" to err.redirectUri,
"errorMessage" to err.message
)
)
}

context.respond(HttpStatusCode.BadRequest, mapOf("redirectUri" to result.exceptionOrNull()!!.message))
else -> context.respond(HttpStatusCode.BadRequest, mapOf("errorMessage" to err?.message))
}
}
}
post("resolvePresentationRequest", {
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/credentials/[credentialId].vue
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@
<div class="md:flex text-gray-500 mb-3 md:mb-1">
<div class="min-w-[19vw]">DID</div>
<div class="font-bold overflow-scroll lg:overflow-auto">
{{ jwtJson.vc.issuer.id ? jwtJson.vc.issuer.id : jwtJson.vc.issuer }}
{{ jwtJson.vc?.issuer?.id ?? jwtJson.vc.issuer }}
</div>
</div>
<hr class="mt-5 mb-3"/>
Expand Down
88 changes: 57 additions & 31 deletions web/src/pages/exchange/presentation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@
</template>

<template v-if="!immediateAccept" v-slot:menu>
<ActionButton icon="heroicons:x-mark"
class="inline-flex focus:outline focus:outline-red-700 focus:outline-offset-2 items-center rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-700 hover:scale-105 hover:animate-pulse focus:animate-none"
display-text="Reject" type="button" @click="navigateTo('/')" />

<ActionButton icon="heroicons:check" :failed="failed"
class="inline-flex focus:outline focus:outline-offset-2 items-center rounded-md px-3 py-2 text-sm font-semibold text-white shadow-sm"
:class="[failed ? 'bg-red-600 animate-pulse focus:outline focus:outline-red-700 focus:outline-offset-2 hover:bg-red-700 hover:scale-105' : 'bg-green-600 focus:outline-green-700 hover:bg-green-700 hover:scale-105 hover:animate-pulse focus:animate-none']"
display-text="Accept" type="button" @click="acceptPresentation" />
<ActionButton
class="inline-flex focus:outline focus:outline-red-700 focus:outline-offset-2 items-center rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-700 hover:scale-105 hover:animate-pulse focus:animate-none"
display-text="Reject"
icon="heroicons:x-mark" type="button" @click="navigateTo('/')"
/>

<ActionButton
:class="[failed ? 'bg-red-600 animate-pulse focus:outline focus:outline-red-700 focus:outline-offset-2 hover:bg-red-700 hover:scale-105' : 'bg-green-600 focus:outline-green-700 hover:bg-green-700 hover:scale-105 hover:animate-pulse focus:animate-none']"
:failed="failed"
class="inline-flex focus:outline focus:outline-offset-2 items-center rounded-md px-3 py-2 text-sm font-semibold text-white shadow-sm"
display-text="Accept"
icon="heroicons:check" type="button" @click="acceptPresentation"
/>
</template>
</PageHeader>
<CenterMain>
Expand All @@ -32,15 +37,18 @@
<div aria-label="Credential list" class="h-full overflow-y-auto shadow-xl">
<div v-for="group in groupedCredentialTypes.keys()" :key="group.id" class="relative">
<div
class="sticky top-0 z-10 border-y border-b-gray-200 border-t-gray-100 bg-gray-50 px-3 py-1.5 text-sm font-semibold leading-6 text-gray-900">
class="sticky top-0 z-10 border-y border-b-gray-200 border-t-gray-100 bg-gray-50 px-3 py-1.5 text-sm font-semibold leading-6 text-gray-900"
>
<h3>{{ group }}s:</h3>
</div>
<ul class="divide-y divide-gray-100" role="list">
<li v-for="credential in groupedCredentialTypes.get(group)" :key="credential"
class="flex gap-x-4 px-3 py-5">
class="flex gap-x-4 px-3 py-5"
>

<CredentialIcon :credentialType="credential.name"
class="h-6 w-6 flex-none rounded-full bg-gray-50"></CredentialIcon>
class="h-6 w-6 flex-none rounded-full bg-gray-50"
></CredentialIcon>

<div class="min-w-0 flex flex-row items-center">
<span class="text-lg font-semibold leading-6 text-gray-900">{{ credential.id }}.</span>
Expand All @@ -56,18 +64,18 @@

<script lang="ts" setup>
import CenterMain from "~/components/CenterMain.vue";
import { CheckIcon, XMarkIcon } from '@heroicons/vue/24/outline'
import PageHeader from "~/components/PageHeader.vue";
import CredentialIcon from "~/components/CredentialIcon.vue";
import ActionButton from "~/components/buttons/ActionButton.vue";
import LoadingIndicator from "~/components/loading/LoadingIndicator.vue";
import { groupBy } from "~/composables/groupings";
import { useTitle } from "@vueuse/core";
import {groupBy} from "~/composables/groupings";
import {useTitle} from "@vueuse/core";
import {parseDate} from "@taquito/michel-codec/dist/types/utils";
async function resolvePresentationRequest(request) {
try {
console.log("RESOLVING request", request)
const response = await $fetch("/r/wallet/exchange/resolvePresentationRequest", { method: 'POST', body: request })
const response = await $fetch("/r/wallet/exchange/resolvePresentationRequest", {method: 'POST', body: request})
console.log(response)
return response
} catch (e) {
Expand Down Expand Up @@ -95,7 +103,7 @@ console.log("inputDescriptors: ", inputDescriptors)
let i = 0
let groupedCredentialTypes = groupBy(inputDescriptors.map(item => {
return { id: ++i, name: item.id }
return {id: ++i, name: item.id}
}), c => c.name)
console.log("groupedCredentialTypes: ", groupedCredentialTypes)
Expand All @@ -104,26 +112,44 @@ const immediateAccept = ref(false)
const failed = ref(false)
async function acceptPresentation() {
try {
const response = await $fetch<{ redirectUri: string | null }>("/r/wallet/exchange/usePresentationRequest", {
method: 'POST',
body: request
})
const response = await fetch("/r/wallet/exchange/usePresentationRequest", {
method: 'POST',
body: request,
redirect: "manual"
})
if (response.ok) {
console.log("Response: " + response)
const parsedResponse: {redirectUri: string} = await response.json()
if (parsedResponse.redirectUri) {
navigateTo(parsedResponse.redirectUri, {
external: true
})
} else {
navigateTo("", {
external: true
})
}
} else {
failed.value = true
const error: {message: string, redirectUri: string | null | undefined} = await response.json()
console.log(response)
console.log("Error response: " + JSON.stringify(error))
window.alert(error.message)
if (response.redirectUri) {
window.location.href = response.redirectUri
if (error.redirectUri != null) {
navigateTo(error.redirectUri as string, {
external: true
})
}
} catch (e) {
console.log("Policy verification failed: ", e)
//console.log("Policy verification failed: ", err)
let sessionId = presentationUrl.searchParams.get('state');
window.location.href = `https://portal.walt.id/success/${sessionId}`;
//let sessionId = presentationUrl.searchParams.get('state');
//window.location.href = `https://portal.walt.id/success/${sessionId}`;
// failed.value = true
// window.alert(e)
// throw e
//window.alert(err)
//throw err
}
}
Expand Down

0 comments on commit 46996e4

Please sign in to comment.