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 5e5457ca..049d34c2 100644 --- a/android/app/src/main/java/io/mosip/residentapp/InjiOpenID4VPModule.java +++ b/android/app/src/main/java/io/mosip/residentapp/InjiOpenID4VPModule.java @@ -3,6 +3,8 @@ package io.mosip.residentapp; import static io.mosip.openID4VP.authorizationResponse.AuthorizationResponseUtilsKt.toJsonString; import static io.mosip.openID4VP.constants.FormatType.LDP_VC; import static io.mosip.openID4VP.constants.FormatType.MSO_MDOC; +import static io.mosip.openID4VP.constants.FormatType.VC_SD_JWT; +import static io.mosip.openID4VP.constants.FormatType.DC_SD_JWT; import android.annotation.SuppressLint; import android.util.Log; @@ -57,6 +59,7 @@ import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.VPTokenSign import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.types.ldp.LdpVPTokenSigningResult; import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.types.mdoc.DeviceAuthentication; import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.types.mdoc.MdocVPTokenSigningResult; +import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.types.sdJwt.SdJwtVPTokenSigningResult; import io.mosip.openID4VP.constants.FormatType; import kotlinx.serialization.json.Json; @@ -79,7 +82,7 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { @SuppressLint("LogNotTimber") @ReactMethod - public void initSdk(String appId, ReadableMap walletMetadata ) { + public void initSdk(String appId, ReadableMap walletMetadata) { Log.d(TAG, "Initializing InjiOpenID4VPModule with " + appId); WalletMetadata metadata = parseWalletMetadata(walletMetadata); @@ -93,17 +96,16 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { @ReactMethod public void authenticateVerifier(String urlEncodedAuthorizationRequest, - ReadableArray trustedVerifiers, - Boolean shouldValidateClient, - Promise promise) { + ReadableArray trustedVerifiers, + Boolean shouldValidateClient, + Promise promise) { try { List verifierList = parseVerifiers(trustedVerifiers); AuthorizationRequest authRequest = openID4VP.authenticateVerifier( urlEncodedAuthorizationRequest, verifierList, - shouldValidateClient - ); + shouldValidateClient); String authRequestJson = gson.toJson(authRequest, AuthorizationRequest.class); promise.resolve(authRequestJson); @@ -113,10 +115,12 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { } @ReactMethod - public void constructUnsignedVPToken(ReadableMap selectedVCs, String holderId, String signatureSuite, Promise promise) { + public void constructUnsignedVPToken(ReadableMap selectedVCs, String holderId, String signatureSuite, + Promise promise) { try { Map>> selectedVCsMap = parseSelectedVCs(selectedVCs); - Map vpTokens = openID4VP.constructUnsignedVPToken(selectedVCsMap, holderId, signatureSuite); + Map vpTokens = openID4VP.constructUnsignedVPToken(selectedVCsMap, holderId, + signatureSuite); promise.resolve(toJsonString(vpTokens)); } catch (Exception e) { rejectWithOpenID4VPExceptions(e, promise); @@ -170,15 +174,19 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { Map vpFormatsSupportedMap = parseVpFormatsSupported(walletMetadata); - return new WalletMetadata( + return new WalletMetadata( presentationDefinitionUriSupported, vpFormatsSupportedMap, - convertReadableArrayToEnumList(walletMetadata, "client_id_schemes_supported", ClientIdScheme.Companion::fromValue), - convertReadableArrayToEnumList(walletMetadata, "request_object_signing_alg_values_supported", RequestSigningAlgorithm.Companion::fromValue), - convertReadableArrayToEnumList(walletMetadata, "authorization_encryption_alg_values_supported", KeyManagementAlgorithm.Companion::fromValue), - convertReadableArrayToEnumList(walletMetadata, "authorization_encryption_enc_values_supported", ContentEncryptionAlgorithm.Companion::fromValue), - convertReadableArrayToEnumList(walletMetadata, "response_type_supported", ResponseType.Companion::fromValue) - ); + convertReadableArrayToEnumList(walletMetadata, "client_id_schemes_supported", + ClientIdScheme.Companion::fromValue), + convertReadableArrayToEnumList(walletMetadata, "request_object_signing_alg_values_supported", + RequestSigningAlgorithm.Companion::fromValue), + convertReadableArrayToEnumList(walletMetadata, "authorization_encryption_alg_values_supported", + KeyManagementAlgorithm.Companion::fromValue), + convertReadableArrayToEnumList(walletMetadata, "authorization_encryption_enc_values_supported", + ContentEncryptionAlgorithm.Companion::fromValue), + convertReadableArrayToEnumList(walletMetadata, "response_type_supported", + ResponseType.Companion::fromValue)); } private Map parseVpFormatsSupported(ReadableMap walletMetadata) { @@ -188,13 +196,17 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { if (vpFormatsMap != null) { addVpFormatSupported(vpFormatsMap, "ldp_vc", vpFormatsSupportedMap); addVpFormatSupported(vpFormatsMap, "mso_mdoc", vpFormatsSupportedMap); + addVpFormatSupported(vpFormatsMap, "vc+sd-jwt", vpFormatsSupportedMap); + addVpFormatSupported(vpFormatsMap, "dc+sd-jwt", vpFormatsSupportedMap); } } return vpFormatsSupportedMap; } - private List convertReadableArrayToEnumList(ReadableMap readableMap, String key, Function converter) { - if (!readableMap.hasKey(key)) return null; + private List convertReadableArrayToEnumList(ReadableMap readableMap, String key, + Function converter) { + if (!readableMap.hasKey(key)) + return null; ReadableArray readableArray = readableMap.getArray(key); List list = new ArrayList<>(); for (int i = 0; i < Objects.requireNonNull(readableArray).size(); i++) { @@ -203,8 +215,8 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { return list; } - - private void addVpFormatSupported(ReadableMap vpFormatsMap, String key, Map vpFormatsSupportedMap) { + private void addVpFormatSupported(ReadableMap vpFormatsMap, String key, + Map vpFormatsSupportedMap) { if (vpFormatsMap.hasKey(key)) { ReadableMap formatMap = vpFormatsMap.getMap(key); if (formatMap != null && formatMap.hasKey("alg_values_supported")) { @@ -215,8 +227,6 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { } } - - private List parseVerifiers(ReadableArray verifiersArray) { List verifiers = new ArrayList(); @@ -230,21 +240,23 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { try { ReadableMap metadataMap = verifierMap.getMap("client_metadata"); String metadataJsonString = readableMapToJson(metadataMap).toString(); - clientMetadata = Json.Default.decodeFromString(ClientMetadataSerializer.INSTANCE, metadataJsonString); + clientMetadata = Json.Default.decodeFromString(ClientMetadataSerializer.INSTANCE, + metadataJsonString); } catch (Exception e) { e.printStackTrace(); } } - + 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); @@ -273,10 +285,10 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { e.printStackTrace(); } } - + return jsonObject; } - + private static JSONArray readableArrayToJson(ReadableArray readableArray) { JSONArray jsonArray = new JSONArray(); for (int i = 0; i < readableArray.size(); i++) { @@ -308,7 +320,6 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { } return jsonArray; } - private Map>> parseSelectedVCs(ReadableMap selectedVCs) { if (selectedVCs == null) { @@ -370,10 +381,10 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { private VPTokenSigningResult createVPTokenSigningResult(FormatType formatType, ReadableMap metadata) { switch (formatType) { case LDP_VC: { - String jws =metadata.getString("jws"); - String proofValue =metadata.getString("proofValue"); - String signatureAlgorithm =metadata.getString("signatureAlgorithm"); - return new LdpVPTokenSigningResult(jws, proofValue, signatureAlgorithm ); + String jws = metadata.getString("jws"); + String proofValue = metadata.getString("proofValue"); + String signatureAlgorithm = metadata.getString("signatureAlgorithm"); + return new LdpVPTokenSigningResult(jws, proofValue, signatureAlgorithm); } case MSO_MDOC: { Map signatureData = new HashMap<>(); @@ -386,13 +397,25 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { String algorithm = requireNonNullString(deviceAuthenticationMap, "mdocAuthenticationAlgorithm"); DeviceAuthentication deviceAuthentication = new DeviceAuthentication( signature = signature, - algorithm = algorithm - ); + algorithm = algorithm); signatureData.put(docType, deviceAuthentication); } } return new MdocVPTokenSigningResult(signatureData); } + case VC_SD_JWT: + case DC_SD_JWT: { + Map uuidToSignature = new HashMap<>(); + ReadableMapKeySetIterator uuidIterator = metadata.keySetIterator(); + while (uuidIterator.hasNextKey()) { + String uuid = uuidIterator.nextKey(); + String signature = metadata.getString(uuid); + if (signature != null) { + uuidToSignature.put(uuid, signature); + } + } + return new SdJwtVPTokenSigningResult(uuidToSignature); + } default: return null; } @@ -417,6 +440,22 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { return mdocVcList; } + case VC_SD_JWT: { + List vcSdJwtList = new ArrayList<>(); + for (int i = 0; i < credentialList.size(); i++) { + String credential = credentialList.getString(i); + vcSdJwtList.add(credential); + } + return vcSdJwtList; + } + case DC_SD_JWT: { + List dcSdJwtList = new ArrayList<>(); + for (int i = 0; i < credentialList.size(); i++) { + String credential = credentialList.getString(i); + dcSdJwtList.add(credential); + } + return dcSdJwtList; + } default: return null; } @@ -427,6 +466,10 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule { return LDP_VC; } else if (MSO_MDOC.getValue().equals(formatStr)) { return MSO_MDOC; + } else if (VC_SD_JWT.getValue().equals(formatStr)) { + return VC_SD_JWT; + } else if (DC_SD_JWT.getValue().equals(formatStr)) { + return DC_SD_JWT; } throw new UnsupportedOperationException("Credential format '" + formatStr + "' is not supported"); } diff --git a/screens/Issuers/TrustIssuerModal.tsx b/components/TrustModal.tsx similarity index 66% rename from screens/Issuers/TrustIssuerModal.tsx rename to components/TrustModal.tsx index 3511fb3a..36ba8a2f 100644 --- a/screens/Issuers/TrustIssuerModal.tsx +++ b/components/TrustModal.tsx @@ -1,52 +1,54 @@ import React from 'react'; -import {Modal, View, Text, Image, ScrollView} from 'react-native'; -import {Button} from '../../components/ui'; -import {Theme} from '../../components/ui/styleUtils'; -import {useTranslation} from 'react-i18next'; +import { Modal, View, Text, Image, ScrollView } from 'react-native'; +import { Button } from './ui'; +import { Theme } from './ui/styleUtils'; +import { useTranslation } from 'react-i18next'; -export const TrustIssuerModal = ({ - isVisible, - issuerLogo, - issuerName, - onConfirm, - onCancel, - }: { +export const TrustModal = ({ + isVisible, + logo, + name, + onConfirm, + onCancel, + flowType = 'issuer', +}: { isVisible: boolean; - issuerLogo: any; - issuerName: string; + logo: any; + name: string; onConfirm: () => void; onCancel: () => void; + flowType?: 'issuer' | 'verifier'; }) => { - const {t} = useTranslation('trustScreen'); + const { t } = useTranslation('trustScreen'); return ( - {(issuerLogo || issuerName) && ( + {(logo || name) && ( - {issuerLogo && ( + {logo && ( )} - {issuerName && ( + {name && ( - {issuerName} + {name} )} )} - {t('description')} + {t(flowType == 'issuer' ? 'description' : 'verifierDescription')} - {t('infoPoints', {returnObjects: true}).map((point, index) => ( + {t(flowType == 'issuer' ? 'infoPoints' : 'verifierInfoPoints', { returnObjects: true }).map((point, index) => ( @@ -57,7 +59,7 @@ export const TrustIssuerModal = ({ - +