[INJIMOB-3502] add: send Client Metadata to Verifer for OVP authenticateVerifier (#2062)

* [INJIMOB-3455] add clientmetadata support in trusted verifier json

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

* [INJIMOB-3455] add clientmetadata support in trusted verifier json - kotlin integration

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

* [INJIMOB-3502] fix: import issues in OpenId4VPModule

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

* [INJIMOB-3502] refactor: accept Verifier with or w/o clientMetadata (OVP)

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

* [INJIMOB-3502] refactor: make clientMetadata as optional in VerifierType

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

* [INJIMOB-3502] refactor: change var to let

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

* [INJIMOB-3502] chore: update ovp lib swft version

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@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-08-26 16:53:19 +05:30
committed by GitHub
parent 3fa11ebb71
commit 0cb769803d
7 changed files with 113 additions and 22 deletions

View File

@@ -393,7 +393,7 @@ fileignoreconfig:
- filename: machines/openID4VP/openID4VPMachine.typegen.ts
checksum: a87664e146d420fb3140a0f6579980aaf82041928b502f8b301b4ebff048351c
- filename: ios/RNOpenID4VPModule.swift
checksum: 4bd3c69556b86024cd15490deafb0d8c6b760ebcfc486f68da5575d63b315d14
checksum: c62c80577be28a06e1aa27bf6a56c3787cd05c59b92f914e6e50b34e04a2b06f
- filename: assets/InjiHomeLogoSmall.svg
checksum: 9f29c9b0b91eba7fd7f5f4d1f78f9b6f96ef2c850c1346d712058a438d01036a
- filename: assets/InjiHomeLogo.svg

View File

@@ -17,10 +17,13 @@ import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.ReadableType;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.mosip.openID4VP.authorizationRequest.clientMetadata.ClientMetadata;
import io.mosip.openID4VP.authorizationRequest.clientMetadata.ClientMetadataSerializer;
import io.mosip.openID4VP.constants.ClientIdScheme;
import io.mosip.openID4VP.constants.ContentEncryptionAlgorithm;
import io.mosip.openID4VP.constants.KeyManagementAlgorithm;
@@ -32,6 +35,9 @@ import io.mosip.openID4VP.exceptions.OpenID4VPExceptions;
import static io.mosip.openID4VP.common.OpenID4VPErrorCodes.ACCESS_DENIED;
import static io.mosip.openID4VP.common.OpenID4VPErrorCodes.INVALID_TRANSACTION_DATA;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
@@ -52,6 +58,7 @@ import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.types.ldp.L
import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.types.mdoc.DeviceAuthentication;
import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.types.mdoc.MdocVPTokenSigningResult;
import io.mosip.openID4VP.constants.FormatType;
import kotlinx.serialization.json.Json;
public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
private static final String TAG = "InjiOpenID4VPModule";
@@ -218,12 +225,90 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
String clientId = verifierMap.getString("client_id");
ReadableArray responseUris = verifierMap.getArray("response_uris");
List<String> responseUriList = convertReadableArrayToList(responseUris);
ClientMetadata clientMetadata = null;
if (verifierMap.hasKey("client_metadata") && !verifierMap.isNull("client_metadata")) {
try {
ReadableMap metadataMap = verifierMap.getMap("client_metadata");
String metadataJsonString = readableMapToJson(metadataMap).toString();
clientMetadata = Json.Default.decodeFromString(ClientMetadataSerializer.INSTANCE, metadataJsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
verifiers.add(new Verifier(clientId, responseUriList));
verifiers.add(new Verifier(clientId, responseUriList, clientMetadata));
}
return verifiers;
}
private static JSONObject readableMapToJson(ReadableMap readableMap) {
JSONObject jsonObject = new JSONObject();
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
while (iterator.hasNextKey()) {
String key = iterator.nextKey();
ReadableType type = readableMap.getType(key);
try {
switch (type) {
case String:
jsonObject.put(key, readableMap.getString(key));
break;
case Number:
jsonObject.put(key, readableMap.getDouble(key));
break;
case Boolean:
jsonObject.put(key, readableMap.getBoolean(key));
break;
case Map:
jsonObject.put(key, readableMapToJson(readableMap.getMap(key)));
break;
case Array:
jsonObject.put(key, readableArrayToJson(readableMap.getArray(key)));
break;
case Null:
jsonObject.put(key, JSONObject.NULL);
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return jsonObject;
}
private static JSONArray readableArrayToJson(ReadableArray readableArray) {
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < readableArray.size(); i++) {
ReadableType type = readableArray.getType(i);
try {
switch (type) {
case String:
jsonArray.put(readableArray.getString(i));
break;
case Number:
jsonArray.put(readableArray.getDouble(i));
break;
case Boolean:
jsonArray.put(readableArray.getBoolean(i));
break;
case Map:
jsonArray.put(readableMapToJson(readableArray.getMap(i)));
break;
case Array:
jsonArray.put(readableArrayToJson(readableArray.getArray(i)));
break;
case Null:
jsonArray.put(JSONObject.NULL);
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return jsonArray;
}
private Map<String, Map<FormatType, List<Object>>> parseSelectedVCs(ReadableMap selectedVCs) {
if (selectedVCs == null) {

View File

@@ -70,7 +70,7 @@
"location" : "https://github.com/mosip/inji-openid4vp-ios-swift.git",
"state" : {
"branch" : "develop",
"revision" : "51a690be810904ed5691e821801591e9ae6600ae"
"revision" : "ca4935478360f45dd20444eac5d6bae9affc6d36"
}
},
{

View File

@@ -35,13 +35,7 @@ class RNOpenId4VpModule: NSObject, RCTBridgeModule {
return
}
let trustedVerifiersList: [Verifier] = try verifierMeta.map { verifierDict in
guard let clientId = verifierDict["client_id"] as? String,
let responseUris = verifierDict["response_uris"] as? [String] else {
throw NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid Verifier data"])
}
return Verifier(clientId: clientId, responseUris: responseUris)
}
let trustedVerifiersList: [Verifier] = try parseVerifiers(verifierMeta)
let authenticationResponse: AuthorizationRequest = try await openID4VP!.authenticateVerifier(
urlEncodedAuthorizationRequest: urlEncodedAuthorizationRequest,
@@ -179,6 +173,23 @@ func sendErrorToVerifier(_ error: String, _ errorCode: String,
}
}
private func parseVerifiers(_ verifiers: [[String: Any]]) throws -> [Verifier] {
return try verifiers.map { verifierDict in
guard let clientId = verifierDict["client_id"] as? String,
let responseUris = verifierDict["response_uris"] as? [String] else {
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)
}
return Verifier(clientId: clientId, responseUris: responseUris,clientMetadata: clientMetadata)
}
}
func toJsonString(jsonObject: AuthorizationRequest) throws -> String {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase

View File

@@ -76,4 +76,5 @@ interface VerifierType {
client_id: string;
redirect_uri: string;
response_uri: string;
client_metadata?: object;
}

View File

@@ -11,11 +11,7 @@ import {QrLogin} from '../QrLogin/QrLogin';
import {useScanScreen} from './ScanScreenController';
import BluetoothStateManager from 'react-native-bluetooth-state-manager';
import {BackHandler, Linking} from 'react-native';
import {
isIOS,
LIVENESS_CHECK,
OVP_ERROR_MESSAGES,
} from '../../shared/constants';
import {isIOS, LIVENESS_CHECK} from '../../shared/constants';
import {BannerNotificationContainer} from '../../components/BannerNotificationContainer';
import {SharingStatusModal} from './SharingStatusModal';
import {SvgImage} from '../../components/ui/svg';

View File

@@ -18,9 +18,7 @@ import {
} from './telemetry/TelemetryUtils';
import {TelemetryConstants} from './telemetry/TelemetryConstants';
import NetInfo from '@react-native-community/netinfo';
import { createCacheObject } from './Utils';
import {createCacheObject} from './Utils';
const isCacheValid = (cachedData: any) => {
if (!cachedData?.cachedTime || typeof cachedData.cachedTime !== 'number') {
@@ -251,7 +249,7 @@ async function generateCacheAPIFunctionWithCachePreference(
return cachedData.response;
} else {
const response = await fetchCall();
if(!response) {
if (!response) {
throw new Error('Received Empty response in fetch call');
}
const cacheObject = createCacheObject(response);
@@ -301,7 +299,7 @@ async function generateCacheAPIFunctionWithAPIPreference(
onErrorHardCodedValue != undefined
}`);
console.error(`The error in fetching api ${cacheKey}`, error);
var cachedData = null;
let cachedData = null;
if (!(await NetInfo.fetch()).isConnected) {
cachedData = await getItem(cacheKey, null, '');
}