[INJIMOB-3392] add token request logic in wallet for vci flow (#2014)

* [INJIMOB-3392] add token request logic in wallet for vci flow

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] chore: update integration of VCIClient native module

Changes are updated as per new changes in the library

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3390] refactor: event structure of token request

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3392] fix tokenEndpoint method and refactorings

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] cnonce decode from accesstoken and credential response destructuring fix

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3390] add: getIssuerMetadata in kotlin NativeModule

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3393] fix: auth callback in android

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3390] fix: proofJwt issue in download flow

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3392] fix credentialofferflow

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392]fix format issues in bridge layer

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392]fix activity log texts on application reopen

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392]cache issuer metadata by key: issuerhost

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] fix error scenarios and cleanup issuermachine

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] refactor request method to handle missing error scenarios

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] fix max lines for txcode description to 2

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] rename credentialissueruri to credentialissuer

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] take cnonce from outside accesstoken

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] declare random-values at entry file

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] set fallback keytype to user priority first

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] add locales for network request failed error

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] remove console log

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3392] refactor and clean up code

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

---------

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>
Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>
Co-authored-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>
This commit is contained in:
KiruthikaJeyashankar
2025-07-24 11:42:00 +05:30
committed by GitHub
parent 0fe6915bb8
commit 5305e7d7ea
37 changed files with 1159 additions and 1519 deletions

View File

@@ -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';

View File

@@ -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'

View File

@@ -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<String>? = null
private var deferredTxCode: CompletableDeferred<String>? = null
private var deferredIssuerTrustResponse: CompletableDeferred<Boolean>? = null
private var deferredTokenResponse: CompletableDeferred<TokenResponse>? = null
fun createProofDeferred(): CompletableDeferred<String> {
deferredProof = CompletableDeferred()
@@ -22,72 +24,86 @@ object VCIClientCallbackBridge {
return deferredAuthCode!!
}
fun createTokenResponseDeferred(): CompletableDeferred<TokenResponse> {
deferredTokenResponse = CompletableDeferred()
return deferredTokenResponse!!
}
fun createTxCodeDeferred(): CompletableDeferred<String> {
deferredTxCode = CompletableDeferred()
return deferredTxCode!!
}
fun createIsuerTrustResponseDeferred(): CompletableDeferred<Boolean> {
fun createIssuerTrustResponseDeferred(): CompletableDeferred<Boolean> {
deferredIssuerTrustResponse = CompletableDeferred()
return deferredIssuerTrustResponse!!
}
fun emitRequestProof(
context: ReactApplicationContext,
accessToken: String,
cNonce: String?,
issuerMetadata: Map<String, *>? = null,
credentialConfigurationId: String? = null
context: ReactApplicationContext,
credentialIssuer: String,
cNonce: String?,
proofSigningAlgorithmsSupported: List<String>,
) {
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<String, Any?>
) {
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<String, *>) {
fun emitRequestIssuerTrust(context: ReactApplicationContext, credentialIssuer: String, issuerDisplay: List<Map<String, Any>>) {
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")
}
}

View File

@@ -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<String, Object> 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);

View File

@@ -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<String> ->
VCIClientCallbackBridge.createProofDeferred()
VCIClientCallbackBridge.emitRequestProof(
reactContext,
credentialIssuer,
cNonce,
proofSigningAlgorithmsSupported
)
VCIClientCallbackBridge.awaitProof()
}
private fun getTokenResponseCallback(): suspend (tokenRequest: TokenRequest) -> TokenResponse =
{ tokenRequest ->
val payload: Map<String, Any?> =
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<Map<String, Any>>) -> Boolean =
{ credentialIssuer, issuerDisplay ->
VCIClientCallbackBridge.createIssuerTrustResponseDeferred()
VCIClientCallbackBridge.emitRequestIssuerTrust(
reactContext,
credentialIssuer,
issuerDisplay
)
VCIClientCallbackBridge.awaitIssuerTrustResponse()
}
}

View File

@@ -19,11 +19,9 @@ import {VCProcessor} from '../common/VCProcessor';
export const VCCardView: React.FC<VCItemProps> = ({
vcMetadata,
margin,
selectable,
selected,
onPress,
onShow,
isDownloading,
isPinned,
flow,
@@ -58,7 +56,7 @@ export const VCCardView: React.FC<VCItemProps> = ({
setVc(processedData);
}
}
loadVc();
}, [isDownloading, controller.credential]);

View File

@@ -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 */;

View File

@@ -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"
}
},

View File

