From 8f17535a2584ebd4bef390d2c54b69fbedac98f0 Mon Sep 17 00:00:00 2001 From: KiruthikaJeyashankar Date: Mon, 6 Oct 2025 14:32:41 +0530 Subject: [PATCH] [INJIMOB-3571] | [INJIMOB-3572] refactor: Modify trusted verifiers construction (#2094) * [INJIMOB-3571] add: modify trusted verifiers Signed-off-by: KiruthikaJeyashankar * [INJIMOB-3571] add: modify trusted verifiers in swift Signed-off-by: KiruthikaJeyashankar * [INJIMOB-3571] refactor: remove unused logs and code Signed-off-by: KiruthikaJeyashankar * [INJIMOB-3572] add: support for unsigned request in pre-registered verifiers Signed-off-by: KiruthikaJeyashankar * [INJIMOB-3572] chore: update openid4vp swift package version Signed-off-by: KiruthikaJeyashankar * [INJIMOB-3571] refactor: revert changes trustedVerifiers cachePreference Signed-off-by: KiruthikaJeyashankar * [INJIMOB-3558] refactor: update vc renderer renderVc to generateCredentualDisplayCOntent Signed-off-by: KiruthikaJeyashankar * [INJIMOB-3559] fix: bridging issue of generateCredentialContent method Signed-off-by: KiruthikaJeyashankar * [INJIMOB-3559] refactor: modify vc renderer native module Signed-off-by: KiruthikaJeyashankar * [INJIMOB-3559] refactor: modify vc renderer native module Signed-off-by: KiruthikaJeyashankar * [INJIMOB-3559] chore: update vc renderer swift package Signed-off-by: KiruthikaJeyashankar --------- Signed-off-by: KiruthikaJeyashankar --- .../residentapp/InjiOpenID4VPModule.java | 17 ++-- .../residentapp/RNInjiVcRendererModule.java | 11 ++- android/build.gradle | 1 - .../xcshareddata/swiftpm/Package.resolved | 4 +- ios/RNInjiVcRenderer.m | 5 +- ios/RNInjiVcRenderer.swift | 88 ++++++++++--------- ios/RNOpenID4VPModule.swift | 10 +-- screens/Home/ViewVcModal.tsx | 2 +- screens/Request/ReceiveVcScreen.tsx | 2 +- shared/api.ts | 3 +- shared/openID4VP/OpenID4VP.ts | 2 +- shared/request.ts | 11 ++- shared/vcRenderer/VcRenderer.ts | 7 +- 13 files changed, 84 insertions(+), 79 deletions(-) diff --git a/android/app/src/main/java/io/mosip/residentapp/InjiOpenID4VPModule.java b/android/app/src/main/java/io/mosip/residentapp/InjiOpenID4VPModule.java index 049d34c2..69e94738 100644 --- a/android/app/src/main/java/io/mosip/residentapp/InjiOpenID4VPModule.java +++ b/android/app/src/main/java/io/mosip/residentapp/InjiOpenID4VPModule.java @@ -26,6 +26,7 @@ import com.google.gson.GsonBuilder; import io.mosip.openID4VP.authorizationRequest.clientMetadata.ClientMetadata; import io.mosip.openID4VP.authorizationRequest.clientMetadata.ClientMetadataSerializer; +import io.mosip.openID4VP.authorizationRequest.clientMetadata.Jwks; import io.mosip.openID4VP.constants.ClientIdScheme; import io.mosip.openID4VP.constants.ContentEncryptionAlgorithm; import io.mosip.openID4VP.constants.KeyManagementAlgorithm; @@ -235,19 +236,21 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { String clientId = verifierMap.getString("client_id"); ReadableArray responseUris = verifierMap.getArray("response_uris"); List responseUriList = convertReadableArrayToList(responseUris); - ClientMetadata clientMetadata = null; - if (verifierMap.hasKey("client_metadata") && !verifierMap.isNull("client_metadata")) { + String jwksUri = null; + if (verifierMap.hasKey("jwks_uri") && !verifierMap.isNull("jwks_uri")) { try { - ReadableMap metadataMap = verifierMap.getMap("client_metadata"); - String metadataJsonString = readableMapToJson(metadataMap).toString(); - clientMetadata = Json.Default.decodeFromString(ClientMetadataSerializer.INSTANCE, - metadataJsonString); + jwksUri = verifierMap.getString("jwks_uri"); } catch (Exception e) { e.printStackTrace(); } } + if(verifierMap.hasKey("allow_unsigned_request")){ + boolean allowUnsignedRequest = verifierMap.getBoolean("allow_unsigned_request"); + verifiers.add(new Verifier(clientId, responseUriList, jwksUri, allowUnsignedRequest)); + continue; + } - verifiers.add(new Verifier(clientId, responseUriList, clientMetadata)); + verifiers.add(new Verifier(clientId, responseUriList, jwksUri)); } return verifiers; diff --git a/android/app/src/main/java/io/mosip/residentapp/RNInjiVcRendererModule.java b/android/app/src/main/java/io/mosip/residentapp/RNInjiVcRendererModule.java index f9012df3..ce478550 100644 --- a/android/app/src/main/java/io/mosip/residentapp/RNInjiVcRendererModule.java +++ b/android/app/src/main/java/io/mosip/residentapp/RNInjiVcRendererModule.java @@ -2,7 +2,6 @@ package io.mosip.residentapp; import androidx.annotation.Nullable; -import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; @@ -35,10 +34,14 @@ public class RNInjiVcRendererModule extends ReactContextBaseJavaModule { } @ReactMethod - public void renderVC(String credentialFormat, String wellKnown, String vcJsonString, Promise promise) { + public void generateCredentialDisplayContent(String credentialFormat, String wellKnown, String vcJsonString, Promise promise) { try { - List results = injiVcRenderer.renderVC( - CredentialFormat.Companion.fromValue(credentialFormat), + CredentialFormat format = CredentialFormat.Companion.fromValue(credentialFormat); + if (format == null) { + throw new UnsupportedOperationException("Invalid credential format: " + credentialFormat); + } + List results = injiVcRenderer.generateCredentialDisplayContent( + format, wellKnown, vcJsonString ); diff --git a/android/build.gradle b/android/build.gradle index 642ad8d0..093153b2 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -14,7 +14,6 @@ buildscript { google() jcenter() mavenCentral() - mavenLocal() } dependencies { classpath("com.android.tools.build:gradle:8.4.0") diff --git a/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved index 6d7796eb..dc60101b 100644 --- a/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -79,7 +79,7 @@ "location" : "https://github.com/mosip/inji-openid4vp-ios-swift.git", "state" : { "branch" : "release-0.5.x", - "revision" : "e939d4acf4e9f54d902b65913b93432fcd068b46" + "revision" : "b3ce7ef9f70229d76e01af89dcf92e7d9d677254" } }, { @@ -88,7 +88,7 @@ "location" : "https://github.com/mosip/inji-vc-renderer-ios-swift.git", "state" : { "branch" : "release-0.1.x", - "revision" : "97842f70c7bc510afb0bb415b9806b4e722808f0" + "revision" : "68b6c14aaf1e572f84307e0f932d93a66134055d" } }, { diff --git a/ios/RNInjiVcRenderer.m b/ios/RNInjiVcRenderer.m index 15991556..657b9353 100644 --- a/ios/RNInjiVcRenderer.m +++ b/ios/RNInjiVcRenderer.m @@ -6,11 +6,10 @@ RCT_EXTERN_METHOD(init:(NSString *)traceabilityId) -RCT_EXTERN_METHOD(renderVC:(NSString *)credentialFormat - wellKnown:(NSString *)wellKnown +RCT_EXTERN_METHOD(generateCredentialDisplayContent: (NSString *)credentialFormat + wellKnown:(NSString * _Nullable)wellKnown vcJsonString:(NSString *)vcJsonString resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) - @end diff --git a/ios/RNInjiVcRenderer.swift b/ios/RNInjiVcRenderer.swift index c0b19848..79db3a56 100644 --- a/ios/RNInjiVcRenderer.swift +++ b/ios/RNInjiVcRenderer.swift @@ -3,55 +3,57 @@ import React import InjiVcRenderer @objc(InjiVcRenderer) class RNInjiVcRenderer: NSObject, RCTBridgeModule { - - private var vcRenderer: InjiVcRenderer? - - @objc static func requiresMainQueueSetup() -> Bool { - return false - } - - static func moduleName() -> String { - return "InjiVcRenderer" - } - + + private var vcRenderer: InjiVcRenderer? + + @objc static func requiresMainQueueSetup() -> Bool { + return false + } + + static func moduleName() -> String { + return "InjiVcRenderer" + } + @objc func `init`(_ traceabilityId: String) { vcRenderer = InjiVcRenderer(traceabilityId: traceabilityId) } - - - @objc(renderVC:wellKnown:vcJsonString:resolver:rejecter:) - func renderVC( - credentialFormat: String, - wellKnown: String?, - vcJsonString: String, - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock - ) { - guard let renderer = self.vcRenderer else { - reject(nil, "InjiVcRenderer not initialized", nil) - return - } - - do { - let format = CredentialFormat.fromValue(credentialFormat) - let result = try renderer.renderVC( - credentialFormat: format, - wellKnownJson: wellKnown, - vcJsonString: vcJsonString - ) - resolve(result) - } catch { - rejectWithVcRendererError(error, reject: reject) - } + + + @objc(generateCredentialDisplayContent:wellKnown:vcJsonString:resolver:rejecter:) + func generateCredentialDisplayContent( + credentialFormat: String, + wellKnown: String?, + vcJsonString: String, + resolve: @escaping RCTPromiseResolveBlock, + reject: @escaping RCTPromiseRejectBlock + ) { + guard let renderer = self.vcRenderer else { + reject(nil, "InjiVcRenderer not initialized", nil) + return } - + + do { + guard let format = CredentialFormat.fromValue(credentialFormat) else { + throw NSError(domain: "Invalid credential format", code: 0) + } + let result = try renderer.generateCredentialDisplayContent( + credentialFormat: format, + wellKnownJson: wellKnown, + vcJsonString: vcJsonString + ) + resolve(result) + } catch { + rejectWithVcRendererError(error, reject: reject) + } + } + func rejectWithVcRendererError(_ error: Error, reject: RCTPromiseRejectBlock) { if let vcRendererError = error as? VcRendererException { - reject(vcRendererError.errorCode, vcRendererError.message, vcRendererError) - } else { - let nsError = NSError(domain: error.localizedDescription, code: 0) - reject("ERR_UNKNOWN", nsError.localizedDescription, nsError) - } + reject(vcRendererError.errorCode, vcRendererError.message, vcRendererError) + } else { + let nsError = NSError(domain: error.localizedDescription, code: 0) + reject("ERR_UNKNOWN", nsError.localizedDescription, nsError) + } } } diff --git a/ios/RNOpenID4VPModule.swift b/ios/RNOpenID4VPModule.swift index 10fc3c53..d5fdeafd 100644 --- a/ios/RNOpenID4VPModule.swift +++ b/ios/RNOpenID4VPModule.swift @@ -197,13 +197,13 @@ func sendErrorToVerifier(_ error: String, _ errorCode: String, throw NSError(domain: "OpenID4VP", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid Verifier data"]) } - var clientMetadata: ClientMetadata? = nil - if let metadata = verifierDict["client_metadata"] as? [String: Any] { - let encoded = try JSONSerialization.data(withJSONObject: metadata) - clientMetadata = try ClientMetadata.deserializeAndValidate(clientMetadata: encoded) + let jwksUri: String? = verifierDict["jwks_uri"] as? String + + if let allowUnsignedRequest = verifierDict["allow_unsigned_request"] as? Bool { + return Verifier(clientId: clientId, responseUris: responseUris, jwksUri: jwksUri, allowUnsignedRequest: allowUnsignedRequest) } - return Verifier(clientId: clientId, responseUris: responseUris,clientMetadata: clientMetadata) + return Verifier(clientId: clientId, responseUris: responseUris,jwksUri: jwksUri) } } diff --git a/screens/Home/ViewVcModal.tsx b/screens/Home/ViewVcModal.tsx index b85e5685..576236e2 100644 --- a/screens/Home/ViewVcModal.tsx +++ b/screens/Home/ViewVcModal.tsx @@ -85,7 +85,7 @@ export const ViewVcModal: React.FC = props => { setLoadingSvg(true); const vcJsonString = JSON.stringify(controller.credential.credential); - const result = await VcRenderer.getInstance().renderVC( + const result = await VcRenderer.getInstance().generateCredentialDisplayContent( controller.verifiableCredentialData.format, wellknown ?? null, vcJsonString, diff --git a/screens/Request/ReceiveVcScreen.tsx b/screens/Request/ReceiveVcScreen.tsx index 1e357b24..16c111dc 100644 --- a/screens/Request/ReceiveVcScreen.tsx +++ b/screens/Request/ReceiveVcScreen.tsx @@ -53,7 +53,7 @@ export const ReceiveVcScreen: React.FC = () => { setLoadingSvg(true); const vcJsonString = JSON.stringify(controller.credential.credential); - const result = await VcRenderer.getInstance().renderVC( + const result = await VcRenderer.getInstance().generateCredentialDisplayContent( verifiableCredentialData.vcMetadata.format, wellknown ?? null, vcJsonString, diff --git a/shared/api.ts b/shared/api.ts index 620801a4..ebfa6816 100644 --- a/shared/api.ts +++ b/shared/api.ts @@ -181,7 +181,8 @@ export const CACHED_API = { ) => generateCacheAPIFunction({ isCachePreferred, - cacheKey: API_CACHED_STORAGE_KEYS.fetchIssuerWellknownConfig(issuerCacheKey), + cacheKey: + API_CACHED_STORAGE_KEYS.fetchIssuerWellknownConfig(issuerCacheKey), fetchCall: API.fetchIssuerWellknownConfig.bind(null, credentialIssuer), }), diff --git a/shared/openID4VP/OpenID4VP.ts b/shared/openID4VP/OpenID4VP.ts index a5dea4da..09c1978d 100644 --- a/shared/openID4VP/OpenID4VP.ts +++ b/shared/openID4VP/OpenID4VP.ts @@ -154,7 +154,7 @@ class OpenID4VP { disclosureSet.size > 0 ? [jwt, ...disclosureSet].join('~') + '~' : jwt + '~'; - + return finalSdJwt; } } diff --git a/shared/request.ts b/shared/request.ts index 0d0faa3e..61d85e4c 100644 --- a/shared/request.ts +++ b/shared/request.ts @@ -5,7 +5,7 @@ import { import {__AppId} from './GlobalVariables'; import {MIMOTO_BASE_URL, REQUEST_TIMEOUT} from './constants'; import NetInfo from '@react-native-community/netinfo'; -import { ErrorMessage } from './openId4VCI/Utils'; +import {ErrorMessage} from './openId4VCI/Utils'; export type HTTP_METHOD = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; @@ -78,16 +78,16 @@ export async function request( 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'); + throw new Error( + ErrorMessage.NETWORK_REQUEST_FAILED + ' Invalid JSON response', + ); } - if (response.status >= 400) { const backendUrl = host + path; const errorMessage = @@ -102,9 +102,8 @@ export async function request( throw new Error(errorMessage); } - if (jsonResponse.errors && jsonResponse.errors.length) { - const { errorCode, errorMessage } = jsonResponse.errors.shift(); + const {errorCode, errorMessage} = jsonResponse.errors.shift(); console.error( `The backend API ${requestUrl} returned structured error --> error code: ${errorCode}, message: ${errorMessage}`, ); diff --git a/shared/vcRenderer/VcRenderer.ts b/shared/vcRenderer/VcRenderer.ts index c425ce1d..cb5eabe2 100644 --- a/shared/vcRenderer/VcRenderer.ts +++ b/shared/vcRenderer/VcRenderer.ts @@ -1,6 +1,5 @@ import {NativeModules} from 'react-native'; import {MMKVLoader} from 'react-native-mmkv-storage'; -import {CACHE_TTL} from '../constants'; import {__AppId} from '../GlobalVariables'; import {isCacheExpired} from '../Utils'; @@ -31,7 +30,7 @@ class VcRenderer { return `${CACHE_KEY_PREFIX}${vcId}`; } - async renderVC( + async generateCredentialDisplayContent( credentialFormat: string, wellKnown: string, vcJson: string, @@ -56,7 +55,7 @@ class VcRenderer { } try { - const result: string[] = await this.InjiVcRenderer.renderVC( + const result: string[] = await this.InjiVcRenderer.generateCredentialDisplayContent( credentialFormat, wellKnown ? JSON.stringify(wellKnown) : null, vcJson, @@ -79,7 +78,7 @@ class VcRenderer { async clearCache(vcId: string) { const cacheKey = this.createCacheKey(vcId); - await MMKV.removeItem(cacheKey); + MMKV.removeItem(cacheKey); } }