diff --git a/package.json b/package.json index fb6553f9..e8887d1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wallet-frontend", - "version": "0.2.2", + "version": "0.2.3", "private": true, "dependencies": { "@cef-ebsi/key-did-resolver": "^1.1.0", diff --git a/src/components/Auth/PrivateRoute.tsx b/src/components/Auth/PrivateRoute.tsx index a41e936f..f114a6a5 100644 --- a/src/components/Auth/PrivateRoute.tsx +++ b/src/components/Auth/PrivateRoute.tsx @@ -184,7 +184,7 @@ const PrivateRoute = ({ children }: { children?: React.ReactNode }): React.React if (fcmToken !== null) { await api.post('/user/session/fcm_token/add', { fcm_token: fcmToken }); setTokenSentInSession(true); - console.log('FCM Token success:', fcmToken); + console.log('FCM Token send:', fcmToken); } else { console.log('FCM Token failed to get fcmtoken in private route', fcmToken); setTokenSentInSession(false); @@ -198,9 +198,9 @@ const PrivateRoute = ({ children }: { children?: React.ReactNode }): React.React } }; - if (isOnline) { + if (isOnline === true && isLoggedIn) { sendFcmTokenToBackend(); - } else { + } else if (isOnline === false) { setTokenSentInSession(false); } }, [ @@ -209,6 +209,7 @@ const PrivateRoute = ({ children }: { children?: React.ReactNode }): React.React isPermissionGranted, setTokenSentInSession, tokenSentInSession, + isLoggedIn, ]); useEffect(() => { diff --git a/src/components/AuthorizationRequestHandler.tsx b/src/components/AuthorizationRequestHandler.tsx index e3d05a06..7924cd89 100644 --- a/src/components/AuthorizationRequestHandler.tsx +++ b/src/components/AuthorizationRequestHandler.tsx @@ -66,12 +66,8 @@ export const AuthorizationRequestHandler = ({ setMessageTitle('messagePopup.insufficientCredentials.title'); setMessageDescription('messagePopup.insufficientCredentials.description'); break; - case HandleAuthorizationRequestError.ONLY_ONE_INPUT_DESCRIPTOR_IS_SUPPORTED: - setMessageTitle('messagePopup.onlyOneInputDescriptor.title'); - setMessageDescription('messagePopup.onlyOneInputDescriptor.description'); - break; case HandleAuthorizationRequestError.NONTRUSTED_VERIFIER: - setMessageTitle('messagePopup.insufficientCredentials.title'); + setMessageTitle('messagePopup.nonTrustedVerifier.title'); setMessageDescription('messagePopup.nonTrustedVerifier.description'); break; default: diff --git a/src/context/ContainerContext.tsx b/src/context/ContainerContext.tsx index b4ab7df3..9b4cd52d 100644 --- a/src/context/ContainerContext.tsx +++ b/src/context/ContainerContext.tsx @@ -103,12 +103,14 @@ export const ContainerContextProvider = ({ children }) => { if ('error' in result) { return { error: "Failed to parse sdjwt" }; } - - const { metadata } = await cont.resolve('OpenID4VCIHelper').getCredentialIssuerMetadata(isOnline, result.beautifiedForm.iss, shouldUseCache); - const credentialConfigurationSupportedObj: CredentialConfigurationSupported | undefined = Object.values(metadata.credential_configurations_supported) - .filter((x: any) => x?.vct && result.beautifiedForm?.vct && x.vct === result.beautifiedForm?.vct) - [0]; - + let credentialConfigurationSupportedObj = null; + const metadataResponse = await cont.resolve('OpenID4VCIHelper').getCredentialIssuerMetadata(isOnline, result.beautifiedForm.iss, shouldUseCache); + if (metadataResponse) { + const { metadata } = metadataResponse; + credentialConfigurationSupportedObj = Object.values(metadata.credential_configurations_supported) + .filter((x: any) => x?.vct && result.beautifiedForm?.vct && x.vct === result.beautifiedForm?.vct) + [0]; + } const credentialHeader = JSON.parse(new TextDecoder().decode(fromBase64(rawCredential.split('.')[0] as string))); const credentialImageSvgTemplateURL = credentialHeader?.vctm?.display && diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js index 7804dd99..6685a607 100644 --- a/src/context/CredentialsContext.js +++ b/src/context/CredentialsContext.js @@ -69,7 +69,7 @@ export const CredentialsProvider = ({ children }) => { try { const userId = api.getSession().uuid; const previousVcList = await getItem("vc", userId); - const previousSize = previousVcList.vc_list.length; + const previousSize = previousVcList?.vc_list.length; const vcEntityList = await fetchVcData(); setVcEntityList(vcEntityList); @@ -91,9 +91,13 @@ export const CredentialsProvider = ({ children }) => { }, [api, fetchVcData, pollForCredentials]); useEffect(() => { - window.addEventListener('newCredential', (e) => { + const handleNewCredentialEvent = () => { getData(true); - }); + }; + window.addEventListener('newCredential', handleNewCredentialEvent); + return () => { + window.removeEventListener('newCredential', handleNewCredentialEvent); + }; }, [getData]); return ( diff --git a/src/firebase.js b/src/firebase.js index f9425542..2509f1e0 100644 --- a/src/firebase.js +++ b/src/firebase.js @@ -39,7 +39,6 @@ const requestForToken = async () => { try { const currentToken = await getToken(messaging, { vapidKey: config.FIREBASE_VAPIDKEY }); if (currentToken) { - console.log('Current token for client:', currentToken); return currentToken; } else { console.log('No registration token available. Request permission to generate one.'); @@ -96,7 +95,6 @@ const reRegisterServiceWorkerAndGetToken = async () => { export const fetchToken = async () => { if (await isEnabledAndIsSupported() && messaging) { const token = await requestForToken(); - console.log('token:', token); if (token) { return token; } else { diff --git a/src/lib/interfaces/IOpenID4VCIHelper.ts b/src/lib/interfaces/IOpenID4VCIHelper.ts index 603d9445..9ba66817 100644 --- a/src/lib/interfaces/IOpenID4VCIHelper.ts +++ b/src/lib/interfaces/IOpenID4VCIHelper.ts @@ -7,7 +7,7 @@ export interface IOpenID4VCIHelper { * @param credentialIssuerIdentifier * @throws */ - getAuthorizationServerMetadata(isOnline: boolean, credentialIssuerIdentifier: string, forceIndexDB: boolean): Promise<{ authzServeMetadata: OpenidAuthorizationServerMetadata }>; + getAuthorizationServerMetadata(isOnline: boolean, credentialIssuerIdentifier: string, forceIndexDB: boolean): Promise<{ authzServeMetadata: OpenidAuthorizationServerMetadata } | null>; /** @@ -15,5 +15,5 @@ export interface IOpenID4VCIHelper { * @param credentialIssuerIdentifier * @throws */ - getCredentialIssuerMetadata(isOnline: boolean, credentialIssuerIdentifier: string, forceIndexDB: boolean): Promise<{ metadata: OpenidCredentialIssuerMetadata }>; + getCredentialIssuerMetadata(isOnline: boolean, credentialIssuerIdentifier: string, forceIndexDB: boolean): Promise<{ metadata: OpenidCredentialIssuerMetadata } | null>; } diff --git a/src/lib/interfaces/IOpenID4VPRelyingParty.ts b/src/lib/interfaces/IOpenID4VPRelyingParty.ts index 6aa80313..85ea702f 100644 --- a/src/lib/interfaces/IOpenID4VPRelyingParty.ts +++ b/src/lib/interfaces/IOpenID4VPRelyingParty.ts @@ -7,7 +7,6 @@ export enum HandleAuthorizationRequestError { INSUFFICIENT_CREDENTIALS, MISSING_PRESENTATION_DEFINITION, MISSING_PRESENTATION_DEFINITION_URI, - ONLY_ONE_INPUT_DESCRIPTOR_IS_SUPPORTED, NONTRUSTED_VERIFIER, INVALID_RESPONSE_MODE, } diff --git a/src/lib/services/OpenID4VCIHelper.ts b/src/lib/services/OpenID4VCIHelper.ts index 1af12862..97201e78 100644 --- a/src/lib/services/OpenID4VCIHelper.ts +++ b/src/lib/services/OpenID4VCIHelper.ts @@ -28,7 +28,7 @@ export class OpenID4VCIHelper implements IOpenID4VCIHelper { } // Fetches authorization server metadata with fallback - async getAuthorizationServerMetadata(isOnline: boolean, credentialIssuerIdentifier: string, forceIndexDB: boolean = false): Promise<{ authzServeMetadata: OpenidAuthorizationServerMetadata }> { + async getAuthorizationServerMetadata(isOnline: boolean, credentialIssuerIdentifier: string, forceIndexDB: boolean = false): Promise<{ authzServeMetadata: OpenidAuthorizationServerMetadata } | null> { const pathAuthorizationServer = `${credentialIssuerIdentifier}/.well-known/oauth-authorization-server`; const pathConfiguration = `${credentialIssuerIdentifier}/.well-known/openid-configuration`; @@ -47,21 +47,32 @@ export class OpenID4VCIHelper implements IOpenID4VCIHelper { OpenidAuthorizationServerMetadataSchema, isOnline, forceIndexDB - ); + ).catch(() => null); + + if (!authzServeMetadata) { + return null; + } return { authzServeMetadata }; } } // Fetches credential issuer metadata - async getCredentialIssuerMetadata(isOnline: boolean, credentialIssuerIdentifier: string, forceIndexDB: boolean = false): Promise<{ metadata: OpenidCredentialIssuerMetadata }> { + async getCredentialIssuerMetadata(isOnline: boolean, credentialIssuerIdentifier: string, forceIndexDB: boolean = false): Promise<{ metadata: OpenidCredentialIssuerMetadata } | null> { const pathCredentialIssuer = `${credentialIssuerIdentifier}/.well-known/openid-credential-issuer`; - const metadata = await this.fetchAndCache( - pathCredentialIssuer, - OpenidCredentialIssuerMetadataSchema, - isOnline, - forceIndexDB - ); - return { metadata }; + try { + const metadata = await this.fetchAndCache( + pathCredentialIssuer, + OpenidCredentialIssuerMetadataSchema, + isOnline, + forceIndexDB + ); + return { metadata }; + } + catch(err) { + console.error(err); + return null; + } + } } diff --git a/src/lib/services/OpenID4VPRelyingParty.ts b/src/lib/services/OpenID4VPRelyingParty.ts index 2856efac..d2a8fb88 100644 --- a/src/lib/services/OpenID4VPRelyingParty.ts +++ b/src/lib/services/OpenID4VPRelyingParty.ts @@ -118,9 +118,6 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { if (!presentation_definition) { return { err: HandleAuthorizationRequestError.MISSING_PRESENTATION_DEFINITION }; } - if (presentation_definition.input_descriptors.length > 1) { - return { err: HandleAuthorizationRequestError.ONLY_ONE_INPUT_DESCRIPTOR_IS_SUPPORTED }; - } const { error } = ResponseModeSchema.safeParse(response_mode); if (error) { @@ -280,6 +277,7 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { let generatedVPs = []; let originalVCs = []; const descriptorMap = []; + let i = 0; for (const [descriptor_id, credentialIdentifier] of selectionMap) { const vcEntity = filteredVCEntities.filter((vc) => vc.credentialIdentifier === credentialIdentifier)[0]; if (vcEntity.format === VerifiableCredentialFormat.SD_JWT_VC) { @@ -295,11 +293,21 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { const { vpjwt } = await this.signJwtPresentationKeystoreFn(nonce, client_id, [presentation]); selectedVCs.push(presentation); generatedVPs.push(vpjwt); - descriptorMap.push({ - id: descriptor_id, - format: VerifiableCredentialFormat.SD_JWT_VC, - path: `$` - }); + if (selectionMap.size > 1) { + descriptorMap.push({ + id: descriptor_id, + format: VerifiableCredentialFormat.SD_JWT_VC, + path: `$[${i++}]` + }); + } + else { + descriptorMap.push({ + id: descriptor_id, + format: VerifiableCredentialFormat.SD_JWT_VC, + path: `$` + }); + } + originalVCs.push(vcEntity); } } @@ -316,7 +324,7 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { const rp_eph_pub_jwk = S.client_metadata.jwks.keys[0]; const rp_eph_pub = await importJWK(rp_eph_pub_jwk, S.client_metadata.authorization_encrypted_response_alg); const jwe = await new EncryptJWT({ - vp_token: generatedVPs[0], + vp_token: generatedVPs.length == 1 ? generatedVPs[0] : generatedVPs, presentation_submission: presentationSubmission, state: S.state ?? undefined }) @@ -327,7 +335,7 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { console.log("JWE = ", jwe) } else { - formData.append('vp_token', generatedVPs[0]); + formData.append('vp_token', generatedVPs.length == 1 ? generatedVPs[0] : JSON.stringify(generatedVPs) ); formData.append('presentation_submission', JSON.stringify(presentationSubmission)); if (S.state) { formData.append('state', S.state);