@@ -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)

View File

@@ -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 {

View File

@@ -221,6 +221,10 @@
"title": "لا يوجد اتصال بالإنترنت",
"message": "الرجاء التحقق من اتصالك وإعادة المحاولة"
},
"networkRequestFailed": {
"title": "فشل طلب الشبكة",
"message": "لا يمكننا معالجة طلبك في الوقت الحالي."
},
"biometricsCancelled": {
"title": "هل تريد إلغاء التنزيل؟",
"message": "مطلوب تأكيد البيومترية لمواصلة تنزيل البطاقة."
@@ -1103,4 +1107,4 @@
"confirm": "نعم، أثق بهذا",
"cancel": "لا، أعدني"
}
}
}

View File

@@ -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."

View File

@@ -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"
}
}
}

View File

@@ -222,6 +222,10 @@
"title": "कोई इंटरनेट कनेक्शन नहीं",
"message": "कृपया अपना कनेक्शन जांचें और पुनः प्रयास करें"
},
"networkRequestFailed": {
"title": "नेटवर्क अनुरोध विफल हुआ",
"message": "हम इस समय आपके अनुरोध को संसाधित करने में असमर्थ हैं।"
},
"biometricsCancelled": {
"title": "क्या आप डाउनलोड रद्द करना चाहते हैं?",
"message": "कार्ड डाउनलोड करना जारी रखने के लिए बायोमेट्रिक पुष्टिकरण आवश्यक है।"
@@ -1107,4 +1111,4 @@
"confirm": "हाँ, मैं इस पर भरोसा करता हूँ",
"cancel": "नहीं, मुझे वापस ले चलो"
}
}
}

View File

@@ -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": "ಇಲ್ಲ, ನನನ್ನು ಹಿಂದಕ್ಕೆ ಕರೆ"
}
}
}

View File

@@ -220,6 +220,10 @@
"title": "இணைய இணைப்பு இல்லை",
"message": "உங்கள் இணைப்பைச் சரிபார்த்து மீண்டும் முயற்சிக்கவும்"
},
"networkRequestFailed": {
"title": "நெட்வொர்க் கோரிக்கை தோல்வியடைந்தது",
"message": "தற்போது உங்கள் கோரிக்கையை செயலாக்க முடியவில்லை."
},
"biometricsCancelled": {
"title": "பதிவிறக்கத்தை ரத்து செய்ய வேண்டுமா?",
"message": "கார்டை தொடர்ந்து பதிவிறக்க பயோமெட்ரிக் உறுதிப்படுத்தல் தேவை."
@@ -1106,4 +1110,4 @@
"confirm": "ஆம், நம்புகிறேன்",
"cancel": "இல்லை, என்னை திரும்ப அழைத்துச் செல்"
}
}
}

View File

@@ -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({

View File

@@ -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}),
};

View File

@@ -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;
}
},
};
};

File diff suppressed because one or more lines are too long

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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<VerificationResult> => {
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;
}

View File

@@ -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<string, Object>;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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
);
}

View File

@@ -113,7 +113,7 @@ export const TransactionCodeModal: React.FC<ExtendedModalProps> = props => {
}`,
)}
</Text>
{textLineCount >= maxLines && <Text
{textLineCount > maxLines && <Text
onPress={() => setShowFullDescription(prev => !prev)}
style={Theme.TransactionCodeScreenStyle.showMoreButton}
>

View File

@@ -19,5 +19,6 @@ export const INITIAL_CONFIG = {
faceSdkModelUrl: '',
openId4VCIDownloadVCTimeout: '30000',
cacheTTLInMilliSeconds: '3600000',
disableCredentialOfferVcVerification: false
},
};

View File

@@ -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
});
};

View File

@@ -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';

View File

@@ -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<string> {
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(

View File

@@ -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<string, string> = {
'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);
}

View File

@@ -35,6 +35,15 @@ class VciClient {
this.InjiVciClient.sendIssuerTrustResponseFromJS(consent);
}
async sendTokenResponse(json: string) {
this.InjiVciClient.sendTokenResponseFromJS(json);
}
async getIssuerMetadata(issuerUri: string): Promise<object> {
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<VerifiableCredential> {
requestTokenResponse: (tokenRequest: object) => void,
requestTrustIssuerConsent: (
credentialIssuer: string,
issuerDisplay: object[],
) => void,
): Promise<any> {
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<VerifiableCredential> {
requestTokenResponse: (tokenRequest: object) => void,
): Promise<any> {
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 ?? '',
};
}
}