diff --git a/src/main/kotlin/eu/europa/ec/eudi/openid4vci/Issuance.kt b/src/main/kotlin/eu/europa/ec/eudi/openid4vci/Issuance.kt index d8d1fa68..85b8f653 100644 --- a/src/main/kotlin/eu/europa/ec/eudi/openid4vci/Issuance.kt +++ b/src/main/kotlin/eu/europa/ec/eudi/openid4vci/Issuance.kt @@ -142,7 +142,7 @@ sealed interface SubmittedRequest : java.io.Serializable { * @param cNonce The c_nonce provided from issuer along the error * @param errorDescription Description of the error that caused the failure */ - class InvalidProof( + data class InvalidProof( val cNonce: CNonce, val errorDescription: String? = null, ) : Errored diff --git a/src/test/kotlin/eu/europa/ec/eudi/openid4vci/CryptoGenerator.kt b/src/test/kotlin/eu/europa/ec/eudi/openid4vci/CryptoGenerator.kt index 7dd57dda..a9abb953 100644 --- a/src/test/kotlin/eu/europa/ec/eudi/openid4vci/CryptoGenerator.kt +++ b/src/test/kotlin/eu/europa/ec/eudi/openid4vci/CryptoGenerator.kt @@ -49,4 +49,13 @@ object CryptoGenerator { val bindingKey = JwtBindingKey.Jwk(keyPair.toPublicJWK()) return PopSigner.jwtPopSigner(keyPair, JWSAlgorithm.ES256, bindingKey) } + + // TODO make this smarter + // taking into account the proofTypeMeta data + fun popSigner(proofTypeMeta: ProofTypeMeta): PopSigner? = + when (proofTypeMeta) { + ProofTypeMeta.Cwt -> null + is ProofTypeMeta.Jwt -> ecProofSigner() + ProofTypeMeta.LdpVp -> null + } } diff --git a/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/Commons.kt b/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/Commons.kt index 407bf4ba..44e52cfb 100644 --- a/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/Commons.kt +++ b/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/Commons.kt @@ -16,43 +16,100 @@ package eu.europa.ec.eudi.openid4vci.examples import com.nimbusds.jose.jwk.Curve -import eu.europa.ec.eudi.openid4vci.CredentialResponseEncryptionPolicy -import eu.europa.ec.eudi.openid4vci.CryptoGenerator -import eu.europa.ec.eudi.openid4vci.KeyGenerationConfig -import eu.europa.ec.eudi.openid4vci.OpenId4VCIConfig +import eu.europa.ec.eudi.openid4vci.* import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.engine.apache.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.cookies.* import io.ktor.client.plugins.logging.* +import io.ktor.client.request.* +import io.ktor.client.request.forms.* +import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json import org.apache.http.conn.ssl.NoopHostnameVerifier import org.apache.http.conn.ssl.TrustSelfSignedStrategy import org.apache.http.ssl.SSLContextBuilder +import org.jsoup.Jsoup +import org.jsoup.nodes.FormElement import java.net.URI +import java.net.URL -const val PID_SdJwtVC_config_id = "eu.europa.ec.eudiw.pid_vc_sd_jwt" -const val PID_MsoMdoc_config_id = "eu.europa.ec.eudiw.pid_mso_mdoc" -const val MDL_config_id = "org.iso.18013.5.1.mDL" +internal object PidDevIssuer { + private const val BASE_URL = "https://dev.issuer-backend.eudiw.dev" + private const val WALLET_CLIENT_ID = "wallet-dev" + private val WalletRedirectURI = URI.create("urn:ietf:wg:oauth:2.0:oob") + val IssuerId = CredentialIssuerId(BASE_URL).getOrThrow() + val TestUser = ActingUser("tneal", "password") -internal class ActingUser( - val username: String, - val password: String, -) + internal class ActingUser( + val username: String, + val password: String, + ) -val DefaultProofSignersMap = mapOf( - PID_SdJwtVC_config_id to CryptoGenerator.rsaProofSigner(), - PID_MsoMdoc_config_id to CryptoGenerator.ecProofSigner(), - MDL_config_id to CryptoGenerator.ecProofSigner(), -) + val PID_SdJwtVC_config_id = CredentialConfigurationIdentifier("eu.europa.ec.eudiw.pid_vc_sd_jwt") + val PID_MsoMdoc_config_id = CredentialConfigurationIdentifier("eu.europa.ec.eudiw.pid_mso_mdoc") + val MDL_config_id = CredentialConfigurationIdentifier("org.iso.18013.5.1.mDL") + + val AllCredentialConfigurationIds = listOf( + PID_SdJwtVC_config_id, + PID_MsoMdoc_config_id, + MDL_config_id, + ) -val DefaultOpenId4VCIConfig = OpenId4VCIConfig( - clientId = "wallet-dev", - authFlowRedirectionURI = URI.create("urn:ietf:wg:oauth:2.0:oob"), - keyGenerationConfig = KeyGenerationConfig(Curve.P_256, 2048), - credentialResponseEncryptionPolicy = CredentialResponseEncryptionPolicy.SUPPORTED, - dPoPSigner = CryptoGenerator.ecProofSigner(), + val Cfg = OpenId4VCIConfig( + clientId = WALLET_CLIENT_ID, + authFlowRedirectionURI = WalletRedirectURI, + keyGenerationConfig = KeyGenerationConfig(Curve.P_256, 2048), + credentialResponseEncryptionPolicy = CredentialResponseEncryptionPolicy.SUPPORTED, + dPoPSigner = CryptoGenerator.ecProofSigner(), + ) + + suspend fun loginUserAndGetAuthCode( + preparedAuthorizationCodeRequest: AuthorizationRequestPrepared, + actingUser: ActingUser, + ): Pair? = coroutineScope { + suspend fun extractASLoginUrl(html: String): URL = withContext(Dispatchers.IO) { + val form = Jsoup.parse(html).body().getElementById("kc-form-login") as FormElement + val action = form.attr("action") + URL(action) + } + + val response = createHttpClient().use { client -> + val loginUrl = async { + val url = preparedAuthorizationCodeRequest.authorizationCodeURL.value + val loginHtml = client.get(url).body() + extractASLoginUrl(loginHtml) + } + client.submitForm( + url = loginUrl.await().toString(), + formParameters = Parameters.build { + append("username", actingUser.username) + append("password", actingUser.password) + }, + ) + } + val redirectLocation = response.headers["Location"].toString() + with(URLBuilder(redirectLocation)) { + parameters["code"] to parameters["state"] + }.toNullable() + } + + private fun Pair.toNullable(): Pair? { + return if (first != null && second != null) first!! to second!! + else null + } +} + +val DefaultProofSignersMap = mapOf( + PidDevIssuer.PID_SdJwtVC_config_id to CryptoGenerator.rsaProofSigner(), + PidDevIssuer.PID_MsoMdoc_config_id to CryptoGenerator.ecProofSigner(), + PidDevIssuer.MDL_config_id to CryptoGenerator.ecProofSigner(), ) internal fun createHttpClient(enableLogging: Boolean = true): HttpClient = HttpClient(Apache) { @@ -70,6 +127,7 @@ internal fun createHttpClient(enableLogging: Boolean = true): HttpClient = HttpC } engine { customizeClient { + followRedirects = true setSSLContext( SSLContextBuilder.create().loadTrustMaterial(TrustSelfSignedStrategy()).build(), ) diff --git a/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/OfferBasedIssuanceUsingAuthorizationFlow.kt b/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/OfferBasedIssuanceUsingAuthorizationFlow.kt index 88b28495..65aa4e8a 100644 --- a/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/OfferBasedIssuanceUsingAuthorizationFlow.kt +++ b/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/OfferBasedIssuanceUsingAuthorizationFlow.kt @@ -17,29 +17,20 @@ package eu.europa.ec.eudi.openid4vci.examples import eu.europa.ec.eudi.openid4vci.* import eu.europa.ec.eudi.openid4vci.internal.ensure -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.request.forms.* -import io.ktor.http.* import kotlinx.coroutines.runBlocking -import org.jsoup.Jsoup -import org.jsoup.nodes.FormElement -import java.net.URL - -private val actingUser = ActingUser("tneal", "password") fun main(): Unit = runBlocking { val credentialOfferUrl = "eudi-openid4ci://?credential_offer=%7B%22" + "credential_issuer%22:%22https://dev.issuer-backend.eudiw.dev%22,%22" + - "credential_configuration_ids%22:[%22$PID_MsoMdoc_config_id%22," + - "%22$PID_SdJwtVC_config_id%22,%22$MDL_config_id%22]," + + "credential_configuration_ids%22:[%22${PidDevIssuer.PID_MsoMdoc_config_id.value}%22," + + "%22${PidDevIssuer.PID_SdJwtVC_config_id.value}%22,%22${PidDevIssuer.MDL_config_id.value}%22]," + "%22grants%22:%7B%22authorization_code%22:%7B%22" + "authorization_server%22:%22https://dev.auth.eudiw.dev/realms/pid-issuer-realm%22%7D%7D%7D" println("[[Scenario: Issuance based on credential offer url: $credentialOfferUrl]] ") val issuer = Issuer.make( - config = DefaultOpenId4VCIConfig, + config = PidDevIssuer.Cfg, credentialOfferUri = credentialOfferUrl, ktorHttpClientFactory = ::createHttpClient, ).getOrThrow() @@ -50,7 +41,7 @@ fun main(): Unit = runBlocking { } authorizationLog("Using authorized code flow to authorize") - val authorizedRequest = authorizeRequestWithAuthCodeUseCase(issuer, actingUser) + val authorizedRequest = authorizeRequestWithAuthCodeUseCase(issuer, PidDevIssuer.TestUser) authorizationLog("Authorization retrieved: $authorizedRequest") val offerCredentialConfIds = credentialOffer.credentialConfigurationIdentifiers @@ -75,7 +66,10 @@ fun main(): Unit = runBlocking { } } -private suspend fun authorizeRequestWithAuthCodeUseCase(issuer: Issuer, actingUser: ActingUser): AuthorizedRequest = +private suspend fun authorizeRequestWithAuthCodeUseCase( + issuer: Issuer, + actingUser: PidDevIssuer.ActingUser, +): AuthorizedRequest = with(issuer) { authorizationLog("Preparing authorization code request") @@ -83,10 +77,9 @@ private suspend fun authorizeRequestWithAuthCodeUseCase(issuer: Issuer, actingUs authorizationLog("Get authorization code URL is: ${prepareAuthorizationCodeRequest.authorizationCodeURL.value}") - val (authorizationCode, serverState) = loginUserAndGetAuthCode( - prepareAuthorizationCodeRequest.authorizationCodeURL.value, - actingUser, - ) ?: error("Could not retrieve authorization code") + val (authorizationCode, serverState) = + PidDevIssuer.loginUserAndGetAuthCode(prepareAuthorizationCodeRequest, actingUser) + ?: error("Could not retrieve authorization code") authorizationLog("Authorization code retrieved: $authorizationCode") @@ -100,33 +93,6 @@ private suspend fun authorizeRequestWithAuthCodeUseCase(issuer: Issuer, actingUs authorizedRequest } -private suspend fun loginUserAndGetAuthCode(getAuthorizationCodeUrl: URL, actingUser: ActingUser): Pair? { - return createHttpClient().use { client -> - val loginUrl = client.get(getAuthorizationCodeUrl).body().extractASLoginUrl() - - val formParameters = mapOf( - "username" to actingUser.username, - "password" to actingUser.password, - ) - val response = client.submitForm( - url = loginUrl.toString(), - formParameters = Parameters.build { - formParameters.entries.forEach { append(it.key, it.value) } - }, - ) - val redirectLocation = response.headers["Location"].toString() - with(URLBuilder(redirectLocation)) { - parameters["code"] to parameters["state"] - }.toNullable() - } -} - -private fun String.extractASLoginUrl(): URL { - val form = Jsoup.parse(this).body().getElementById("kc-form-login") as FormElement - val action = form.attr("action") - return URL(action) -} - private suspend fun submitProvidingNoProofs( issuer: Issuer, authorized: AuthorizedRequest.NoProofRequired, @@ -156,7 +122,7 @@ private suspend fun submitProvidingProofs( credentialConfigurationId: CredentialConfigurationIdentifier, ): String { with(issuer) { - val proofSigner = DefaultProofSignersMap[credentialConfigurationId.value] + val proofSigner = DefaultProofSignersMap[credentialConfigurationId] ?: error("No signer found for credential $credentialConfigurationId") val requestPayload = IssuanceRequestPayload.ConfigurationBased(credentialConfigurationId, null) @@ -176,7 +142,7 @@ private suspend fun handleSuccess( submittedRequest: SubmittedRequest.Success, issuer: Issuer, authorized: AuthorizedRequest, -) = when (val issuedCredential = submittedRequest.credentials[0]) { +): String = when (val issuedCredential = submittedRequest.credentials[0]) { is IssuedCredential.Issued -> issuedCredential.credential is IssuedCredential.Deferred -> { handleDeferred(issuer, authorized, issuedCredential) diff --git a/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/OfferBasedIssuanceUsingPreAuthorizationFlow.kt b/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/OfferBasedIssuanceUsingPreAuthorizationFlow.kt index bf05cd10..05527156 100644 --- a/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/OfferBasedIssuanceUsingPreAuthorizationFlow.kt +++ b/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/OfferBasedIssuanceUsingPreAuthorizationFlow.kt @@ -99,7 +99,7 @@ private suspend fun submitProvidingProofs( credentialConfigurationId: CredentialConfigurationIdentifier, ): String { with(issuer) { - val proofSigner = DefaultProofSignersMap[credentialConfigurationId.value] + val proofSigner = DefaultProofSignersMap[credentialConfigurationId] ?: error("No signer found for credential $credentialConfigurationId") val requestPayload = IssuanceRequestPayload.ConfigurationBased(credentialConfigurationId, null) diff --git a/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/WalletInitiatedIssuanceUsingAuthorizationFlow.kt b/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/WalletInitiatedIssuanceUsingAuthorizationFlow.kt index 4734199a..21fa6f33 100644 --- a/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/WalletInitiatedIssuanceUsingAuthorizationFlow.kt +++ b/src/test/kotlin/eu/europa/ec/eudi/openid4vci/examples/WalletInitiatedIssuanceUsingAuthorizationFlow.kt @@ -17,35 +17,23 @@ package eu.europa.ec.eudi.openid4vci.examples import eu.europa.ec.eudi.openid4vci.* import eu.europa.ec.eudi.openid4vci.internal.ensure -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.request.forms.* -import io.ktor.http.* import kotlinx.coroutines.runBlocking -import org.jsoup.Jsoup -import org.jsoup.nodes.FormElement -import java.net.URL - -private const val CredentialIssuerURL = "https://dev.issuer-backend.eudiw.dev" -private val actingUser = ActingUser("tneal", "password") fun main(): Unit = runBlocking { - val credentialIssuerId = CredentialIssuerId(CredentialIssuerURL).getOrThrow() - val credentialConfigurationIds = listOf(PID_SdJwtVC_config_id, PID_MsoMdoc_config_id, MDL_config_id) - - runUseCase(credentialIssuerId, credentialConfigurationIds) + runUseCase(PidDevIssuer.IssuerId, PidDevIssuer.AllCredentialConfigurationIds) } -fun runUseCase(credentialIssuerId: CredentialIssuerId, credentialConfigurationIds: List): Unit = runBlocking { +fun runUseCase( + credentialIssuerId: CredentialIssuerId, + credentialConfigurationIds: List, +): Unit = runBlocking { println("[[Scenario: Issuance based on credential configuration ids: $credentialConfigurationIds]] ") val (issuerMetadata, authorizationServersMetadata) = createHttpClient().use { client -> Issuer.metaData(client, credentialIssuerId) } - val identifiers = credentialConfigurationIds.map { CredentialConfigurationIdentifier(it) } - - identifiers.forEach { + credentialConfigurationIds.forEach { ensure(issuerMetadata.credentialConfigurationsSupported[it] != null) { error("Credential identifier $it not supported by issuer") } @@ -55,125 +43,97 @@ fun runUseCase(credentialIssuerId: CredentialIssuerId, credentialConfigurationId credentialIssuerIdentifier = credentialIssuerId, credentialIssuerMetadata = issuerMetadata, authorizationServerMetadata = authorizationServersMetadata[0], - credentialConfigurationIdentifiers = identifiers, + credentialConfigurationIdentifiers = credentialConfigurationIds, ) val issuer = Issuer.make( - config = DefaultOpenId4VCIConfig, + config = PidDevIssuer.Cfg, credentialOffer = credentialOffer, ktorHttpClientFactory = ::createHttpClient, ).getOrThrow() - authorizationLog("Using authorized code flow to authorize") - val authorizedRequest = authorizeRequestWithAuthCodeUseCase(issuer, actingUser) - authorizationLog("Authorization retrieved: $authorizedRequest") + with(issuer) { + authorizationLog("Using authorized code flow to authorize") + val authorizedRequest = authorizeRequestWithAuthCodeUseCase(PidDevIssuer.TestUser).also { + authorizationLog("Authorization retrieved: $it") + } - credentialOffer.credentialConfigurationIdentifiers.forEach { credentialIdentifier -> - issuanceLog("Requesting issuance of '$credentialIdentifier'") - val outcome = when (authorizedRequest) { - is AuthorizedRequest.NoProofRequired -> submitProvidingNoProofs(issuer, authorizedRequest, credentialIdentifier) - is AuthorizedRequest.ProofRequired -> submitProvidingProofs(issuer, authorizedRequest, credentialIdentifier) + with(authorizedRequest) { + credentialOffer.credentialConfigurationIdentifiers.forEach { credentialIdentifier -> + submitCredentialRequest(this@with, credentialIdentifier).also { + println("--> Issued credential: $it \n") + } + } } - println("--> Issued credential: $outcome \n") } } -private suspend fun authorizeRequestWithAuthCodeUseCase(issuer: Issuer, actingUser: ActingUser): AuthorizedRequest = - with(issuer) { - authorizationLog("Preparing authorization code request") - - val prepareAuthorizationCodeRequest = issuer.prepareAuthorizationRequest().getOrThrow() +private suspend fun Issuer.authorizeRequestWithAuthCodeUseCase(actingUser: PidDevIssuer.ActingUser): AuthorizedRequest { + authorizationLog("Preparing authorization code request") - authorizationLog("Get authorization code URL is: ${prepareAuthorizationCodeRequest.authorizationCodeURL.value}") + val prepareAuthorizationCodeRequest = prepareAuthorizationRequest().getOrThrow().also { + authorizationLog("Get authorization code URL is: ${it.authorizationCodeURL.value}") + } - val (authorizationCode, serverState) = loginUserAndGetAuthCode( - prepareAuthorizationCodeRequest.authorizationCodeURL.value, + return with(prepareAuthorizationCodeRequest) { + val (authorizationCode, serverState) = PidDevIssuer.loginUserAndGetAuthCode( + prepareAuthorizationCodeRequest, actingUser, ) ?: error("Could not retrieve authorization code") authorizationLog("Authorization code retrieved: $authorizationCode") - val authorizedRequest = prepareAuthorizationCodeRequest.authorizeWithAuthorizationCode( - AuthorizationCode(authorizationCode), - serverState, - ).getOrThrow() - - authorizationLog("Authorization code exchanged with access token : ${authorizedRequest.accessToken.accessToken}") - - authorizedRequest + authorizeWithAuthorizationCode(AuthorizationCode(authorizationCode), serverState).getOrThrow().also { + authorizationLog("Authorization code exchanged with access token : ${it.accessToken.accessToken}") + } } +} -private suspend fun loginUserAndGetAuthCode(getAuthorizationCodeUrl: URL, actingUser: ActingUser): Pair? { - return createHttpClient().use { client -> - val loginUrl = client.get(getAuthorizationCodeUrl).body().extractASLoginUrl() +private suspend fun Issuer.submitCredentialRequest( + authorizedRequest: AuthorizedRequest, + credentialConfigurationId: CredentialConfigurationIdentifier, +): String { + issuanceLog("Requesting issuance of '$credentialConfigurationId'") + return when (authorizedRequest) { + is AuthorizedRequest.NoProofRequired -> submitProvidingNoProofs(authorizedRequest, credentialConfigurationId) - val formParameters = mapOf( - "username" to actingUser.username, - "password" to actingUser.password, - ) - val response = client.submitForm( - url = loginUrl.toString(), - formParameters = Parameters.build { - formParameters.entries.forEach { append(it.key, it.value) } - }, - ) - val redirectLocation = response.headers["Location"].toString() - with(URLBuilder(redirectLocation)) { - parameters["code"] to parameters["state"] - }.toNullable() + is AuthorizedRequest.ProofRequired -> submitProvidingProofs(authorizedRequest, credentialConfigurationId) } } -internal fun Pair.toNullable(): Pair? { - return if (first != null && second != null) first!! to second!! - else null -} -private fun String.extractASLoginUrl(): URL { - val form = Jsoup.parse(this).body().getElementById("kc-form-login") as FormElement - val action = form.attr("action") - return URL(action) -} - -private suspend fun submitProvidingNoProofs( - issuer: Issuer, +private suspend fun Issuer.submitProvidingNoProofs( authorized: AuthorizedRequest.NoProofRequired, credentialConfigurationId: CredentialConfigurationIdentifier, ): String { - with(issuer) { - val requestPayload = IssuanceRequestPayload.ConfigurationBased(credentialConfigurationId, null) - return when (val submittedRequest = authorized.requestSingle(requestPayload).getOrThrow()) { - is SubmittedRequest.Success -> handleSuccess(submittedRequest, issuer, authorized) - is SubmittedRequest.Failed -> throw submittedRequest.error - is SubmittedRequest.InvalidProof -> { - submitProvidingProofs( - issuer, - authorized.handleInvalidProof(submittedRequest.cNonce), - credentialConfigurationId, - ) - } + val requestPayload = IssuanceRequestPayload.ConfigurationBased(credentialConfigurationId, null) + return when (val submittedRequest = authorized.requestSingle(requestPayload).getOrThrow()) { + is SubmittedRequest.Success -> handleSuccess(submittedRequest, this@submitProvidingNoProofs, authorized) + is SubmittedRequest.Failed -> throw submittedRequest.error + is SubmittedRequest.InvalidProof -> { + this@submitProvidingNoProofs.submitProvidingProofs( + authorized.handleInvalidProof(submittedRequest.cNonce), + credentialConfigurationId, + ) } } } -private suspend fun submitProvidingProofs( - issuer: Issuer, +private suspend fun Issuer.submitProvidingProofs( authorized: AuthorizedRequest.ProofRequired, credentialConfigurationId: CredentialConfigurationIdentifier, ): String { - with(issuer) { - val proofSigner = DefaultProofSignersMap[credentialConfigurationId.value] - ?: error("No signer found for credential $credentialConfigurationId") + val proofSigner = DefaultProofSignersMap[credentialConfigurationId] + ?: error("No signer found for credential $credentialConfigurationId") - val requestPayload = IssuanceRequestPayload.ConfigurationBased(credentialConfigurationId, null) - val submittedRequest = authorized.requestSingle(requestPayload, proofSigner).getOrThrow() + val requestPayload = IssuanceRequestPayload.ConfigurationBased(credentialConfigurationId, null) + val submittedRequest = authorized.requestSingle(requestPayload, proofSigner).getOrThrow() - return when (submittedRequest) { - is SubmittedRequest.Success -> handleSuccess(submittedRequest, issuer, authorized) - is SubmittedRequest.Failed -> throw submittedRequest.error - is SubmittedRequest.InvalidProof -> throw IllegalStateException( - "Although providing a proof with c_nonce the proof is still invalid", - ) - } + return when (submittedRequest) { + is SubmittedRequest.Success -> handleSuccess(submittedRequest, this@submitProvidingProofs, authorized) + is SubmittedRequest.Failed -> throw submittedRequest.error + is SubmittedRequest.InvalidProof -> throw IllegalStateException( + "Although providing a proof with c_nonce the proof is still invalid", + ) } }