diff --git a/App.tsx b/App.tsx index e5cc265d..97228adf 100644 --- a/App.tsx +++ b/App.tsx @@ -1,3 +1,4 @@ +import 'react-native-get-random-values'; import React, {useContext, useEffect, useState} from 'react'; import {AppLayout} from './screens/AppLayout'; import {useFont} from './shared/hooks/useFont'; diff --git a/android/app/build.gradle b/android/app/build.gradle index 257e2224..9eb9ae46 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -280,7 +280,7 @@ dependencies { implementation("io.mosip:pixelpass-aar:0.7.0-SNAPSHOT") implementation("io.mosip:secure-keystore:0.3.0") implementation("io.mosip:tuvali:0.5.2") - implementation("io.mosip:inji-vci-client:0.4.0-SNAPSHOT") + implementation("io.mosip:inji-vci-client-aar:0.4.0-SNAPSHOT") implementation("com.google.code.gson:gson:2.10.1") implementation("io.mosip:vcverifier-aar:1.3.0-SNAPSHOT") { exclude group: 'org.bouncycastle', module: 'bcpkix-jdk15on' diff --git a/android/app/src/main/java/io/mosip/residentapp/InjiVCIClientCallback.kt b/android/app/src/main/java/io/mosip/residentapp/InjiVCIClientCallback.kt index 9a5a9413..a89c1298 100644 --- a/android/app/src/main/java/io/mosip/residentapp/InjiVCIClientCallback.kt +++ b/android/app/src/main/java/io/mosip/residentapp/InjiVCIClientCallback.kt @@ -4,6 +4,7 @@ import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.modules.core.DeviceEventManagerModule import com.google.gson.Gson +import io.mosip.vciclient.token.TokenResponse import kotlinx.coroutines.CompletableDeferred object VCIClientCallbackBridge { @@ -11,6 +12,7 @@ object VCIClientCallbackBridge { private var deferredAuthCode: CompletableDeferred? = null private var deferredTxCode: CompletableDeferred? = null private var deferredIssuerTrustResponse: CompletableDeferred? = null + private var deferredTokenResponse: CompletableDeferred? = null fun createProofDeferred(): CompletableDeferred { deferredProof = CompletableDeferred() @@ -22,72 +24,86 @@ object VCIClientCallbackBridge { return deferredAuthCode!! } + fun createTokenResponseDeferred(): CompletableDeferred { + deferredTokenResponse = CompletableDeferred() + return deferredTokenResponse!! + } + fun createTxCodeDeferred(): CompletableDeferred { deferredTxCode = CompletableDeferred() return deferredTxCode!! } - fun createIsuerTrustResponseDeferred(): CompletableDeferred { + fun createIssuerTrustResponseDeferred(): CompletableDeferred { deferredIssuerTrustResponse = CompletableDeferred() return deferredIssuerTrustResponse!! } fun emitRequestProof( - context: ReactApplicationContext, - accessToken: String, - cNonce: String?, - issuerMetadata: Map? = null, - credentialConfigurationId: String? = null + context: ReactApplicationContext, + credentialIssuer: String, + cNonce: String?, + proofSigningAlgorithmsSupported: List, ) { val params = - Arguments.createMap().apply { - putString("accessToken", accessToken) - if (cNonce != null) putString("cNonce", cNonce) - if (issuerMetadata != null) { - val json = Gson().toJson(issuerMetadata) - putString("issuerMetadata", json) - } - if (credentialConfigurationId != null) { - putString("credentialConfigurationId", credentialConfigurationId) - } - } + Arguments.createMap().apply { + putString("credentialIssuer", credentialIssuer) + if (cNonce != null) putString("cNonce", cNonce) + val json = Gson().toJson(proofSigningAlgorithmsSupported) + putString("proofSigningAlgorithmsSupported", json) + } context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) - .emit("onRequestProof", params) + .emit("onRequestProof", params) } fun emitRequestAuthCode(context: ReactApplicationContext, authorizationEndpoint: String) { val params = - Arguments.createMap().apply { - putString("authorizationEndpoint", authorizationEndpoint) - } + Arguments.createMap().apply { + putString("authorizationUrl", authorizationEndpoint) + } context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) - .emit("onRequestAuthCode", params) + .emit("onRequestAuthCode", params) + } + + fun emitTokenRequest( + context: ReactApplicationContext, + payload: Map + ) { + val params = + Arguments.createMap().apply { + putString("tokenRequest", Gson().toJson(payload)) + } + context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) + .emit("onRequestTokenResponse", params) } fun emitRequestTxCode( - context: ReactApplicationContext, - inputMode: String?, - description: String?, - length: Int? + context: ReactApplicationContext, + inputMode: String?, + description: String?, + length: Int? ) { val params = - Arguments.createMap().apply { - putString("inputMode", inputMode) - putString("description", description) - if( length != null) + Arguments.createMap().apply { + putString("inputMode", inputMode) + putString("description", description) + if (length != null) putInt("length", length) - } + } context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) - .emit("onRequestTxCode", params) + .emit("onRequestTxCode", params) } - fun emitRequestIssuerTrust(context: ReactApplicationContext, issuerMetadata: Map) { + + fun emitRequestIssuerTrust(context: ReactApplicationContext, credentialIssuer: String, issuerDisplay: List>) { val params = - Arguments.createMap().apply { - putString("issuerMetadata", Gson().toJson(issuerMetadata)) - } + Arguments.createMap().apply { +//TODO: Convert Gson construction to singleton pattern + putString("credentialIssuer", credentialIssuer) + putString("issuerDisplay", Gson().toJson(issuerDisplay)) + } context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) - .emit("onCheckIssuerTrust", params) + .emit("onCheckIssuerTrust", params) } @JvmStatic @@ -95,16 +111,25 @@ object VCIClientCallbackBridge { deferredProof?.complete(jwt) deferredProof = null } + @JvmStatic fun completeAuthCode(code: String) { deferredAuthCode?.complete(code) deferredAuthCode = null } + @JvmStatic fun completeTxCode(code: String) { deferredTxCode?.complete(code) deferredTxCode = null } + + @JvmStatic + fun completeTokenResponse(tokenResponse: TokenResponse) { + deferredTokenResponse?.complete(tokenResponse) + deferredTokenResponse = null + } + @JvmStatic fun completeIssuerTrustResponse(trusted: Boolean) { deferredIssuerTrustResponse?.complete(trusted) @@ -117,7 +142,12 @@ object VCIClientCallbackBridge { suspend fun awaitAuthCode(): String { return deferredAuthCode?.await() - ?: throw IllegalStateException("No auth code callback was set") + ?: throw IllegalStateException("No auth code callback was set") + } + + suspend fun awaitTokenResponse(): TokenResponse { + return deferredTokenResponse?.await() + ?: throw IllegalStateException("No TokenResponse callback was set") } suspend fun awaitTxCode(): String { @@ -126,6 +156,6 @@ object VCIClientCallbackBridge { suspend fun awaitIssuerTrustResponse(): Boolean { return deferredIssuerTrustResponse?.await() - ?: throw IllegalStateException("No issuer trust response callback was set") + ?: throw IllegalStateException("No issuer trust response callback was set") } } diff --git a/android/app/src/main/java/io/mosip/residentapp/InjiVciClientModule.java b/android/app/src/main/java/io/mosip/residentapp/InjiVciClientModule.java index 10ef8ef0..83dc62b1 100644 --- a/android/app/src/main/java/io/mosip/residentapp/InjiVciClientModule.java +++ b/android/app/src/main/java/io/mosip/residentapp/InjiVciClientModule.java @@ -9,22 +9,14 @@ import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; import com.google.gson.Gson; -import java.util.Objects; -import io.mosip.residentapp.VCIClientCallbackBridge; -import io.mosip.residentapp.VCIClientBridge; + +import java.util.Map; import io.mosip.vciclient.VCIClient; -import io.mosip.vciclient.constants.CredentialFormat; -import io.mosip.vciclient.credentialOffer.CredentialOffer; -import io.mosip.vciclient.credentialOffer.CredentialOfferService; -import io.mosip.vciclient.credentialResponse.CredentialResponse; -import io.mosip.vciclient.proof.jwt.JWTProof; -import io.mosip.vciclient.proof.Proof; -import io.mosip.vciclient.issuerMetadata.IssuerMetadata; -import io.mosip.vciclient.clientMetadata.ClientMetadata; +import io.mosip.vciclient.authorizationCodeFlow.clientMetadata.ClientMetadata; +import io.mosip.vciclient.credential.response.CredentialResponse; +import io.mosip.vciclient.token.TokenResponse; public class InjiVciClientModule extends ReactContextBaseJavaModule { private VCIClient vciClient; @@ -69,6 +61,29 @@ public class InjiVciClientModule extends ReactContextBaseJavaModule { VCIClientCallbackBridge.completeIssuerTrustResponse(trusted); } + @ReactMethod + public void sendTokenResponseFromJS(String tokenResponseJson) { + TokenResponse tokenResponse = new Gson().fromJson(tokenResponseJson, TokenResponse.class); + VCIClientCallbackBridge.completeTokenResponse(tokenResponse); + } + + @ReactMethod + public void getIssuerMetadata(String credentialIssuer, Promise promise) { + new Thread(() -> { + try { + Map issuerMetadata = vciClient.getIssuerMetadata(credentialIssuer); + reactContext.runOnUiQueueThread(() -> { + String json = new Gson().toJson(issuerMetadata, Map.class); + promise.resolve(json); + }); + } catch (Exception e) { + reactContext.runOnUiQueueThread(() -> { + promise.reject("GET_ISSUER_METADATA_FAILED", e.getMessage(), e); + }); + } + }).start(); + } + @ReactMethod public void requestCredentialByOffer(String credentialOffer,String clientMetadataJson, Promise promise) { new Thread(() -> { @@ -88,15 +103,13 @@ public class InjiVciClientModule extends ReactContextBaseJavaModule { } @ReactMethod - public void requestCredentialFromTrustedIssuer(String resolvedIssuerMetaJson, String clientMetadataJson, Promise promise) { + public void requestCredentialFromTrustedIssuer(String credentialIssuer, String credentialConfigurationId, String clientMetadataJson, Promise promise) { new Thread(() -> { try { - IssuerMetadata issuerMetaData = new Gson().fromJson( - resolvedIssuerMetaJson, IssuerMetadata.class); ClientMetadata clientMetadata= new Gson().fromJson( clientMetadataJson, ClientMetadata.class); - CredentialResponse response = VCIClientBridge.requestCredentialFromTrustedIssuerSync(vciClient, issuerMetaData,clientMetadata); + CredentialResponse response = VCIClientBridge.requestCredentialFromTrustedIssuerSync(vciClient, credentialIssuer, credentialConfigurationId,clientMetadata); reactContext.runOnUiQueueThread(() -> { promise.resolve(response != null ? response.toJsonString() : null); diff --git a/android/app/src/main/java/io/mosip/residentapp/VCIClientBridge.kt b/android/app/src/main/java/io/mosip/residentapp/VCIClientBridge.kt index 3a9499a1..b647a852 100644 --- a/android/app/src/main/java/io/mosip/residentapp/VCIClientBridge.kt +++ b/android/app/src/main/java/io/mosip/residentapp/VCIClientBridge.kt @@ -2,10 +2,12 @@ package io.mosip.residentapp import com.facebook.react.bridge.ReactApplicationContext import io.mosip.vciclient.VCIClient -import io.mosip.vciclient.clientMetadata.ClientMetadata -import io.mosip.vciclient.credentialResponse.CredentialResponse -import io.mosip.vciclient.issuerMetadata.IssuerMetadata -import io.mosip.residentapp.VCIClientBridge +import io.mosip.vciclient.authorizationCodeFlow.clientMetadata.ClientMetadata +import io.mosip.vciclient.credential.response.CredentialResponse +import io.mosip.vciclient.token.TokenRequest +import io.mosip.vciclient.token.TokenResponse +import io.mosip.vciclient.constants.AuthorizeUserCallback +import io.mosip.vciclient.constants.ProofJwtCallback import kotlinx.coroutines.runBlocking object VCIClientBridge { @@ -18,62 +20,94 @@ object VCIClientBridge { client: VCIClient, offer: String, clientMetaData: ClientMetadata - ): CredentialResponse? = runBlocking { + ): CredentialResponse = runBlocking { client.requestCredentialByCredentialOffer( credentialOffer = offer, clientMetadata = clientMetaData, - getTxCode = { inputMode, description, length -> - VCIClientCallbackBridge.createTxCodeDeferred() - VCIClientCallbackBridge.emitRequestTxCode(VCIClientBridge.reactContext, - inputMode, - description, - length - ) - VCIClientCallbackBridge.awaitTxCode() - }, - getProofJwt = { accessToken, cNonce, issuerMetadata, credentialConfigurationId -> - VCIClientCallbackBridge.createProofDeferred() - VCIClientCallbackBridge.emitRequestProof( - VCIClientBridge.reactContext, - accessToken, - cNonce, - issuerMetadata, - credentialConfigurationId - ) - VCIClientCallbackBridge.awaitProof() - }, - getAuthCode = { endpoint -> - VCIClientCallbackBridge.createAuthCodeDeferred() - VCIClientCallbackBridge.emitRequestAuthCode(VCIClientBridge.reactContext, endpoint) - VCIClientCallbackBridge.awaitAuthCode() - }, - onCheckIssuerTrust = { issuerMetadata -> - VCIClientCallbackBridge.createIsuerTrustResponseDeferred() - VCIClientCallbackBridge.emitRequestIssuerTrust(reactContext, issuerMetadata) - VCIClientCallbackBridge.awaitIssuerTrustResponse() - } + getTxCode = getTxCodeCallback(), + authorizeUser = authorizeUserCallback(), + getTokenResponse = getTokenResponseCallback(), + getProofJwt = getProofJwtCallback(), + onCheckIssuerTrust = onCheckIssuerTrustCallback() ) } @JvmStatic fun requestCredentialFromTrustedIssuerSync( client: VCIClient, - resolvedIssuerMetaData: IssuerMetadata, + credentialIssuer: String, + credentialConfigurationId: String, clientMetaData: ClientMetadata - ): CredentialResponse? = runBlocking { + ): CredentialResponse = runBlocking { client.requestCredentialFromTrustedIssuer( - issuerMetadata = resolvedIssuerMetaData, - clientMetadata = clientMetaData, - getProofJwt = { accessToken, cNonce, _, _ -> - VCIClientCallbackBridge.createProofDeferred() - VCIClientCallbackBridge.emitRequestProof(reactContext, accessToken, cNonce) - VCIClientCallbackBridge.awaitProof() - }, - getAuthCode = { authorizationEndpoint -> - VCIClientCallbackBridge.createAuthCodeDeferred() - VCIClientCallbackBridge.emitRequestAuthCode(reactContext, authorizationEndpoint) - VCIClientCallbackBridge.awaitAuthCode() - } + credentialIssuer, + credentialConfigurationId, + clientMetaData, + authorizeUser = authorizeUserCallback(), + getTokenResponse = getTokenResponseCallback(), + getProofJwt = getProofJwtCallback(), ) } + + private fun authorizeUserCallback(): AuthorizeUserCallback = { endpoint -> + VCIClientCallbackBridge.createAuthCodeDeferred() + VCIClientCallbackBridge.emitRequestAuthCode(reactContext, endpoint) + VCIClientCallbackBridge.awaitAuthCode() + } + + private fun getProofJwtCallback(): ProofJwtCallback = + { + credentialIssuer: String, + cNonce: String?, + proofSigningAlgorithmsSupported: List -> + VCIClientCallbackBridge.createProofDeferred() + VCIClientCallbackBridge.emitRequestProof( + reactContext, + credentialIssuer, + cNonce, + proofSigningAlgorithmsSupported + ) + VCIClientCallbackBridge.awaitProof() + } + + private fun getTokenResponseCallback(): suspend (tokenRequest: TokenRequest) -> TokenResponse = + { tokenRequest -> + val payload: Map = + mapOf( + "grantType" to tokenRequest.grantType.value, + "tokenEndpoint" to tokenRequest.tokenEndpoint, + "authCode" to tokenRequest.authCode, + "preAuthCode" to tokenRequest.preAuthCode, + "txCode" to tokenRequest.txCode, + "clientId" to tokenRequest.clientId, + "redirectUri" to tokenRequest.redirectUri, + "codeVerifier" to tokenRequest.codeVerifier + ) + VCIClientCallbackBridge.createTokenResponseDeferred() + VCIClientCallbackBridge.emitTokenRequest(reactContext, payload) + VCIClientCallbackBridge.awaitTokenResponse() + } + + private fun getTxCodeCallback(): suspend (String?, String?, Int?) -> String = + { inputMode, description, length -> + VCIClientCallbackBridge.createTxCodeDeferred() + VCIClientCallbackBridge.emitRequestTxCode( + reactContext, + inputMode, + description, + length + ) + VCIClientCallbackBridge.awaitTxCode() + } + + private fun onCheckIssuerTrustCallback(): suspend (String, List>) -> Boolean = + { credentialIssuer, issuerDisplay -> + VCIClientCallbackBridge.createIssuerTrustResponseDeferred() + VCIClientCallbackBridge.emitRequestIssuerTrust( + reactContext, + credentialIssuer, + issuerDisplay + ) + VCIClientCallbackBridge.awaitIssuerTrustResponse() + } } diff --git a/components/VC/Views/VCCardView.tsx b/components/VC/Views/VCCardView.tsx index b6597a7f..79511e2d 100644 --- a/components/VC/Views/VCCardView.tsx +++ b/components/VC/Views/VCCardView.tsx @@ -19,11 +19,9 @@ import {VCProcessor} from '../common/VCProcessor'; export const VCCardView: React.FC = ({ vcMetadata, - margin, selectable, selected, onPress, - onShow, isDownloading, isPinned, flow, @@ -58,7 +56,7 @@ export const VCCardView: React.FC = ({ setVc(processedData); } } - + loadVc(); }, [isDownloading, controller.credential]); diff --git a/ios/Inji.xcodeproj/project.pbxproj b/ios/Inji.xcodeproj/project.pbxproj index b5207f2f..180e8ed2 100644 --- a/ios/Inji.xcodeproj/project.pbxproj +++ b/ios/Inji.xcodeproj/project.pbxproj @@ -32,10 +32,10 @@ 9C4850532C3E59E2002ECBD5 /* RNEventEmitterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C4850522C3E59E2002ECBD5 /* RNEventEmitterProtocol.swift */; }; 9C7CDF3E2C7CBEDE00243A9A /* RNSecureKeystoreModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C7CDF3D2C7CBEDE00243A9A /* RNSecureKeystoreModule.swift */; }; 9C7CDF432C7CC13500243A9A /* RNSecureKeystoreModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C7CDF422C7CC13500243A9A /* RNSecureKeystoreModule.m */; }; + 9CAE74EE2E2E38F800C2532C /* pixelpass in Frameworks */ = {isa = PBXBuildFile; productRef = 9CAE74ED2E2E38F800C2532C /* pixelpass */; }; 9CCCA19E2CF87A8400D5A461 /* securekeystore in Frameworks */ = {isa = PBXBuildFile; productRef = 9CCCA19D2CF87A8400D5A461 /* securekeystore */; }; 9CD470CE2DFFF86600C207F9 /* OpenID4VP in Frameworks */ = {isa = PBXBuildFile; productRef = 9CD470CD2DFFF86600C207F9 /* OpenID4VP */; }; - 9CD470D12DFFF89C00C207F9 /* VCIClient in Frameworks */ = {isa = PBXBuildFile; productRef = 9CD470D02DFFF89C00C207F9 /* VCIClient */; }; - 9CFB37492DDDC9A000C199A8 /* pixelpass in Frameworks */ = {isa = PBXBuildFile; productRef = 9CFB37482DDDC9A000C199A8 /* pixelpass */; }; + 9CDFD3102E28CA7B00505CEF /* VCIClient in Frameworks */ = {isa = PBXBuildFile; productRef = 9CDFD30F2E28CA7B00505CEF /* VCIClient */; }; B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; }; BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; }; E86208152C0335C5007C3E24 /* RNVCIClientModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86208142C0335C5007C3E24 /* RNVCIClientModule.swift */; }; @@ -123,10 +123,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9CD470D12DFFF89C00C207F9 /* VCIClient in Frameworks */, + 9CDFD3102E28CA7B00505CEF /* VCIClient in Frameworks */, 9C4850432C3E5873002ECBD5 /* ios-tuvali-library in Frameworks */, + 9CAE74EE2E2E38F800C2532C /* pixelpass in Frameworks */, 9CCCA19E2CF87A8400D5A461 /* securekeystore in Frameworks */, - 9CFB37492DDDC9A000C199A8 /* pixelpass in Frameworks */, 9CD470CE2DFFF86600C207F9 /* OpenID4VP in Frameworks */, 96905EF65AED1B983A6B3ABC /* libPods-Inji.a in Frameworks */, ); @@ -305,6 +305,7 @@ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */, D11A8C363B4A5B625DB10379 /* [CP] Embed Pods Frameworks */, + 9CDFD3112E2A2F7900505CEF /* ShellScript */, ); buildRules = ( ); @@ -314,9 +315,9 @@ packageProductDependencies = ( 9C4850422C3E5873002ECBD5 /* ios-tuvali-library */, 9CCCA19D2CF87A8400D5A461 /* securekeystore */, - 9CFB37482DDDC9A000C199A8 /* pixelpass */, 9CD470CD2DFFF86600C207F9 /* OpenID4VP */, - 9CD470D02DFFF89C00C207F9 /* VCIClient */, + 9CDFD30F2E28CA7B00505CEF /* VCIClient */, + 9CAE74ED2E2E38F800C2532C /* pixelpass */, ); productName = Inji; productReference = 13B07F961A680F5B00A75B9A /* Inji.app */; @@ -347,9 +348,9 @@ packageReferences = ( 9C4850412C3E5873002ECBD5 /* XCRemoteSwiftPackageReference "tuvali-ios-swift" */, 9CCCA19C2CF87A8400D5A461 /* XCRemoteSwiftPackageReference "secure-keystore-ios-swift" */, - 9CFB37472DDDC99F00C199A8 /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */, 9CD470CC2DFFF86600C207F9 /* XCRemoteSwiftPackageReference "inji-openid4vp-ios-swift" */, - 9CD470CF2DFFF89C00C207F9 /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */, + 9CDFD30E2E28CA7B00505CEF /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */, + 9CAE74EC2E2E38F800C2532C /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */, ); productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; projectDirPath = ""; @@ -833,6 +834,14 @@ version = 0.5.0; }; }; + 9CAE74EC2E2E38F800C2532C /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/mosip/pixelpass-ios-swift/"; + requirement = { + branch = "release-0.6.x"; + kind = branch; + }; + }; 9CCCA19C2CF87A8400D5A461 /* XCRemoteSwiftPackageReference "secure-keystore-ios-swift" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/mosip/secure-keystore-ios-swift"; @@ -849,19 +858,11 @@ kind = branch; }; }; - 9CD470CF2DFFF89C00C207F9 /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */ = { + 9CDFD30E2E28CA7B00505CEF /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/mosip/inji-vci-client-ios-swift/"; requirement = { - branch = develop; - kind = branch; - }; - }; - 9CFB37472DDDC99F00C199A8 /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/mosip/pixelpass-ios-swift/"; - requirement = { - branch = develop; + branch = "release-0.4.x"; kind = branch; }; }; @@ -873,6 +874,11 @@ package = 9C4850412C3E5873002ECBD5 /* XCRemoteSwiftPackageReference "tuvali-ios-swift" */; productName = "ios-tuvali-library"; }; + 9CAE74ED2E2E38F800C2532C /* pixelpass */ = { + isa = XCSwiftPackageProductDependency; + package = 9CAE74EC2E2E38F800C2532C /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */; + productName = pixelpass; + }; 9CCCA19D2CF87A8400D5A461 /* securekeystore */ = { isa = XCSwiftPackageProductDependency; package = 9CCCA19C2CF87A8400D5A461 /* XCRemoteSwiftPackageReference "secure-keystore-ios-swift" */; @@ -883,16 +889,11 @@ package = 9CD470CC2DFFF86600C207F9 /* XCRemoteSwiftPackageReference "inji-openid4vp-ios-swift" */; productName = OpenID4VP; }; - 9CD470D02DFFF89C00C207F9 /* VCIClient */ = { + 9CDFD30F2E28CA7B00505CEF /* VCIClient */ = { isa = XCSwiftPackageProductDependency; - package = 9CD470CF2DFFF89C00C207F9 /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */; + package = 9CDFD30E2E28CA7B00505CEF /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */; productName = VCIClient; }; - 9CFB37482DDDC9A000C199A8 /* pixelpass */ = { - isa = XCSwiftPackageProductDependency; - package = 9CFB37472DDDC99F00C199A8 /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */; - productName = pixelpass; - }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; diff --git a/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved index 393f1ad8..624502f5 100644 --- a/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -78,8 +78,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/mosip/inji-vci-client-ios-swift/", "state" : { - "branch" : "develop", - "revision" : "8a39bbf7805af4c615904090a027fa472e5f4534" + "branch" : "release-0.4.x", + "revision" : "56359149fbfa61e4fd334df21bf2116e05b4d02d" } }, { @@ -96,8 +96,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/mosip/pixelpass-ios-swift/", "state" : { - "branch" : "develop", - "revision" : "78a8b507f5bd0046e273e3ba962696b44aea0e33" + "branch" : "release-0.6.x", + "revision" : "78faea2ff48626ef9a6d198123bcf7b299acefd1" } }, { @@ -130,9 +130,9 @@ { "identity" : "swiftcbor", "kind" : "remoteSourceControl", - "location" : "https://github.com/valpackett/SwiftCBOR", + "location" : "https://github.com/abhip2565/SwiftCBOR", "state" : { - "revision" : "04ccff117f6549121d5721ec84fdf0162122b90e", + "revision" : "cc4e195a0ea2dce88f2fd6c6d73b2504e3c884fd", "version" : "0.5.0" } }, diff --git a/ios/RNVCIClientModule.m b/ios/RNVCIClientModule.m index 6c9aa5be..12ec35d9 100644 --- a/ios/RNVCIClientModule.m +++ b/ios/RNVCIClientModule.m @@ -12,12 +12,18 @@ RCT_EXTERN_METHOD(requestCredentialByOffer:(NSString *)credentialOffer resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) -// Requests a credential from a trusted issuer using issuer metadata and client metadata (both as JSON strings) -RCT_EXTERN_METHOD(requestCredentialFromTrustedIssuer:(NSString *)issuerMetadata +// Requests a credential from a trusted issuer using issuer URI, configuration ID, and client metadata (all as strings) +RCT_EXTERN_METHOD(requestCredentialFromTrustedIssuer:(NSString *)credentialIssuer + credentialConfigurationId:(NSString *)credentialConfigurationId clientMetadata:(NSString *)clientMetadata resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +// Gets issuer metadata (discovery) +RCT_EXTERN_METHOD(getIssuerMetadata:(NSString *)credentialIssuer + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + // Sends proof JWT back to native side (in response to onRequestProof) RCT_EXTERN_METHOD(sendProofFromJS:(NSString *)jwtProof) @@ -30,6 +36,9 @@ RCT_EXTERN_METHOD(sendTxCodeFromJS:(NSString *)txCode) // Sends issuer trust decision (true/false) back to native side (in response to onCheckIssuerTrust) RCT_EXTERN_METHOD(sendIssuerTrustResponseFromJS:(BOOL)isTrusted) +// Sends token response JSON back to native side (in response to onRequestTokenResponse) +RCT_EXTERN_METHOD(sendTokenResponseFromJS:(NSString *)tokenResponseJson) + // Required by React Native RCT_EXTERN_METHOD(requiresMainQueueSetup:(BOOL)isRequired) diff --git a/ios/RNVCIClientModule.swift b/ios/RNVCIClientModule.swift index e584e8db..8a329928 100644 --- a/ios/RNVCIClientModule.swift +++ b/ios/RNVCIClientModule.swift @@ -4,10 +4,13 @@ import VCIClient @objc(InjiVciClient) class RNVCIClientModule: NSObject, RCTBridgeModule { + private var vciClient: VCIClient? + private var pendingProofContinuation: ((String) -> Void)? private var pendingAuthCodeContinuation: ((String) -> Void)? private var pendingTxCodeContinuation: ((String) -> Void)? + private var pendingTokenResponseContinuation: ((String) -> Void)? private var pendingIssuerTrustDecision: ((Bool) -> Void)? static func moduleName() -> String { @@ -19,6 +22,8 @@ class RNVCIClientModule: NSObject, RCTBridgeModule { vciClient = VCIClient(traceabilityId: traceabilityId) } + // MARK: - Public API + @objc func requestCredentialByOffer( _ credentialOffer: String, @@ -45,19 +50,24 @@ class RNVCIClientModule: NSObject, RCTBridgeModule { length: length ) }, - getProofJwt: { accessToken, cNonce, issuerMetadata, credentialConfigId in - try await self.getProofContinuationHook( - accessToken: accessToken, - cNonce: cNonce, - issuerMetadata: issuerMetadata, - credentialConfigId: credentialConfigId - ) - }, - getAuthCode: { authUrl in + authorizeUser: { authUrl in try await self.getAuthCodeContinuationHook(authUrl: authUrl) }, - onCheckIssuerTrust: { issuerMetadata in - try await self.getIssuerTrustDecisionHook(issuerMetadata: issuerMetadata) + getTokenResponse: { tokenRequest in + try await self.getTokenResponseHook(tokenRequest: tokenRequest) + }, + getProofJwt: { credentialIssuer, cNonce, algos in + try await self.getProofContinuationHook( + credentialIssuer: credentialIssuer, + cNonce: cNonce, + proofSigningAlgorithmsSupported: algos + ) + }, + onCheckIssuerTrust: { credentialIssuer, issuerDisplay in + try await self.getIssuerTrustDecisionHook( + credentialIssuer: credentialIssuer, + issuerDisplay: issuerDisplay + ) } ) @@ -70,7 +80,8 @@ class RNVCIClientModule: NSObject, RCTBridgeModule { @objc func requestCredentialFromTrustedIssuer( - _ issuerMetadata: String, + _ credentialIssuer: String, + credentialConfigurationId: String, clientMetadata: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock @@ -82,22 +93,24 @@ class RNVCIClientModule: NSObject, RCTBridgeModule { return } - let issuer = try parseIssuerMeta(from: issuerMetadata) let clientMeta = try parseClientMetadata(from: clientMetadata) let response = try await vciClient.requestCredentialFromTrustedIssuer( - issuerMetadata: issuer, + credentialIssuer: credentialIssuer, + credentialConfigurationId: credentialConfigurationId, clientMetadata: clientMeta, - getProofJwt: { accessToken, cNonce, issuerMetadata, credentialConfigId in - try await self.getProofContinuationHook( - accessToken: accessToken, - cNonce: cNonce, - issuerMetadata: issuerMetadata, - credentialConfigId: credentialConfigId - ) - }, - getAuthCode: { authUrl in + authorizeUser: { authUrl in try await self.getAuthCodeContinuationHook(authUrl: authUrl) + }, + getTokenResponse: { tokenRequest in + try await self.getTokenResponseHook(tokenRequest: tokenRequest) + }, + getProofJwt: { credentialIssuer, cNonce, algos in + try await self.getProofContinuationHook( + credentialIssuer: credentialIssuer, + cNonce: cNonce, + proofSigningAlgorithmsSupported: algos + ) } ) @@ -107,54 +120,51 @@ class RNVCIClientModule: NSObject, RCTBridgeModule { } } } + + @objc + func getIssuerMetadata( + _ credentialIssuer: String, + resolver resolve: @escaping RCTPromiseResolveBlock, + rejecter reject: @escaping RCTPromiseRejectBlock + ) { + Task { + do { + guard let vciClient = vciClient else { + reject(nil, "VCIClient not initialized", nil) + return + } - private func getProofContinuationHook( - accessToken: String, - cNonce: String?, - issuerMetadata: [String: Any]?, - credentialConfigId: String? - ) async throws -> String { - var issuerMetadataJson: String = "" + let metadata = try await vciClient.getIssuerMetadata(credentialIssuer: credentialIssuer) - if let issuerMetadata = issuerMetadata { - if let data = try? JSONSerialization.data(withJSONObject: issuerMetadata, options: []), - let jsonString = String(data: data, encoding: .utf8) { - issuerMetadataJson = jsonString + let data = try JSONSerialization.data(withJSONObject: metadata, options: []) + guard let jsonString = String(data: data, encoding: .utf8) else { + throw NSError(domain: "JSONEncodingError", code: 0) + } + + resolve(jsonString) + } catch { + reject(nil, error.localizedDescription, nil) } } - - if let bridge = RCTBridge.current() { - let payload: [String: Any] = [ - "accessToken": accessToken, - "cNonce": cNonce ?? NSNull(), - "issuerMetadata": issuerMetadataJson, - "credentialConfigurationId": credentialConfigId ?? NSNull(), - ] - bridge.eventDispatcher().sendAppEvent(withName: "onRequestProof", body: payload) - } - - return try await withCheckedThrowingContinuation { continuation in - self.pendingProofContinuation = { jwt in continuation.resume(returning: jwt) } - } } - private func getAuthCodeContinuationHook(authUrl: String) async throws -> String { - if let bridge = RCTBridge.current() { - bridge.eventDispatcher().sendAppEvent(withName: "onRequestAuthCode", body: ["authorizationEndpoint": authUrl]) - } - return try await withCheckedThrowingContinuation { continuation in - self.pendingAuthCodeContinuation = { code in continuation.resume(returning: code) } - } - } + // MARK: - Callbacks to JS - private func getTxCodeHook(inputMode: String?, description: String?, length: Int? ) async throws -> String { + private func getTxCodeHook( + inputMode: String?, + description: String?, + length: Int? + ) async throws -> String { if let bridge = RCTBridge.current() { - bridge.eventDispatcher().sendAppEvent(withName: "onRequestTxCode", body: [ - "inputMode": inputMode, - "description": description, - "length": length - ]) + bridge.eventDispatcher().sendAppEvent( + withName: "onRequestTxCode", + body: [ + "inputMode": inputMode, + "description": description, + "length": length + ] + ) } return try await withCheckedThrowingContinuation { continuation in @@ -162,15 +172,87 @@ class RNVCIClientModule: NSObject, RCTBridgeModule { } } - private func getIssuerTrustDecisionHook(issuerMetadata: [String: Any]) async throws -> Bool { - var metadataJson = "" - if let data = try? JSONSerialization.data(withJSONObject: issuerMetadata, options: []), - let string = String(data: data, encoding: .utf8) { - metadataJson = string + private func getAuthCodeContinuationHook(authUrl: String) async throws -> String { + if let bridge = RCTBridge.current() { + bridge.eventDispatcher().sendAppEvent( + withName: "onRequestAuthCode", + body: ["authorizationUrl": authUrl] + ) } + return try await withCheckedThrowingContinuation { continuation in + self.pendingAuthCodeContinuation = { code in continuation.resume(returning: code) } + } + } + + private func getProofContinuationHook( + credentialIssuer: String, + cNonce: String?, + proofSigningAlgorithmsSupported: [String] + ) async throws -> String { + let jsonData = try JSONSerialization.data(withJSONObject: proofSigningAlgorithmsSupported, options: []) + let jsonString = String(data: jsonData, encoding: .utf8) ?? "{}" if let bridge = RCTBridge.current() { - bridge.eventDispatcher().sendAppEvent(withName: "onCheckIssuerTrust", body: ["issuerMetadata": metadataJson]) + bridge.eventDispatcher().sendAppEvent( + withName: "onRequestProof", + body: [ + "credentialIssuer": credentialIssuer, + "cNonce": cNonce, + "proofSigningAlgorithmsSupported": jsonString + ] + ) + } + + return try await withCheckedThrowingContinuation { continuation in + self.pendingProofContinuation = { jwt in continuation.resume(returning: jwt) } + } + } + + private func getTokenResponseHook(tokenRequest: TokenRequest) async throws -> TokenResponse { + if let bridge = RCTBridge.current() { + let tokenRequest: [String: Any] = [ + "grantType": tokenRequest.grantType.rawValue, + "tokenEndpoint": tokenRequest.tokenEndpoint, + "authCode": tokenRequest.authCode ?? NSNull(), + "preAuthCode": tokenRequest.preAuthCode ?? NSNull(), + "txCode": tokenRequest.txCode ?? NSNull(), + "clientId": tokenRequest.clientId ?? NSNull(), + "redirectUri": tokenRequest.redirectUri ?? NSNull(), + "codeVerifier": tokenRequest.codeVerifier ?? NSNull() + ] + + bridge.eventDispatcher().sendAppEvent( + withName: "onRequestTokenResponse", + body: ["tokenRequest":tokenRequest] + ) + } + + let json = try await withCheckedThrowingContinuation { continuation in + self.pendingTokenResponseContinuation = { json in continuation.resume(returning: json) } + } + + guard let data = json.data(using: .utf8) else { + throw NSError(domain: "Invalid JSON", code: 0) + } + + return try JSONDecoder().decode(TokenResponse.self, from: data) + } + + private func getIssuerTrustDecisionHook( + credentialIssuer: String, + issuerDisplay: [[String: Any]] + ) async throws -> Bool { + // Convert issuerDisplay to JSON string + let jsonData = try JSONSerialization.data(withJSONObject: issuerDisplay, options: []) + let jsonString = String(data: jsonData, encoding: .utf8) ?? "[]" + if let bridge = RCTBridge.current() { + bridge.eventDispatcher().sendAppEvent( + withName: "onCheckIssuerTrust", + body: [ + "credentialIssuer": credentialIssuer, + "issuerDisplay": jsonString + ] + ) } return try await withCheckedThrowingContinuation { continuation in @@ -178,6 +260,8 @@ class RNVCIClientModule: NSObject, RCTBridgeModule { } } + // MARK: - Receivers from JS + @objc(sendProofFromJS:) func sendProofFromJS(_ jwt: String) { pendingProofContinuation?(jwt) @@ -196,24 +280,25 @@ class RNVCIClientModule: NSObject, RCTBridgeModule { pendingTxCodeContinuation = nil } + @objc(sendTokenResponseFromJS:) + func sendTokenResponseFromJS(_ json: String) { + pendingTokenResponseContinuation?(json) + pendingTokenResponseContinuation = nil + } + @objc(sendIssuerTrustResponseFromJS:) func sendIssuerTrustResponseFromJS(_ trusted: Bool) { pendingIssuerTrustDecision?(trusted) pendingIssuerTrustDecision = nil } - private func parseClientMetadata(from jsonString: String) throws -> ClientMetaData { + // MARK: - JSON Parsing + + private func parseClientMetadata(from jsonString: String) throws -> ClientMetadata { guard let data = jsonString.data(using: .utf8) else { throw NSError(domain: "Invalid JSON string for clientMetadata", code: 0) } - return try JSONDecoder().decode(ClientMetaData.self, from: data) - } - - private func parseIssuerMeta(from jsonString: String) throws -> IssuerMetadata { - guard let data = jsonString.data(using: .utf8) else { - throw NSError(domain: "Invalid JSON string for issuerMetadata", code: 0) - } - return try JSONDecoder().decode(IssuerMetadata.self, from: data) + return try JSONDecoder().decode(ClientMetadata.self, from: data) } @objc static func requiresMainQueueSetup() -> Bool { diff --git a/locales/ara.json b/locales/ara.json index c5516698..32298026 100644 --- a/locales/ara.json +++ b/locales/ara.json @@ -221,6 +221,10 @@ "title": "لا يوجد اتصال بالإنترنت", "message": "الرجاء التحقق من اتصالك وإعادة المحاولة" }, + "networkRequestFailed": { + "title": "فشل طلب الشبكة", + "message": "لا يمكننا معالجة طلبك في الوقت الحالي." + }, "biometricsCancelled": { "title": "هل تريد إلغاء التنزيل؟", "message": "مطلوب تأكيد البيومترية لمواصلة تنزيل البطاقة." @@ -1103,4 +1107,4 @@ "confirm": "نعم، أثق بهذا", "cancel": "لا، أعدني" } -} +} \ No newline at end of file diff --git a/locales/en.json b/locales/en.json index 4e79e0f5..cdc80ea6 100644 --- a/locales/en.json +++ b/locales/en.json @@ -221,6 +221,10 @@ "title": "No internet connection", "message": "Please check your connection and retry" }, + "networkRequestFailed":{ + "title": "Network request failed", + "message": "We are unable to precess your request at the moment." + }, "biometricsCancelled": { "title": "Do you want to cancel download?", "message": "Biometric confirmation is required to continue downloading the card." diff --git a/locales/fil.json b/locales/fil.json index 1b10a3f9..6fdcbddc 100644 --- a/locales/fil.json +++ b/locales/fil.json @@ -221,6 +221,10 @@ "title": "Pakisuri ang iyong koneksyon at subukang muli", "message": "Mangyaring kumonekta sa internet at subukang muli." }, + "networkRequestFailed": { + "title": "Nabigo ang kahilingan sa network", + "message": "Hindi namin maiproseso ang iyong kahilingan sa ngayon." + }, "biometricsCancelled": { "title": "Gusto mo bang kanselahin ang pag-download?", "message": "Kinakailangan ang biometric confirmation para magpatuloy sa pag-download ng card." @@ -887,7 +891,7 @@ "title": "Oops! Isang Error ang Naganap.", "message": "Nagkaroon ng teknikal na problema habang pinoproseso ang iyong kahilingan. Maaari mong subukang muli pagkatapos ng ilang sandali." }, - "vpFormatsNotSupported": { + "vpFormatsNotSupported": { "title": "Hindi Suportadong Kahilingan", "message": "Ang kahilingang ito ay hindi suportado. Pakiusap, sabihan ang tagapagsuri na subukan sa ibang paraan." }, @@ -1106,4 +1110,4 @@ "confirm": "Oo, Pinagkakatiwalaan Ko Ito", "cancel": "Hindi, Bumalik Tayo" } -} +} \ No newline at end of file diff --git a/locales/hin.json b/locales/hin.json index 1d8a0a31..02d019a7 100644 --- a/locales/hin.json +++ b/locales/hin.json @@ -222,6 +222,10 @@ "title": "कोई इंटरनेट कनेक्शन नहीं", "message": "कृपया अपना कनेक्शन जांचें और पुनः प्रयास करें" }, + "networkRequestFailed": { + "title": "नेटवर्क अनुरोध विफल हुआ", + "message": "हम इस समय आपके अनुरोध को संसाधित करने में असमर्थ हैं।" + }, "biometricsCancelled": { "title": "क्या आप डाउनलोड रद्द करना चाहते हैं?", "message": "कार्ड डाउनलोड करना जारी रखने के लिए बायोमेट्रिक पुष्टिकरण आवश्यक है।" @@ -1107,4 +1111,4 @@ "confirm": "हाँ, मैं इस पर भरोसा करता हूँ", "cancel": "नहीं, मुझे वापस ले चलो" } -} +} \ No newline at end of file diff --git a/locales/kan.json b/locales/kan.json index 08ba57e1..9c87752b 100644 --- a/locales/kan.json +++ b/locales/kan.json @@ -220,6 +220,10 @@ "title": "ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ", "message": "ದಯವಿಟ್ಟು ನಿಮ್ಮ ಸಂಪರ್ಕವನ್ನು ಪರಿಶೀಲಿಸಿ ಮತ್ತು ಮರುಪ್ರಯತ್ನಿಸಿ" }, + "networkRequestFailed": { + "title": "ನೆಟ್‌ವರ್ಕ್ ವಿನಂತಿ ವಿಫಲವಾಗಿದೆ", + "message": "ಈ ಕ್ಷಣದಲ್ಲಿ ನಿಮ್ಮ ವಿನಂತಿಯನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ." + }, "biometricsCancelled": { "title": "ನೀವು ಡೌನ್‌ಲೋಡ್ ರದ್ದುಗೊಳಿಸಲು ಬಯಸುವಿರಾ?", "message": "ಕಾರ್ಡ್ ಡೌನ್‌ಲೋಡ್ ಮಾಡುವುದನ್ನು ಮುಂದುವರಿಸಲು ಬಯೋಮೆಟ್ರಿಕ್ ದೃಢೀಕರಣದ ಅಗತ್ಯವಿದೆ." @@ -887,7 +891,7 @@ "title": "ಓಹ್! ಒಂದು ದೋಷ ಸಂಭವಿಸಿದೆ.", "message": "ನಿಮ್ಮ ವಿನಂತಿಯನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವಾಗ ತಾಂತ್ರಿಕ ತೊಂದರೆ ಸಂಭವಿಸಿದೆ. ದಯವಿಟ್ಟು ಸ್ವಲ್ಪ ಸಮಯದ ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ." }, - "vpFormatsNotSupported": { + "vpFormatsNotSupported": { "title": "ಬೆಂಬಲಿಸಲ್ಪಟ್ಟ ವಿನಂತಿಯಲ್ಲ", "message": "ಈ ವಿನಂತಿಯನ್ನು ಬೆಂಬಲಿಸಲಾಗದು. ದಯವಿಟ್ಟು ಪರಿಶೀಲಕರನ್ನು ಬೇರೆ ಮಾರ್ಗದಿಂದ ಪ್ರಯತ್ನಿಸಲು ಕೇಳಿ." }, @@ -1106,4 +1110,4 @@ "confirm": "ಹೌದು, ನಾನು ನಂಬುತ್ತೇನೆ", "cancel": "ಇಲ್ಲ, ನನನ್ನು ಹಿಂದಕ್ಕೆ ಕರೆ" } -} +} \ No newline at end of file diff --git a/locales/tam.json b/locales/tam.json index 5df39e78..a1d44925 100644 --- a/locales/tam.json +++ b/locales/tam.json @@ -220,6 +220,10 @@ "title": "இணைய இணைப்பு இல்லை", "message": "உங்கள் இணைப்பைச் சரிபார்த்து மீண்டும் முயற்சிக்கவும்" }, + "networkRequestFailed": { + "title": "நெட்வொர்க் கோரிக்கை தோல்வியடைந்தது", + "message": "தற்போது உங்கள் கோரிக்கையை செயலாக்க முடியவில்லை." + }, "biometricsCancelled": { "title": "பதிவிறக்கத்தை ரத்து செய்ய வேண்டுமா?", "message": "கார்டை தொடர்ந்து பதிவிறக்க பயோமெட்ரிக் உறுதிப்படுத்தல் தேவை." @@ -1106,4 +1110,4 @@ "confirm": "ஆம், நம்புகிறேன்", "cancel": "இல்லை, என்னை திரும்ப அழைத்துச் செல்" } -} +} \ No newline at end of file diff --git a/machines/Issuers/IssuersActions.ts b/machines/Issuers/IssuersActions.ts index cb1ea5b8..127fa1a5 100644 --- a/machines/Issuers/IssuersActions.ts +++ b/machines/Issuers/IssuersActions.ts @@ -8,6 +8,7 @@ import { import { EXPIRED_VC_ERROR_CODE, MY_VCS_STORE_KEY, + NO_INTERNET, REQUEST_TIMEOUT, isIOS, } from '../../shared/constants'; @@ -25,9 +26,8 @@ import { } from '../../shared/telemetry/TelemetryUtils'; import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants'; import {NativeModules} from 'react-native'; -import {KeyTypes} from '../../shared/cryptoutil/KeyTypes'; import {VCActivityLog} from '../../components/ActivityLogEvent'; -import {isNetworkError} from '../../shared/Utils'; +import {isNetworkError, parseJSON} from '../../shared/Utils'; import {issuerType} from './IssuersMachine'; const {RNSecureKeystoreModule} = NativeModules; @@ -52,9 +52,6 @@ export const IssuersActions = (model: any) => { setIssuers: model.assign({ issuers: (_: any, event: any) => event.data as issuerType[], }), - setNoInternet: model.assign({ - errorMessage: () => ErrorMessage.NO_INTERNET, - }), setLoadingReasonAsDisplayIssuers: model.assign({ loadingReason: 'displayIssuers', }), @@ -75,7 +72,7 @@ export const IssuersActions = (model: any) => { return proofTypesSupported.jwt .proof_signing_alg_values_supported as string[]; } else { - return [KeyTypes.RS256] as string[]; + return [] as string[]; } }, }), @@ -85,17 +82,6 @@ export const IssuersActions = (model: any) => { resetSelectedCredentialType: model.assign({ selectedCredentialType: {}, }), - setNetworkOrTechnicalError: model.assign({ - errorMessage: (_: any, event: any) => { - console.error( - `Error occurred during ${event} flow`, - event.data.message, - ); - return isNetworkError(event.data.message) - ? ErrorMessage.NO_INTERNET - : ErrorMessage.TECHNICAL_DIFFICULTIES; - }, - }), setCredentialTypeListDownloadFailureError: model.assign({ errorMessage: (_: any, event: any) => { if (isNetworkError(event.data.message)) { @@ -109,9 +95,12 @@ export const IssuersActions = (model: any) => { errorMessage: (_: any, event: any) => { console.error(`Error occurred while ${event} -> `, event.data.message); const error = event.data.message; - if (isNetworkError(error)) { + if (error.includes(NO_INTERNET)) { return ErrorMessage.NO_INTERNET; } + if (isNetworkError(error)) { + return ErrorMessage.NETWORK_REQUEST_FAILED; + } if (error.includes(REQUEST_TIMEOUT)) { return ErrorMessage.REQUEST_TIMEDOUT; } @@ -126,9 +115,6 @@ export const IssuersActions = (model: any) => { return ErrorMessage.GENERIC; }, }), - setOIDCConfigError: model.assign({ - errorMessage: (_: any, event: any) => event.data.toString(), - }), resetError: model.assign({ errorMessage: '', }), @@ -236,20 +222,24 @@ export const IssuersActions = (model: any) => { return context.issuers.find(issuer => issuer.issuer_id === event.id); }, }), - + resetSelectedIssuer: model.assign({ + selectedIssuer: () => ({} as issuerType), + }), updateIssuerFromWellknown: model.assign({ selectedIssuer: (context: any, event: any) => ({ ...context.selectedIssuer, - credential_audience: event.data.credential_issuer, credential_endpoint: event.data.credential_endpoint, credential_configurations_supported: event.data.credential_configurations_supported, display: event.data.display, authorization_servers: event.data.authorization_servers, }), + selectedIssuerWellknownResponse: (_: any, event: any) => { + return event.data; + }, }), setCredential: model.assign({ - credential: (_: any, event: any) => event.data, + credential: (_: any, event: any) => event.data.credential, }), setQrData: model.assign({ qrData: (_: any, event: any) => event.data, @@ -261,7 +251,7 @@ export const IssuersActions = (model: any) => { }), setAccessToken: model.assign({ accessToken: (_: any, event: any) => { - return event.accessToken; + return event.data.access_token; }, }), setCNonce: model.assign({ @@ -269,20 +259,41 @@ export const IssuersActions = (model: any) => { return event.cNonce; }, }), - setOfferCredentialTypeContexts: model.assign({ - selectedCredentialType: (context: any, event: any) => { - return event.credentialTypes[0]; - }, - supportedCredentialTypes: (context: any, event: any) => { - return event.credentialTypes; - }, - accessToken: (context: any, event: any) => { - return event.accessToken; - }, - cNonce: (context: any, event: any) => { - return event.cNonce; + setCredentialConfigurationId: model.assign({ + credentialConfigurationId: (_: any, event: any) => { + return event.data.credentialConfigurationId; }, }), + setCredentialOfferCredentialType: model.assign({ + selectedCredentialType: (context: any, event: any) => { + let credentialTypes: Array<{id: string; [key: string]: any}> = []; + const credentialConfigurationId = context.credentialConfigurationId; + const issuerMetadata = context.selectedIssuerWellknownResponse; + if ( + issuerMetadata.credential_configurations_supported[ + credentialConfigurationId + ] + ) { + credentialTypes.push({ + id: credentialConfigurationId, + ...issuerMetadata.credential_configurations_supported[ + credentialConfigurationId + ], + }); + return credentialTypes[0]; + } + }, + }), + supportedCredentialTypes: (context: any, event: any) => { + return event.credentialTypes; + }, + accessToken: (context: any, event: any) => { + return event.accessToken; + }, + cNonce: (context: any, event: any) => { + return event.cNonce; + }, + setRequestTxCode: model.assign({ isTransactionCodeRequested: (_: any, event: any) => { return true; @@ -295,22 +306,32 @@ export const IssuersActions = (model: any) => { }, }), setCredentialOfferIssuerWellknownResponse: model.assign({ - selectedIssuerWellknownResponse: (_: any, event: any) => { - return event.issuerMetadata; + selectedIssuer: (_: any, event: any) => { + return event.data; }, - wellknownKeyTypes: (_: any, event: any) => { - const credType = Object.entries(event.credentialTypes)[0][1]; - const proofTypesSupported = credType.proof_types_supported; - if (proofTypesSupported?.jwt) { - return proofTypesSupported.jwt - .proof_signing_alg_values_supported as string[]; - } else { - return [KeyTypes.RS256] as string[]; - } + selectedIssuerWellknownResponse: (_: any, event: any) => { + return event.data; }, }), - updateSelectedIssuerWellknownResponse: model.assign({ - selectedIssuerWellknownResponse: (_: any, event: any) => event.data, + setWellknwonKeyTypes: model.assign({ + wellknownKeyTypes: (_: any, event: any) => { + return event.proofSigningAlgosSupported; + }, + }), + setSelectedCredentialIssuer: model.assign({ + credentialOfferCredentialIssuer: (_: any, event: any) => { + return event.issuer; + }, + }), + setTokenRequestObject: model.assign({ + tokenRequestObject: (_: any, event: any) => { + return parseJSON(event.tokenRequest); + }, + }), + setTokenResponseObject: model.assign({ + tokenResponse: (_: any, event: any) => { + return event.data; + }, }), setSelectedIssuerId: model.assign({ selectedIssuerId: (_: any, event: any) => event.id, @@ -330,22 +351,17 @@ export const IssuersActions = (model: any) => { txCodeDescription: (_: any, event: any) => event.description, txCodeLength: (_: any, event: any) => event.length, }), - setCredentialOfferIssuerMetadata: model.assign({ - credentialOfferIssuerMetadata: (_: any, event: any) => { - return event.issuerMetadata; - }, - }), setIssuerDisplayDetails: model.assign({ - issuerLogo: (context: any, _: any) => { - const displayArray = context.credentialOfferIssuerMetadata?.display; + issuerLogo: (_: any, event: any) => { + const displayArray = event.issuerDisplay; const display = displayArray ? getDisplayObjectForCurrentLanguage(displayArray) : undefined; return display?.logo?.url ?? ''; }, - issuerName: (context: any, _: any) => { - const displayArray = context.credentialOfferIssuerMetadata?.display; + issuerName: (_: any, event: any) => { + const displayArray = event.issuerDisplay; const display = displayArray ? getDisplayObjectForCurrentLanguage(displayArray) : undefined; @@ -353,13 +369,13 @@ export const IssuersActions = (model: any) => { }, }), - setFlowType: model.assign({ + setCredentialOfferFlowType: model.assign({ isCredentialOfferFlow: (_: any, event: any) => { return true; }, }), - resetFlowType: model.assign({ + resetCredentialOfferFlowType: model.assign({ isCredentialOfferFlow: (_: any, event: any) => { return false; }, @@ -402,7 +418,9 @@ export const IssuersActions = (model: any) => { type: 'VC_DOWNLOADED', timestamp: Date.now(), deviceName: '', - issuer: context.selectedIssuerId, + issuer: + context.selectedIssuer.credential_issuer_host ?? + context.credentialOfferCredentialIssuer, credentialConfigurationId: context.selectedCredentialType.id, }), context.selectedIssuerWellknownResponse, @@ -441,8 +459,9 @@ export const IssuersActions = (model: any) => { }, updateVerificationErrorMessage: assign({ - verificationErrorMessage: (_, event: any) => - (event.data as Error).message, + verificationErrorMessage: (_, event: any) => { + return (event.data as Error).message; + }, }), resetVerificationErrorMessage: model.assign({ diff --git a/machines/Issuers/IssuersEvents.ts b/machines/Issuers/IssuersEvents.ts index e3cae459..c28611d1 100644 --- a/machines/Issuers/IssuersEvents.ts +++ b/machines/Issuers/IssuersEvents.ts @@ -33,5 +33,6 @@ export const IssuersEvents = { TX_CODE_REQUEST: () => ({}), TX_CODE_RECEIVED: (txCode: string) => ({txCode}), ON_CONSENT_GIVEN: () => ({}), - TRUST_ISSUER_CONSENT_REQUEST: (issuerMetadata: object) => ({issuerMetadata}) + TRUST_ISSUER_CONSENT_REQUEST: (issuerMetadata: object) => ({issuerMetadata}), + TOKEN_REQUEST: (tokenRequest: object) => ({tokenRequest}), }; diff --git a/machines/Issuers/IssuersGuards.ts b/machines/Issuers/IssuersGuards.ts index c00188f8..a4b9cbbb 100644 --- a/machines/Issuers/IssuersGuards.ts +++ b/machines/Issuers/IssuersGuards.ts @@ -1,6 +1,5 @@ import {isSignedInResult} from '../../shared/CloudBackupAndRestoreUtils'; import {ErrorMessage, OIDCErrors} from '../../shared/openId4VCI/Utils'; -import {isHardwareKeystoreExists} from '../../shared/cryptoutil/cryptoUtil'; import {BiometricCancellationError} from '../../shared/error/BiometricCancellationError'; import {VerificationErrorType} from '../../shared/vcjs/verifyCredential'; @@ -17,32 +16,6 @@ export const IssuersGuards = () => { return context.keyType == ''; }, isInternetConnected: (_: any, event: any) => !!event.data.isConnected, - isOIDCflowCancelled: (_: any, event: any) => { - // iOS & Android have different error strings for user cancelled flow - const err = [ - OIDCErrors.OIDC_FLOW_CANCELLED_ANDROID, - OIDCErrors.OIDC_FLOW_CANCELLED_IOS, - ]; - return ( - !!event.data && - typeof event.data.toString === 'function' && - err.some(e => event.data.toString().includes(e)) - ); - }, - isOIDCConfigError: (_: any, event: any) => { - return ( - !!event.data && - typeof event.data.toString === 'function' && - event.data.toString().includes(OIDCErrors.OIDC_CONFIG_ERROR_PREFIX) - ); - }, - isGrantTypeNotSupportedError: (_: any, event: any) => { - return ( - !!event.data && - event.data.toString() === - OIDCErrors.AUTHORIZATION_ENDPOINT_DISCOVERY.GRANT_TYPE_NOT_SUPPORTED - ); - }, canSelectIssuerAgain: (context: any) => { return ( context.errorMessage.includes(OIDCErrors.OIDC_CONFIG_ERROR_PREFIX) || @@ -50,18 +23,13 @@ export const IssuersGuards = () => { ); }, shouldFetchIssuersAgain: (context: any) => context.issuers.length === 0, - isCustomSecureKeystore: () => isHardwareKeystoreExists, hasUserCancelledBiometric: (_: any, event: any) => event.data instanceof BiometricCancellationError, - isGenericError: (_: any, event: any) => { - const errorMessage = event.data.message; - return errorMessage === ErrorMessage.GENERIC; - }, isCredentialOfferFlow: (context: any) => { return context.isCredentialOfferFlow; }, - isIssuerIdInTrustedIssuers: (_: any,event:any) => { + isIssuerIdInTrustedIssuers: (_: any, event: any) => { return event.data; - } + }, }; }; diff --git a/machines/Issuers/IssuersMachine.ts b/machines/Issuers/IssuersMachine.ts index 56db9016..38199a21 100644 --- a/machines/Issuers/IssuersMachine.ts +++ b/machines/Issuers/IssuersMachine.ts @@ -12,7 +12,7 @@ export const Issuer_Tab_Ref_Id = 'issuersMachine'; export const IssuersMachine = model.createMachine( { - /** @xstate-layout N4IgpgJg5mDOIC5QEtawK5gE6wLIEMBjAC2QDswA6CVABwBt8BPASTUxwGIIB7Cy8gDceAayqoM2PEVL8asBszaScCIT0L4ALsj4BtAAwBdQ0cShaPWMh19zIAB6IATAE4AbAA5KBzwFZPTwAWAHZ-MNcggBoQJkR3P2cfTwSARncDNxTXAF8cmIkOaRJyKnlFVnYpTmwsHixKRS0AM3qAWwEqnAISuTpGSpVYNTJhTVsyU1N7S2sJ+ycENy9kgOCwvwjo2MQAZlSQylSPY5Cg50DPVxC8gq7i2Spa+s4AFQAlAE0AfQBBAHFfiwAHLTJAgWY2XRkBaIIIGXaUAJ+SIIoKhZzOdzbOIIY6Ivzw3xnfzuTEXW4gQpSHqPSjPLBvL5-QEgvSpMzgyHzcGLXZeJKbTwGBK7C6pILuXYxXGuTxJELOEKpPypfzOAyJSnU7oyUr0rB1RkfH4AoGg5ycixWKF2XmIRUyuGpZyIq6u3ZBfbuVzpbX3Wn6hmcd4AUQAyqHXt9Q+93gB5d5g61zaGwhD8xVIsIivxizwSqVOvEGEKuSi7TXojL+dG7G75KkBvX8WBgehgQg6MhQZQcTjhgDCv2B30HYYAIqHga8WL8ADLfeMAMWXse+AEV3mP41PkxCbTzQIs3AFVoFQuErjjEGqQn5KM4vUFPPtIq5Mu5-UNA63253u17LpOAneMAHVgXneNfgnb4WAnfduTTe0EDJBFKFcDxzkyIJNguYssRWY4lTLPxCV2T1vyKX8qDbDsu3IICVAHUN51DQdXlDWCWHDcMAFVY0Qw9kOPeJnGLc5QiRF90XODI1SCKiaRbKhCCwSAwDIHR8HoCceAAdzIegeHwCBlzqNp42aZpsG4PhxFGURxGbXpVPUiBNO03SDKMkyzIsqybKwEYxm0aEpmMGZhLtUSlkibxfDWS8hUiAjrgMSh-FLAwVRCGsRSU3VXMoNSNK05AdL0wzjNM8yeEs6zbIZRpGBadpOh-FSSvczyKu86q-LqhqgpCjQwv0YwhNTGLHBcDwEv8C8Ni2Ysy3LeViSle8DDlL9Gx1B59VKjzysqnyav8+rAqaw16ha7RWiwDoDpo7qyq8qrfNqgLGuC9RxnCyaOSi6aYRQ5YFqS5brwk1IMpCM4DgSPx3Dyr09ruTriuO3qzoG76rt+zgAAUExXb4ww3ATw1eKbbTB2LUgOYtC1SSgQl2QlCUwnbAj8QrDv4HHTv6r7LuG2zfj414AAkY2BCdifjEFozDQdQxYAA1Li6aPWaMw1B8zmcF0UkCZYJN9ShcIMUsgmOTIxVcfn9pculhY+87Bp+oK3gADR3KcKdDKmI1pyKuWihn9aZkJi0CNmAmI-wXT8UtUgF16Pb6z6LqG66GjbMgIFeBxB3jDy7P4dQxA66iuuzvGxfz37KCLkuy4rsBRoBiaTAjlN6fTNPESfE37yCOVVXlVa5SOLF60rXZnaXzOG56kXc+9wmgrbzSO-LyvmqaR7nrdo6N89-HxYLvfi9Lw-u-+8bJkmgeD1B4f0PceT4TWr0Z47AQCEAwQRpKvlcMvJmyNnBr2xpfHOXsCYSwaGIJgBAyD4BgG0Tye8tDhn-F2SAABpMATAq4OWELXF6693qIOvi3XeaCMFYLADgrSeCCH0S0CQshPcX4RStB-IeKFFQZSrF4PM5wXSpGlEA2Oo9QGulVMvdwao4HuwQU3POPtsCUGYfgTB2DcFtnwYQnhEBSHkOPq1U+ddlLwLodo7eKD9FkJYcYjhpiuEAV4UwfhExBEgxEbFCG551hXlSvItUiJrhnGxMENUBZdgaIvk40WOid56IMUYthuCYBaCscTfAyAsBDSsbALQ9QwAUIEI5ah58hZaIyS42+OTWHsK0JQApRSSllIshUqp6kAmA37kIpCM0TyhHcBWeUZxFQSlTizA4ijzic1kScfwqSmnpK3sgtp7jDEdPyWAQpZDimlPKWQyp1Sai3QaCfdqNDHEnSvs3XRqDDm5M6d005vTLkDOuUMp+jle6vzGcEvWiwxE+EJJIz0JsTZyNxC6H+7N5QmzkmcSBGdXZY00bspBN9W7tM8V0np5y+lXKYDc9SdyjT3Tak9exRUCWvPoe8rJnz0FHLJb8s5TALn9PqoM6pIy+7snGVHdMbgwjhOSiteReZEQZGcCjVGk8fQu0xvXF5uMWn7JJV845HCKWCqpYCmlwL6V3Uecy55bL9V7OJUw41fKzVCupbSkFoVAmTUtJCkSMdOZgPrJPBGeYV6vhZvsQ41Z6xM1VEqc42y3KEoYR8txPLvm4PQG2LAg5DGEHbB2CAAAhXQOCtBYGQIQJkppWSgnfhM6O0KNSwslP4BFMjkW3n2GAi4SKVTomdh4VNb12XOMNa67NJqul5uwIWsgxb6ClorfVU5Na61hkjNGWMCYkzNuleDea8roZRJRSA7w9tVQHBAfyHKDYdUOMdZvIljDsluryaazS2BtBgH+YyXg1d6nOXxWkydBqXWftne639WB-2AfFeC3WQbFh3gfJPTF-I06ZExCzNViIyy23IrIqsKS8W6tfW8zJrjSXfq6YQPglSsDoC7MTOoPBmi1JrmBqjEGnXvszfRn5TGyAsbY1oDjPAuPIaCZHT+4NpmzOTQs+2aqY3oWOFtZezslRknHY3KDH7uUeIYyVZj1bJPSa4zah5tinmNLTZB51Jms1mdE5Z1j7HOPNDk2-KVinQnXEhktSJN48Sc28MRnKmxnZhALOO3g18+zYDAiWkQZAfI8dAyywWZQiWpawOl1dmWfL+YhQpkJ+sto+HvYipU1xNgSTVWA+86Qdqugxbi59rL9TJbFkVkr9AyuGTs4yuxDr+uFa6MN0bZAKuocmXsAU2ZhSinFJKXtGYyKPjw-e+EKRYGUZfdN6+g5mmvCYLQOAOWqF8dO3IIlF30lXZu8MZ+frKuDyhbeNVSRxT-ZFAcK4sMzg+Fwh+JmemMZNnA0987l3ru3ZsQ9Rz8OCuI9e8jj7oKBEBcDctjMy9MqqhRkdz0ngywReXpsHw2InyRBfNiJLz2kfvfrSyc0S3W1-cSI+AsQO1ERBa6jSgZJdiBARK6WRuFx10QAoxF7kG3s1OHMCdW84efpjhuJIBkv+QVglGKbKCRNXy-MUr9nNTIxsQ4lxMck5pyzgXN8V4nxiahm1yhJmevcQJtHu1x2b50RPrh-x-gImTGnJ8UQyxZC7tOTy69KPXiY-mL8Yto9QX9ZikOGWLw1PXx-2ZkAp8cNHzYsgfE7msOpuR6-T87xGf4-WPuRN9HEeqCp66c37hmfPujO94zaej5PQUQRr6SsngCJ5SSGslEKMDhqgKidvrDfYPmY9RakVQLbnAcoUn+v3fG8nIFZ6y13qs+Beq+h0frovT1jLGRmfZeJTeFRrmOLUpMTavD49k-TfH5bfAFXfK1W5VHJlM+DHdzXlLfP5SlUAtoUVYZQfCVbPW-PYJUdmeaIvT0dOOOMvfYAHe8E2K4YIKHcdHvflQDL1a1SAybJzWAnNH9c-HfZAvfVAvHL7SVQnXnPERIbwB-CfZ-afAiSeNmaXbac4OUV8Kg0-Vg2gy-eg9vO1aArvZgudGgxA4VDg8Arg31IfANKrX7BADwJIWOZfLwXwMecQpmDCZeUsAIW2OGOvJg6ghdAtItEtSAddKtLdTnM0NkDA0wvPHAwveKfA5UQg3EZRcsCNWRMkCXVGNwmAjw-NJdFdNdStTdWtEMCMKMGMOMRMYfGOQQsfR-SfF-AiH+B8YIPMHKA3CIeQoAk5CgBDHhQDRPBpNIhQ8leDRDHQ6-PgnXe-cfJ-KfXwAiMeR8ZnT0Vwcva4VnLHSDWAboh7dfTHMWZXfVXHQw9Am-UwtwSXM9cLYsfYNUJELKNRBYsjJYtffLagNndJNYhgzvAAp4lY3Y4YkwtDW8K4NmY4RIH+dZMifwAifYa9UBZ2JGcvPKZY7Y5pV41Qhze1JggbC6HYkWPYsaHg4GX4onMJRKMLFKCLE2CUDCH0QIBJNRXCMPY-T4xEl48bNQ5PLqDEvyLEryHEsFKYYwn7P4uKFYYkiJUk4sPMNmL0NEMkSBb0ek9E541YzgdXTXUok8U9EUhVGGMvC4eI+UL0M4IkRIP-Bkjk0yLkvqWASgTwzInw8tHI6tPIk0LnYIw4wUtVBIeeSeFGX-SNAiFUGZSeJ2aXCidVBEzEpE60jI7w1dXwh0gIndQo-dEokI9052ULUUxVWIyXGZB9DmdIDmWScdQQbAZAZoJgK3dJdYtk4qEsmtcsysyDH4gUonT0IiKUTCciBGe2c410Q4H0H0LCRUM2eUmAusssisnsC0nSFk1E9Qj48chsqc5pZs4RUIztI4Ds52A0xGc42OCHGw1Gfkb0RSB416RcycqAac+gWctHNEsc0spcq8lctAlDfEls-gts7wdIXTLs3csvSIB8J2KnOGSIWRCjXrR44gQxCADsTWQcTWR82tF+ZcEpegdAOlRM6MbWd4FgZcH4ZMw9N0onNRNOWFXMc4YUe2bbNwW2I4O8bCMib0+XIZRiashk2lRiVcltdMNREnJUCiRFBOX0c4kUDKU4XwF0TESUZ2cdZAWCtXeMXAYmNiTiBCVMonAM8sDwHafEJmXXbbdEKnJEfTBIUkXCY7SC16eSjsZUkcVUjS-gxICSb08XJmW2H+MIZUF2RsLLDyeAcEY-EYlCAAWlcBZhFAPNtmiuiqZiS36CUHuGCtimcrL2CAF0SBww1FthTTPK6gZGStz1p2tmCDFDIjUXAvcHFOOArACFwiDOVHSEsv-02L3m4UYiK0Kr5BCyRE1AlFCF1w1Vnx9HZmVFLHrCp0VBNKYKM1cw+S6viHCqAU2HERfH5GCFdDJDlzyr1TfQzS5QEAUoWqWBSIrHRnlEgVfC1QI0yGtkgSVExF8HlDkJ2uow5Vo1vnbgfi7mOvzAwjyjIkAp-lor8Hjg8HZlAU5hNg1U1AgpaseNmqEwOp72OvRDZjVRzGRBAp7PkRFG0tlKnixFCH5EM2aTmuRr6M4RbysVRquEfCFE1EWmVBxpRVyjuouP0qdnrFJvTU5To0ppAN0JQLAGOt9ySB-nhFCF9B-gRBiL+wWIwklC9A1ElEas8B5pcyRv5taI4RtJjOyI3UdMIFpvLHrDTjhmmVltfxRVDIrERSX3igZw1sE32u1o8zaL-U6J0NFuxDAR2gTRRh2hynw3kTcCSEiClAN0eugWdr2r5oOR1sYy82s182OsxEuNwkrEVBNkyEVDlrxDDsVsjtfGjr9FerO0G1mwyyy0Ml+vRFJwDIpxfGp1FxmQupAQXiyh63htejNIgGvNVwCo-PTA8ERGymILzAvFARazzGtjI0lwLACE5mmpgIVwYmXOxxu1FvKMysoqp1py9FhmMpASnhARRByhaPdq0l+qWtiOktGrIhFGXmFEF0vrgKb3T371b2OqpwIkJEOHVH8AWMSSlDfpYP6LYKQOFuOo5gynhC2sNgS2uAhOMq9Cnx-mdnInVvLo3yvvnWjOXTtL8NyONoJP4OMtjhVuFzFEzAhLpwjSUTzDyhSLAa0JgHaMGPNVKVFrVTZlfHPqa0yDlBQbjUcJkKvUf3DM5KRNFtKqOBhylDJ2RBZmuBmUwk9Gh35HUdHI0L7uvKtJspFrIZlXTjq1zuDt8FCGmJRAwmhJFGev4akfNMjL1sIdjPtMNq3TToonLHREENkRRFwjzAhIOGtlAUCDLHH0X2LMfMvOvN+qfHEv9tkWUUIj3LcHovdEaISCwnHWguLjgoQqQrBVQuQHQvUl+oS3F0ZwerIkrE1FEpynF3Sn5AuEuB0Y+M4p7FRttkRCwx2h-hB2tr2BVGi22gyE5jRElDkqOuMZ92Z2tgyEgUSEVHiwiyMoSiVDwlkQOFVFZwoFFsVDAVwOJuIMXpcpSFGvvDMtAVhryDyCAA */ + /** @xstate-layout N4IgpgJg5mDOIC5QEtawK5gE6wLIEMBjAC2QDswA6CVABwBt8BPASTUxwGIIB7Cy8gDceAayqoM2PEVL8asBszaScCIT0L4ALsj4BtAAwBdQ0cShaPWMh19zIAB6IATAE4AbAA5KBzwFZPTwAWAHZ-MNcggBoQJkR3P2cfTwSARncDNxTXAF8cmIkOaRJyKnlFVnYpTmwsHixKRS0AM3qAWwEqnAISuTpGSpVYNTJhTVsyU1N7S2sJ+ycENy9kgOCwvwjo2MQAZlSQylSPY5Cg50DPVxC8gq7i2Spa+s4AFQAlAE0AfQBBAHFfiwAHLTJAgWY2XRkBaIIIGXaUAJ+SIIoKhZzOdzbOIIY6Ivzw3xnfzuTEXW4gQpSHqPSjPLBvL5-QEgvSpMzgyHzcGLXZeJKbTwGBK7C6pILuXYxXGuTxJELOEKpPypfzOAyJSnU7oyUr0rB1RkfH4AoGg5ycixWKF2XmIRUyuGpZyIq6u3ZBfbuVzpbX3Wn6hlM02s0G7K0Qm080B8kLuQ5CgwhPx+dypVK7flOhC7ZOUDWYkJo3xk-1DQP8YPvACiAGUa69vjX3u8APLvMHWubQ2G5hOCsIivxizwSqU51LJ1yUPOEyW+ee7G75KkBvX8WBgehgQg6MhQZQcTh1gDCv2B31PtYAIjXga8WL8ADLfNsAMXfLe+AEV3le2zvLsox7O1YxcVwAlWQJQnCK4cUQNUUwLL0gk8fZIlcTJ3HLIpKyoLcdz3chDy6TgbzbAB1YFnzbX4b2+Fgb2A7le3tBAyQRShXA8c5MiCTYLhzLEVmOJUQkgwksyCXCaQ3Ajt13fdSJUE8a2fGtT1eGsGJYOs6wAVRbFjozY8COOcHNzlCJE0PRc4MjVGTVx1B59QAd3wKED3feofywOtNDITg-wAu9vjPC9gR0kzQJhdjlz8ShJU8FMrOXdxZzcYssV2fwDFSWTdV6KhPO8qBfKwfzAvwYLz2BU91Ni214vMxLkq8NKdgQASM24-xINy-LCpc9cSsoQgsEgMAyB0fB6BvHh3LIegeHwCB3zqNo22aZpsG4PhxFGURxDGulJum2bkHmxbltW9bNp4bbduwEYxm0aEpmMGZTLAxwILQ6D1jgyJhOuAxKHy4sVXjXwRSKtz+AuiAZrmhalpWtaNq2na9sZBlGkYFp2k6Ct5ImqaUaum6Mfu7Gntx171HGT7jGamN-qWDxvEXGCNi2HMJJneViSlFMDDlHDRrJ8bkdR670burHHuevGakNepCe0VosA6Vz8Ipy60duzGHpxl6sDejQPv0NmOR+uK+2WHn-D5kGEJ6qdKBCM4DgSNN4y9KW7hl87KflmmlbNhmLbeNsAGl72+WsfyMutXnZszObcfNgn5eVXDy-lIJzMUwlnY4g9cZxMwllcQ7w8m5epxXTfp1X9oABXbD9k5rVP6wz76uV+1rOYzEJJ0lVJvd2QlCR4iXAj8BGDeb43aeV821d+AzXgACWbYEb07tsQSbWtGpYAA1GLh+7Fq+zFTVvfOF0UkCZYrN9ZK-AMZMgjHEyGKSCq8m7hxbibOmKtGbGgABphRrH3Ae6dM5-UWBPHMgQZ4BDEv4F0f9lRgNlhAjeUd26wKZAZdOjF9JGX-KeNswIGwPmQWnIekZWLoL2FiGcSZNiF3Qj6PwpdXTeHTO6Aq-IUTYmIWHI2CsoFbxjmreqjVnxoLHnGAS3FlxejcEXYRoiggzh9MWeMIR+Temcg3OSJCFGRzbjAi2lAtAnTIO8MAABHTAsAtAHX4OoMQpNG72KpmQpx29sCuPcZ4nxcAtBWxZrbEw98QKPwSjZOehcuq4mcOcGcPEy6Yl8PKdCcj9Tr0UZvaOHcGhuLEB47xvj-EEyaDrPWZ1KmkOqeQ5xeMYmNLiS0pJNtJhszSVwrRewskokSsJEcSVNiZmuBqT+5TpahPkeE3pkSVHRK3GQCArxYlwEsGQLcASjrCGCfrcBDjW7QKiQ0Q5xzTkKD4FuUZEwvqcNHk-TYRxnAiO6sCueSJlS7FWaUi4uwKlIx6Y4p5+yXkzTeUMs5nywDqyNFrYmusQl2O2RHR5yi6mUFeScjFHyLlgG+azVJfzHYJUBQQhZkEfCQuhesuFmyiXdIeUo2psCJrEF3CIEiR5sCvCwOgPxVyBDHVuV0hFgqakUJcSQcVkqugyrlYk5mYzfkOwyeZASmVOogrySiJKyYVmKhhRs2xxViWQPVf06JWrCASoPFKrAer5W8ECUq06ocBU7KRWSkVXqfUqQ4AGg1x1knjJMPbEezKzVpkoJa4SCQggQvtWsspvLnWIyoFUyNwrNWIvoLAoVEBTxYtmpwNRTVJn-PYoSJIKVckuFhkcExiQSk8vheWmt9aPUNArbWi29bG20ubUwgCzD7xNn+Dfe8mi+xdo6qlK1EFMSQ3QlcB1I6+UuvDSSidzyKVovnYcrQwIeBaH+MgQQM0FVBNDVsy9bq+k3tefe1GT6X1vpmvSlJW6EorDsvM0F-aJSDWHcW0dhsI2kqrQMwDTbQPvuCkG65J1CUXtVeh69KLb1HKA7NV9eGIMpqg+ZFESRq7c17bmRc2a1RKmQ7C1D07yPkuwwu3DH62lEw6cRstaGr3uoA3enDtHwOGp+RMplprOaQVMcC3NhIC1QtPSh890mBNyYo8Jh9SmyCUHQLQCAH0DwJsgH658qB-EEcVTc79-LSOyf-eZhTImrM2bsw5qATmIAubc-R416aNO4nSJ6ZKhceNFthTERY5rs17v4+OszQnAuWbA9Z2z9nlIRai4Gw6nmiN3LCX5vZBWqOKeKyFsrJEKtdFc34mLdt1McwS1KfNJjilpfQhluEWbLW5bVf5prDaWt4coOtGgvrdU8E60MT9IapNrzy3NkVFnUbBZWzqlQJzNtFF64yk1HM+SFwLGx-deIAiZRG6lx1Ja1xht83+xrIqyrKUqq8BwjaUYtovOoxj2dwWbARGy7qGFEQZnlIqMbX26uuoici8lgOSLA9BzwcHrwEGMPCpfGsG7mLtozTDpZxZ9g6cR-iI43G0efZm2R-Lh20Ug7B9ijzX7dv3K5wdlxlLCco2u9DxYwLhaqjTEz3EWYLjezOEO9HnOGs4550cvnRPsXie1iTTHv7sdRvF7zyXdKVMMply4FEkMFdkme1mQIBZ1fkg58Zvbs3-suLEEwAgZB8AwDaKjW9Wg6yKT3JAeOYAmDba88L+rf2dcB4T8H0PYBw+zUj9HoiWg48J+lzTjTiwHU+EJF4Ecb8a7Sm6hPREGpzhzxWRIrXaeLcDMD1nsPEetxR5j0XiA8fE9G-xZ0n7Y6-fp575n2q2fc9aHz8P4vTBS-9azrL7mQNYJClBo3tUiJrhnGxMENUY4Mcqpn6L-38+g+L-73nmAWgx+dy8lgFWY+-H1AF9VoXU3X7c3TDaJXvJ-HPCPV-d-T-b-BPX-KaTfW7bfFwUITKPKJUDECUBHBLA4ZvAwVvVUKFCRFeH3EXbXbvMAhfEPZ-FfaAhPD-ZAL-LaH-NxKaHFTWdpE3G-GTLvUAhocAmgyAl-MAN-Bg2Alg+Atgm3JNI1NTZA7hBASvTUFKWvGuevScESb2eUGuByM4QuEaUtX3O-OfKgx-IQ5fSgegpgRg5gp6Vgv-DghoLgglIA2-Cg-gygQQpfKA0QmApguApgBAmQ96VTVNLfRQ7KF2NYffAWRvEcREDIYFdwBMExYRTvEAjVB-PvYQugvw8QgIyQoI6QpwvFSTNw3gzIydLw6gnwkQsQmwiQ+wqQv-aXS0BQ6ZPEOefNPRU-EcSCIuScfYQ4dEMWDMVUTA5wDI3ZUwgQ2o2gmzLcLAU8WqQgbcHcCAAAIV0HDy0CwGQEIBDBZHNHtyUI1Cr1UM9HUMzCGIlALHlEzBVHRC02Dm+x-WAJmMoLmPMLqJXzlWwBWLIDWPoA2O2KelEP2MONrAbCbBbHbE7DLzuwghWF5mBgPw9gOF8GShVAngZ0cnrjeJ83cL4KyLMJyMsJgAoCwG0DAH8MZEFx2wqNMzF2yIgIpJmmwBpLpKQLiyRLxD3WS10OkX-nJE0JHG9iwhUP2DnC9GmMrVJO+PJIj0IE+T2PQD3E7jqB4GaCT1qx4OZPvzJLZOVNVNlQ1K1OaB5Ifj5PyXjFnFRywMASV0QjzGRw8GXChUGnjCmLINTyqJvW8IWJVIuTVPNJ4G1NKJcKn3eOJP9Io0DNyImlNPVK0E1PDMtNt0g0RJQK5nLlRNiPgiGKggkn-hhkgjCDHH4w3DjWwEonWJEDIAxl1OVWnwmmrL9TrJBIbIxitPSRtLOAuJzW6nRGXFnAyEiAcgKmCCrN6BrKwE7PoG7OWkjIk24NbM0FnI7PrMbOWl7KmSdgHJUKHNxAEmuB8AGLEkcmnN9LpFoDqEIDWLQBIlPBrWbO8xIyoDvI0EfOsAPBfIeT3I7XMnyQhnPy9HY1CEyGzUsXsixCnJsUJI-OoHVS3K7J3PwwAMZJ4N4HIVQsXPQsAtp0WDFk5QRHUKVGuE2CsmBXzRTHSAljEUxEMMQukxwrbjwqXOCgn3KOwpQq6AXM4sIvLz2AFAhWFFFHFElAb2V1TALEyCVBLBSB9KMPJlf3-PQ1eCYFoDgDfJTzpDUprU0u0uGEzIY2zMiL0x7WezQiuGSgGnRDgqclQwMoeSMp0u4rXJjKsNEPUpJTcpMtkLCNOJot3Qgp4ltWxBFGrivIQoqJco0q0p0pNGOLZHMs6JCqspzAmMOAdQwkcuvJUvGkIiUmfMMsSohwajbQiM6KnEskRyEQrn0WTGHDSNQ2KuIj-LKu0rUg0i0h0ivFvFXSfFfFeE+E7hrFOIzDquV0hQ91VGAQwnRAJIqLYrpl8pblgF0pWvVXWrRgCtCLtzSqdkET335kLOZzVCRHynTGrlrmuFQ1Wqxl2oVk2o8tcN4vIWevmn2utiCqOvYjVB-mOESBSLb1TH8GEn2G8HhEHT9nyT9gep2prVeo1mcNXPetbMevWi+voB+uTSmDTWtJzOdlOvdmEgzHzQ8DlBSDQnTAEmWo+rbhxpRtxSjL0v1CxobWRraOquOpRNdjRLiNxBHBni9DRDJELm9AZsxqRoeU2t3gPiPhPjPlYQpyp2Cv8Fov9jHExFTChVLiDg9wEi9zPUKrpE5uZrjkTkvBTnYQ1r03jHBpdGBX6NLnnCdyxAxG9zNo5tlvQ02u7jbF7ltsHlOLFHSGS3CrJBdv1sR0NswI129pYoNgtuRoqqh3+uAt33zLOsPzyQuBnDCHyT0SJESFIJ9rkD9pJVgEGRmmGQSS2sZrWuRtrqaXiR61MtiyJsUM9EOGyTg2V09EyiwhMRFDKXQnLuTvJlTrltbvrvlTeujKJOQs+pboaTruaQSSEr5N7tnDmXY17r4XTBVAFECDnkRtXtnspXeXOUuQZOT22svv9so3RQ3ppS+U7vkN5JzLnkOBwJmQkiRGPrTHHvPpvN9qfurpfqpTftvsN1RrKM8uXpnufuvupTge3p-tZWdNzH6J8GAdPonovqZpbuDL8TNNTItMbplsgY2qTJDIobTO1MwcUK9BnhrglgHr2DwZFHGMIbAYrrKCrrobIdDMofTJXONwxq8pQagdEcYYtJYc6LYYLCnByVdyyG4gIKwn4cnsfpIdnvkZTKYZ1MXvZsrtob2vofIeMcUc-vCI6L7BUY4fUdET-i0dHt0eIebtnv+OWNWPWMgDBN2MhKOLNFSt5vYmSKShdEHWjr1tcHJqzXeywjFCzDTFeP0Z8efr8cBOBNBJ2IhIOM4GhMbGbFbA7GCsgmiLdnRMhpSDHOTCls9HRG8aepboTMsMHwLyUnX2oZkeEasc6YH1EJ6dj1HxL3sbDrzAlOPMQAAFo0I2nsaOn5jEzum18Jnx8EG2asn2nZ7hm88NnC918lGn4ZmJI5mEB5mPBlmuaDm1n2SGjbDAjgj+nkHBmXqaifiFjrCXmijgizmEp9hvY1GuHrnbnwGLGDHn7Dm8jnmmi2gHD2CzG9mVmHmfnEy-nEXkWQjfrDrIm2oQXlROH2MbnMmm79nYXHnfCEXCjmjijHDUXKX0XqXMWnm6TXnpDpdCa+yf7iWwX2NAUhQCE7nmbvmlT6jOWAWSjmWaGYWoG4XvK6W7CkWWjECpn2jv6e6BXSXnthWwhRWoWhHLGvmlXcmAmQSgnCm9jinkrwnQRM7OYxQkoEwntJwDhOUda9GWX7m2XJW-ili8nAmtibXQnSnYSKmETCXnXgVoL3XG9AGRXgUxXVn2XfCqSuSCj6TMKH7fXxWlXKTOSi9uSpmnW+QQWoU852MDg+FDWU3jXKB319jmgmBSqHl3mkLm3kBW3230MgW2oUojgpRwrwLfZRFRyfQfReJFQP5pavLu3e3OqO25WF3sAe223l3+2y2Y2+Qh3EtR3lxx2LrDgCDfAsRLEpR0hYqeDF3N2oAcbJHJ9zGqA72+2SUeXd2ZlRIR3IIx3AEwYdEQFUo1HAEsxUNiBaoIAdxr5Txr513mgDixl3wvJ6B0B2CI3vhb53gWB3wfg4TKny34gVQIZNQWqLgCCbjQVJTWdUo+JUxB02q2CSJO3pMECSIB3OZ0woUPcVd34xxfRS4RQIZThfBnb8l0jG3kBoPsVGFcBO4NJtJqcv2XsfRuJxz8QMxarpK4Q0JEwlQUjkRsQtQpOZP06qrHHO1prdOOVj7-4UiwhlRSDVxGyUZ4BwQ3DLOzUcxFn3G-5-4oqsxYnchG3ygBg-V3Pu7OjEhhJgh7jEhpENR-5zhUMGQvPnWoUkpYMXbj6sx3Asrjg97ggF5lwMwyxG32rlI-V0v7ty4-5VQlrarUjhJ4xC6SXLFHPFQfXWy8cfI-IAogoavEADArIUQZ47ORQEwQPuuvKDTZihuOIPYzhT2r85RAEi7r91z9tDSGhpOdwFuL30Cg4C5DES5G9CxktRsk6mTtvZi57N6-EFuRvE3y53t2dTap6-TPjPC0HYGsUnvJwtNuIUt3ujNBHKjvuFTRVtU1tztZVHvtXOjnu8lsDLuPsPubvZ8viIf5o60dqcMAfQUxQWMQfeMnVPusdIfqijtZoQMrNCfrUCpgeruMf9TbvseafRMx59z2J4RxE90p4eJgfJiKaJQUvG25uOfCtjtWtSswtLtsBustAGfEIhs0fQe+MJf2efvpeaNWtTtYf40Nt4eR8IuVf+SVRmf0eweKezcqeb1euKp6h9cUYFvFnPBc10J1eyfNvZvteoeJd+c3e0JYvPWilrfNfwfJfPC4WFuEugGXbJRR6a4PfG9ONixJQsQJQKO1Q5SMMoelXjnemtmFu0IZxgUhxkQQOAOj9AURstOMwQFlw8-BMRVC38jGj6W1XGWpoFupqkgUiYaJJ0gMhlxNDq5uIk-n5JRlRc+teseY+aW88LWgSQ3gminCBS-bLEoCoCDYZlxU+Et0msoCEbrabxeo--fqj2-M2S3s2+-sR81SWT6JYCpMRx+WMpKi4SkyuW-ucM902eeIxmGW1IHcU+v8PMGjlqqKhJ453CfpEClDf8NQv-CXu2X4rbkMYbvDwFZB9igUMw9nKbk51QxfkHycAX8g+xrRYD8uw5QaKzinCTdHOKoO5hxXQoLcWmTuE+kpU9CpQ86cILQgXByhShhozlHyl1TgBUCCuWYLjPQIc7Tc2qw+d9i3Dcp99Eg3gBLucECCWI-2OnT2KlG9hLw4cKIAqKmzlpgDTElzAXt1Hmb8gSecoZ2mSCHqgJQunzb6gIBk4Hc7UpFBSi6F8ChBhIcuDxjo1AYzcPmprVwevTbotJzeSoHjiPSCEXAiGzgsIbjWgY31-uiPPsMjwPSi1tGY9BIQI1t7QtsmcjZMiAOaDm99gUFOIXkLPohCkKsjOhiv3ybWtwStrTfhkKiZZgZw6IVQZmBRACQRwkNT1jDU0GFwvQNqEwf62NKzQDuPseNlc3mbH4kQpZBAeYjCCTDFWS-FfEX3GZj5ohPoGeNUK8ZJCFWdDdviqy5Z-5ohqUREDDXiG1CNhZwrYYsQBKWsCmrQyEhUJUKBCahiQ8Hg0KGbPCi21JO-p3ywAVDAayUXIccPB5vst2JKNgSBSOCcNMwroEGtQOVwugZwKOauFIgSC8QIOUHGDnBwQ5IcJgKHZAGh174dC2oFZbNPkmrhdcRw-8V3KWWzTgwbBlwVKEx3qAkRS+-8W4biI8DpgKypcFUN4B9h-xR+f8FphS1bJ7cwAffWmh1E4aJBFQ5ZD2OiHdyZAUwioR4nRURoUA++ioSmp1FCBBdxQ1lZUT7BTAJBhQ8IEcHkDyBAA */ predictableActionArguments: true, preserveActionOrder: true, id: Issuer_Tab_Ref_Id, @@ -59,7 +59,7 @@ export const IssuersMachine = model.createMachine( }, { cond: 'isCredentialOfferFlow', - actions: ['setLoadingReasonAsSettingUp', 'resetError'], + actions: ['resetError', 'resetCredentialOfferFlowType'], target: 'selectingIssuer', }, { @@ -68,7 +68,7 @@ export const IssuersMachine = model.createMachine( }, ], RESET_ERROR: { - actions: 'resetError', + actions: ['resetError', 'resetCredentialOfferFlowType'], target: 'selectingIssuer', }, }, @@ -111,28 +111,20 @@ export const IssuersMachine = model.createMachine( }, credentialDownloadFromOffer: { + entry: ['setCredentialOfferFlowType', 'resetSelectedIssuer'], invoke: { src: 'downloadCredentialFromOffer', onDone: { actions: [ 'setCredential', + 'setCredentialConfigurationId', model.assign({ authEndpointToOpen: false, }), ], - target: 'proccessingCredential', + target: 'cachingCredentialOfferIssuerWellknown', }, onError: [ - { - cond: 'isGenericError', - actions: [ - 'resetSelectedCredentialType', - 'setError', - 'resetLoadingReason', - 'sendDownloadingFailedToVcMeta', - ], - target: 'error', - }, { actions: ['setError', 'resetLoadingReason'], target: 'error', @@ -140,11 +132,15 @@ export const IssuersMachine = model.createMachine( ], }, on: { + TOKEN_REQUEST: { + actions: ['setTokenRequestObject'], + target: '.tokenRequest', + }, PROOF_REQUEST: { actions: [ - 'setCredentialOfferIssuer', - 'setCredentialOfferIssuerWellknownResponse', - 'setOfferCredentialTypeContexts', + 'setCNonce', + 'setWellknwonKeyTypes', + 'setSelectedCredentialIssuer', ], target: '.keyManagement', }, @@ -161,22 +157,49 @@ export const IssuersMachine = model.createMachine( target: '.waitingForTxCode', }, TRUST_ISSUER_CONSENT_REQUEST: { - actions: ['setCredentialOfferIssuerMetadata'], + actions: ['setIssuerDisplayDetails', 'setSelectedCredentialIssuer'], target: '.checkingIssuerTrust', }, - CANCEL: { - actions: [ - 'resetLoadingReason', - 'resetQrData', - 'resetRequestTxCode', - 'resetRequestConsentToTrustIssuer', - ], + actions: ['resetLoadingReason'], target: '#issuersMachine.selectingIssuer', }, }, states: { idle: {}, + tokenRequest: { + invoke: { + src: 'sendTokenRequest', + onDone: { + actions: ['setTokenResponseObject'], + target: 'sendTokenResponse', + }, + onError: { + actions: [ + 'setError', + 'resetLoadingReason', + 'resetRequestConsentToTrustIssuer', + ], + target: '#issuersMachine.error', + }, + }, + }, + sendTokenResponse: { + invoke: { + src: 'sendTokenResponse', + onDone: { + target: '#issuersMachine.credentialDownloadFromOffer.idle', + }, + onError: { + actions: [ + 'setError', + 'resetLoadingReason', + 'sendDownloadingFailedToVcMeta', + ], + target: '#issuersMachine.error', + }, + }, + }, checkingIssuerTrust: { invoke: { src: 'checkIssuerIdInStoredTrustedIssuers', @@ -186,10 +209,7 @@ export const IssuersMachine = model.createMachine( target: 'sendConsentGiven', }, { - actions: [ - 'setRequestConsentToTrustIssuer', - 'setIssuerDisplayDetails', - ], + actions: ['setRequestConsentToTrustIssuer'], target: 'credentialOfferDownloadConsent', }, ], @@ -211,7 +231,6 @@ export const IssuersMachine = model.createMachine( actions: [ 'setLoadingReasonAsDownloadingCredentials', 'resetRequestConsentToTrustIssuer', - 'setQrData', ], target: 'sendConsentGiven', }, @@ -233,12 +252,11 @@ export const IssuersMachine = model.createMachine( }, onError: { actions: [ - 'resetCredentialOfferIssuer', 'resetLoadingReason', - 'resetQrData', + 'setError', 'resetRequestConsentToTrustIssuer', ], - target: '#issuersMachine.selectingIssuer', + target: '#issuersMachine.error', }, }, states: { @@ -255,6 +273,9 @@ export const IssuersMachine = model.createMachine( target: 'addingIssuerToTrustedIssuers', }, ], + onError: { + target: 'addingIssuerToTrustedIssuers', + }, }, }, addingIssuerToTrustedIssuers: { @@ -263,6 +284,9 @@ export const IssuersMachine = model.createMachine( onDone: { target: '#issuersMachine.credentialDownloadFromOffer.idle', }, + onError: { + target: '#issuersMachine.credentialDownloadFromOffer.idle', + }, }, }, }, @@ -272,8 +296,8 @@ export const IssuersMachine = model.createMachine( CANCEL: { actions: [ 'resetLoadingReason', - 'resetQrData', 'resetRequestTxCode', + 'sendDownloadingFailedToVcMeta', ], target: '#issuersMachine.selectingIssuer', }, @@ -291,12 +315,12 @@ export const IssuersMachine = model.createMachine( }, onError: { actions: [ - 'resetCredentialOfferIssuer', 'resetLoadingReason', - 'resetQrData', 'resetRequestTxCode', + 'setError', + 'sendDownloadingFailedToVcMeta', ], - target: '#issuersMachine.selectingIssuer', + target: '#issuersMachine.error', }, }, }, @@ -312,12 +336,11 @@ export const IssuersMachine = model.createMachine( }, onError: { actions: [ - 'resetSelectedCredentialType', 'setError', 'resetLoadingReason', 'sendDownloadingFailedToVcMeta', ], - target: '#issuersMachine.selectingIssuer', + target: '#issuersMachine.error', }, }, }, @@ -336,12 +359,11 @@ export const IssuersMachine = model.createMachine( { cond: 'isKeyTypeNotFound', actions: [ - 'resetSelectedCredentialType', 'setError', 'resetLoadingReason', 'sendDownloadingFailedToVcMeta', ], - target: '#issuersMachine.selectingIssuer', + target: '#issuersMachine.error', }, { target: 'generateKeyPair', @@ -352,7 +374,6 @@ export const IssuersMachine = model.createMachine( userCancelledBiometric: { on: { TRY_AGAIN: { - actions: ['setLoadingReasonAsDownloadingCredentials'], target: 'getKeyPairFromKeystore', }, RESET_ERROR: { @@ -383,12 +404,11 @@ export const IssuersMachine = model.createMachine( }, onError: { actions: [ - 'resetSelectedCredentialType', 'setError', 'resetLoadingReason', 'sendDownloadingFailedToVcMeta', ], - target: '#issuersMachine.selectingIssuer', + target: '#issuersMachine.error', }, }, }, @@ -396,6 +416,23 @@ export const IssuersMachine = model.createMachine( }, }, }, + cachingCredentialOfferIssuerWellknown: { + invoke: { + src: 'cacheIssuerWellknown', + onDone: { + actions: [ + 'setCredentialOfferIssuer', + 'setCredentialOfferIssuerWellknownResponse', + 'setCredentialOfferCredentialType', + ], + target: 'proccessingCredential', + }, + onError: { + actions: ['resetLoadingReason'], + target: 'error', + }, + }, + }, proccessingCredential: { invoke: { src: 'updateCredential', @@ -403,38 +440,27 @@ export const IssuersMachine = model.createMachine( actions: [ 'setVerifiableCredential', 'setCredentialWrapper', - 'sendSuccessEndEvent', - 'setVerificationResult', // to be modified after verification is implemented for external issuers ], - target: 'storing', + target: 'verifyingCredential', }, }, }, - downloadIssuerWellknown: { invoke: { src: 'downloadIssuerWellknown', onDone: { - actions: [ - 'updateIssuerFromWellknown', - 'updateSelectedIssuerWellknownResponse', - ], + actions: ['updateIssuerFromWellknown'], target: 'getCredentialTypes', }, onError: { - actions: ['setNetworkOrTechnicalError', 'resetLoadingReason'], + actions: ['setError', 'resetLoadingReason'], target: 'error', }, }, }, getCredentialTypes: { - on: { - TRY_AGAIN: { - actions: ['downloadIssuerWellknown'], - target: 'idle', - }, - }, + description: 'fetches the supported credential types from the issuer', invoke: { src: 'getCredentialTypes', onDone: { @@ -452,6 +478,10 @@ export const IssuersMachine = model.createMachine( }, selectingCredentialType: { + description: 'waits for the user to select a credential type', + entry: model.assign({ + authEndpointToOpen: () => false, + }), on: { CANCEL: { target: 'displayIssuers', @@ -482,16 +512,6 @@ export const IssuersMachine = model.createMachine( cond: 'hasUserCancelledBiometric', target: '.userCancelledBiometric', }, - { - cond: 'isGenericError', - actions: [ - 'resetSelectedCredentialType', - 'setError', - 'resetLoadingReason', - 'sendDownloadingFailedToVcMeta', - ], - target: 'selectingIssuer', - }, { actions: ['setError', 'resetLoadingReason'], target: 'error', @@ -507,8 +527,12 @@ export const IssuersMachine = model.createMachine( }), ], }, + TOKEN_REQUEST: { + actions: ['setTokenRequestObject'], + target: '.tokenRequest', + }, PROOF_REQUEST: { - actions: ['setAccessToken', 'setCNonce'], + actions: ['setCNonce', 'setWellknwonKeyTypes'], target: '.keyManagement', }, CANCEL: { @@ -519,9 +543,50 @@ export const IssuersMachine = model.createMachine( initial: 'idle', states: { idle: {}, + tokenRequest: { + invoke: { + src: 'sendTokenRequest', + onDone: { + actions: ['setTokenResponseObject', 'setAccessToken'], + target: 'sendTokenResponse', + }, + onError: { + actions: [ + 'setError', + (_context, event, _meta) => + console.error( + 'Error sending token request in downloadCredentials', + event, + ), + 'resetLoadingReason', + ], + target: '#issuersMachine.error', + }, + }, + }, + sendTokenResponse: { + invoke: { + src: 'sendTokenResponse', + onDone: { + target: '#issuersMachine.downloadCredentials.idle', + }, + onError: { + actions: [ + 'setError', + (_context, event, _meta) => + console.error( + 'Error sending token response in downloadCredentials', + event, + ), + 'resetLoadingReason', + ], + target: '#issuersMachine.error', + }, + }, + }, constructProof: { invoke: { - src: 'constructProofForTrustedIssuers', + src: 'constructAndSendProofForTrustedIssuers', onDone: { target: '#issuersMachine.downloadCredentials.idle', }, @@ -532,7 +597,6 @@ export const IssuersMachine = model.createMachine( }, { actions: [ - 'resetSelectedCredentialType', 'setError', 'resetLoadingReason', 'sendDownloadingFailedToVcMeta', @@ -565,12 +629,11 @@ export const IssuersMachine = model.createMachine( }, onError: { actions: [ - 'resetSelectedCredentialType', 'setError', 'resetLoadingReason', 'sendDownloadingFailedToVcMeta', ], - target: '#issuersMachine.selectingIssuer', + target: '#issuersMachine.error', }, }, }, @@ -590,12 +653,11 @@ export const IssuersMachine = model.createMachine( { cond: 'isKeyTypeNotFound', actions: [ - 'resetSelectedCredentialType', 'setError', 'resetLoadingReason', 'sendDownloadingFailedToVcMeta', ], - target: '#issuersMachine.selectingIssuer', + target: '#issuersMachine.error', }, { target: 'generateKeyPair', @@ -624,7 +686,16 @@ export const IssuersMachine = model.createMachine( 'setLoadingReasonAsDownloadingCredentials', 'storeKeyPair', ], - target: '#issuersMachine.downloadCredentials', + target: + '#issuersMachine.downloadCredentials.constructProof', + }, + onError: { + actions: [ + 'setError', + 'resetLoadingReason', + 'sendDownloadingFailedToVcMeta', + ], + target: '#issuersMachine.error', }, }, }, @@ -637,7 +708,7 @@ export const IssuersMachine = model.createMachine( invoke: { src: 'verifyCredential', onDone: { - actions: ['sendSuccessEndEvent', 'setVerificationResult'], + actions: ['sendSuccessEndEvent', 'setVerificationResult','resetCredentialOfferFlowType',], target: 'storing', }, onError: [ @@ -662,6 +733,7 @@ export const IssuersMachine = model.createMachine( on: { RESET_VERIFY_ERROR: { actions: ['resetVerificationErrorMessage'], + target: 'selectingIssuer', }, }, }, @@ -681,6 +753,7 @@ export const IssuersMachine = model.createMachine( onDone: { cond: 'isSignedIn', actions: ['sendBackupEvent'], + target: 'done', }, }, }, @@ -732,17 +805,13 @@ export interface issuerType { credential_issuer: string; protocol: string; client_id: string; - '.well-known': string; redirect_uri: string; token_endpoint: string; - proxy_token_endpoint: string; credential_endpoint: string; - credential_audience: string; credential_configurations_supported: object; display: [displayType]; credentialTypes: [CredentialTypes]; authorizationEndpoint: string; - grants: object; credential_issuer_host: string; authorization_servers: [string]; } diff --git a/machines/Issuers/IssuersMachine.typegen.ts b/machines/Issuers/IssuersMachine.typegen.ts index 75f673ff..e69de29b 100644 --- a/machines/Issuers/IssuersMachine.typegen.ts +++ b/machines/Issuers/IssuersMachine.typegen.ts @@ -1,556 +0,0 @@ -// This file was automatically generated. Edits will be overwritten - -export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - 'done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]': { - type: 'done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]': { - type: 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]': { - type: 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]': { - type: 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]': { - type: 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]': { - type: 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.credentialDownloadFromOffer:invocation[0]': { - type: 'done.invoke.issuersMachine.credentialDownloadFromOffer:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.displayIssuers:invocation[0]': { - type: 'done.invoke.issuersMachine.displayIssuers:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]': { - type: 'done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]': { - type: 'done.invoke.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]': { - type: 'done.invoke.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.downloadCredentials:invocation[0]': { - type: 'done.invoke.issuersMachine.downloadCredentials:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]': { - type: 'done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.getCredentialTypes:invocation[0]': { - type: 'done.invoke.issuersMachine.getCredentialTypes:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.proccessingCredential:invocation[0]': { - type: 'done.invoke.issuersMachine.proccessingCredential:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.storing:invocation[0]': { - type: 'done.invoke.issuersMachine.storing:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.issuersMachine.verifyingCredential:invocation[0]': { - type: 'done.invoke.issuersMachine.verifyingCredential:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]': { - type: 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]': { - type: 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]': { - type: 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]': { - type: 'error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]': { - type: 'error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.credentialDownloadFromOffer:invocation[0]': { - type: 'error.platform.issuersMachine.credentialDownloadFromOffer:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.displayIssuers:invocation[0]': { - type: 'error.platform.issuersMachine.displayIssuers:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]': { - type: 'error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]': { - type: 'error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]': { - type: 'error.platform.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.downloadCredentials:invocation[0]': { - type: 'error.platform.issuersMachine.downloadCredentials:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.downloadIssuerWellknown:invocation[0]': { - type: 'error.platform.issuersMachine.downloadIssuerWellknown:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.getCredentialTypes:invocation[0]': { - type: 'error.platform.issuersMachine.getCredentialTypes:invocation[0]'; - data: unknown; - }; - 'error.platform.issuersMachine.verifyingCredential:invocation[0]': { - type: 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - data: unknown; - }; - 'xstate.init': {type: 'xstate.init'}; - }; - invokeSrcNameMap: { - addIssuerToTrustedIssuers: 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.addingIssuerToTrustedIssuers:invocation[0]'; - checkIssuerIdInStoredTrustedIssuers: - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]' - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]'; - constructProof: 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]'; - constructProofForTrustedIssuers: 'done.invoke.issuersMachine.downloadCredentials.constructProof:invocation[0]'; - downloadCredential: 'done.invoke.issuersMachine.downloadCredentials:invocation[0]'; - downloadCredentialFromOffer: 'done.invoke.issuersMachine.credentialDownloadFromOffer:invocation[0]'; - downloadIssuerWellknown: 'done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]'; - downloadIssuersList: 'done.invoke.issuersMachine.displayIssuers:invocation[0]'; - generateKeyPair: - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]' - | 'done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]'; - getCredentialTypes: 'done.invoke.issuersMachine.getCredentialTypes:invocation[0]'; - getKeyOrderList: - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]' - | 'done.invoke.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]'; - getKeyPair: - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'done.invoke.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]'; - isUserSignedAlready: 'done.invoke.issuersMachine.storing:invocation[0]'; - sendConsentGiven: 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]'; - sendConsentNotGiven: 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentNotGiven:invocation[0]'; - sendTxCode: 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]'; - updateCredential: 'done.invoke.issuersMachine.proccessingCredential:invocation[0]'; - verifyCredential: 'done.invoke.issuersMachine.verifyingCredential:invocation[0]'; - }; - missingImplementations: { - actions: - | 'downloadIssuerWellknown' - | 'loadKeyPair' - | 'logDownloaded' - | 'resetCredentialOfferIssuer' - | 'resetError' - | 'resetLoadingReason' - | 'resetQrData' - | 'resetRequestConsentToTrustIssuer' - | 'resetRequestTxCode' - | 'resetSelectedCredentialType' - | 'resetVerificationErrorMessage' - | 'resetVerificationResult' - | 'sendBackupEvent' - | 'sendDownloadingFailedToVcMeta' - | 'sendErrorEndEvent' - | 'sendImpressionEvent' - | 'sendSuccessEndEvent' - | 'setAccessToken' - | 'setCNonce' - | 'setCredential' - | 'setCredentialOfferIssuer' - | 'setCredentialOfferIssuerMetadata' - | 'setCredentialOfferIssuerWellknownResponse' - | 'setCredentialTypeListDownloadFailureError' - | 'setCredentialWrapper' - | 'setError' - | 'setIssuerDisplayDetails' - | 'setIssuers' - | 'setLoadingReasonAsDisplayIssuers' - | 'setLoadingReasonAsDownloadingCredentials' - | 'setLoadingReasonAsSettingUp' - | 'setMetadataInCredentialData' - | 'setNetworkOrTechnicalError' - | 'setOfferCredentialTypeContexts' - | 'setPrivateKey' - | 'setPublicKey' - | 'setQrData' - | 'setRequestConsentToTrustIssuer' - | 'setRequestTxCode' - | 'setSelectedCredentialType' - | 'setSelectedIssuerId' - | 'setSelectedIssuers' - | 'setSelectedKey' - | 'setSupportedCredentialTypes' - | 'setTxCode' - | 'setTxCodeDisplayDetails' - | 'setVCMetadata' - | 'setVerifiableCredential' - | 'setVerificationResult' - | 'storeKeyPair' - | 'storeVcMetaContext' - | 'storeVcsContext' - | 'storeVerifiableCredentialData' - | 'storeVerifiableCredentialMeta' - | 'updateIssuerFromWellknown' - | 'updateSelectedIssuerWellknownResponse' - | 'updateVerificationErrorMessage'; - delays: never; - guards: - | 'canSelectIssuerAgain' - | 'hasUserCancelledBiometric' - | 'isCredentialOfferFlow' - | 'isGenericError' - | 'isIssuerIdInTrustedIssuers' - | 'isKeyTypeNotFound' - | 'isSignedIn' - | 'isVerificationPendingBecauseOfNetworkIssue' - | 'shouldFetchIssuersAgain'; - services: - | 'addIssuerToTrustedIssuers' - | 'checkIssuerIdInStoredTrustedIssuers' - | 'constructProof' - | 'constructProofForTrustedIssuers' - | 'downloadCredential' - | 'downloadCredentialFromOffer' - | 'downloadIssuerWellknown' - | 'downloadIssuersList' - | 'generateKeyPair' - | 'getCredentialTypes' - | 'getKeyOrderList' - | 'getKeyPair' - | 'isUserSignedAlready' - | 'sendConsentGiven' - | 'sendConsentNotGiven' - | 'sendTxCode' - | 'updateCredential' - | 'verifyCredential'; - }; - eventsCausingActions: { - downloadIssuerWellknown: 'TRY_AGAIN'; - loadKeyPair: - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'done.invoke.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]'; - logDownloaded: - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]' - | 'done.invoke.issuersMachine.verifyingCredential:invocation[0]' - | 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - resetCredentialOfferIssuer: - | 'error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]'; - resetError: 'RESET_ERROR' | 'TRY_AGAIN'; - resetLoadingReason: - | 'CANCEL' - | 'RESET_ERROR' - | 'done.invoke.issuersMachine.displayIssuers:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials:invocation[0]' - | 'error.platform.issuersMachine.downloadIssuerWellknown:invocation[0]' - | 'error.platform.issuersMachine.getCredentialTypes:invocation[0]' - | 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - resetQrData: - | 'CANCEL' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]'; - resetRequestConsentToTrustIssuer: - | 'CANCEL' - | 'ON_CONSENT_GIVEN' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]'; - resetRequestTxCode: - | 'CANCEL' - | 'TX_CODE_RECEIVED' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]'; - resetSelectedCredentialType: - | 'CANCEL' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials:invocation[0]'; - resetVerificationErrorMessage: 'RESET_VERIFY_ERROR'; - resetVerificationResult: 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - sendBackupEvent: 'done.invoke.issuersMachine.storing:invocation[0]'; - sendDownloadingFailedToVcMeta: - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials:invocation[0]'; - sendErrorEndEvent: 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - sendImpressionEvent: 'done.invoke.issuersMachine.displayIssuers:invocation[0]'; - sendSuccessEndEvent: - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]' - | 'done.invoke.issuersMachine.verifyingCredential:invocation[0]'; - setAccessToken: 'PROOF_REQUEST'; - setCNonce: 'PROOF_REQUEST'; - setCredential: 'done.invoke.issuersMachine.credentialDownloadFromOffer:invocation[0]'; - setCredentialOfferIssuer: 'PROOF_REQUEST'; - setCredentialOfferIssuerMetadata: 'TRUST_ISSUER_CONSENT_REQUEST'; - setCredentialOfferIssuerWellknownResponse: 'PROOF_REQUEST'; - setCredentialTypeListDownloadFailureError: 'error.platform.issuersMachine.getCredentialTypes:invocation[0]'; - setCredentialWrapper: - | 'done.invoke.issuersMachine.downloadCredentials:invocation[0]' - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]'; - setError: - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]' - | 'error.platform.issuersMachine.credentialDownloadFromOffer:invocation[0]' - | 'error.platform.issuersMachine.displayIssuers:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials:invocation[0]'; - setIssuerDisplayDetails: 'done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]'; - setIssuers: 'done.invoke.issuersMachine.displayIssuers:invocation[0]'; - setLoadingReasonAsDisplayIssuers: 'TRY_AGAIN'; - setLoadingReasonAsDownloadingCredentials: - | 'ON_CONSENT_GIVEN' - | 'QR_CODE_SCANNED' - | 'SELECTED_CREDENTIAL_TYPE' - | 'TRY_AGAIN' - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]' - | 'done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]'; - setLoadingReasonAsSettingUp: 'SELECTED_ISSUER' | 'TRY_AGAIN'; - setMetadataInCredentialData: - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]' - | 'done.invoke.issuersMachine.verifyingCredential:invocation[0]' - | 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - setNetworkOrTechnicalError: 'error.platform.issuersMachine.downloadIssuerWellknown:invocation[0]'; - setOfferCredentialTypeContexts: 'PROOF_REQUEST'; - setPrivateKey: - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]' - | 'done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]'; - setPublicKey: - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]' - | 'done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]'; - setQrData: 'ON_CONSENT_GIVEN' | 'QR_CODE_SCANNED'; - setRequestConsentToTrustIssuer: 'done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]'; - setRequestTxCode: 'TX_CODE_REQUEST'; - setSelectedCredentialType: 'SELECTED_CREDENTIAL_TYPE'; - setSelectedIssuerId: 'SELECTED_ISSUER'; - setSelectedIssuers: 'SELECTED_ISSUER'; - setSelectedKey: - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]' - | 'done.invoke.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]'; - setSupportedCredentialTypes: 'done.invoke.issuersMachine.getCredentialTypes:invocation[0]'; - setTxCode: 'TX_CODE_RECEIVED'; - setTxCodeDisplayDetails: 'TX_CODE_REQUEST'; - setVCMetadata: - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]' - | 'done.invoke.issuersMachine.verifyingCredential:invocation[0]' - | 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - setVerifiableCredential: - | 'done.invoke.issuersMachine.downloadCredentials:invocation[0]' - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]'; - setVerificationResult: - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]' - | 'done.invoke.issuersMachine.verifyingCredential:invocation[0]'; - storeKeyPair: - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]' - | 'done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]'; - storeVcMetaContext: - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]' - | 'done.invoke.issuersMachine.verifyingCredential:invocation[0]' - | 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - storeVcsContext: - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]' - | 'done.invoke.issuersMachine.verifyingCredential:invocation[0]' - | 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - storeVerifiableCredentialData: - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]' - | 'done.invoke.issuersMachine.verifyingCredential:invocation[0]' - | 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - storeVerifiableCredentialMeta: - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]' - | 'done.invoke.issuersMachine.verifyingCredential:invocation[0]' - | 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - updateIssuerFromWellknown: 'done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]'; - updateSelectedIssuerWellknownResponse: 'done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]'; - updateVerificationErrorMessage: 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - }; - eventsCausingDelays: {}; - eventsCausingGuards: { - canSelectIssuerAgain: 'TRY_AGAIN'; - hasUserCancelledBiometric: - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials:invocation[0]'; - isCredentialOfferFlow: 'TRY_AGAIN'; - isGenericError: - | 'error.platform.issuersMachine.credentialDownloadFromOffer:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials:invocation[0]'; - isIssuerIdInTrustedIssuers: - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]' - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]'; - isKeyTypeNotFound: - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]'; - isSignedIn: 'done.invoke.issuersMachine.storing:invocation[0]'; - isVerificationPendingBecauseOfNetworkIssue: 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - shouldFetchIssuersAgain: 'TRY_AGAIN'; - }; - eventsCausingServices: { - addIssuerToTrustedIssuers: 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]'; - checkIssuerIdInStoredTrustedIssuers: - | 'TRUST_ISSUER_CONSENT_REQUEST' - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]'; - constructProof: - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]' - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]'; - constructProofForTrustedIssuers: - | 'TRY_AGAIN' - | 'done.invoke.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]'; - downloadCredential: 'SELECTED_CREDENTIAL_TYPE'; - downloadCredentialFromOffer: 'QR_CODE_SCANNED'; - downloadIssuerWellknown: 'SELECTED_ISSUER' | 'TRY_AGAIN'; - downloadIssuersList: 'CANCEL' | 'TRY_AGAIN' | 'xstate.init'; - generateKeyPair: - | 'error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]' - | 'error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]'; - getCredentialTypes: 'done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]'; - getKeyOrderList: 'PROOF_REQUEST'; - getKeyPair: - | 'TRY_AGAIN' - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]' - | 'done.invoke.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]'; - isUserSignedAlready: - | 'done.invoke.issuersMachine.proccessingCredential:invocation[0]' - | 'done.invoke.issuersMachine.verifyingCredential:invocation[0]' - | 'error.platform.issuersMachine.verifyingCredential:invocation[0]'; - sendConsentGiven: - | 'ON_CONSENT_GIVEN' - | 'done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]'; - sendConsentNotGiven: 'CANCEL'; - sendTxCode: 'TX_CODE_RECEIVED'; - updateCredential: 'done.invoke.issuersMachine.credentialDownloadFromOffer:invocation[0]'; - verifyCredential: 'done.invoke.issuersMachine.downloadCredentials:invocation[0]'; - }; - matchesStates: - | 'credentialDownloadFromOffer' - | 'credentialDownloadFromOffer.checkingIssuerTrust' - | 'credentialDownloadFromOffer.credentialOfferDownloadConsent' - | 'credentialDownloadFromOffer.idle' - | 'credentialDownloadFromOffer.keyManagement' - | 'credentialDownloadFromOffer.keyManagement.constructProof' - | 'credentialDownloadFromOffer.keyManagement.generateKeyPair' - | 'credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore' - | 'credentialDownloadFromOffer.keyManagement.setSelectedKey' - | 'credentialDownloadFromOffer.keyManagement.userCancelledBiometric' - | 'credentialDownloadFromOffer.sendConsentGiven' - | 'credentialDownloadFromOffer.sendConsentGiven.addingIssuerToTrustedIssuers' - | 'credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList' - | 'credentialDownloadFromOffer.sendConsentNotGiven' - | 'credentialDownloadFromOffer.sendTxCode' - | 'credentialDownloadFromOffer.waitingForTxCode' - | 'displayIssuers' - | 'done' - | 'downloadCredentials' - | 'downloadCredentials.constructProof' - | 'downloadCredentials.idle' - | 'downloadCredentials.keyManagement' - | 'downloadCredentials.keyManagement.generateKeyPair' - | 'downloadCredentials.keyManagement.getKeyPairFromKeystore' - | 'downloadCredentials.keyManagement.setSelectedKey' - | 'downloadCredentials.keyManagement.userCancelledBiometric' - | 'downloadCredentials.userCancelledBiometric' - | 'downloadIssuerWellknown' - | 'error' - | 'getCredentialTypes' - | 'handleVCVerificationFailure' - | 'idle' - | 'proccessingCredential' - | 'selectingCredentialType' - | 'selectingIssuer' - | 'storing' - | 'verifyingCredential' - | 'waitingForQrScan' - | { - credentialDownloadFromOffer?: - | 'checkingIssuerTrust' - | 'credentialOfferDownloadConsent' - | 'idle' - | 'keyManagement' - | 'sendConsentGiven' - | 'sendConsentNotGiven' - | 'sendTxCode' - | 'waitingForTxCode' - | { - keyManagement?: - | 'constructProof' - | 'generateKeyPair' - | 'getKeyPairFromKeystore' - | 'setSelectedKey' - | 'userCancelledBiometric'; - sendConsentGiven?: - | 'addingIssuerToTrustedIssuers' - | 'updatingTrustedIssuerList'; - }; - downloadCredentials?: - | 'constructProof' - | 'idle' - | 'keyManagement' - | 'userCancelledBiometric' - | { - keyManagement?: - | 'generateKeyPair' - | 'getKeyPairFromKeystore' - | 'setSelectedKey' - | 'userCancelledBiometric'; - }; - }; - tags: never; -} diff --git a/machines/Issuers/IssuersModel.ts b/machines/Issuers/IssuersModel.ts index 2386bf6f..36f94d1f 100644 --- a/machines/Issuers/IssuersModel.ts +++ b/machines/Issuers/IssuersModel.ts @@ -1,15 +1,14 @@ -import {createModel} from 'xstate/lib/model'; -import {AuthorizeResult} from 'react-native-app-auth'; +import { createModel } from 'xstate/lib/model'; import { CredentialTypes, CredentialWrapper, IssuerWellknownResponse, VerifiableCredential, } from '../VerifiableCredential/VCMetaMachine/vc'; -import {AppServices} from '../../shared/GlobalContext'; -import {VCMetadata} from '../../shared/VCMetadata'; -import {IssuersEvents} from './IssuersEvents'; -import {issuerType} from './IssuersMachine'; +import { AppServices } from '../../shared/GlobalContext'; +import { VCMetadata } from '../../shared/VCMetadata'; +import { IssuersEvents } from './IssuersEvents'; +import { issuerType } from './IssuersMachine'; export const IssuersModel = createModel( { @@ -18,7 +17,7 @@ export const IssuersModel = createModel( qrData: '' as string, selectedIssuer: {} as issuerType, selectedIssuerWellknownResponse: {} as IssuerWellknownResponse, - tokenResponse: {} as AuthorizeResult, + tokenResponse: {} as object, errorMessage: '' as string, loadingReason: 'displayIssuers' as string, verifiableCredential: null as VerifiableCredential | null, @@ -45,7 +44,9 @@ export const IssuersModel = createModel( txCodeDescription: '' as string, txCodeLength: null as number | null, isCredentialOfferFlow: false as boolean, - credentialOfferIssuerMetadata: {} as object, + credentialOfferCredentialIssuer: {} as string, + tokenRequestObject: {} as object, + credentialConfigurationId: '' as string, }, { events: IssuersEvents, diff --git a/machines/Issuers/IssuersSelectors.ts b/machines/Issuers/IssuersSelectors.ts index ed78ba77..68715ce7 100644 --- a/machines/Issuers/IssuersSelectors.ts +++ b/machines/Issuers/IssuersSelectors.ts @@ -104,7 +104,3 @@ export function selectSupportedCredentialTypes(state: State) { export function selectIsQrScanning(state: State) { return state.matches('waitingForQrScan'); } - -export function selectCredentialOfferData(state: State) { - return state.context.credentialOfferData; -} diff --git a/machines/Issuers/IssuersService.ts b/machines/Issuers/IssuersService.ts index 600388eb..c66e3bc9 100644 --- a/machines/Issuers/IssuersService.ts +++ b/machines/Issuers/IssuersService.ts @@ -1,23 +1,23 @@ import NetInfo from '@react-native-community/netinfo'; -import {NativeModules} from 'react-native'; +import { NativeModules } from 'react-native'; import Cloud from '../../shared/CloudBackupAndRestoreUtils'; -import {CACHED_API} from '../../shared/api'; +import getAllConfigurations, { CACHED_API } from '../../shared/api'; import { fetchKeyPair, generateKeyPair, } from '../../shared/cryptoutil/cryptoUtil'; import { - constructIssuerMetaData, constructProofJWT, hasKeyPair, updateCredentialInformation, verifyCredentialData, } from '../../shared/openId4VCI/Utils'; import VciClient from '../../shared/vciClient/VciClient'; -import {issuerType} from './IssuersMachine'; -import {setItem} from '../store'; -import {API_CACHED_STORAGE_KEYS} from '../../shared/constants'; -import {createCacheObject} from '../../shared/Utils'; +import { displayType, issuerType } from './IssuersMachine'; +import { setItem } from '../store'; +import { API_CACHED_STORAGE_KEYS } from '../../shared/constants'; +import { createCacheObject } from '../../shared/Utils'; +import { VerificationResult } from '../../shared/vcjs/verifyCredential'; export const IssuersService = () => { return { @@ -30,21 +30,26 @@ export const IssuersService = () => { }, checkInternet: async () => await NetInfo.fetch(), downloadIssuerWellknown: async (context: any) => { - const wellknownResponse = await CACHED_API.fetchIssuerWellknownConfig( - context.selectedIssuer.issuer_id, - context.selectedIssuer.credential_issuer_host - ? context.selectedIssuer.credential_issuer_host - : context.selectedIssuer.credential_issuer, + const wellknownResponse = (await VciClient.getInstance().getIssuerMetadata( + context.selectedIssuer.credential_issuer_host, + )) as issuerType; + const wellknownCacheObject = createCacheObject(wellknownResponse); + await setItem( + API_CACHED_STORAGE_KEYS.fetchIssuerWellknownConfig( + context.selectedIssuer.credential_issuer_host, + ), + wellknownCacheObject, + '', ); return wellknownResponse; }, getCredentialTypes: async (context: any) => { - const credentialTypes = []; + const credentialTypes: Array<{id: string; [key: string]: any}> = []; const selectedIssuer = context.selectedIssuer; - const keys = - selectedIssuer.credential_configuration_ids ?? - Object.keys(selectedIssuer.credential_configurations_supported); + const keys = Object.keys( + selectedIssuer.credential_configurations_supported, + ); for (const key of keys) { if (selectedIssuer.credential_configurations_supported[key]) { @@ -70,26 +75,35 @@ export const IssuersService = () => { authEndpoint: authorizationEndpoint, }); }; - const getProofJwt = async (accessToken: string, cNonce: string) => { + const getProofJwt = async ( + credentialIssuer: string, + cNonce: string | null, + proofSigningAlgosSupported: string[] | null, + ) => { sendBack({ type: 'PROOF_REQUEST', - accessToken: accessToken, + credentialIssuer: credentialIssuer, cNonce: cNonce, + proofSigningAlgosSupported: proofSigningAlgosSupported, }); }; - const credential = + const getTokenResponse = (tokenRequest: object) => { + sendBack({ + type: 'TOKEN_REQUEST', + tokenRequest: tokenRequest, + }); + }; + const {credential} = await VciClient.getInstance().requestCredentialFromTrustedIssuer( - constructIssuerMetaData( - context.selectedIssuer, - context.selectedCredentialType, - context.selectedCredentialType.scope, - ), + context.selectedIssuer.credential_issuer_host, + context.selectedCredentialType.id, { clientId: context.selectedIssuer.client_id, redirectUri: context.selectedIssuer.redirect_uri, }, getProofJwt, navigateToAuthView, + getTokenResponse, ); return updateCredentialInformation(context, credential); }, @@ -109,7 +123,7 @@ export const IssuersService = () => { const {RNSecureKeystoreModule} = NativeModules; try { return await RNSecureKeystoreModule.hasAlias( - context.credentialOfferIssuerMetadata.credential_issuer, + context.credentialOfferCredentialIssuer, ); } catch (error) { console.error( @@ -123,8 +137,8 @@ export const IssuersService = () => { const {RNSecureKeystoreModule} = NativeModules; try { await RNSecureKeystoreModule.storeData( - context.credentialOfferIssuerMetadata.credential_issuer, - JSON.stringify(context.credentialOfferIssuerMetadata), + context.credentialOfferCredentialIssuer, + 'trusted', ); } catch { console.error('Error updating issuer trust in keystore'); @@ -138,39 +152,16 @@ export const IssuersService = () => { }); }; const getSignedProofJwt = async ( - accessToken: string, + credentialIssuer: string, cNonce: string | null, - issuerMetadata: object, - credentialConfigurationId: string, + proofSigningAlgosSupported: string[] | null, ) => { - let issuer = issuerMetadata as issuerType; - issuer.issuer_id = issuer.credential_issuer; - const wellknownCacheObject = createCacheObject(issuer); - await setItem( - API_CACHED_STORAGE_KEYS.fetchIssuerWellknownConfig(issuer.issuer_id), - wellknownCacheObject, - '', - ); - - let credentialTypes: Array<{id: string; [key: string]: any}> = []; - if ( - issuer.credential_configurations_supported[credentialConfigurationId] - ) { - credentialTypes.push({ - id: credentialConfigurationId, - ...issuer.credential_configurations_supported[ - credentialConfigurationId - ], - }); - sendBack({ - type: 'PROOF_REQUEST', - accessToken: accessToken, - cNonce: cNonce, - issuerMetadata: issuerMetadata, - issuer: issuer, - credentialTypes: credentialTypes, - }); - } + sendBack({ + type: 'PROOF_REQUEST', + cNonce: cNonce, + issuer: credentialIssuer, + proofSigningAlgosSupported: proofSigningAlgosSupported, + }); }; const getTxCode = async ( @@ -186,24 +177,55 @@ export const IssuersService = () => { }); }; - const requesTrustIssuerConsent = async (issuerMetadata: object) => { - const issuerMetadataObject = issuerMetadata as issuerType; + const requesTrustIssuerConsent = async ( + credentialIssuer: string, + issuerDisplay: object[], + ) => { + const issuerDisplayObject = issuerDisplay as displayType[]; sendBack({ type: 'TRUST_ISSUER_CONSENT_REQUEST', - issuerMetadata: issuerMetadataObject, + issuerDisplay: issuerDisplayObject, + issuer: credentialIssuer, + }); + }; + const getTokenResponse = (tokenRequest: object) => { + sendBack({ + type: 'TOKEN_REQUEST', + tokenRequest: tokenRequest, }); }; - const credential = await VciClient.getInstance().requestCredentialByOffer( - context.qrData, - getTxCode, - getSignedProofJwt, - navigateToAuthView, - requesTrustIssuerConsent, - ); - return credential; + const credentialResponse = + await VciClient.getInstance().requestCredentialByOffer( + context.qrData, + getTxCode, + getSignedProofJwt, + navigateToAuthView, + getTokenResponse, + requesTrustIssuerConsent, + ); + return credentialResponse; }, + sendTokenRequest: async (context: any) => { + const tokenRequestObject = context.tokenRequestObject; + return await sendTokenRequest( + tokenRequestObject, + context.selectedIssuer?.token_endpoint, + ); + }, + sendTokenResponse: async (context: any) => { + const tokenResponse = context.tokenResponse; + if (!tokenResponse) { + throw new Error( + 'Could not send token response, tokenResponse is undefined or null', + ); + } + return await VciClient.getInstance().sendTokenResponse( + JSON.stringify(tokenResponse), + ); + }, + updateCredential: async (context: any) => { const credential = await updateCredentialInformation( context, @@ -211,13 +233,25 @@ export const IssuersService = () => { ); return credential; }, + cacheIssuerWellknown: async (context: any) => { + const credentialIssuer = context.credentialOfferCredentialIssuer; + const issuerMetadata = (await VciClient.getInstance().getIssuerMetadata( + credentialIssuer, + )) as issuerType; + const wellknownCacheObject = createCacheObject(issuerMetadata); + await setItem( + API_CACHED_STORAGE_KEYS.fetchIssuerWellknownConfig(credentialIssuer), + wellknownCacheObject, + '', + ); + return issuerMetadata; + }, constructProof: async (context: any) => { - const issuerMeta = context.selectedIssuer; const proofJWT = await constructProofJWT( context.publicKey, context.privateKey, - context.accessToken, - issuerMeta, + context.credentialOfferCredentialIssuer, + null, context.keyType, context.wellknownKeyTypes, true, @@ -226,13 +260,13 @@ export const IssuersService = () => { await VciClient.getInstance().sendProof(proofJWT); return proofJWT; }, - constructProofForTrustedIssuers: async (context: any) => { + constructAndSendProofForTrustedIssuers: async (context: any) => { const issuerMeta = context.selectedIssuer; const proofJWT = await constructProofJWT( context.publicKey, context.privateKey, - context.accessToken, - issuerMeta, + context.selectedIssuer.credential_issuer_host, + context.selectedIssuer.client_id, context.keyType, context.wellknownKeyTypes, false, @@ -267,16 +301,82 @@ export const IssuersService = () => { return context.keyType; }, - verifyCredential: async (context: any) => { + verifyCredential: async (context: any): Promise => { + const { isCredentialOfferFlow, verifiableCredential, selectedCredentialType } = context; + if (isCredentialOfferFlow) { + const configurations = await getAllConfigurations(); + if (configurations.disableCredentialOfferVcVerification) { + return { + isVerified: true, + verificationMessage: '', + verificationErrorCode: '', + }; + } + } const verificationResult = await verifyCredentialData( - context.verifiableCredential?.credential, - context.selectedCredentialType.format + verifiableCredential?.credential, + selectedCredentialType.format, ); if (!verificationResult.isVerified) { throw new Error(verificationResult.verificationErrorCode); } - + return verificationResult; + } + +} +} +async function sendTokenRequest( + tokenRequestObject: any, + proxyTokenEndpoint: any = null, +) { + if (proxyTokenEndpoint) { + tokenRequestObject.tokenEndpoint = proxyTokenEndpoint; + } + if (!tokenRequestObject?.tokenEndpoint) { + console.error('tokenEndpoint is not provided in tokenRequestObject'); + throw new Error('tokenEndpoint is required'); + } + + const formBody = new URLSearchParams(); + + formBody.append('grant_type', tokenRequestObject.grantType); + + if (tokenRequestObject.authCode) { + formBody.append('code', tokenRequestObject.authCode); + } + if (tokenRequestObject.preAuthCode) { + formBody.append('pre-authorized_code', tokenRequestObject.preAuthCode); + } + if (tokenRequestObject.txCode) { + formBody.append('tx_code', tokenRequestObject.txCode); + } + if (tokenRequestObject.clientId) { + formBody.append('client_id', tokenRequestObject.clientId); + } + if (tokenRequestObject.redirectUri) { + formBody.append('redirect_uri', tokenRequestObject.redirectUri); + } + if (tokenRequestObject.codeVerifier) { + formBody.append('code_verifier', tokenRequestObject.codeVerifier); + } + const response = await fetch(tokenRequestObject.tokenEndpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', }, - }; -}; + body: formBody.toString(), + }); + + if (!response.ok) { + const errorText = await response.text(); + console.error( + 'Token request failed with status:', + response.status, + errorText, + ); + throw new Error(`Token request failed: ${response.status} ${errorText}`); + } + const tokenResponse = await response.json(); + return tokenResponse; +} diff --git a/machines/activityLog.ts b/machines/activityLog.ts index 3b3f7506..161d0245 100644 --- a/machines/activityLog.ts +++ b/machines/activityLog.ts @@ -157,7 +157,7 @@ export const activityLogMachine = setAllWellknownConfigResponse: model.assign({ wellKnownIssuerMap: (_, event) => { Object.entries(event.response).forEach(([key, value]) => { - event.response[key] = parseJSON(value); + event.response[key] = parseJSON(value).response; }); return event.response as Record; diff --git a/machines/app.typegen.ts b/machines/app.typegen.ts index 98542632..e7afcf10 100644 --- a/machines/app.typegen.ts +++ b/machines/app.typegen.ts @@ -1,120 +1,80 @@ // This file was automatically generated. Edits will be overwritten -export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - 'done.invoke.app.init.checkKeyPairs:invocation[0]': { - type: 'done.invoke.app.init.checkKeyPairs:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.app.init.generateKeyPairs:invocation[0]': { - type: 'done.invoke.app.init.generateKeyPairs:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.app.ready.focus.active:invocation[0]': { - type: 'done.invoke.app.ready.focus.active:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'error.platform.app.init.checkKeyPairs:invocation[0]': { - type: 'error.platform.app.init.checkKeyPairs:invocation[0]'; - data: unknown; - }; - 'xstate.init': {type: 'xstate.init'}; - }; - invokeSrcNameMap: { - checkFocusState: 'done.invoke.app.ready.focus:invocation[0]'; - checkKeyPairs: 'done.invoke.app.init.checkKeyPairs:invocation[0]'; - checkNetworkState: 'done.invoke.app.ready.network:invocation[0]'; - generateKeyPairsAndStoreOrder: 'done.invoke.app.init.generateKeyPairs:invocation[0]'; - getAppInfo: 'done.invoke.app.init.info:invocation[0]'; - isQrLoginByDeepLink: 'done.invoke.app.ready.focus.active:invocation[0]'; - resetQRLoginDeepLinkData: 'done.invoke.app.ready.focus.active:invocation[1]'; - }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - services: never; - }; - eventsCausingActions: { - forwardToServices: 'ACTIVE' | 'INACTIVE' | 'OFFLINE' | 'ONLINE'; - loadCredentialRegistryHostFromStorage: 'READY'; - loadCredentialRegistryInConstants: 'STORE_RESPONSE'; - loadEsignetHostFromConstants: 'STORE_RESPONSE'; - loadEsignetHostFromStorage: 'READY'; - logServiceEvents: 'done.invoke.app.init.checkKeyPairs:invocation[0]'; - logStoreEvents: - | 'BIOMETRIC_CANCELLED' - | 'KEY_INVALIDATE_ERROR' - | 'RESET_KEY_INVALIDATE_ERROR_DISMISS' - | 'xstate.init'; - requestDeviceInfo: 'REQUEST_DEVICE_INFO'; - resetKeyInvalidateError: 'READY' | 'RESET_KEY_INVALIDATE_ERROR_DISMISS'; - resetLinkCode: 'RESET_LINKCODE'; - setAppInfo: 'APP_INFO_RECEIVED'; - setIsDecryptError: 'DECRYPT_ERROR'; - setIsReadError: 'ERROR'; - setLinkCode: 'done.invoke.app.ready.focus.active:invocation[0]'; - spawnServiceActors: 'done.invoke.app.init.checkKeyPairs:invocation[0]'; - spawnStoreActor: - | 'BIOMETRIC_CANCELLED' - | 'KEY_INVALIDATE_ERROR' - | 'RESET_KEY_INVALIDATE_ERROR_DISMISS' - | 'xstate.init'; - unsetIsDecryptError: 'DECRYPT_ERROR_DISMISS' | 'READY'; - unsetIsReadError: 'READY'; - updateKeyInvalidateError: 'ERROR' | 'KEY_INVALIDATE_ERROR'; - }; - eventsCausingDelays: {}; - eventsCausingGuards: {}; - eventsCausingServices: { - checkFocusState: 'APP_INFO_RECEIVED'; - checkKeyPairs: - | 'READY' - | 'done.invoke.app.init.generateKeyPairs:invocation[0]'; - checkNetworkState: 'APP_INFO_RECEIVED'; - generateKeyPairsAndStoreOrder: 'error.platform.app.init.checkKeyPairs:invocation[0]'; - getAppInfo: 'STORE_RESPONSE'; - isQrLoginByDeepLink: 'ACTIVE'; - resetQRLoginDeepLinkData: 'ACTIVE'; - }; - matchesStates: - | 'init' - | 'init.checkKeyPairs' - | 'init.credentialRegistry' - | 'init.generateKeyPairs' - | 'init.info' - | 'init.services' - | 'init.store' - | 'ready' - | 'ready.focus' - | 'ready.focus.active' - | 'ready.focus.checking' - | 'ready.focus.inactive' - | 'ready.network' - | 'ready.network.checking' - | 'ready.network.offline' - | 'ready.network.online' - | 'waiting' - | { - init?: - | 'checkKeyPairs' - | 'credentialRegistry' - | 'generateKeyPairs' - | 'info' - | 'services' - | 'store'; - ready?: - | 'focus' - | 'network' - | { - focus?: 'active' | 'checking' | 'inactive'; - network?: 'checking' | 'offline' | 'online'; - }; - }; - tags: never; -} + export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + "done.invoke.app.init.checkKeyPairs:invocation[0]": { type: "done.invoke.app.init.checkKeyPairs:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.app.init.fetchConfig:invocation[0]": { type: "done.invoke.app.init.fetchConfig:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.app.init.generateKeyPairs:invocation[0]": { type: "done.invoke.app.init.generateKeyPairs:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.app.ready.focus.active:invocation[0]": { type: "done.invoke.app.ready.focus.active:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.app.ready.focus.active:invocation[2]": { type: "done.invoke.app.ready.focus.active:invocation[2]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"error.platform.app.init.checkKeyPairs:invocation[0]": { type: "error.platform.app.init.checkKeyPairs:invocation[0]"; data: unknown }; +"error.platform.app.init.fetchConfig:invocation[0]": { type: "error.platform.app.init.fetchConfig:invocation[0]"; data: unknown }; +"xstate.init": { type: "xstate.init" }; + }; + invokeSrcNameMap: { + "checkFocusState": "done.invoke.app.ready.focus:invocation[0]"; +"checkKeyPairs": "done.invoke.app.init.checkKeyPairs:invocation[0]"; +"checkNetworkState": "done.invoke.app.ready.network:invocation[0]"; +"fetchAndUpdateCacheTTLFromConfig": "done.invoke.app.init.fetchConfig:invocation[0]"; +"generateKeyPairsAndStoreOrder": "done.invoke.app.init.generateKeyPairs:invocation[0]"; +"getAppInfo": "done.invoke.app.init.info:invocation[0]"; +"getOVPDeepLinkIntent": "done.invoke.app.ready.focus.active:invocation[2]"; +"getQrLoginDeepLinkIntent": "done.invoke.app.ready.focus.active:invocation[0]"; +"resetOVPDeepLinkIntent": "done.invoke.app.ready.focus.active:invocation[3]"; +"resetQrLoginDeepLinkIntent": "done.invoke.app.ready.focus.active:invocation[1]"; + }; + missingImplementations: { + actions: "forwardToServices"; + delays: never; + guards: never; + services: never; + }; + eventsCausingActions: { + "forwardToServices": "ACTIVE" | "INACTIVE" | "OFFLINE" | "ONLINE"; +"loadCredentialRegistryHostFromStorage": "READY"; +"loadCredentialRegistryInConstants": "STORE_RESPONSE"; +"loadEsignetHostFromConstants": "STORE_RESPONSE"; +"loadEsignetHostFromStorage": "READY"; +"logServiceEvents": "done.invoke.app.init.checkKeyPairs:invocation[0]"; +"logStoreEvents": "BIOMETRIC_CANCELLED" | "KEY_INVALIDATE_ERROR" | "RESET_KEY_INVALIDATE_ERROR_DISMISS" | "xstate.init"; +"requestDeviceInfo": "REQUEST_DEVICE_INFO"; +"resetAuthorizationRequest": "RESET_AUTHORIZATION_REQUEST"; +"resetKeyInvalidateError": "READY" | "RESET_KEY_INVALIDATE_ERROR_DISMISS"; +"resetLinkCode": "RESET_LINKCODE"; +"setAppInfo": "APP_INFO_RECEIVED"; +"setAuthorizationRequest": "done.invoke.app.ready.focus.active:invocation[2]"; +"setIsDecryptError": "DECRYPT_ERROR"; +"setIsReadError": "ERROR"; +"setLinkCode": "done.invoke.app.ready.focus.active:invocation[0]"; +"spawnServiceActors": "done.invoke.app.init.checkKeyPairs:invocation[0]"; +"spawnStoreActor": "BIOMETRIC_CANCELLED" | "KEY_INVALIDATE_ERROR" | "RESET_KEY_INVALIDATE_ERROR_DISMISS" | "xstate.init"; +"unsetIsDecryptError": "DECRYPT_ERROR_DISMISS" | "READY"; +"unsetIsReadError": "READY"; +"updateKeyInvalidateError": "ERROR" | "KEY_INVALIDATE_ERROR"; + }; + eventsCausingDelays: { + + }; + eventsCausingGuards: { + + }; + eventsCausingServices: { + "checkFocusState": "APP_INFO_RECEIVED"; +"checkKeyPairs": "READY" | "done.invoke.app.init.fetchConfig:invocation[0]" | "error.platform.app.init.fetchConfig:invocation[0]"; +"checkNetworkState": "APP_INFO_RECEIVED"; +"fetchAndUpdateCacheTTLFromConfig": "done.invoke.app.init.generateKeyPairs:invocation[0]"; +"generateKeyPairsAndStoreOrder": "error.platform.app.init.checkKeyPairs:invocation[0]"; +"getAppInfo": "STORE_RESPONSE"; +"getOVPDeepLinkIntent": "ACTIVE"; +"getQrLoginDeepLinkIntent": "ACTIVE"; +"resetOVPDeepLinkIntent": "ACTIVE"; +"resetQrLoginDeepLinkIntent": "ACTIVE"; + }; + matchesStates: "init" | "init.checkKeyPairs" | "init.credentialRegistry" | "init.fetchConfig" | "init.generateKeyPairs" | "init.info" | "init.services" | "init.store" | "ready" | "ready.focus" | "ready.focus.active" | "ready.focus.checking" | "ready.focus.inactive" | "ready.network" | "ready.network.checking" | "ready.network.offline" | "ready.network.online" | "waiting" | { "init"?: "checkKeyPairs" | "credentialRegistry" | "fetchConfig" | "generateKeyPairs" | "info" | "services" | "store"; +"ready"?: "focus" | "network" | { "focus"?: "active" | "checking" | "inactive"; +"network"?: "checking" | "offline" | "online"; }; }; + tags: never; + } + \ No newline at end of file diff --git a/machines/backupAndRestore/restore/restoreMachine.typegen.ts b/machines/backupAndRestore/restore/restoreMachine.typegen.ts index 8e3808e9..11d359a9 100644 --- a/machines/backupAndRestore/restore/restoreMachine.typegen.ts +++ b/machines/backupAndRestore/restore/restoreMachine.typegen.ts @@ -1,156 +1,63 @@ -// This file was automatically generated. Edits will be overwritten -export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]': { - type: 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]': { - type: 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]': { - type: 'done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]': { - type: 'done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'error.platform.restore.restoreBackup.checkInternet:invocation[0]': { - type: 'error.platform.restore.restoreBackup.checkInternet:invocation[0]'; - data: unknown; - }; - 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]': { - type: 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]'; - data: unknown; - }; - 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]': { - type: 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]'; - data: unknown; - }; - 'xstate.init': {type: 'xstate.init'}; - }; - invokeSrcNameMap: { - checkInternet: 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]'; - checkStorageAvailability: 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]'; - downloadLatestBackup: 'done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]'; - readBackupFile: 'done.invoke.restore.restoreBackup.readBackupFile:invocation[0]'; - unzipBackupFile: 'done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]'; - }; - missingImplementations: { - actions: - | 'cleanupFiles' - | 'downloadUnsyncedBackupFiles' - | 'loadDataToMemory' - | 'refreshVCs' - | 'sendDataRestoreErrorEvent' - | 'sendDataRestoreFailureEvent' - | 'sendDataRestoreStartEvent' - | 'sendDataRestoreSuccessEvent' - | 'setBackupFileName' - | 'setDataFromBackupFile' - | 'setRestoreErrorReason' - | 'setRestoreErrorReasonAsNetworkError' - | 'setRestoreTechnicalError' - | 'setShowRestoreInProgress' - | 'unsetShowRestoreInProgress'; - delays: never; - guards: - | 'isInternetConnected' - | 'isMinimumStorageRequiredForBackupRestorationReached'; - services: - | 'checkInternet' - | 'checkStorageAvailability' - | 'downloadLatestBackup' - | 'readBackupFile' - | 'unzipBackupFile'; - }; - eventsCausingActions: { - cleanupFiles: - | 'STORE_ERROR' - | 'STORE_RESPONSE' - | 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]' - | 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]' - | 'error.platform.restore.restoreBackup.checkInternet:invocation[0]' - | 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]' - | 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]'; - downloadUnsyncedBackupFiles: 'DOWNLOAD_UNSYNCED_BACKUP_FILES'; - loadDataToMemory: 'DATA_FROM_FILE'; - refreshVCs: 'STORE_RESPONSE'; - sendDataRestoreErrorEvent: - | 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]' - | 'error.platform.restore.restoreBackup.checkInternet:invocation[0]'; - sendDataRestoreFailureEvent: - | 'STORE_ERROR' - | 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]' - | 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]' - | 'error.platform.restore.restoreBackup.checkInternet:invocation[0]' - | 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]' - | 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]'; - sendDataRestoreStartEvent: 'BACKUP_RESTORE'; - sendDataRestoreSuccessEvent: 'STORE_RESPONSE'; - setBackupFileName: 'done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]'; - setDataFromBackupFile: 'DATA_FROM_FILE'; - setRestoreErrorReason: - | 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]' - | 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]'; - setRestoreErrorReasonAsNetworkError: - | 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]' - | 'error.platform.restore.restoreBackup.checkInternet:invocation[0]'; - setRestoreTechnicalError: - | 'STORE_ERROR' - | 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]'; - setShowRestoreInProgress: 'BACKUP_RESTORE'; - unsetShowRestoreInProgress: - | 'DISMISS_SHOW_RESTORE_IN_PROGRESS' - | 'STORE_ERROR' - | 'STORE_RESPONSE' - | 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]' - | 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]' - | 'error.platform.restore.restoreBackup.checkInternet:invocation[0]' - | 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]' - | 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]'; - }; - eventsCausingDelays: {}; - eventsCausingGuards: { - isInternetConnected: 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]'; - isMinimumStorageRequiredForBackupRestorationReached: 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]'; - }; - eventsCausingServices: { - checkInternet: 'BACKUP_RESTORE'; - checkStorageAvailability: 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]'; - downloadLatestBackup: 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]'; - readBackupFile: 'done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]'; - unzipBackupFile: 'done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]'; - }; - matchesStates: - | 'init' - | 'restoreBackup' - | 'restoreBackup.checkInternet' - | 'restoreBackup.checkStorageAvailability' - | 'restoreBackup.downloadBackupFileFromCloud' - | 'restoreBackup.failure' - | 'restoreBackup.loadDataToMemory' - | 'restoreBackup.readBackupFile' - | 'restoreBackup.success' - | 'restoreBackup.unzipBackupFile' - | { - restoreBackup?: - | 'checkInternet' - | 'checkStorageAvailability' - | 'downloadBackupFileFromCloud' - | 'failure' - | 'loadDataToMemory' - | 'readBackupFile' - | 'success' - | 'unzipBackupFile'; - }; - tags: never; -} + // This file was automatically generated. Edits will be overwritten + + export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + "done.invoke.restore.restoreBackup.checkInternet:invocation[0]": { type: "done.invoke.restore.restoreBackup.checkInternet:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]": { type: "done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]": { type: "done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]": { type: "done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"error.platform.restore.restoreBackup.checkInternet:invocation[0]": { type: "error.platform.restore.restoreBackup.checkInternet:invocation[0]"; data: unknown }; +"error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]": { type: "error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]"; data: unknown }; +"error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]": { type: "error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]"; data: unknown }; +"xstate.init": { type: "xstate.init" }; + }; + invokeSrcNameMap: { + "checkInternet": "done.invoke.restore.restoreBackup.checkInternet:invocation[0]"; +"checkStorageAvailability": "done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]"; +"downloadLatestBackup": "done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]"; +"readBackupFile": "done.invoke.restore.restoreBackup.readBackupFile:invocation[0]"; +"unzipBackupFile": "done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]"; + }; + missingImplementations: { + actions: "cleanupFiles" | "downloadUnsyncedBackupFiles" | "loadDataToMemory" | "refreshVCs" | "sendDataRestoreErrorEvent" | "sendDataRestoreFailureEvent" | "sendDataRestoreStartEvent" | "sendDataRestoreSuccessEvent" | "setBackupFileName" | "setDataFromBackupFile" | "setRestoreErrorReason" | "setRestoreErrorReasonAsNetworkError" | "setRestoreTechnicalError" | "setShowRestoreInProgress" | "unsetShowRestoreInProgress"; + delays: never; + guards: "isInternetConnected" | "isMinimumStorageRequiredForBackupRestorationReached"; + services: "checkInternet" | "checkStorageAvailability" | "downloadLatestBackup" | "readBackupFile" | "unzipBackupFile"; + }; + eventsCausingActions: { + "cleanupFiles": "STORE_ERROR" | "STORE_RESPONSE" | "done.invoke.restore.restoreBackup.checkInternet:invocation[0]" | "done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]" | "error.platform.restore.restoreBackup.checkInternet:invocation[0]" | "error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]" | "error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]"; +"downloadUnsyncedBackupFiles": "DOWNLOAD_UNSYNCED_BACKUP_FILES"; +"loadDataToMemory": "DATA_FROM_FILE"; +"refreshVCs": "STORE_RESPONSE"; +"sendDataRestoreErrorEvent": "done.invoke.restore.restoreBackup.checkInternet:invocation[0]" | "error.platform.restore.restoreBackup.checkInternet:invocation[0]"; +"sendDataRestoreFailureEvent": "STORE_ERROR" | "done.invoke.restore.restoreBackup.checkInternet:invocation[0]" | "done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]" | "error.platform.restore.restoreBackup.checkInternet:invocation[0]" | "error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]" | "error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]"; +"sendDataRestoreStartEvent": "BACKUP_RESTORE"; +"sendDataRestoreSuccessEvent": "STORE_RESPONSE"; +"setBackupFileName": "done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]"; +"setDataFromBackupFile": "DATA_FROM_FILE"; +"setRestoreErrorReason": "error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]" | "error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]"; +"setRestoreErrorReasonAsNetworkError": "done.invoke.restore.restoreBackup.checkInternet:invocation[0]" | "error.platform.restore.restoreBackup.checkInternet:invocation[0]"; +"setRestoreTechnicalError": "STORE_ERROR" | "done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]"; +"setShowRestoreInProgress": "BACKUP_RESTORE"; +"unsetShowRestoreInProgress": "DISMISS_SHOW_RESTORE_IN_PROGRESS" | "STORE_ERROR" | "STORE_RESPONSE" | "done.invoke.restore.restoreBackup.checkInternet:invocation[0]" | "done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]" | "error.platform.restore.restoreBackup.checkInternet:invocation[0]" | "error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]" | "error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]"; + }; + eventsCausingDelays: { + + }; + eventsCausingGuards: { + "isInternetConnected": "done.invoke.restore.restoreBackup.checkInternet:invocation[0]"; +"isMinimumStorageRequiredForBackupRestorationReached": "done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]"; + }; + eventsCausingServices: { + "checkInternet": "BACKUP_RESTORE"; +"checkStorageAvailability": "done.invoke.restore.restoreBackup.checkInternet:invocation[0]"; +"downloadLatestBackup": "done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]"; +"readBackupFile": "done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]"; +"unzipBackupFile": "done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]"; + }; + matchesStates: "init" | "restoreBackup" | "restoreBackup.checkInternet" | "restoreBackup.checkStorageAvailability" | "restoreBackup.downloadBackupFileFromCloud" | "restoreBackup.failure" | "restoreBackup.loadDataToMemory" | "restoreBackup.readBackupFile" | "restoreBackup.success" | "restoreBackup.unzipBackupFile" | { "restoreBackup"?: "checkInternet" | "checkStorageAvailability" | "downloadBackupFileFromCloud" | "failure" | "loadDataToMemory" | "readBackupFile" | "success" | "unzipBackupFile"; }; + tags: never; + } + \ No newline at end of file diff --git a/machines/store.typegen.ts b/machines/store.typegen.ts index 6d6f0df0..e69de29b 100644 --- a/machines/store.typegen.ts +++ b/machines/store.typegen.ts @@ -1,54 +0,0 @@ - - // This file was automatically generated. Edits will be overwritten - - export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - "done.invoke._store": { type: "done.invoke._store"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"done.invoke.store.checkFreshInstall:invocation[0]": { type: "done.invoke.store.checkFreshInstall:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"done.invoke.store.resettingStorage:invocation[0]": { type: "done.invoke.store.resettingStorage:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"error.platform._store": { type: "error.platform._store"; data: unknown }; -"xstate.init": { type: "xstate.init" }; - }; - invokeSrcNameMap: { - "checkFreshInstall": "done.invoke.store.checkFreshInstall:invocation[0]"; -"checkStorageInitialisedOrNot": "done.invoke.store.checkStorageInitialisation:invocation[0]"; -"clear": "done.invoke.store.resettingStorage:invocation[0]"; -"clearKeys": "done.invoke.store.clearIosKeys:invocation[0]"; -"generateEncryptionKey": "done.invoke.store.generatingEncryptionKey:invocation[0]"; -"getEncryptionKey": "done.invoke.store.gettingEncryptionKey:invocation[0]"; -"hasEncryptionKey": "done.invoke.store.checkEncryptionKey:invocation[0]"; -"store": "done.invoke._store"; - }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - services: never; - }; - eventsCausingActions: { - "forwardStoreRequest": "APPEND" | "CLEAR" | "EXPORT" | "FETCH_ALL_WELLKNOWN_CONFIG" | "GET" | "GET_VCS_DATA" | "PREPEND" | "REMOVE" | "REMOVE_ITEMS" | "REMOVE_VC_METADATA" | "RESTORE_BACKUP" | "SET" | "UPDATE"; -"notifyParent": "KEY_RECEIVED" | "READY" | "done.invoke.store.resettingStorage:invocation[0]"; -"setEncryptionKey": "KEY_RECEIVED"; - }; - eventsCausingDelays: { - - }; - eventsCausingGuards: { - "hasData": "done.invoke.store.checkFreshInstall:invocation[0]"; -"isCustomSecureKeystore": "KEY_RECEIVED"; - }; - eventsCausingServices: { - "checkFreshInstall": "BIOMETRIC_CANCELLED" | "xstate.init"; -"checkStorageInitialisedOrNot": "ERROR"; -"clear": "KEY_RECEIVED"; -"clearKeys": "done.invoke.store.checkFreshInstall:invocation[0]"; -"generateEncryptionKey": "ERROR" | "IGNORE" | "READY"; -"getEncryptionKey": "TRY_AGAIN"; -"hasEncryptionKey": never; -"store": "KEY_RECEIVED" | "READY" | "done.invoke.store.resettingStorage:invocation[0]"; - }; - matchesStates: "checkEncryptionKey" | "checkFreshInstall" | "checkStorageInitialisation" | "clearIosKeys" | "failedReadingKey" | "generatingEncryptionKey" | "gettingEncryptionKey" | "ready" | "resettingStorage"; - tags: never; - } - \ No newline at end of file diff --git a/screens/Issuers/IssuerScreenController.tsx b/screens/Issuers/IssuerScreenController.tsx index 97cc33c2..5a6f9df8 100644 --- a/screens/Issuers/IssuerScreenController.tsx +++ b/screens/Issuers/IssuerScreenController.tsx @@ -12,17 +12,14 @@ import { selectSelectedIssuer, selectSelectingCredentialType, selectStoring, - selectVerificationErrorMessage, - selectIsNonGenericError, - selectIsQrScanning, - selectCredentialOfferData, + selectVerificationErrorMessage, selectIsQrScanning, selectAuthWebViewStatus, selectAuthEndPoint, selectIsTxCodeRequested, selectIsConsentRequested, selectIssuerLogo, selectIssuerName, - selectTxCodeDisplayDetails, + selectTxCodeDisplayDetails } from '../../machines/Issuers/IssuersSelectors'; import { ActorRefFrom } from 'xstate'; import { BOTTOM_TAB_ROUTES } from '../../routes/routesConstants'; @@ -40,10 +37,10 @@ export function useIssuerScreenController({ route, navigation }) { return { issuers: useSelector(service, selectIssuers), - issuerLogo: useSelector(service,selectIssuerLogo), - issuerName: useSelector(service,selectIssuerName), - isTxCodeRequested: useSelector(service,selectIsTxCodeRequested), - txCodeDisplayDetails: useSelector(service,selectTxCodeDisplayDetails), + issuerLogo: useSelector(service, selectIssuerLogo), + issuerName: useSelector(service, selectIssuerName), + isTxCodeRequested: useSelector(service, selectIsTxCodeRequested), + txCodeDisplayDetails: useSelector(service, selectTxCodeDisplayDetails), authEndpount: useSelector(service, selectAuthEndPoint), selectedIssuer: useSelector(service, selectSelectedIssuer), errorMessageType: useSelector(service, selectErrorMessageType), @@ -51,7 +48,6 @@ export function useIssuerScreenController({ route, navigation }) { isBiometricsCancelled: useSelector(service, selectIsBiometricCancelled), isDone: useSelector(service, selectIsDone), isIdle: useSelector(service, selectIsIdle), - isNonGenericError: useSelector(service, selectIsNonGenericError), loadingReason: useSelector(service, selectLoadingReason), isStoring: useSelector(service, selectStoring), isQrScanning: useSelector(service, selectIsQrScanning), @@ -61,9 +57,8 @@ export function useIssuerScreenController({ route, navigation }) { selectSelectingCredentialType, ), isConsentRequested: useSelector( - service,selectIsConsentRequested + service, selectIsConsentRequested ), - credentialOfferData: useSelector(service, selectCredentialOfferData), supportedCredentialTypes: useSelector( service, selectSupportedCredentialTypes, diff --git a/screens/Issuers/IssuersScreen.tsx b/screens/Issuers/IssuersScreen.tsx index f7f6331a..51e9053b 100644 --- a/screens/Issuers/IssuersScreen.tsx +++ b/screens/Issuers/IssuersScreen.tsx @@ -38,6 +38,7 @@ import { IssuersModel } from '../../machines/Issuers/IssuersModel'; import { AUTH_ROUTES } from '../../routes/routesConstants'; import { TransactionCodeModal } from './TransactionCodeScreen'; import { TrustIssuerModal } from './TrustIssuerModal'; +import i18next from 'i18next'; export const IssuersScreen: React.FC< HomeRouteProps | RootRouteProps > = props => { @@ -49,7 +50,7 @@ export const IssuersScreen: React.FC< const [search, setSearch] = useState(''); const [tapToSearch, setTapToSearch] = useState(false); const [clearSearchIcon, setClearSearchIcon] = useState(false); - const showFullScreenError = controller.isError && controller.errorMessageType; + const showFullScreenError = controller.isError const isVerificationFailed = controller.verificationErrorMessage !== ''; @@ -57,7 +58,8 @@ export const IssuersScreen: React.FC< const verificationErrorMessage = isTranslationKeyFound(translationKey, t) ? t(translationKey) - : t(`errors.verificationFailed.ERR_GENERIC`); + : t('errors.verificationFailed.ERR_GENERIC'); + useLayoutEffect(() => { if (controller.loadingReason || showFullScreenError) { @@ -124,7 +126,8 @@ export const IssuersScreen: React.FC< controller.errorMessageType === ErrorMessage.CREDENTIAL_TYPE_DOWNLOAD_FAILURE || controller.errorMessageType === - ErrorMessage.AUTHORIZATION_GRANT_TYPE_NOT_SUPPORTED + ErrorMessage.AUTHORIZATION_GRANT_TYPE_NOT_SUPPORTED || + controller.errorMessageType === ErrorMessage.NETWORK_REQUEST_FAILED ); } diff --git a/screens/Issuers/TransactionCodeScreen.tsx b/screens/Issuers/TransactionCodeScreen.tsx index 0ee71a8a..0f24d1fb 100644 --- a/screens/Issuers/TransactionCodeScreen.tsx +++ b/screens/Issuers/TransactionCodeScreen.tsx @@ -113,7 +113,7 @@ export const TransactionCodeModal: React.FC = props => { }`, )} - {textLineCount >= maxLines && maxLines && setShowFullDescription(prev => !prev)} style={Theme.TransactionCodeScreenStyle.showMoreButton} > diff --git a/shared/InitialConfig.ts b/shared/InitialConfig.ts index 84516b61..099e1458 100644 --- a/shared/InitialConfig.ts +++ b/shared/InitialConfig.ts @@ -19,5 +19,6 @@ export const INITIAL_CONFIG = { faceSdkModelUrl: '', openId4VCIDownloadVCTimeout: '30000', cacheTTLInMilliSeconds: '3600000', + disableCredentialOfferVcVerification: false }, }; diff --git a/shared/VCMetadata.ts b/shared/VCMetadata.ts index e8f86b0a..2c2b37df 100644 --- a/shared/VCMetadata.ts +++ b/shared/VCMetadata.ts @@ -129,7 +129,7 @@ export function parseMetadatas(metadataStrings: object[]) { } export const getVCMetadata = (context: object, keyType: string) => { - const issuer = context.selectedIssuer.credential_issuer; + const issuer = context.selectedIssuer.credential_issuer_host ?? context.selectedIssuer.credential_issuer; const credentialId = `${UUID.generate()}_${issuer}`; return VCMetadata.fromVC({ @@ -147,7 +147,7 @@ export const getVCMetadata = (context: object, keyType: string) => { format: context['credentialWrapper'].format, downloadKeyType: keyType, credentialType: getCredentialType(context.selectedCredentialType), - issuerHost: context.selectedIssuer.credential_issuer_host ?? context.selectedIssuer.credential_issuer, + issuerHost: issuer }); }; diff --git a/shared/constants.ts b/shared/constants.ts index f3d2a2c1..964119dc 100644 --- a/shared/constants.ts +++ b/shared/constants.ts @@ -155,6 +155,7 @@ export type IndividualId = { export const TECHNICAL_ERROR = 'Technical error'; export const NETWORK_REQUEST_FAILED = 'Network request failed'; +export const NO_INTERNET = 'No internet connection'; export const IOS_SIGNIN_FAILED = 'iCloud not available'; export const REQUEST_TIMEOUT = 'request timeout'; export const BIOMETRIC_CANCELLED = 'User has cancelled biometric'; diff --git a/shared/openId4VCI/Utils.ts b/shared/openId4VCI/Utils.ts index fce38f20..b6289b14 100644 --- a/shared/openId4VCI/Utils.ts +++ b/shared/openId4VCI/Utils.ts @@ -1,6 +1,5 @@ import base64url from 'base64url'; import i18next from 'i18next'; -import jwtDecode from 'jwt-decode'; import jose from 'node-jose'; import {NativeModules} from 'react-native'; import {vcVerificationBannerDetails} from '../../components/BannerNotificationContainer'; @@ -10,11 +9,9 @@ import { DETAIL_VIEW_ADD_ON_FIELDS, getCredentialTypeFromWellKnown, } from '../../components/VC/common/VCUtils'; -import i18n from '../../i18n'; -import {displayType, issuerType} from '../../machines/Issuers/IssuersMachine'; +import {displayType} from '../../machines/Issuers/IssuersMachine'; import { Credential, - CredentialTypes, CredentialWrapper, VerifiableCredential, } from '../../machines/VerifiableCredential/VCMetaMachine/vc'; @@ -22,16 +19,11 @@ import getAllConfigurations, {CACHED_API} from '../api'; import { ED25519_PROOF_SIGNING_ALGO, isAndroid, - isIOS, JWT_ALG_TO_KEY_TYPE, KEY_TYPE_TO_JWT_ALG, } from '../constants'; import {getJWT} from '../cryptoutil/cryptoUtil'; -import { - VerificationErrorMessage, - VerificationErrorType, - verifyCredential, -} from '../vcjs/verifyCredential'; +import {verifyCredential} from '../vcjs/verifyCredential'; import {getVerifiableCredential} from '../../machines/VerifiableCredential/VCItemMachine/VCItemSelectors'; import {getErrorEventData, sendErrorEvent} from '../telemetry/TelemetryUtils'; import {TelemetryConstants} from '../telemetry/TelemetryConstants'; @@ -268,22 +260,21 @@ export enum ErrorMessage { TECHNICAL_DIFFICULTIES = 'technicalDifficulty', CREDENTIAL_TYPE_DOWNLOAD_FAILURE = 'credentialTypeListDownloadFailure', AUTHORIZATION_GRANT_TYPE_NOT_SUPPORTED = 'authorizationGrantTypeNotSupportedByWallet', + NETWORK_REQUEST_FAILED = 'networkRequestFailed', } export async function constructProofJWT( publicKey: any, privateKey: any, - accessToken: string, - selectedIssuer: issuerType, + selectedIssuer: string, + client_id: string | null, keyType: string, proofSigningAlgosSupported: string[] = [], isCredentialOfferFlow: boolean, cNonce?: string, ): Promise { const jwk = await getJWK(publicKey, keyType); - const decodedToken = jwtDecode(accessToken); - const nonce = cNonce ?? decodedToken?.c_nonce; - + const nonce = cNonce; const alg = keyType === KeyTypes.ED25519 ? resolveEd25519Alg(proofSigningAlgosSupported) @@ -302,9 +293,9 @@ export async function constructProofJWT( }; const jwtPayload = { - iss: selectedIssuer.client_id, + ...(client_id ? {iss: client_id} : {}), nonce, - aud: selectedIssuer.credential_audience ?? selectedIssuer.credential_issuer, + aud: selectedIssuer, iat: Math.floor(Date.now() / 1000), exp: Math.floor(Date.now() / 1000) + 18000, }; @@ -410,38 +401,9 @@ export function selectCredentialRequestKey( return keyType; } } - - return KeyTypes.ED25519; + return keyOrder[0]; } -export const constructIssuerMetaData = ( - selectedIssuer: issuerType, - selectedCredentialType: CredentialTypes, - scope: string, -): Object => { - const issuerMeta: Object = { - credentialAudience: selectedIssuer.credential_audience, - credentialEndpoint: selectedIssuer.credential_endpoint, - credentialFormat: isIOS() - ? selectedCredentialType.format - : selectedCredentialType.format.toUpperCase(), - authorizationServers: selectedIssuer['authorization_servers'], - tokenEndpoint: selectedIssuer.token_endpoint, - scope: scope, - }; - if (selectedCredentialType.format === VCFormat.ldp_vc) { - issuerMeta['credentialType'] = selectedCredentialType?.credential_definition - ?.type ?? ['VerifiableCredential']; - if (selectedCredentialType?.credential_definition['@context']) - issuerMeta['context'] = - selectedCredentialType?.credential_definition['@context']; - } else if (selectedCredentialType.format === VCFormat.mso_mdoc) { - issuerMeta['doctype'] = selectedCredentialType.doctype; - issuerMeta['claims'] = selectedCredentialType.claims; - } - return issuerMeta; -}; - export function getMatchingCredentialIssuerMetadata( wellknown: any, credentialConfigurationId: string, @@ -470,11 +432,11 @@ export async function verifyCredentialData( credential: Credential, credentialFormat: string, ) { - const verificationResult = await verifyCredential( - credential, - credentialFormat, - ); - return verificationResult; + const verificationResult = await verifyCredential( + credential, + credentialFormat, + ); + return verificationResult; } function resolveEd25519Alg(proofSigningAlgosSupported: string[]) { return proofSigningAlgosSupported.includes( diff --git a/shared/request.ts b/shared/request.ts index 4b7a9f6b..0d0faa3e 100644 --- a/shared/request.ts +++ b/shared/request.ts @@ -4,6 +4,8 @@ import { } from '../machines/VerifiableCredential/VCMetaMachine/vc'; import {__AppId} from './GlobalVariables'; import {MIMOTO_BASE_URL, REQUEST_TIMEOUT} from './constants'; +import NetInfo from '@react-native-community/netinfo'; +import { ErrorMessage } from './openId4VCI/Utils'; export type HTTP_METHOD = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; @@ -14,6 +16,14 @@ export class BackendResponseError extends Error { } } +async function assertInternetConnection() { + const net = await NetInfo.fetch(); + if (!net.isConnected || net.isInternetReachable === false) { + console.info('No internet'); + throw new Error('No internet connection'); + } +} + export async function request( method: HTTP_METHOD, path: `/${string}` | string, @@ -22,66 +32,81 @@ export async function request( headers: Record = { 'Content-Type': 'application/json', }, - timeoutMillis?: undefined | number, + timeoutMillis?: number | undefined, ) { - if (path.includes('v1/mimoto')) headers['X-AppId'] = __AppId.getValue(); + if (path.includes('v1/mimoto')) { + headers['X-AppId'] = __AppId.getValue(); + } + + const requestUrl = path.startsWith('https://') ? path : host + path; let response; - const requestUrl = path.indexOf('https://') != -1 ? path : host + path; - if (timeoutMillis === undefined) { - response = await fetch(requestUrl, { - method, - headers, - body: body ? JSON.stringify(body) : undefined, - }); - } else { - console.log(`making a web request to ${requestUrl}`); - let controller = new AbortController(); - setTimeout(() => { - controller.abort(); - }, timeoutMillis); - try { + + try { + if (timeoutMillis === undefined) { response = await fetch(requestUrl, { method, headers, body: body ? JSON.stringify(body) : undefined, - signal: controller.signal, }); - } catch (error) { - console.error( - `Error occurred while making request: ${host + path}: ${error}`, - ); - if (error.name === 'AbortError') { - throw new Error(REQUEST_TIMEOUT); + } else { + console.info(`Making a web request to ${requestUrl}`); + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeoutMillis); + + try { + response = await fetch(requestUrl, { + method, + headers, + body: body ? JSON.stringify(body) : undefined, + signal: controller.signal, + }); + } catch (error: any) { + clearTimeout(timeoutId); + console.error(`Request failed: ${requestUrl}:`, error); + + if (error.name === 'AbortError') { + throw new Error(REQUEST_TIMEOUT); + } + + await assertInternetConnection(); + throw error; } - throw error; } + } catch (error: any) { + console.error(`Failed to fetch from ${requestUrl}:`, error); + await assertInternetConnection(); + throw error; + } + + + let jsonResponse; + try { + jsonResponse = await response.json(); + } catch (jsonError) { + console.warn(`Failed to parse JSON from ${requestUrl}`, jsonError); + throw new Error(ErrorMessage.NETWORK_REQUEST_FAILED+' Invalid JSON response'); } - const jsonResponse = await response.json(); if (response.status >= 400) { - let backendUrl = host + path; - let errorMessage = + const backendUrl = host + path; + const errorMessage = jsonResponse.message || (typeof jsonResponse.error === 'object' ? JSON.stringify(jsonResponse.error) : jsonResponse.error); + console.error( `The backend API ${backendUrl} returned error code ${response.status} with message --> ${errorMessage}`, ); throw new Error(errorMessage); } + if (jsonResponse.errors && jsonResponse.errors.length) { - let backendUrl = host + path; - const {errorCode, errorMessage} = jsonResponse.errors.shift(); + const { errorCode, errorMessage } = jsonResponse.errors.shift(); console.error( - 'The backend API ' + - backendUrl + - ' returned error response --> error code is : ' + - errorCode + - ' error message is : ' + - errorMessage, + `The backend API ${requestUrl} returned structured error --> error code: ${errorCode}, message: ${errorMessage}`, ); throw new BackendResponseError(errorCode, errorMessage); } diff --git a/shared/vciClient/VciClient.ts b/shared/vciClient/VciClient.ts index 846a9dc4..bc8f9803 100644 --- a/shared/vciClient/VciClient.ts +++ b/shared/vciClient/VciClient.ts @@ -35,6 +35,15 @@ class VciClient { this.InjiVciClient.sendIssuerTrustResponseFromJS(consent); } + async sendTokenResponse(json: string) { + this.InjiVciClient.sendTokenResponseFromJS(json); + } + + async getIssuerMetadata(issuerUri: string): Promise { + const response = await this.InjiVciClient.getIssuerMetadata(issuerUri); + return JSON.parse(response); + } + async requestCredentialByOffer( credentialOffer: string, getTxCode: ( @@ -43,30 +52,29 @@ class VciClient { length: number | undefined, ) => void, getProofJwt: ( - accessToken: string, + credentialIssuer: string, cNonce: string | null, - issuerMetadata: object, - credentialConfigurationId: string, + proofSigningAlgosSupported: string[] | null, ) => void, navigateToAuthView: (authorizationEndpoint: string) => void, - requestTrustIssuerConsent: (issuerMetadata: object) => void, - ): Promise { + requestTokenResponse: (tokenRequest: object) => void, + requestTrustIssuerConsent: ( + credentialIssuer: string, + issuerDisplay: object[], + ) => void, + ): Promise { + const proofListener = emitter.addListener( 'onRequestProof', - ({accessToken, cNonce, issuerMetadata, credentialConfigurationId}) => { - getProofJwt( - accessToken, - cNonce, - JSON.parse(issuerMetadata), - credentialConfigurationId, - ); + ({credentialIssuer, cNonce, proofSigningAlgorithmsSupported}) => { + getProofJwt(credentialIssuer, cNonce, JSON.parse(proofSigningAlgorithmsSupported)); }, ); const authListener = emitter.addListener( 'onRequestAuthCode', - ({authorizationEndpoint}) => { - navigateToAuthView(authorizationEndpoint); + ({authorizationUrl}) => { + navigateToAuthView(authorizationUrl); }, ); @@ -77,21 +85,29 @@ class VciClient { }, ); + const tokenResponseListener = emitter.addListener( + 'onRequestTokenResponse', + ({tokenRequest}) => { + requestTokenResponse(tokenRequest); + }, + ); + const trustIssuerListener = emitter.addListener( 'onCheckIssuerTrust', - ({issuerMetadata}) => { - requestTrustIssuerConsent(JSON.parse(issuerMetadata)); + ({credentialIssuer, issuerDisplay}) => { + requestTrustIssuerConsent(credentialIssuer, JSON.parse(issuerDisplay)); }, ); let response = ''; try { + const clientMetadata = { + clientId: 'wallet', + redirectUri: 'io.mosip.residentapp.inji://oauthredirect', + }; response = await this.InjiVciClient.requestCredentialByOffer( credentialOffer, - JSON.stringify({ - clientId: 'wallet', - redirectUri: 'io.mosip.residentapp.inji://oauthredirect', - }), + JSON.stringify(clientMetadata), ); } catch (error) { console.error('Error requesting credential by offer:', error); @@ -100,37 +116,59 @@ class VciClient { proofListener.remove(); authListener.remove(); txCodeListener.remove(); + tokenResponseListener.remove(); trustIssuerListener.remove(); } - return JSON.parse(response) as VerifiableCredential; + const parsedResponse = JSON.parse(response); + return { + credential: { + credential: parsedResponse.credential, + } as VerifiableCredential, + credentialConfigurationId: + parsedResponse.credentialConfigurationId ?? {}, + credentialIssuer: parsedResponse.credentialIssuer ?? '', + }; } async requestCredentialFromTrustedIssuer( - resolvedIssuerMetaData: object, + credentialIssuerUri: string, + credentialConfigurationId: string, clientMetadata: object, - getProofJwt: (accessToken: string, cNonce: string) => void, + getProofJwt: ( + credentialIssuer: string, + cNonce: string | null, + proofSigningAlgosSupported: string[] | null, + ) => void, navigateToAuthView: (authorizationEndpoint: string) => void, - ): Promise { + requestTokenResponse: (tokenRequest: object) => void, + ): Promise { const proofListener = emitter.addListener( 'onRequestProof', - ({accessToken, cNonce}) => { - getProofJwt(accessToken, cNonce); - proofListener.remove(); + ({credentialIssuer, cNonce, proofSigningAlgorithmsSupported}) => { + getProofJwt(credentialIssuer, cNonce, JSON.parse(proofSigningAlgorithmsSupported)); }, ); const authListener = emitter.addListener( 'onRequestAuthCode', - ({authorizationEndpoint}) => { - navigateToAuthView(authorizationEndpoint); + ({authorizationUrl}) => { + navigateToAuthView(authorizationUrl); + }, + ); + + const tokenResponseListener = emitter.addListener( + 'onRequestTokenResponse', + ({tokenRequest}) => { + requestTokenResponse(tokenRequest); }, ); let response = ''; try { response = await this.InjiVciClient.requestCredentialFromTrustedIssuer( - JSON.stringify(resolvedIssuerMetaData), + credentialIssuerUri, + credentialConfigurationId, JSON.stringify(clientMetadata), ); } catch (error) { @@ -139,9 +177,18 @@ class VciClient { } finally { proofListener.remove(); authListener.remove(); + tokenResponseListener.remove(); } - return JSON.parse(response) as VerifiableCredential; + const parsedResponse = JSON.parse(response); + return { + credential: { + credential: parsedResponse.credential, + } as VerifiableCredential, + credentialConfigurationId: + parsedResponse.credentialConfigurationId ?? {}, + credentialIssuer: parsedResponse.credentialIssuer ?? '', + }; } }