From e182c352f04859da8ccc49907bb289051160d398 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 11 Nov 2024 17:18:04 +0200 Subject: [PATCH 001/162] OpenID4VCIClient dependency now inherits the ability to generate multiple proofs using the keystore --- src/context/ContainerContext.tsx | 6 +++--- src/lib/services/OpenID4VCIClient.ts | 10 ++++++---- src/lib/services/OpenID4VCIClientFactory.ts | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/context/ContainerContext.tsx b/src/context/ContainerContext.tsx index 6e6c070bc..5e57431e9 100644 --- a/src/context/ContainerContext.tsx +++ b/src/context/ContainerContext.tsx @@ -214,11 +214,11 @@ export const ContainerContextProvider = ({ children }) => { cont.register('OpenID4VCIClientFactory', OpenID4VCIClientFactory, cont.resolve('HttpProxy'), cont.resolve('OpenID4VCIClientStateRepository'), - async (cNonce: string, audience: string, clientId: string): Promise<{ jws: string }> => { - const [{ proof_jwts: [proof_jwt] }, newPrivateData, keystoreCommit] = await keystore.generateOpenid4vciProofs([{ nonce: cNonce, audience, issuer: clientId }]); + async (requests: { nonce: string, audience: string, issuer: string }[]): Promise<{ proof_jwts: string[] }> => { + const [{ proof_jwts }, newPrivateData, keystoreCommit] = await keystore.generateOpenid4vciProofs(requests); await api.updatePrivateData(newPrivateData); await keystoreCommit(); - return { jws: proof_jwt }; + return { proof_jwts }; }, async function storeCredential(c: StorableCredential) { await api.post('/storage/vc', { diff --git a/src/lib/services/OpenID4VCIClient.ts b/src/lib/services/OpenID4VCIClient.ts index f0f26c5ab..4af0e2158 100644 --- a/src/lib/services/OpenID4VCIClient.ts +++ b/src/lib/services/OpenID4VCIClient.ts @@ -20,7 +20,7 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { constructor(private config: ClientConfig, private httpProxy: IHttpProxy, private openID4VCIClientStateRepository: IOpenID4VCIClientStateRepository, - private generateNonceProof: (cNonce: string, audience: string, clientId: string) => Promise<{ jws: string }>, + private generateNonceProofs: (requests: { nonce: string, audience: string, issuer: string }[]) => Promise<{ proof_jwts: string[] }>, private storeCredential: (c: StorableCredential) => Promise, private authorizationRequestModifier: (credentialIssuerIdentifier: string, url: string, request_uri?: string, client_id?: string) => Promise<{ url: string }> = async (_credentialIssuerIdentifier: string, url: string) => ({ url }), ) { } @@ -357,9 +357,11 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { let jws; try { - const generateProofResult = await this.generateNonceProof(c_nonce, this.config.credentialIssuerIdentifier, this.config.clientId); - jws = generateProofResult.jws; - console.log("proof = ", jws) + const generateProofsResult = await this.generateNonceProofs([ + { nonce: c_nonce, issuer: this.config.clientId, audience: this.config.credentialIssuerIdentifier } + ]); + + jws = generateProofsResult.proof_jwts[0]; if (jws) { dispatchEvent(new CustomEvent("generatedProof")); } diff --git a/src/lib/services/OpenID4VCIClientFactory.ts b/src/lib/services/OpenID4VCIClientFactory.ts index 5d6819f35..37ec59724 100644 --- a/src/lib/services/OpenID4VCIClientFactory.ts +++ b/src/lib/services/OpenID4VCIClientFactory.ts @@ -8,12 +8,12 @@ export class OpenID4VCIClientFactory { constructor(private httpProxy: IHttpProxy, private openID4VCIClientStateRepository: IOpenID4VCIClientStateRepository, - private generateNonceProof: (cNonce: string, audience: string, clientId: string) => Promise<{ jws: string }>, + private generateNonceProofs: (requests: { nonce: string, audience: string, issuer: string }[]) => Promise<{ proof_jwts: string[] }>, private storeCredential: (c: StorableCredential) => Promise, private authorizationRequestModifier: (credentialIssuerIdentifier: string, url: string, request_uri?: string, client_id?: string) => Promise<{ url: string }>, ) { } createClient(config: ClientConfig): OpenID4VCIClient { - return new OpenID4VCIClient(config, this.httpProxy, this.openID4VCIClientStateRepository, this.generateNonceProof, this.storeCredential, this.authorizationRequestModifier); + return new OpenID4VCIClient(config, this.httpProxy, this.openID4VCIClientStateRepository, this.generateNonceProofs, this.storeCredential, this.authorizationRequestModifier); } } From 002831056620aa3d6d936468ad06bdf5d32773e5 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Fri, 15 Nov 2024 11:46:32 +0200 Subject: [PATCH 002/162] get batch size from metadata --- .../OpenidCredentialIssuerMetadataSchema.ts | 3 ++ src/lib/services/OpenID4VCIClient.ts | 37 ++++++++++++------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts b/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts index ae6b6f63b..ae8142dfe 100644 --- a/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts +++ b/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts @@ -8,6 +8,9 @@ export const OpenidCredentialIssuerMetadataSchema = z.object({ name: z.string(), locale: z.string(), })).optional(), + batch_credential_issuance: z.object({ + batch_size: z.number(), + }).optional(), credential_configurations_supported: z.record(CredentialConfigurationSupportedSchema) }) diff --git a/src/lib/services/OpenID4VCIClient.ts b/src/lib/services/OpenID4VCIClient.ts index 7f0e80dcb..eaf73170c 100644 --- a/src/lib/services/OpenID4VCIClient.ts +++ b/src/lib/services/OpenID4VCIClient.ts @@ -364,7 +364,7 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { * @param cachedProof cachedProof is used in case a failure due to invalid dpop-nonce is caused and the last proof can be re-used. * @returns */ - private async credentialRequest(response: any, flowState: OpenID4VCIClientState, cachedProof?: string) { + private async credentialRequest(response: any, flowState: OpenID4VCIClientState, cachedProofs?: string[]) { const { data: { access_token, c_nonce }, } = response; @@ -394,14 +394,16 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { credentialRequestHeaders['dpop'] = credentialEndpointDPoP; } - let jws; + let proofsArray: string[] = []; try { - const generateProofsResult = await this.generateNonceProofs([ - { nonce: c_nonce, issuer: this.config.clientId, audience: this.config.credentialIssuerIdentifier } - ]); - - jws = generateProofsResult.proof_jwts[0]; - if (jws) { + + const numberOfProofs = this.config.credentialIssuerMetadata.batch_credential_issuance?.batch_size ?? 1; + const generateProofsResult = await this.generateNonceProofs(new Array(numberOfProofs).map(() => + ({ nonce: c_nonce, issuer: this.config.clientId, audience: this.config.credentialIssuerIdentifier }) + )); + + proofsArray = generateProofsResult.proof_jwts; + if (proofsArray) { dispatchEvent(new CustomEvent("generatedProof")); } } @@ -411,14 +413,23 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { } const credentialConfigurationSupported = this.config.credentialIssuerMetadata.credential_configurations_supported[flowState.credentialConfigurationId]; + const credentialEndpointBody = { - "proof": { - "proof_type": "jwt", - "jwt": jws, - }, "format": this.config.credentialIssuerMetadata.credential_configurations_supported[flowState.credentialConfigurationId].format, } as any; + if (this.config.credentialIssuerMetadata.batch_credential_issuance?.batch_size) { + credentialEndpointBody.proofs = { + jwt: proofsArray + } + } + else { + credentialEndpointBody.proof = { + proof_type: "jwt", + jwt: proofsArray[0], + } + } + if (credentialConfigurationSupported.format === VerifiableCredentialFormat.SD_JWT_VC && credentialConfigurationSupported.vct) { credentialEndpointBody.vct = credentialConfigurationSupported.vct; } @@ -434,7 +445,7 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { console.log("Calling credentialRequest with new dpop-nonce....") response.headers['dpop-nonce'] = credentialResponse.err.headers["dpop-nonce"]; - await this.credentialRequest(response, flowState, jws); + await this.credentialRequest(response, flowState, proofsArray); return; } throw new Error("Credential Request failed"); From 6272c820546e2e991c1f7962999d93cce8014bb6 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 15 Nov 2024 16:57:52 +0200 Subject: [PATCH 003/162] Fix redundant event listener for newCredential --- src/context/CredentialsContext.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js index 7804dd99c..2fbe72b33 100644 --- a/src/context/CredentialsContext.js +++ b/src/context/CredentialsContext.js @@ -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 ( From 90536d324a9196c403898fc4489270245e7ad701 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 15 Nov 2024 17:05:03 +0200 Subject: [PATCH 004/162] Prevent resend fcm token on reload --- src/components/Auth/PrivateRoute.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Auth/PrivateRoute.tsx b/src/components/Auth/PrivateRoute.tsx index a41e936fb..7e2428311 100644 --- a/src/components/Auth/PrivateRoute.tsx +++ b/src/components/Auth/PrivateRoute.tsx @@ -198,9 +198,9 @@ const PrivateRoute = ({ children }: { children?: React.ReactNode }): React.React } }; - if (isOnline) { + if (isOnline === true) { sendFcmTokenToBackend(); - } else { + } else if (isOnline === false) { setTokenSentInSession(false); } }, [ From 8128582d8e6fd044e48b290a5f104824fc24b22d Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 15 Nov 2024 17:07:40 +0200 Subject: [PATCH 005/162] Fix send fcm token after logout --- src/components/Auth/PrivateRoute.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Auth/PrivateRoute.tsx b/src/components/Auth/PrivateRoute.tsx index 7e2428311..5f98b506a 100644 --- a/src/components/Auth/PrivateRoute.tsx +++ b/src/components/Auth/PrivateRoute.tsx @@ -198,7 +198,7 @@ const PrivateRoute = ({ children }: { children?: React.ReactNode }): React.React } }; - if (isOnline === true) { + if (isOnline === true && isLoggedIn) { sendFcmTokenToBackend(); } else if (isOnline === false) { setTokenSentInSession(false); @@ -209,6 +209,7 @@ const PrivateRoute = ({ children }: { children?: React.ReactNode }): React.React isPermissionGranted, setTokenSentInSession, tokenSentInSession, + isLoggedIn, ]); useEffect(() => { From 504ab3c8e73482bcee198029f0bc172232edf49c Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 15 Nov 2024 17:11:08 +0200 Subject: [PATCH 006/162] Reduce noice console logs about fcm token --- src/components/Auth/PrivateRoute.tsx | 2 +- src/firebase.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/Auth/PrivateRoute.tsx b/src/components/Auth/PrivateRoute.tsx index 5f98b506a..f114a6a5a 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); diff --git a/src/firebase.js b/src/firebase.js index f9425542a..2509f1e0b 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 { From ebe69a6505205efb0e8db78235a0d68f7cd9a66d Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 15 Nov 2024 17:37:36 +0200 Subject: [PATCH 007/162] Revert to 76b7fd26bd98c2122c317cee5f9b59ba66da8eea --- src/components/Auth/PrivateRoute.tsx | 7 +++---- src/firebase.js | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/Auth/PrivateRoute.tsx b/src/components/Auth/PrivateRoute.tsx index f114a6a5a..a41e936fb 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 send:', fcmToken); + console.log('FCM Token success:', 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 === true && isLoggedIn) { + if (isOnline) { sendFcmTokenToBackend(); - } else if (isOnline === false) { + } else { setTokenSentInSession(false); } }, [ @@ -209,7 +209,6 @@ const PrivateRoute = ({ children }: { children?: React.ReactNode }): React.React isPermissionGranted, setTokenSentInSession, tokenSentInSession, - isLoggedIn, ]); useEffect(() => { diff --git a/src/firebase.js b/src/firebase.js index 2509f1e0b..f9425542a 100644 --- a/src/firebase.js +++ b/src/firebase.js @@ -39,6 +39,7 @@ 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.'); @@ -95,6 +96,7 @@ const reRegisterServiceWorkerAndGetToken = async () => { export const fetchToken = async () => { if (await isEnabledAndIsSupported() && messaging) { const token = await requestForToken(); + console.log('token:', token); if (token) { return token; } else { From 09a7c99772e1d4bfcaa11c9fd4f26412e1c0a0f0 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 15 Nov 2024 17:52:38 +0200 Subject: [PATCH 008/162] Prevent resend fcm token on reload --- src/components/Auth/PrivateRoute.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Auth/PrivateRoute.tsx b/src/components/Auth/PrivateRoute.tsx index a41e936fb..7e2428311 100644 --- a/src/components/Auth/PrivateRoute.tsx +++ b/src/components/Auth/PrivateRoute.tsx @@ -198,9 +198,9 @@ const PrivateRoute = ({ children }: { children?: React.ReactNode }): React.React } }; - if (isOnline) { + if (isOnline === true) { sendFcmTokenToBackend(); - } else { + } else if (isOnline === false) { setTokenSentInSession(false); } }, [ From f3ce956e1c3606f635b6c8e42a4d7e2591bce851 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 15 Nov 2024 17:53:40 +0200 Subject: [PATCH 009/162] Fix send fcm token after logout --- src/components/Auth/PrivateRoute.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Auth/PrivateRoute.tsx b/src/components/Auth/PrivateRoute.tsx index 7e2428311..5f98b506a 100644 --- a/src/components/Auth/PrivateRoute.tsx +++ b/src/components/Auth/PrivateRoute.tsx @@ -198,7 +198,7 @@ const PrivateRoute = ({ children }: { children?: React.ReactNode }): React.React } }; - if (isOnline === true) { + if (isOnline === true && isLoggedIn) { sendFcmTokenToBackend(); } else if (isOnline === false) { setTokenSentInSession(false); @@ -209,6 +209,7 @@ const PrivateRoute = ({ children }: { children?: React.ReactNode }): React.React isPermissionGranted, setTokenSentInSession, tokenSentInSession, + isLoggedIn, ]); useEffect(() => { From c98450cb176fec987f126375656ce0204fef6b78 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 15 Nov 2024 17:54:45 +0200 Subject: [PATCH 010/162] Reduce noice console logs about fcm token --- src/components/Auth/PrivateRoute.tsx | 2 +- src/firebase.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/Auth/PrivateRoute.tsx b/src/components/Auth/PrivateRoute.tsx index 5f98b506a..f114a6a5a 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); diff --git a/src/firebase.js b/src/firebase.js index f9425542a..2509f1e0b 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 { From 7ca00e211ce8a37c22416fcf52f11d23b873d2cc Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 15 Nov 2024 19:01:33 +0200 Subject: [PATCH 011/162] Handle null or undefined in function to prevent TypeError --- src/context/CredentialsContext.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js index 2fbe72b33..6685a6078 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); From f8b991310bc4b438215fd22bbfaccae29a565600 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 18 Nov 2024 12:34:53 +0200 Subject: [PATCH 012/162] Refactor StatusProvider included connectivity object with Internet access and speed and improve online status handling --- src/context/StatusContext.tsx | 93 +++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 9 deletions(-) diff --git a/src/context/StatusContext.tsx b/src/context/StatusContext.tsx index 6150c6081..f0c36860a 100644 --- a/src/context/StatusContext.tsx +++ b/src/context/StatusContext.tsx @@ -1,31 +1,105 @@ import React, { useEffect, createContext, useState } from 'react'; +import axios from 'axios'; +import { BACKEND_URL } from '../config'; + +interface Connectivity { + navigatorOnline: boolean; + Internet: boolean; + speed: number; +} interface StatusContextValue { isOnline: boolean; updateAvailable: boolean; + connectivity: Connectivity; + updateOnlineStatus: () => Promise; } - -const StatusContext: React.Context = createContext({ +const StatusContext = createContext({ isOnline: null, updateAvailable: false, + connectivity: { navigatorOnline: null, Internet: null, speed: 0 }, + updateOnlineStatus: async () => { }, }); -function getOnlineStatus(): boolean { +// Function to calculate speed based on RTT (lower RTT means higher speed) +function calculateNetworkSpeed(rtt: number): number { + if (rtt < 100) return 5; // Excellent speed + if (rtt < 200) return 4; // Good speed + if (rtt < 500) return 3; // Moderate speed + if (rtt < 1000) return 2; // Slow speed + return 1; // Very slow speed +} + +async function checkInternetConnection(): Promise<{ isConnected: boolean; speed: number }> { + try { + const startTime = new Date().getTime(); + await axios.get(`${BACKEND_URL}/status`, { + timeout: 5000, // Timeout of 5 seconds + headers: { + 'Content-Type': 'application/json', + }, + }); + const endTime = new Date().getTime(); + const rtt = endTime - startTime; // Calculate RTT + + const speed = calculateNetworkSpeed(rtt); + console.log('Internet:', true, '- Speed:', speed); + return { isConnected: true, speed }; + } catch (error) { + return { isConnected: false, speed: 0 }; + } +} + +function getNavigatorOnlineStatus(): boolean { return navigator.onLine; } export const StatusProvider = ({ children }: { children: React.ReactNode }) => { - const [isOnline, setIsOnline] = useState(getOnlineStatus); + const [isOnline, setIsOnline] = useState(null); const [updateAvailable, setUpdateAvailable] = useState(false); - const updateOnlineStatus = () => { - setIsOnline(getOnlineStatus()); + const [connectivity, setConnectivity] = useState({ + navigatorOnline: null, + Internet: null, + speed: 0, + }); + + const updateOnlineStatus = async () => { + + const navigatorOnline = getNavigatorOnlineStatus(); + const internetConnection = await checkInternetConnection(); + + setConnectivity((prev) => { + if ( + prev.navigatorOnline === navigatorOnline && + prev.Internet === internetConnection.isConnected && + prev.speed === internetConnection.speed + ) { + return prev; // No changes, return previous state to prevent rerender + } + return { + ...prev, + navigatorOnline, + Internet: internetConnection.isConnected, + speed: internetConnection.speed, + }; + }); + + setIsOnline((prev) => { + if (prev === internetConnection.isConnected) { + return prev; // No change in `isOnline` + } + return internetConnection.isConnected; + }); }; useEffect(() => { window.addEventListener('online', updateOnlineStatus); window.addEventListener('offline', updateOnlineStatus); + // Initial check for online and backend connection status + updateOnlineStatus(); + return () => { window.removeEventListener('online', updateOnlineStatus); window.removeEventListener('offline', updateOnlineStatus); @@ -33,8 +107,9 @@ export const StatusProvider = ({ children }: { children: React.ReactNode }) => { }, []); useEffect(() => { - console.log("Online status changed to:", isOnline); - }, [isOnline]); + console.log('Online status:', isOnline); + console.log('Internet connection status:', connectivity); + }, [isOnline, connectivity]); navigator.serviceWorker.addEventListener('message', (event) => { if (event.data && event.data.type === 'NEW_CONTENT_AVAILABLE') { @@ -49,7 +124,7 @@ export const StatusProvider = ({ children }: { children: React.ReactNode }) => { }); return ( - + {children} ); From e14019af7629259ce6b8a561699c4e94ddcefba3 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 18 Nov 2024 12:40:44 +0200 Subject: [PATCH 013/162] Add polling check internet connection every 7 seconds when is offline --- src/context/StatusContext.tsx | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/context/StatusContext.tsx b/src/context/StatusContext.tsx index f0c36860a..c31e366ac 100644 --- a/src/context/StatusContext.tsx +++ b/src/context/StatusContext.tsx @@ -111,6 +111,29 @@ export const StatusProvider = ({ children }: { children: React.ReactNode }) => { console.log('Internet connection status:', connectivity); }, [isOnline, connectivity]); + // Polling logic when offline + useEffect(() => { + let pollingInterval: NodeJS.Timeout | null = null; + const startPolling = () => { + pollingInterval = setInterval(async () => { + console.log('Polling backend connection...'); + updateOnlineStatus(); + }, 7000); // Poll every 7 seconds + }; + + if (!isOnline) { + startPolling(); + } else if (pollingInterval) { + clearInterval(pollingInterval); + } + + return () => { + if (pollingInterval) { + clearInterval(pollingInterval); + } + }; + }, [isOnline]); + navigator.serviceWorker.addEventListener('message', (event) => { if (event.data && event.data.type === 'NEW_CONTENT_AVAILABLE') { const isWindowHidden = document.hidden; From 177ee0ab6cc9d6514b0c6a9772e6e59f48ec79fb Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 18 Nov 2024 12:53:57 +0200 Subject: [PATCH 014/162] Call updateOnlineStatus on location change and remote the initial check from StatusContext --- src/App.js | 5 ++++- src/context/StatusContext.tsx | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/App.js b/src/App.js index 0f2a57a41..d5106d64a 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,4 @@ -import React, { useEffect, Suspense, useState } from 'react'; +import React, { useEffect, Suspense, useState, useContext } from 'react'; import { Routes, Route, Outlet, useLocation } from 'react-router-dom'; // Import i18next and set up translations import { I18nextProvider } from 'react-i18next'; @@ -15,6 +15,7 @@ import Snowfalling from './components/ChristmasAnimation/Snowfalling'; import Spinner from './components/Shared/Spinner'; import { withContainerContext } from './context/ContainerContext'; +import StatusContext from './context/StatusContext'; import UpdateNotification from './components/Notifications/UpdateNotification'; import CredentialDetails from './pages/Home/CredentialDetails'; @@ -80,6 +81,7 @@ const Settings = React.lazy(() => import('./pages/Settings/Settings')); const VerificationResult = React.lazy(() => import('./pages/VerificationResult/VerificationResult')); function App() { + const { updateOnlineStatus } = useContext(StatusContext); const location = useLocation(); const [url, setUrl] = useState(window.location.href); const { @@ -99,6 +101,7 @@ function App() { useEffect(() => { setUrl(window.location.href); checkForUpdates(); + updateOnlineStatus(); }, [location]) useEffect(() => { diff --git a/src/context/StatusContext.tsx b/src/context/StatusContext.tsx index c31e366ac..cb37d2366 100644 --- a/src/context/StatusContext.tsx +++ b/src/context/StatusContext.tsx @@ -97,9 +97,6 @@ export const StatusProvider = ({ children }: { children: React.ReactNode }) => { window.addEventListener('online', updateOnlineStatus); window.addEventListener('offline', updateOnlineStatus); - // Initial check for online and backend connection status - updateOnlineStatus(); - return () => { window.removeEventListener('online', updateOnlineStatus); window.removeEventListener('offline', updateOnlineStatus); From 2f597cb60f95cbf246adb9b2f5029807f3798862 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 18 Nov 2024 13:14:39 +0200 Subject: [PATCH 015/162] Call updateOnlineStatus on key actions on login --- src/pages/Login/Login.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pages/Login/Login.tsx b/src/pages/Login/Login.tsx index 7a64929dd..784b3fe91 100644 --- a/src/pages/Login/Login.tsx +++ b/src/pages/Login/Login.tsx @@ -212,7 +212,7 @@ const WebauthnSignupLogin = ({ error: React.ReactNode, setError: (error: React.ReactNode) => void, }) => { - const { isOnline } = useContext(StatusContext); + const { isOnline, updateOnlineStatus } = useContext(StatusContext); const { api, keystore } = useContext(SessionContext); const [inProgress, setInProgress] = useState(false); @@ -356,6 +356,7 @@ const WebauthnSignupLogin = ({ setInProgress(false); setIsSubmitting(false); checkForUpdates(); + updateOnlineStatus(); }; const onLoginCachedUser = async (cachedUser: CachedUser) => { @@ -366,6 +367,7 @@ const WebauthnSignupLogin = ({ setInProgress(false); setIsSubmitting(false); checkForUpdates(); + updateOnlineStatus(); }; const onForgetCachedUser = (cachedUser: CachedUser) => { @@ -557,7 +559,7 @@ const WebauthnSignupLogin = ({ }; const Auth = () => { - const { isOnline } = useContext(StatusContext); + const { isOnline, updateOnlineStatus } = useContext(StatusContext); const { api, isLoggedIn, keystore } = useContext(SessionContext); const { t } = useTranslation(); const location = useLocation(); @@ -640,6 +642,7 @@ const Auth = () => { setIsLogin(!isLogin); setError(''); checkForUpdates(); + updateOnlineStatus(); }; } @@ -648,6 +651,7 @@ const Auth = () => { setError(''); setWebauthnError(''); checkForUpdates(); + updateOnlineStatus(); } return ( From b95d17b05ca2363d4c0a7f3aa61f8cab3b70e8ee Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 18 Nov 2024 13:23:08 +0200 Subject: [PATCH 016/162] Add forceCheck prop to updateOnlineStatus and lastupdate tile in order to reduce the unnecessary internet checks --- src/App.js | 2 +- src/context/StatusContext.tsx | 30 ++++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/App.js b/src/App.js index d5106d64a..c1b630aa9 100644 --- a/src/App.js +++ b/src/App.js @@ -101,7 +101,7 @@ function App() { useEffect(() => { setUrl(window.location.href); checkForUpdates(); - updateOnlineStatus(); + updateOnlineStatus(false); }, [location]) useEffect(() => { diff --git a/src/context/StatusContext.tsx b/src/context/StatusContext.tsx index cb37d2366..97c172fcd 100644 --- a/src/context/StatusContext.tsx +++ b/src/context/StatusContext.tsx @@ -12,7 +12,7 @@ interface StatusContextValue { isOnline: boolean; updateAvailable: boolean; connectivity: Connectivity; - updateOnlineStatus: () => Promise; + updateOnlineStatus: (forceCheck?: boolean) => Promise; } const StatusContext = createContext({ @@ -63,10 +63,26 @@ export const StatusProvider = ({ children }: { children: React.ReactNode }) => { Internet: null, speed: 0, }); + const lastUpdateCallTime = React.useRef(0); - const updateOnlineStatus = async () => { + const updateOnlineStatus = async (forceCheck = true) => { const navigatorOnline = getNavigatorOnlineStatus(); + + console.log('updateOnlineStatus with force:', forceCheck) + // Get the current time + const now = Date.now(); + + // If not a forced check and last call was within the last 5 seconds, skip the update + if (!forceCheck && now - lastUpdateCallTime.current < 5000) { + console.log('Skipping updateOnlineStatus: Called too recently'); + return; + } + + // Update the last call time + lastUpdateCallTime.current = now; + console.log('lastUpdateCallTime', Date.now()) + const internetConnection = await checkInternetConnection(); setConnectivity((prev) => { @@ -94,12 +110,14 @@ export const StatusProvider = ({ children }: { children: React.ReactNode }) => { }; useEffect(() => { - window.addEventListener('online', updateOnlineStatus); - window.addEventListener('offline', updateOnlineStatus); + // Add event listeners for online/offline status + window.addEventListener('online', () => updateOnlineStatus()); + window.addEventListener('offline', () => updateOnlineStatus()); + // Cleanup event listeners on unmount return () => { - window.removeEventListener('online', updateOnlineStatus); - window.removeEventListener('offline', updateOnlineStatus); + window.removeEventListener('online', () => updateOnlineStatus()); + window.removeEventListener('offline', () => updateOnlineStatus()); }; }, []); From c1d74a456707eb9a1102e2bf1163f3ca0bcb91ee Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 18 Nov 2024 13:25:56 +0200 Subject: [PATCH 017/162] Add polling updateOnlineStatus every 20 sec if lastUpdateCallTime did before 20 sec --- src/context/StatusContext.tsx | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/context/StatusContext.tsx b/src/context/StatusContext.tsx index 97c172fcd..43ee7ac0f 100644 --- a/src/context/StatusContext.tsx +++ b/src/context/StatusContext.tsx @@ -149,6 +149,38 @@ export const StatusProvider = ({ children }: { children: React.ReactNode }) => { }; }, [isOnline]); + // Polling logic when online + + useEffect(() => { + let pollingInterval: NodeJS.Timeout | null = null; + + const startOnlinePolling = () => { + pollingInterval = setInterval(() => { + const now = Date.now(); + + // Check if it's been more than 20 seconds since the last update call + if (now - lastUpdateCallTime.current > 20000) { + console.log('Polling updateOnlineStatus while online...'); + updateOnlineStatus(false); // Pass `false` to indicate this is a periodic check + } else { + console.log('Skipping online polling: Called too recently'); + } + }, 20000); // Poll every 20 seconds + }; + + if (isOnline) { + startOnlinePolling(); + } else if (pollingInterval) { + clearInterval(pollingInterval); + } + + return () => { + if (pollingInterval) { + clearInterval(pollingInterval); + } + }; + }, [isOnline]); + navigator.serviceWorker.addEventListener('message', (event) => { if (event.data && event.data.type === 'NEW_CONTENT_AVAILABLE') { const isWindowHidden = document.hidden; From a73e5cc5a77ced94635f484da4b2ab4a2a69950e Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 18 Nov 2024 14:13:51 +0200 Subject: [PATCH 018/162] SelectCredentialsPopup: get credentials from credential context --- src/components/Popups/SelectCredentialsPopup.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/Popups/SelectCredentialsPopup.js b/src/components/Popups/SelectCredentialsPopup.js index ee043201b..8daa22041 100644 --- a/src/components/Popups/SelectCredentialsPopup.js +++ b/src/components/Popups/SelectCredentialsPopup.js @@ -10,6 +10,7 @@ import SessionContext from '../../context/SessionContext'; import ContainerContext from '../../context/ContainerContext'; import useScreenType from '../../hooks/useScreenType'; import Slider from '../Shared/Slider'; +import CredentialsContext from '../../context/CredentialsContext'; const formatTitle = (title) => { if (title) { @@ -60,6 +61,7 @@ const StepBar = ({ totalSteps, currentStep, stepTitles }) => { function SelectCredentialsPopup({ isOpen, setIsOpen, setSelectionMap, conformantCredentialsMap, verifierDomainName }) { const { api } = useContext(SessionContext); const [vcEntities, setVcEntities] = useState([]); + const { vcEntityList } = useContext(CredentialsContext); const navigate = useNavigate(); const { t } = useTranslation(); const keys = useMemo(() => Object.keys(conformantCredentialsMap), [conformantCredentialsMap]); @@ -82,9 +84,8 @@ function SelectCredentialsPopup({ isOpen, setIsOpen, setSelectionMap, conformant } try { - const response = await api.get('/storage/vc'); const vcEntities = await Promise.all( - response.data.vc_list.map(async vcEntity => { + vcEntityList.map(async vcEntity => { return container.credentialParserRegistry.parse(vcEntity.credential).then((c) => { if ('error' in c) { return; From de3a859e908901c1db66a8929acffcf275e5d6a3 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 18 Nov 2024 14:15:05 +0200 Subject: [PATCH 019/162] change addNewCredentialKeypair to addNewCredentialKeypairs --- src/services/LocalStorageKeystore.ts | 24 +++--- src/services/keystore.test.ts | 4 +- src/services/keystore.ts | 116 ++++++++++++++++----------- 3 files changed, 82 insertions(+), 62 deletions(-) diff --git a/src/services/LocalStorageKeystore.ts b/src/services/LocalStorageKeystore.ts index afa75d268..6033a557d 100644 --- a/src/services/LocalStorageKeystore.ts +++ b/src/services/LocalStorageKeystore.ts @@ -375,20 +375,16 @@ export function useLocalStorageKeystore(): LocalStorageKeystore { CommitCallback, ]> => ( await editPrivateData(async (originalContainer) => { - let container = originalContainer; - let proof_jwts = []; - for (const { nonce, audience, issuer } of requests) { - const [{ proof_jwt }, newContainer] = await keystore.generateOpenid4vciProof( - container, - config.DID_KEY_VERSION, - nonce, - audience, - issuer - ); - proof_jwts.push(proof_jwt); - container = newContainer; - } - return [{ proof_jwts }, container]; + const { nonce, audience, issuer } = requests[0]; // the first row is enough since the nonce remains the same + const [{ proof_jwts }, newContainer] = await keystore.generateOpenid4vciProofs( + originalContainer, + config.DID_KEY_VERSION, + nonce, + audience, + issuer, + requests.length + ); + return [{ proof_jwts }, newContainer]; }) ), }; diff --git a/src/services/keystore.test.ts b/src/services/keystore.test.ts index 7bf87146f..e0fb9cc6d 100644 --- a/src/services/keystore.test.ts +++ b/src/services/keystore.test.ts @@ -258,7 +258,7 @@ describe("The keystore", () => { const [{ exportedMainKey },] = await keystore.unlockPrf(privateData, mockCredential, async () => false); const mainKey = await keystore.importMainKey(exportedMainKey); const test = async (didKeyVersion: DidKeyVersion) => { - const [{ proof_jwt }, [newPrivateData, newMainKey]] = await keystore.generateOpenid4vciProof( + const [{ proof_jwts }, [newPrivateData, newMainKey]] = await keystore.generateOpenid4vciProofs( [privateData, mainKey], didKeyVersion, "test-nonce", @@ -269,7 +269,7 @@ describe("The keystore", () => { const [newPrivateDataContents,] = await keystore.openPrivateData(newExportedMainKey, newPrivateData); const { kid, publicKey: publicKeyJwk } = Object.values(newPrivateDataContents.keypairs)[0]; const publicKey = await jose.importJWK(publicKeyJwk) - const { protectedHeader } = await jose.jwtVerify(proof_jwt, publicKey, { audience: "test-audience", issuer: "test-issuer" }); + const { protectedHeader } = await jose.jwtVerify(proof_jwts[0], publicKey, { audience: "test-audience", issuer: "test-issuer" }); assert.equal(await jose.calculateJwkThumbprint(protectedHeader.jwk), kid); }; it("p256-pub.", async () => test("p256-pub")); diff --git a/src/services/keystore.ts b/src/services/keystore.ts index 64eaf4119..3046b5d7e 100644 --- a/src/services/keystore.ts +++ b/src/services/keystore.ts @@ -1041,45 +1041,63 @@ async function createW3CDID(publicKey: CryptoKey): Promise<{ didKeyString: strin return { didKeyString }; } -async function addNewCredentialKeypair( +async function addNewCredentialKeypairs( [privateData, mainKey]: OpenedContainer, didKeyVersion: DidKeyVersion, deriveKid: (publicKey: CryptoKey, did: string) => Promise, + numberOfKeyPairs: number = 1 ): Promise<{ - privateKey: CryptoKey, - keypair: CredentialKeyPair, + privateKeys: CryptoKey[], + keypairs: CredentialKeyPair[], newPrivateData: OpenedContainer, }> { - const { publicKey, privateKey } = await crypto.subtle.generateKey( - { name: "ECDSA", namedCurve: "P-256" }, - true, - ['sign'] - ); - const publicKeyJwk: JWK = await crypto.subtle.exportKey("jwk", publicKey) as JWK; - const wrappedPrivateKey = await wrapPrivateKey(privateKey, mainKey); - const did = await createDid(publicKey, didKeyVersion); - const kid = await deriveKid(publicKey, did); - - const keypair: CredentialKeyPair = { - kid, - did, - alg: "ES256", - publicKey: publicKeyJwk, - wrappedPrivateKey, - }; + const keypairsWithPrivateKeys = await Promise.all(Array.from({ length: numberOfKeyPairs }).map(async () => { + const { publicKey, privateKey } = await crypto.subtle.generateKey( + { name: "ECDSA", namedCurve: "P-256" }, + true, + ['sign'] + ); + const publicKeyJwk: JWK = await crypto.subtle.exportKey("jwk", publicKey) as JWK; + const wrappedPrivateKey = await wrapPrivateKey(privateKey, mainKey); + const did = await createDid(publicKey, didKeyVersion); + const kid = await deriveKid(publicKey, did); + + const keypair: CredentialKeyPair = { + kid, + did, + alg: "ES256", + publicKey: publicKeyJwk, + wrappedPrivateKey, + }; + + return { kid, keypair, privateKey }; + })); + + + + console.log("addNewredentialKeypair: Before update private data") return { - privateKey, - keypair, + privateKeys: keypairsWithPrivateKeys.map((k) => k.privateKey), + keypairs: keypairsWithPrivateKeys.map((k) => k.keypair), newPrivateData: await updatePrivateData( [privateData, mainKey], - async (privateData: PrivateData) => ({ - ...privateData, - keypairs: { - ...privateData.keypairs, - [kid]: keypair, - }, - }), + async (privateData: PrivateData) => { + + const combinedKeypairs = { + ...privateData.keypairs + }; + + for (const { kid, keypair } of keypairsWithPrivateKeys) { + combinedKeypairs[kid] = keypair; + } + return { + ...privateData, + keypairs: { + ...combinedKeypairs + }, + } + } ), }; } @@ -1127,31 +1145,37 @@ export async function signJwtPresentation([privateData, mainKey]: [PrivateData, return { vpjwt: jws }; } -export async function generateOpenid4vciProof( +export async function generateOpenid4vciProofs( container: OpenedContainer, didKeyVersion: DidKeyVersion, nonce: string, audience: string, - issuer: string -): Promise<[{ proof_jwt: string }, OpenedContainer]> { + issuer: string, + numberOfKeyPairs: number = 1 +): Promise<[{ proof_jwts: string[] }, OpenedContainer]> { const deriveKid = async (publicKey: CryptoKey) => { const pubKey = await crypto.subtle.exportKey("jwk", publicKey); const jwkThumbprint = await jose.calculateJwkThumbprint(pubKey as JWK, "sha256"); return jwkThumbprint; }; - const { privateKey, keypair, newPrivateData } = await addNewCredentialKeypair(container, didKeyVersion, deriveKid); - - const jws = await new SignJWT({ - nonce: nonce, - aud: audience, - iss: issuer, - }) - .setProtectedHeader({ - alg: keypair.alg, - typ: "openid4vci-proof+jwt", - jwk: { ...keypair.publicKey, key_ops: ['verify'] } as JWK, + const { privateKeys, newPrivateData, keypairs } = await addNewCredentialKeypairs(container, didKeyVersion, deriveKid, numberOfKeyPairs); + + const proof_jwts = await Promise.all(keypairs.map(async (keypair, index) => { + const privateKey = privateKeys[index]; + const jws: string = await new SignJWT({ + nonce: nonce, + aud: audience, + iss: issuer, }) - .setIssuedAt() - .sign(privateKey); - return [{ proof_jwt: jws }, newPrivateData]; + .setProtectedHeader({ + alg: keypair.alg, + typ: "openid4vci-proof+jwt", + jwk: { ...keypair.publicKey, key_ops: ['verify'] } as JWK, + }) + .setIssuedAt() + .sign(privateKey); + return jws; + })); + + return [{ proof_jwts: proof_jwts }, newPrivateData]; } From 3607d2af15cd360976340c7a98b3c707d3fad20b Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 18 Nov 2024 14:16:12 +0200 Subject: [PATCH 020/162] add instanceId and sigCount counters in StorableCredential type. Must be mapped with the backend --- src/lib/types/StorableCredential.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/types/StorableCredential.ts b/src/lib/types/StorableCredential.ts index 7c8abad14..0e4175a30 100644 --- a/src/lib/types/StorableCredential.ts +++ b/src/lib/types/StorableCredential.ts @@ -6,4 +6,6 @@ export type StorableCredential = { credential: string; credentialConfigurationId: string; credentialIssuerIdentifier: string; + instanceId: number; + sigCount: number; }; From 8143c61f0c9c917d8213f52e9ce1ea60e9bfbc3d Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 18 Nov 2024 14:19:35 +0200 Subject: [PATCH 021/162] support batch credential issuance --- src/lib/services/OpenID4VCIClient.ts | 45 +++++++++++++++------ src/lib/services/OpenID4VCIClientFactory.ts | 4 +- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/lib/services/OpenID4VCIClient.ts b/src/lib/services/OpenID4VCIClient.ts index 6ef24673d..26150966b 100644 --- a/src/lib/services/OpenID4VCIClient.ts +++ b/src/lib/services/OpenID4VCIClient.ts @@ -21,7 +21,7 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { private httpProxy: IHttpProxy, private openID4VCIClientStateRepository: IOpenID4VCIClientStateRepository, private generateNonceProofs: (requests: { nonce: string, audience: string, issuer: string }[]) => Promise<{ proof_jwts: string[] }>, - private storeCredential: (c: StorableCredential) => Promise, + private storeCredentials: (cList: StorableCredential[]) => Promise, private authorizationRequestModifier: (credentialIssuerIdentifier: string, url: string, request_uri?: string, client_id?: string) => Promise<{ url: string }> = async (_credentialIssuerIdentifier: string, url: string) => ({ url }), ) { } @@ -395,13 +395,17 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { } let proofsArray: string[] = []; + const numberOfProofs = this.config.credentialIssuerMetadata.batch_credential_issuance?.batch_size ?? 1; try { - - const numberOfProofs = this.config.credentialIssuerMetadata.batch_credential_issuance?.batch_size ?? 1; - const generateProofsResult = await this.generateNonceProofs(new Array(numberOfProofs).map(() => - ({ nonce: c_nonce, issuer: this.config.clientId, audience: this.config.credentialIssuerIdentifier }) - )); - + const inputs = []; + for (let i = 0; i < numberOfProofs; i++) { + inputs.push({ + nonce: c_nonce, + issuer: this.config.clientId, + audience: this.config.credentialIssuerIdentifier + }) + } + const generateProofsResult = await this.generateNonceProofs(inputs); proofsArray = generateProofsResult.proof_jwts; if (proofsArray) { dispatchEvent(new CustomEvent("generatedProof")); @@ -413,12 +417,12 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { } const credentialConfigurationSupported = this.config.credentialIssuerMetadata.credential_configurations_supported[flowState.credentialConfigurationId]; - + const credentialEndpointBody = { "format": this.config.credentialIssuerMetadata.credential_configurations_supported[flowState.credentialConfigurationId].format, } as any; - if (this.config.credentialIssuerMetadata.batch_credential_issuance?.batch_size) { + if (this.config.credentialIssuerMetadata?.batch_credential_issuance?.batch_size) { credentialEndpointBody.proofs = { jwt: proofsArray } @@ -452,7 +456,15 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { } console.log("Credential response = ", credentialResponse) - const { credential } = credentialResponse.data; + + const credentialArray = []; + if (numberOfProofs == 1) { + const { credential } = credentialResponse.data; + credentialArray.push(credential); + } + else { + credentialArray.push(...credentialResponse.data.credentials); + } const new_c_nonce = credentialResponse.data.c_nonce; const new_c_nonce_expires_in = credentialResponse.data.c_nonce_expires_in; @@ -464,14 +476,21 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { await this.openID4VCIClientStateRepository.cleanupExpired(flowState.userHandleB64U); - await this.storeCredential({ - credentialIdentifier: generateRandomIdentifier(32), + const identifier = generateRandomIdentifier(32); + const storableCredentials: StorableCredential[] = credentialArray.map((credential, index) => ({ + credentialIdentifier: identifier, credential: credential, format: this.config.credentialIssuerMetadata.credential_configurations_supported[flowState.credentialConfigurationId].format, credentialConfigurationId: flowState.credentialConfigurationId, credentialIssuerIdentifier: this.config.credentialIssuerIdentifier, + sigCount: 0, + instanceId: index, + })); + + this.storeCredentials(storableCredentials).then(() => { + dispatchEvent(new CustomEvent('newCredential')); }); - dispatchEvent(new CustomEvent('newCredential')); + return; } diff --git a/src/lib/services/OpenID4VCIClientFactory.ts b/src/lib/services/OpenID4VCIClientFactory.ts index 37ec59724..6cab4e98f 100644 --- a/src/lib/services/OpenID4VCIClientFactory.ts +++ b/src/lib/services/OpenID4VCIClientFactory.ts @@ -9,11 +9,11 @@ export class OpenID4VCIClientFactory { constructor(private httpProxy: IHttpProxy, private openID4VCIClientStateRepository: IOpenID4VCIClientStateRepository, private generateNonceProofs: (requests: { nonce: string, audience: string, issuer: string }[]) => Promise<{ proof_jwts: string[] }>, - private storeCredential: (c: StorableCredential) => Promise, + private storeCredentials: (cList: StorableCredential[]) => Promise, private authorizationRequestModifier: (credentialIssuerIdentifier: string, url: string, request_uri?: string, client_id?: string) => Promise<{ url: string }>, ) { } createClient(config: ClientConfig): OpenID4VCIClient { - return new OpenID4VCIClient(config, this.httpProxy, this.openID4VCIClientStateRepository, this.generateNonceProofs, this.storeCredential, this.authorizationRequestModifier); + return new OpenID4VCIClient(config, this.httpProxy, this.openID4VCIClientStateRepository, this.generateNonceProofs, this.storeCredentials, this.authorizationRequestModifier); } } From 76fc4f0fc6597afdd3b65068009b210a039138ab Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 18 Nov 2024 14:21:04 +0200 Subject: [PATCH 022/162] CredentialContext: show only the first instance of each credential --- src/context/CredentialsContext.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js index 7804dd99c..793b451d0 100644 --- a/src/context/CredentialsContext.js +++ b/src/context/CredentialsContext.js @@ -15,9 +15,9 @@ export const CredentialsProvider = ({ children }) => { const response = await api.get('/storage/vc'); const fetchedVcList = response.data.vc_list; - const vcEntityList = await Promise.all(fetchedVcList.map(async vcEntity => { + const vcEntityList = (await Promise.all(fetchedVcList.map(async (vcEntity) => { return { ...vcEntity }; - })); + }))).filter((vcEntity) => vcEntity.instanceId == 0); // show only the first instance vcEntityList.sort(reverse(compareBy(vc => vc.id))); From 4d0f3debe78e4b73b124a72f02392e0cb55d98ac Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 18 Nov 2024 14:22:04 +0200 Subject: [PATCH 023/162] present the least used credential. update sigCount when credential is used --- src/context/ContainerContext.tsx | 14 ++++++++++-- src/lib/services/CredentialBatchHelper.ts | 26 +++++++++++++++++++++++ src/lib/services/OpenID4VPRelyingParty.ts | 18 +++++++++++++--- 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 src/lib/services/CredentialBatchHelper.ts diff --git a/src/context/ContainerContext.tsx b/src/context/ContainerContext.tsx index 93763681d..f13e9f958 100644 --- a/src/context/ContainerContext.tsx +++ b/src/context/ContainerContext.tsx @@ -25,6 +25,7 @@ import defaultCredentialImage from "../assets/images/cred.png"; import renderSvgTemplate from "../components/Credentials/RenderSvgTemplate"; import renderCustomSvgTemplate from "../components/Credentials/RenderCustomSvgTemplate"; import StatusContext from "./StatusContext"; +import { CredentialBatchHelper } from "../lib/services/CredentialBatchHelper"; export type ContainerContextValue = { httpProxy: IHttpProxy, @@ -90,6 +91,14 @@ export const ContainerContextProvider = ({ children }) => { cont.register('OpenID4VCIClientStateRepository', OpenID4VCIClientStateRepository, userData.settings.openidRefreshTokenMaxAgeInSeconds); cont.register('OpenID4VCIHelper', OpenID4VCIHelper, cont.resolve('HttpProxy')); + + cont.register('CredentialBatchHelper', CredentialBatchHelper, + async function updateCredential(storableCredential: StorableCredential) { + await api.post('/storage/vc/update', { + credential: storableCredential + }); + } + ) const credentialParserRegistry = cont.resolve('CredentialParserRegistry'); credentialParserRegistry.addParser({ @@ -190,6 +199,7 @@ export const ContainerContextProvider = ({ children }) => { cont.resolve('OpenID4VPRelyingPartyStateRepository'), cont.resolve('HttpProxy'), cont.resolve('CredentialParserRegistry'), + cont.resolve('CredentialBatchHelper'), async function getAllStoredVerifiableCredentials() { const fetchAllCredentials = await api.get('/storage/vc'); return { verifiableCredentials: fetchAllCredentials.data.vc_list }; @@ -220,9 +230,9 @@ export const ContainerContextProvider = ({ children }) => { await keystoreCommit(); return { proof_jwts }; }, - async function storeCredential(c: StorableCredential) { + async function storeCredentials(cList: StorableCredential[]) { await api.post('/storage/vc', { - ...c + credentials: cList }); }, ); diff --git a/src/lib/services/CredentialBatchHelper.ts b/src/lib/services/CredentialBatchHelper.ts new file mode 100644 index 000000000..64a617571 --- /dev/null +++ b/src/lib/services/CredentialBatchHelper.ts @@ -0,0 +1,26 @@ +import { compareBy } from "../../util"; +import { StorableCredential } from "../types/StorableCredential"; + +export class CredentialBatchHelper { + + constructor(private updateCredential: (storableCredential: StorableCredential) => Promise) { } + + /** + * + * @param credentialIdentifier + * @param cList all verifiable credentials of the wallet + * @returns + * Always return credential with the least amount of usages + */ + public async getLeastUsedCredential(credentialIdentifier: string, cList: StorableCredential[]): Promise<{ credential: StorableCredential }> { + const creds = cList.filter((c) => c.credentialIdentifier === credentialIdentifier); + creds.sort(compareBy((c) => c.sigCount)); + console.log("Ordered by sigCount = ", creds) + return { credential: creds[0] } + } + + public async useCredential(storableCredential: StorableCredential): Promise { + storableCredential.sigCount = storableCredential.sigCount + 1; + await this.updateCredential(storableCredential); + } +} diff --git a/src/lib/services/OpenID4VPRelyingParty.ts b/src/lib/services/OpenID4VPRelyingParty.ts index 2856efac0..a05ad0b94 100644 --- a/src/lib/services/OpenID4VPRelyingParty.ts +++ b/src/lib/services/OpenID4VPRelyingParty.ts @@ -12,6 +12,7 @@ import { ICredentialParserRegistry } from "../interfaces/ICredentialParser"; import { extractSAN, getPublicKeyFromB64Cert } from "../utils/pki"; import axios from "axios"; import { BACKEND_URL, OPENID4VP_SAN_DNS_CHECK_SSL_CERTS, OPENID4VP_SAN_DNS_CHECK } from "../../config"; +import { CredentialBatchHelper } from "./CredentialBatchHelper"; export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { @@ -20,6 +21,7 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { private openID4VPRelyingPartyStateRepository: OpenID4VPRelyingPartyStateRepository, private httpProxy: IHttpProxy, private credentialParserRegistry: ICredentialParserRegistry, + private credentialBatchHelper: CredentialBatchHelper, private getAllStoredVerifiableCredentials: () => Promise<{ verifiableCredentials: StorableCredential[] }>, private signJwtPresentationKeystoreFn: (nonce: string, audience: string, verifiableCredentials: any[]) => Promise<{ vpjwt: string }>, private storeVerifiablePresentation: (presentation: string, format: string, identifiersOfIncludedCredentials: string[], presentationSubmission: any, audience: string) => Promise @@ -271,7 +273,14 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { let { verifiableCredentials } = await this.getAllStoredVerifiableCredentials(); const allSelectedCredentialIdentifiers = Array.from(selectionMap.values()); - const filteredVCEntities = verifiableCredentials + + // returns the credentials with the minimum usages for each credential identifier + const credentialsFilteredByUsage = await Promise.all(allSelectedCredentialIdentifiers.map(async (credentialIdentifier) => { + const result = await this.credentialBatchHelper.getLeastUsedCredential(credentialIdentifier, verifiableCredentials) + return result.credential; + })); + + const filteredVCEntities = credentialsFilteredByUsage .filter((vc) => allSelectedCredentialIdentifiers.includes(vc.credentialIdentifier), ); @@ -337,9 +346,12 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { const credentialIdentifiers = originalVCs.map((vc) => vc.credentialIdentifier); - await this.storeVerifiablePresentation(generatedVPs[0], presentationSubmission.descriptor_map[0].format, credentialIdentifiers, presentationSubmission, client_id); + const storePresentationPromise = this.storeVerifiablePresentation(generatedVPs[0], presentationSubmission.descriptor_map[0].format, credentialIdentifiers, presentationSubmission, client_id); + const updateCredentialPromise = filteredVCEntities.map(async (cred) => this.credentialBatchHelper.useCredential(cred)) + + const updateRepositoryPromise = this.openID4VPRelyingPartyStateRepository.store(S); - await this.openID4VPRelyingPartyStateRepository.store(S); + await Promise.all([storePresentationPromise, ...updateCredentialPromise, updateRepositoryPromise]); const res = await this.httpProxy.post(response_uri, formData.toString(), { 'Content-Type': 'application/x-www-form-urlencoded', From 16e2a76a74aff0cd91f5c669feb8df244b650b6a Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 18 Nov 2024 14:39:10 +0200 Subject: [PATCH 024/162] Update connection status icon with quality bars base on connectivity and update all relevant components --- src/components/Layout/Header.js | 2 +- .../Layout/Navigation/ConnectionStatusIcon.js | 47 ++++++++++++++++--- src/components/Layout/Navigation/Sidebar.js | 2 +- src/locales/en.json | 10 ++++ src/pages/Login/Login.tsx | 2 +- src/pages/Login/LoginState.js | 2 +- 6 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/components/Layout/Header.js b/src/components/Layout/Header.js index a42f99ed3..80bc0c57e 100644 --- a/src/components/Layout/Header.js +++ b/src/components/Layout/Header.js @@ -36,7 +36,7 @@ const Header = () => { return (
- +
- {title &&

} + {title &&

}

)} @@ -87,20 +94,37 @@ const CredentialLayout = ({ children, title = null }) => {
{/* Block 1: credential */}
-
+
{vcEntity && ( // Open the modal when the credential is clicked - +
+ + {screenType !== 'mobile' && zeroSigCount !== null && sigTotal && +
+ +

{zeroSigCount}/{sigTotal} Available Usages

+
+ } +
)} +
{screenType === 'mobile' && ( -

{credentialFiendlyName}

+
+

{credentialFiendlyName}

+ {zeroSigCount !== null && sigTotal && +
+ +

{zeroSigCount}/{sigTotal} Available Usages

+
+ } +
)}
diff --git a/src/components/Credentials/StatusRibbon.js b/src/components/Credentials/StatusRibbon.js index 2a743b03f..704a1a5ba 100644 --- a/src/components/Credentials/StatusRibbon.js +++ b/src/components/Credentials/StatusRibbon.js @@ -9,7 +9,7 @@ const StatusRibbon = ({ parsedCredential }) => { return ( <> {parsedCredential && CheckExpired(parsedCredential.expiry_date) && -
+
{t('statusRibbon.expired')}
} diff --git a/src/components/Credentials/UsagesRibbon.js b/src/components/Credentials/UsagesRibbon.js new file mode 100644 index 000000000..6ebf42cf6 --- /dev/null +++ b/src/components/Credentials/UsagesRibbon.js @@ -0,0 +1,19 @@ +// StatusRibbon.js +import React from 'react'; +import { PiCardsBold } from "react-icons/pi"; + +const UsagesRibbon = ({ vcEntityInstances }) => { + const zeroSigCount = vcEntityInstances?.filter(instance => instance.sigCount === 0).length || 0; + + return ( + <> + {vcEntityInstances && +
+ {zeroSigCount} +
+ } + + ); +}; + +export default UsagesRibbon; diff --git a/src/components/Popups/SelectCredentialsPopup.js b/src/components/Popups/SelectCredentialsPopup.js index 8daa22041..ea3de69c9 100644 --- a/src/components/Popups/SelectCredentialsPopup.js +++ b/src/components/Popups/SelectCredentialsPopup.js @@ -61,7 +61,7 @@ const StepBar = ({ totalSteps, currentStep, stepTitles }) => { function SelectCredentialsPopup({ isOpen, setIsOpen, setSelectionMap, conformantCredentialsMap, verifierDomainName }) { const { api } = useContext(SessionContext); const [vcEntities, setVcEntities] = useState([]); - const { vcEntityList } = useContext(CredentialsContext); + const { vcEntityList, vcEntityListInstances } = useContext(CredentialsContext); const navigate = useNavigate(); const { t } = useTranslation(); const keys = useMemo(() => Object.keys(conformantCredentialsMap), [conformantCredentialsMap]); @@ -159,16 +159,18 @@ function SelectCredentialsPopup({ isOpen, setIsOpen, setSelectionMap, conformant const renderSlideContent = (vcEntity) => ( ); @@ -89,15 +89,19 @@ const Home = () => { ) : (
- {vcEntityList.map((vcEntity) => ( + {vcEntityListInstances && vcEntityList.map((vcEntity) => ( ))} From eabcbd779ce021a5fb0eb18b2df5d1bd8e3fafd9 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 19 Nov 2024 13:51:18 +0200 Subject: [PATCH 027/162] Rename StatusRibbon to ExpiredRibbon --- src/components/Credentials/CredentialImage.js | 6 +++--- .../Credentials/{StatusRibbon.js => ExpiredRibbon.js} | 8 ++++---- src/components/Credentials/UsagesRibbon.js | 2 +- src/locales/en.json | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) rename src/components/Credentials/{StatusRibbon.js => ExpiredRibbon.js} (79%) diff --git a/src/components/Credentials/CredentialImage.js b/src/components/Credentials/CredentialImage.js index 694bbad0d..3051fa10c 100644 --- a/src/components/Credentials/CredentialImage.js +++ b/src/components/Credentials/CredentialImage.js @@ -1,6 +1,6 @@ import { useState, useEffect, useContext } from "react"; -import StatusRibbon from '../../components/Credentials/StatusRibbon'; -import UsagesRibbon from "../../components/Credentials/UsagesRibbon"; +import ExpiredRibbon from './ExpiredRibbon'; +import UsagesRibbon from "./UsagesRibbon"; import ContainerContext from '../../context/ContainerContext'; const CredentialImage = ({ credential, className, onClick, showRibbon = true, vcEntityInstances = null }) => { @@ -25,7 +25,7 @@ const CredentialImage = ({ credential, className, onClick, showRibbon = true, vc {"Credential"} )} {parsedCredential && showRibbon && - + } {vcEntityInstances && showRibbon && diff --git a/src/components/Credentials/StatusRibbon.js b/src/components/Credentials/ExpiredRibbon.js similarity index 79% rename from src/components/Credentials/StatusRibbon.js rename to src/components/Credentials/ExpiredRibbon.js index 704a1a5ba..b2372d863 100644 --- a/src/components/Credentials/StatusRibbon.js +++ b/src/components/Credentials/ExpiredRibbon.js @@ -1,20 +1,20 @@ -// StatusRibbon.js +// ExpiredRibbon.js import React from 'react'; import { useTranslation } from 'react-i18next'; import { CheckExpired } from '../../functions/CheckExpired'; -const StatusRibbon = ({ parsedCredential }) => { +const ExpiredRibbon = ({ parsedCredential }) => { const { t } = useTranslation(); return ( <> {parsedCredential && CheckExpired(parsedCredential.expiry_date) &&
- {t('statusRibbon.expired')} + {t('expiredRibbon.expired')}
} ); }; -export default StatusRibbon; +export default ExpiredRibbon; diff --git a/src/components/Credentials/UsagesRibbon.js b/src/components/Credentials/UsagesRibbon.js index 6ebf42cf6..888721390 100644 --- a/src/components/Credentials/UsagesRibbon.js +++ b/src/components/Credentials/UsagesRibbon.js @@ -1,4 +1,4 @@ -// StatusRibbon.js +// UsagesRibbon.js import React from 'react'; import { PiCardsBold } from "react-icons/pi"; diff --git a/src/locales/en.json b/src/locales/en.json index 5ef6ee3b1..d571471aa 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -276,7 +276,7 @@ "poweredBy": "Powered by wwWallet", "poweredByAriaLabel": "GitHub repository of wwWallet" }, - "statusRibbon": { + "expiredRibbon": { "expired": "Expired" }, "tourGuide": { From cc28bba36665622aa3b46ca223ecf591c5213319 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 19 Nov 2024 13:51:49 +0200 Subject: [PATCH 028/162] Hide ribbons on history details page/popup --- src/components/History/HistoryDetailContent.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/History/HistoryDetailContent.js b/src/components/History/HistoryDetailContent.js index 795563892..46d54d31d 100644 --- a/src/components/History/HistoryDetailContent.js +++ b/src/components/History/HistoryDetailContent.js @@ -18,7 +18,7 @@ const HistoryDetailContent = ({ historyItem }) => { aria-label={credential.friendlyName} title={t('pageCredentials.credentialFullScreenTitle', { friendlyName: credential.friendlyName })} > - +
); From b12cc3e46b4b18afd0639c5f34f6dc3d7525627f Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 19 Nov 2024 13:52:32 +0200 Subject: [PATCH 029/162] fix width style on credential layout --- src/components/Credentials/CredentialLayout.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Credentials/CredentialLayout.js b/src/components/Credentials/CredentialLayout.js index bee6af92a..b8eca2780 100644 --- a/src/components/Credentials/CredentialLayout.js +++ b/src/components/Credentials/CredentialLayout.js @@ -93,7 +93,7 @@ const CredentialLayout = ({ children, title = null }) => {
{/* Block 1: credential */} -
+
{vcEntity && ( // Open the modal when the credential is clicked From b666b28aa43c8556c0c6a933a34a97c9a3f1391b Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 19 Nov 2024 14:01:05 +0200 Subject: [PATCH 030/162] Fix code format --- src/index.css | 2 +- src/services/keystore.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/index.css b/src/index.css index 2527edd21..83e15cdb8 100644 --- a/src/index.css +++ b/src/index.css @@ -148,4 +148,4 @@ input:-webkit-autofill { .overflow-visible-force { overflow: visible !important; -} \ No newline at end of file +} diff --git a/src/services/keystore.ts b/src/services/keystore.ts index 3046b5d7e..086c071da 100644 --- a/src/services/keystore.ts +++ b/src/services/keystore.ts @@ -156,8 +156,8 @@ type WebauthnPrfEncryptionKeyInfoV1 = WebauthnPrfSaltInfo & WebauthnPrfEncryptio } export type WebauthnPrfEncryptionKeyInfoV2 = ( WebauthnPrfSaltInfo - & WebauthnPrfEncryptionKeyDeriveKeyParams - & StaticEncapsulationInfo + & WebauthnPrfEncryptionKeyDeriveKeyParams + & StaticEncapsulationInfo ); export function isPrfKeyV2(prfKeyInfo: WebauthnPrfEncryptionKeyInfo): prfKeyInfo is WebauthnPrfEncryptionKeyInfoV2 { return ( @@ -794,7 +794,7 @@ export async function upgradePrfKey( prfKeyInfo: WebauthnPrfEncryptionKeyInfoV1, promptForPrfRetry: () => Promise, ): Promise { - const [prfKey,, prfCredential] = await getPrfKey( + const [prfKey, , prfCredential] = await getPrfKey( { ...privateData, prfKeys: privateData.prfKeys.filter((keyInfo) => ( @@ -1062,7 +1062,7 @@ async function addNewCredentialKeypairs( const wrappedPrivateKey = await wrapPrivateKey(privateKey, mainKey); const did = await createDid(publicKey, didKeyVersion); const kid = await deriveKid(publicKey, did); - + const keypair: CredentialKeyPair = { kid, did, From 46c81dc36f21e719ac5160e56c80d29ed2417949 Mon Sep 17 00:00:00 2001 From: jlsOsorio <61560186+jlsOsorio@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:35:10 +0000 Subject: [PATCH 031/162] feat: add language selector in UI Refactor the language selector in order to display a pre-styled popup/modal with the available languages and add to the initial login page and the sidebar. The refactor has to do only with the appearance that could fit well in both scenarios, as long as it is a reusable component. --- .../LanguageSelector/LanguageOption.tsx | 37 +++++++++++++++++ .../LanguageSelector/LanguageSelector.js | 33 --------------- .../LanguageSelector/LanguageSelector.tsx | 41 +++++++++++++++++++ src/components/LanguageSelector/languages.ts | 9 ++++ src/components/Layout/Navigation/Sidebar.js | 2 + src/locales/en.json | 3 ++ src/pages/Login/Login.tsx | 6 ++- 7 files changed, 97 insertions(+), 34 deletions(-) create mode 100644 src/components/LanguageSelector/LanguageOption.tsx delete mode 100644 src/components/LanguageSelector/LanguageSelector.js create mode 100644 src/components/LanguageSelector/LanguageSelector.tsx create mode 100644 src/components/LanguageSelector/languages.ts diff --git a/src/components/LanguageSelector/LanguageOption.tsx b/src/components/LanguageSelector/LanguageOption.tsx new file mode 100644 index 000000000..9c3e711ac --- /dev/null +++ b/src/components/LanguageSelector/LanguageOption.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; + +import Button from "../Buttons/Button"; +import { languageOptions } from "./languages"; + +type LanguageOptionProps = { + onClose: () => void; +}; + +const LanguageOption = ({ onClose }: LanguageOptionProps) => { + const { i18n } = useTranslation(); + const { language } = i18n; + + const handleLanguageChange = (value: string) => { + i18n.changeLanguage(value); + onClose(); + }; + + return ( +
+ {languageOptions.map((lang) => ( + + ))} +
+ ); +}; + +export default LanguageOption; diff --git a/src/components/LanguageSelector/LanguageSelector.js b/src/components/LanguageSelector/LanguageSelector.js deleted file mode 100644 index 13b3f1439..000000000 --- a/src/components/LanguageSelector/LanguageSelector.js +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import { useTranslation } from 'react-i18next'; - -const LanguageSelector = () => { - const { i18n } = useTranslation(); - const { language } = i18n; - - const languageOptions = [ - { value: 'en', label: '🇺🇸 English' }, - { value: 'el', label: '🇬🇷 Ελληνικά' }, - ]; - - const handleChangeLanguage = (event) => { - const selectedLanguage = event.target.value; - i18n.changeLanguage(selectedLanguage); - }; - - return ( - - ); -}; - -export default LanguageSelector; diff --git a/src/components/LanguageSelector/LanguageSelector.tsx b/src/components/LanguageSelector/LanguageSelector.tsx new file mode 100644 index 000000000..f34b02561 --- /dev/null +++ b/src/components/LanguageSelector/LanguageSelector.tsx @@ -0,0 +1,41 @@ +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { FaLanguage } from "react-icons/fa"; + +import PopupLayout from "../Popups/PopupLayout"; +import LanguageOption from "./LanguageOption"; + +type LanguageSelectorProps = { + className: string; + iconSize?: number; + hasLabel: boolean; +}; + +const LanguageSelector = ({ + className, + iconSize, + hasLabel = true, +}: LanguageSelectorProps) => { + const { t } = useTranslation(); + const [isOpenLanguageOptions, setIsOpenLanguageOptions] = useState(false); + + return ( + <> + + setIsOpenLanguageOptions(false)} + > + setIsOpenLanguageOptions(false)} /> + + + ); +}; + +export default LanguageSelector; diff --git a/src/components/LanguageSelector/languages.ts b/src/components/LanguageSelector/languages.ts new file mode 100644 index 000000000..0d3b8731e --- /dev/null +++ b/src/components/LanguageSelector/languages.ts @@ -0,0 +1,9 @@ +type Option = { + value: string; + label: string; +}; + +export const languageOptions: Option[] = [ + { value: "en", label: "🇺🇸 English" }, + // { value: 'el', label: '🇬🇷 Ελληνικά' }, +]; diff --git a/src/components/Layout/Navigation/Sidebar.js b/src/components/Layout/Navigation/Sidebar.js index e63fbc43d..ac3502685 100644 --- a/src/components/Layout/Navigation/Sidebar.js +++ b/src/components/Layout/Navigation/Sidebar.js @@ -10,6 +10,7 @@ import StatusContext from '../../../context/StatusContext'; import SessionContext from '../../../context/SessionContext'; import { MdNotifications } from "react-icons/md"; import ConnectionStatusIcon from './ConnectionStatusIcon'; +import LanguageSelector from '../../LanguageSelector/LanguageSelector'; const NavItem = ({ children, @@ -153,6 +154,7 @@ const Sidebar = ({ isOpen, toggle }) => {
+ {screenType !== 'mobile' && zeroSigCount !== null && sigTotal && -
- -

{zeroSigCount}/{sigTotal} Available Usages

-
+ }
)} @@ -118,12 +130,7 @@ const CredentialLayout = ({ children, title = null }) => { {screenType === 'mobile' && (

{credentialFiendlyName}

- {zeroSigCount !== null && sigTotal && -
- -

{zeroSigCount}/{sigTotal} Available Usages

-
- } +
)}
diff --git a/src/locales/en.json b/src/locales/en.json index d571471aa..b5240e8ef 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -135,6 +135,7 @@ "deletePopupMessage": "Are you sure you want to delete the {{credentialName}} credential?
If you delete it, all the presentations that include this VC will be removed from your history.", "description": "View all of your credentials", "details": { + "availableUsages": "Available Usages", "description": "View all the information about the chosen credential", "expired": "This Credential has been expired" }, From 7b084e9675e60055cffa0f2978e170386d178a9a Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 19 Nov 2024 15:39:24 +0200 Subject: [PATCH 033/162] Fix center login content and position section at the bottom --- src/components/Auth/LoginLayout.tsx | 52 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/components/Auth/LoginLayout.tsx b/src/components/Auth/LoginLayout.tsx index 19b4b7ba6..be6cd988e 100644 --- a/src/components/Auth/LoginLayout.tsx +++ b/src/components/Auth/LoginLayout.tsx @@ -4,43 +4,43 @@ import { Trans, useTranslation } from 'react-i18next'; import * as config from '../../config'; import logo from '../../assets/images/logo.png'; - export default function LoginLayout({ children, heading }: { children: React.ReactNode, heading: React.ReactNode }) { const { t } = useTranslation(); return ( -
-
-
- - logo - +
+
+ + logo + -

- {heading} -

+

+ {heading} +

-
- {children} -
+
+ {children}
-
-

- + +

+

+ - }} - /> -

-

{config.APP_VERSION}

-
-
+ ) + }} + /> +

+

{config.APP_VERSION}

+
); } From c00c60c32ff19610c4b75842ec6c63ba664078cc Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 19 Nov 2024 15:48:04 +0200 Subject: [PATCH 034/162] Hide app version from UI but keep it accessible via inspect --- src/components/Auth/LoginLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Auth/LoginLayout.tsx b/src/components/Auth/LoginLayout.tsx index be6cd988e..7ed38df15 100644 --- a/src/components/Auth/LoginLayout.tsx +++ b/src/components/Auth/LoginLayout.tsx @@ -39,7 +39,7 @@ export default function LoginLayout({ children, heading }: { children: React.Rea }} />

-

{config.APP_VERSION}

+

v{config.APP_VERSION}

); From fb365be2d2bb4d7bebdddeff2e4dd50ac89c8c4d Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 19 Nov 2024 16:41:19 +0200 Subject: [PATCH 035/162] Update package.json version to 0.2.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb6553f91..e8887d1db 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", From 869464f80695ee14a38ea553b573bffff0e3e779 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Wed, 20 Nov 2024 14:52:04 +0200 Subject: [PATCH 036/162] handle errors when metadata cannot be fetched for a specific issuer through the OpenID4VCIHelper dependency --- src/context/ContainerContext.tsx | 14 ++++++----- src/lib/interfaces/IOpenID4VCIHelper.ts | 4 ++-- src/lib/services/OpenID4VCIHelper.ts | 31 +++++++++++++++++-------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/context/ContainerContext.tsx b/src/context/ContainerContext.tsx index b4ab7df39..9b4cd52dc 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/lib/interfaces/IOpenID4VCIHelper.ts b/src/lib/interfaces/IOpenID4VCIHelper.ts index 603d94452..9ba668173 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/services/OpenID4VCIHelper.ts b/src/lib/services/OpenID4VCIHelper.ts index 1af128627..97201e782 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; + } + } } From a39f3ff02afefde3b87eb0cfa5a05ddbe88c6e0f Mon Sep 17 00:00:00 2001 From: kkmanos Date: Wed, 20 Nov 2024 16:45:01 +0200 Subject: [PATCH 037/162] support combined presentation --- src/hooks/useCheckURL.ts | 5 ---- src/lib/interfaces/IOpenID4VPRelyingParty.ts | 1 - src/lib/services/OpenID4VPRelyingParty.ts | 28 +++++++++++++------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/hooks/useCheckURL.ts b/src/hooks/useCheckURL.ts index c200cf99b..502482e53 100644 --- a/src/hooks/useCheckURL.ts +++ b/src/hooks/useCheckURL.ts @@ -81,11 +81,6 @@ function useCheckURL(urlToCheck: string): { setTypeMessagePopup('error'); setMessagePopup(true); } - else if (result.err === HandleAuthorizationRequestError.ONLY_ONE_INPUT_DESCRIPTOR_IS_SUPPORTED) { - setTextMessagePopup({ title: `${t('messagePopup.onlyOneInputDescriptor.title')}`, description: `${t('messagePopup.onlyOneInputDescriptor.description')}` }); - setTypeMessagePopup('error'); - setMessagePopup(true); - } else if (result.err === HandleAuthorizationRequestError.NONTRUSTED_VERIFIER) { setTextMessagePopup({ title: `${t('messagePopup.nonTrustedVerifier.title')}`, description: `${t('messagePopup.nonTrustedVerifier.description')}` }); setTypeMessagePopup('error'); diff --git a/src/lib/interfaces/IOpenID4VPRelyingParty.ts b/src/lib/interfaces/IOpenID4VPRelyingParty.ts index 6aa80313a..85ea702fb 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/OpenID4VPRelyingParty.ts b/src/lib/services/OpenID4VPRelyingParty.ts index 2856efac0..d2a8fb882 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); From c76b1bb69e8acba3a20ac860e642b31864a61a48 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Wed, 20 Nov 2024 17:36:39 +0200 Subject: [PATCH 038/162] Fix dark mode batch issuance style --- src/components/Credentials/CredentialLayout.js | 8 ++++---- src/components/Credentials/UsagesRibbon.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/Credentials/CredentialLayout.js b/src/components/Credentials/CredentialLayout.js index bc8150433..04f166831 100644 --- a/src/components/Credentials/CredentialLayout.js +++ b/src/components/Credentials/CredentialLayout.js @@ -69,12 +69,12 @@ const CredentialLayout = ({ children, title = null }) => { const UsageStats = ({ zeroSigCount, sigTotal }) => { if (zeroSigCount === null || sigTotal === null) return null; - const usageClass = zeroSigCount === 0 ? 'text-orange-600' : 'text-green-600'; + const usageClass = zeroSigCount === 0 ? 'text-orange-600 dark:text-orange-500' : 'text-green-600 dark:text-green-500'; return ( -
- -

+

+ +

{zeroSigCount} /{sigTotal} {t('pageCredentials.details.availableUsages')}

diff --git a/src/components/Credentials/UsagesRibbon.js b/src/components/Credentials/UsagesRibbon.js index 888721390..ec3502b7f 100644 --- a/src/components/Credentials/UsagesRibbon.js +++ b/src/components/Credentials/UsagesRibbon.js @@ -8,7 +8,7 @@ const UsagesRibbon = ({ vcEntityInstances }) => { return ( <> {vcEntityInstances && -
+
{zeroSigCount}
} From 842d1d1c0ef7d65b6fd9dc9243825d7c5572acdd Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 22 Nov 2024 09:03:41 +0200 Subject: [PATCH 039/162] Add global background styles to mitigate white screen flash --- src/index.css | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/index.css b/src/index.css index 1c6adcf15..8654c2023 100644 --- a/src/index.css +++ b/src/index.css @@ -9,6 +9,22 @@ -moz-osx-font-smoothing: grayscale; } +/* Global Background */ +html, +body { + background-color: rgb(243 244 246); + /* Light mode background */ +} + +@media (prefers-color-scheme: dark) { + + html, + body { + background-color: rgb(17 24 39); + /* Dark mode background */ + } +} + /* Custom scrollbar */ .custom-scrollbar::-webkit-scrollbar { width: 10px; From 231af706899b10baeecbf19e94093e80c8c9444c Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 22 Nov 2024 09:04:07 +0200 Subject: [PATCH 040/162] Optimize spinner loading to prevent delays and improve UX --- src/components/Shared/Spinner.js | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/components/Shared/Spinner.js b/src/components/Shared/Spinner.js index 99f7bc242..4639011ab 100644 --- a/src/components/Shared/Spinner.js +++ b/src/components/Shared/Spinner.js @@ -1,25 +1,16 @@ -import React, { useState, useEffect } from 'react'; -import logo from '../../assets/images/logo.png'; - -function Spinner() { - const [imageLoaded, setImageLoaded] = useState(false); - - useEffect(() => { - const img = new Image(); - img.src = logo; - img.onload = () => setImageLoaded(true); - }, []); +import React from 'react'; +const Spinner = () => { return ( -
+
-
-
- Loading... setImageLoaded(true)} /> +
+
+ Loading...
); -} +}; export default Spinner; From e8757ff24d8bc9131ed948530188ea4d3a161278 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Fri, 22 Nov 2024 15:31:04 +0200 Subject: [PATCH 041/162] exported getSdJwtVcMetadata on utils to isolate the way sd jwt vc metadata are fetched --- src/context/ContainerContext.tsx | 21 +++++++++++-------- src/lib/utils/getSdJwtVcMetadata.ts | 32 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 src/lib/utils/getSdJwtVcMetadata.ts diff --git a/src/context/ContainerContext.tsx b/src/context/ContainerContext.tsx index 9b4cd52dc..02a9ffc2c 100644 --- a/src/context/ContainerContext.tsx +++ b/src/context/ContainerContext.tsx @@ -18,13 +18,12 @@ import SessionContext from "../context/SessionContext"; import { ICredentialParserRegistry } from "../lib/interfaces/ICredentialParser"; import { CredentialParserRegistry } from "../lib/services/CredentialParserRegistry"; import { parseSdJwtCredential } from "../functions/parseSdJwtCredential"; -import { CredentialConfigurationSupported } from "../lib/schemas/CredentialConfigurationSupportedSchema"; import { generateRandomIdentifier } from "../lib/utils/generateRandomIdentifier"; -import { fromBase64 } from "../util"; import defaultCredentialImage from "../assets/images/cred.png"; import renderSvgTemplate from "../components/Credentials/RenderSvgTemplate"; import renderCustomSvgTemplate from "../components/Credentials/RenderCustomSvgTemplate"; import StatusContext from "./StatusContext"; +import { getSdJwtVcMetadata } from "../lib/utils/getSdJwtVcMetadata"; export type ContainerContextValue = { httpProxy: IHttpProxy, @@ -111,12 +110,16 @@ export const ContainerContextProvider = ({ children }) => { .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 && - credentialHeader.vctm.display[0] && credentialHeader.vctm.display[0][defaultLocale] && - credentialHeader.vctm.display[0][defaultLocale]?.rendering?.svg_templates.length > 0 ? - credentialHeader.vctm.display[0][defaultLocale]?.rendering?.svg_templates[0]?.uri + const getSdJwtVcMetadataResult = await getSdJwtVcMetadata(rawCredential); + + + const credentialImageSvgTemplateURL = !('error' in getSdJwtVcMetadataResult) && + getSdJwtVcMetadataResult.credentialMetadata?.display && + getSdJwtVcMetadataResult.credentialMetadata?.display?.length != 0 && + getSdJwtVcMetadataResult.credentialMetadata.display.filter((d) => d.lang === defaultLocale)[0] && + getSdJwtVcMetadataResult.credentialMetadata.display.filter((d) => d.lang === defaultLocale)[0]?.rendering?.svg_templates.length > 0 ? + getSdJwtVcMetadataResult.credentialMetadata.display.filter((d) => d.lang === defaultLocale)[0].rendering?.svg_templates[0]?.uri : null; let credentialFriendlyName = credentialHeader?.vctm?.display?.[0]?.[defaultLocale]?.name @@ -127,9 +130,9 @@ export const ContainerContextProvider = ({ children }) => { || credentialConfigurationSupportedObj?.display?.[0]?.description || "Credential"; - const svgContent = await renderSvgTemplate({ beautifiedForm: result.beautifiedForm, credentialImageSvgTemplateURL: credentialImageSvgTemplateURL,claims:credentialHeader?.vctm?.claims }); + const svgContent = await renderSvgTemplate({ beautifiedForm: result.beautifiedForm, credentialImageSvgTemplateURL: credentialImageSvgTemplateURL, claims: getSdJwtVcMetadataResult?.metadata?.claims }); - const simple = credentialHeader?.vctm?.display?.[0]?.[defaultLocale]?.rendering?.simple; + const simple = sdjwtvcMetadataDocument.display?.[0]?.[defaultLocale]?.rendering?.simple; const issuerMetadata = credentialConfigurationSupportedObj?.display?.[0]; if (svgContent) { diff --git a/src/lib/utils/getSdJwtVcMetadata.ts b/src/lib/utils/getSdJwtVcMetadata.ts new file mode 100644 index 000000000..9ba8746f7 --- /dev/null +++ b/src/lib/utils/getSdJwtVcMetadata.ts @@ -0,0 +1,32 @@ +import axios from "axios"; +import { fromBase64 } from "../../util"; + +/** uses https://datatracker.ietf.org/doc/draft-ietf-oauth-sd-jwt-vc/05/ to fetch the metadata */ +export async function getSdJwtVcMetadata(credential: string): Promise<{ credentialMetadata: any } | { error: "NOT_FOUND" }> { + try { + const credentialHeader = JSON.parse(new TextDecoder().decode(fromBase64(credential.split('.')[0] as string))); + const credentialPayload = JSON.parse(new TextDecoder().decode(fromBase64(credential.split('.')[1] as string))); + + if (credentialHeader.vctm) { + const sdjwtvcMetadataDocument = credentialHeader.vctm.map((encodedMetadataDocument: string) => + JSON.parse(new TextDecoder().decode(fromBase64(encodedMetadataDocument))) + ).filter(((metadataDocument) => metadataDocument.vct === credentialPayload.vct))[0]; + if (sdjwtvcMetadataDocument) { + return { credentialMetadata: sdjwtvcMetadataDocument }; + } + } + + + // use vct to fetch metadata if hosted + const fetchResult = (await axios.get(credentialPayload.vct).catch(() => null)); + if (fetchResult && fetchResult.data.vct === credentialPayload.vct) { + return { credentialMetadata: fetchResult.data }; + } + + return { error: "NOT_FOUND" }; + } + catch(err) { + console.log(err); + return { error: "NOT_FOUND" }; + } +} From d6912804892cc0a101b85922fba41174430b05f0 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 22 Nov 2024 22:15:53 +0200 Subject: [PATCH 042/162] Enhance spinner handling and improve lazy loading strategy --- src/App.js | 21 +++++++++++++++------ src/components/Shared/Spinner.js | 26 +++++++++++++++++++++----- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/App.js b/src/App.js index 0f2a57a41..3f938260a 100644 --- a/src/App.js +++ b/src/App.js @@ -57,7 +57,15 @@ const reactLazyWithNonDefaultExports = (load, ...names) => { return defaultExport; }; -const Layout = React.lazy(() => import('./components/Layout/Layout')); +const lazyWithDelay = (importFunction, delay = 1000) => { + return React.lazy(() => + Promise.all([ + importFunction(), + new Promise((resolve) => setTimeout(resolve, delay)), + ]).then(([module]) => module) + ); +}; + const MessagePopup = React.lazy(() => import('./components/Popups/MessagePopup')); const PinInputPopup = React.lazy(() => import('./components/Popups/PinInput')); const PrivateRoute = reactLazyWithNonDefaultExports( @@ -65,20 +73,21 @@ const PrivateRoute = reactLazyWithNonDefaultExports( 'NotificationPermissionWarning', ); const SelectCredentialsPopup = React.lazy(() => import('./components/Popups/SelectCredentialsPopup')); - const AddCredentials = React.lazy(() => import('./pages/AddCredentials/AddCredentials')); const Credential = React.lazy(() => import('./pages/Home/Credential')); const CredentialHistory = React.lazy(() => import('./pages/Home/CredentialHistory')); const History = React.lazy(() => import('./pages/History/History')); const HistoryDetail = React.lazy(() => import('./pages/History/HistoryDetail')); const Home = React.lazy(() => import('./pages/Home/Home')); -const Login = React.lazy(() => import('./pages/Login/Login')); -const LoginState = React.lazy(() => import('./pages/Login/LoginState')); -const NotFound = React.lazy(() => import('./pages/NotFound/NotFound')); const SendCredentials = React.lazy(() => import('./pages/SendCredentials/SendCredentials')); const Settings = React.lazy(() => import('./pages/Settings/Settings')); const VerificationResult = React.lazy(() => import('./pages/VerificationResult/VerificationResult')); +const Layout = lazyWithDelay(() => import('./components/Layout/Layout'), 400); +const Login = lazyWithDelay(() => import('./pages/Login/Login'), 400); +const LoginState = lazyWithDelay(() => import('./pages/Login/LoginState'), 400); +const NotFound = lazyWithDelay(() => import('./pages/NotFound/NotFound'), 400); + function App() { const location = useLocation(); const [url, setUrl] = useState(window.location.href); @@ -133,7 +142,7 @@ function App() { - }> + }> diff --git a/src/components/Shared/Spinner.js b/src/components/Shared/Spinner.js index 4639011ab..d39f058a1 100644 --- a/src/components/Shared/Spinner.js +++ b/src/components/Shared/Spinner.js @@ -1,12 +1,28 @@ import React from 'react'; -const Spinner = () => { +const Spinner = ({ size = 'large' }) => { + + const sizes = { + 'large': { + container: 'h-40 w-40', + image: 'w-24', + opacity: 'opacity-100', + }, + 'small': { + container: 'h-20 w-20', + image: 'w-12', + opacity: 'opacity-50', + }, + }; + + const currentSize = sizes[size] || sizes.large; + return (
-
-
-
- Loading... +
+
+
+ Loading...
From 047b8085ce97f28def35a022a378442730c72a32 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Sun, 24 Nov 2024 09:02:10 +0200 Subject: [PATCH 043/162] Update credential parse extraction values base on getSdJwtVcMetadataResult --- src/context/ContainerContext.tsx | 33 +++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/context/ContainerContext.tsx b/src/context/ContainerContext.tsx index 02a9ffc2c..9710f53aa 100644 --- a/src/context/ContainerContext.tsx +++ b/src/context/ContainerContext.tsx @@ -113,26 +113,29 @@ export const ContainerContextProvider = ({ children }) => { const getSdJwtVcMetadataResult = await getSdJwtVcMetadata(rawCredential); + // Validate the metadata object + const isValidMetadata = !('error' in getSdJwtVcMetadataResult) && getSdJwtVcMetadataResult.credentialMetadata; - const credentialImageSvgTemplateURL = !('error' in getSdJwtVcMetadataResult) && - getSdJwtVcMetadataResult.credentialMetadata?.display && - getSdJwtVcMetadataResult.credentialMetadata?.display?.length != 0 && - getSdJwtVcMetadataResult.credentialMetadata.display.filter((d) => d.lang === defaultLocale)[0] && - getSdJwtVcMetadataResult.credentialMetadata.display.filter((d) => d.lang === defaultLocale)[0]?.rendering?.svg_templates.length > 0 ? - getSdJwtVcMetadataResult.credentialMetadata.display.filter((d) => d.lang === defaultLocale)[0].rendering?.svg_templates[0]?.uri + // Extract metadata and claims + const metadata = isValidMetadata && getSdJwtVcMetadataResult.credentialMetadata?.display?.find((d) => d.lang === defaultLocale) || null; + const claims = isValidMetadata && getSdJwtVcMetadataResult.credentialMetadata?.claims?.length + ? getSdJwtVcMetadataResult.credentialMetadata.claims : null; - let credentialFriendlyName = credentialHeader?.vctm?.display?.[0]?.[defaultLocale]?.name - || credentialConfigurationSupportedObj?.display?.[0]?.name - || "Credential"; + // Extract key values + const credentialImageSvgTemplateURL = metadata?.rendering?.svg_templates?.[0]?.uri || null; + const credentialFriendlyName = metadata?.name || "Credential"; + const credentialDescription = metadata?.description || "Verifiable Credential"; + const simple = metadata?.rendering?.simple || null; - let credentialDescription = credentialHeader?.vctm?.display?.[0]?.[defaultLocale]?.description - || credentialConfigurationSupportedObj?.display?.[0]?.description - || "Credential"; - - const svgContent = await renderSvgTemplate({ beautifiedForm: result.beautifiedForm, credentialImageSvgTemplateURL: credentialImageSvgTemplateURL, claims: getSdJwtVcMetadataResult?.metadata?.claims }); + // Render SVG content + const svgContent = await renderSvgTemplate({ + beautifiedForm: result.beautifiedForm, + credentialImageSvgTemplateURL, + claims + }); - const simple = sdjwtvcMetadataDocument.display?.[0]?.[defaultLocale]?.rendering?.simple; + // Extract issuer metadata const issuerMetadata = credentialConfigurationSupportedObj?.display?.[0]; if (svgContent) { From 4fc40f96740cff75b2e77bec8cd104cc611d0021 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Sun, 24 Nov 2024 09:03:01 +0200 Subject: [PATCH 044/162] Fix code format of getSdJwtVcMetadata --- src/lib/utils/getSdJwtVcMetadata.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/utils/getSdJwtVcMetadata.ts b/src/lib/utils/getSdJwtVcMetadata.ts index 9ba8746f7..9ca29f953 100644 --- a/src/lib/utils/getSdJwtVcMetadata.ts +++ b/src/lib/utils/getSdJwtVcMetadata.ts @@ -6,26 +6,26 @@ export async function getSdJwtVcMetadata(credential: string): Promise<{ credenti try { const credentialHeader = JSON.parse(new TextDecoder().decode(fromBase64(credential.split('.')[0] as string))); const credentialPayload = JSON.parse(new TextDecoder().decode(fromBase64(credential.split('.')[1] as string))); - + if (credentialHeader.vctm) { - const sdjwtvcMetadataDocument = credentialHeader.vctm.map((encodedMetadataDocument: string) => + const sdjwtvcMetadataDocument = credentialHeader.vctm.map((encodedMetadataDocument: string) => JSON.parse(new TextDecoder().decode(fromBase64(encodedMetadataDocument))) ).filter(((metadataDocument) => metadataDocument.vct === credentialPayload.vct))[0]; if (sdjwtvcMetadataDocument) { return { credentialMetadata: sdjwtvcMetadataDocument }; } } - - + + // use vct to fetch metadata if hosted const fetchResult = (await axios.get(credentialPayload.vct).catch(() => null)); if (fetchResult && fetchResult.data.vct === credentialPayload.vct) { return { credentialMetadata: fetchResult.data }; } - + return { error: "NOT_FOUND" }; } - catch(err) { + catch (err) { console.log(err); return { error: "NOT_FOUND" }; } From 92a61db225461ec96687bc2ed9b0e9ce8a26658e Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Sun, 24 Nov 2024 17:12:54 +0200 Subject: [PATCH 045/162] Add null check for vcEntityList and ensure robust rendering of credentials --- src/context/CredentialsContext.js | 2 +- src/pages/Home/Home.js | 92 ++++++++++++++++--------------- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js index 6685a6078..2dd2c46e1 100644 --- a/src/context/CredentialsContext.js +++ b/src/context/CredentialsContext.js @@ -7,7 +7,7 @@ const CredentialsContext = createContext(); export const CredentialsProvider = ({ children }) => { const { api } = useContext(SessionContext); - const [vcEntityList, setVcEntityList] = useState([]); + const [vcEntityList, setVcEntityList] = useState(null); const [latestCredentials, setLatestCredentials] = useState(new Set()); const [currentSlide, setCurrentSlide] = useState(1); diff --git a/src/pages/Home/Home.js b/src/pages/Home/Home.js index 5f2d06d54..8fd1b2590 100644 --- a/src/pages/Home/Home.js +++ b/src/pages/Home/Home.js @@ -59,53 +59,55 @@ const Home = () => { {screenType !== 'mobile' && (

{t('pageCredentials.description')}

)} -
- {vcEntityList.length === 0 ? ( -
- -
- ) : ( - <> - {screenType !== 'desktop' ? ( - <> -
- setCurrentSlide(currentIndex + 1)} - /> - - {/* Update HistoryList based on current slide */} - {vcEntityList[currentSlide - 1] && ( - + {vcEntityList.length === 0 ? ( +
+ +
+ ) : ( + <> + {screenType !== 'desktop' ? ( + <> +
+ setCurrentSlide(currentIndex + 1)} /> - )} + + {/* Update HistoryList based on current slide */} + {vcEntityList[currentSlide - 1] && ( + + )} +
+ + ) : ( +
+ {vcEntityList.map((vcEntity) => ( + + ))} +
- - ) : ( -
- {vcEntityList.map((vcEntity) => ( - - ))} - -
- )} - - )} -
+ )} + + )} +
+ )}
); From 2d5e881c0fa9e2c00168d710b46694e0323efa27 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 25 Nov 2024 12:45:26 +0200 Subject: [PATCH 046/162] decoupled prompt for selection to call it by promptForCredentialSelection from the IOpenID4VPRelyingParty --- .../Popups/SelectCredentialsPopup.js | 60 ++++++++------ src/context/ContainerContext.tsx | 35 +++++++- src/lib/interfaces/IOpenID4VCIClient.ts | 2 +- src/lib/interfaces/IOpenID4VPRelyingParty.ts | 1 + src/lib/services/OpenID4VCIClient.ts | 82 ++++++++----------- src/lib/services/OpenID4VCIClientFactory.ts | 5 +- src/lib/services/OpenID4VPRelyingParty.ts | 9 +- 7 files changed, 114 insertions(+), 80 deletions(-) diff --git a/src/components/Popups/SelectCredentialsPopup.js b/src/components/Popups/SelectCredentialsPopup.js index ee043201b..87a84de81 100644 --- a/src/components/Popups/SelectCredentialsPopup.js +++ b/src/components/Popups/SelectCredentialsPopup.js @@ -57,27 +57,27 @@ const StepBar = ({ totalSteps, currentStep, stepTitles }) => { ); }; -function SelectCredentialsPopup({ isOpen, setIsOpen, setSelectionMap, conformantCredentialsMap, verifierDomainName }) { +function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopup }) { + const { api } = useContext(SessionContext); + const container = useContext(ContainerContext); const [vcEntities, setVcEntities] = useState([]); - const navigate = useNavigate(); const { t } = useTranslation(); - const keys = useMemo(() => Object.keys(conformantCredentialsMap), [conformantCredentialsMap]); - const stepTitles = useMemo(() => Object.keys(conformantCredentialsMap).map(key => key), [conformantCredentialsMap]); + const keys = useMemo(() => popupState?.options ? Object.keys(popupState.options.conformantCredentialsMap) : null, [popupState]); + const stepTitles = useMemo(() => popupState?.options ? Object.keys(popupState.options.conformantCredentialsMap).map(key => key) : null, [popupState]); const [currentIndex, setCurrentIndex] = useState(0); const [currentSelectionMap, setCurrentSelectionMap] = useState({}); const [requestedFields, setRequestedFields] = useState([]); const [showAllFields, setShowAllFields] = useState(false); const [selectedCredential, setSelectedCredential] = useState(null); - const container = useContext(ContainerContext); const screenType = useScreenType(); const [currentSlide, setCurrentSlide] = useState(1); useEffect(() => { const getData = async () => { - if (currentIndex === Object.keys(conformantCredentialsMap).length) { - setSelectionMap(currentSelectionMap); - setIsOpen(false); + if (currentIndex === Object.keys(popupState.options.conformantCredentialsMap).length) { + setPopupState({ isOpen: false }); + popupState.resolve(new Map(Object.entries(currentSelectionMap))); return; } @@ -95,33 +95,41 @@ function SelectCredentialsPopup({ isOpen, setIsOpen, setSelectionMap, conformant ); const filteredVcEntities = vcEntities.filter(vcEntity => - conformantCredentialsMap[keys[currentIndex]].credentials.includes(vcEntity.credentialIdentifier) + popupState.options.conformantCredentialsMap[keys[currentIndex]].credentials.includes(vcEntity.credentialIdentifier) ); - setRequestedFields(conformantCredentialsMap[keys[currentIndex]].requestedFields); + setRequestedFields(popupState.options.conformantCredentialsMap[keys[currentIndex]].requestedFields); setVcEntities(filteredVcEntities); } catch (error) { console.error('Failed to fetch data', error); } }; - getData(); + if (popupState?.options) { + console.log("opts = ", popupState.options) + getData(); + } }, [ api, - conformantCredentialsMap, currentIndex, currentSelectionMap, keys, - setSelectionMap, - setIsOpen, - container.credentialParserRegistry, + container, + popupState ]); useEffect(() => { - const currentKey = keys[currentIndex]; - const selectedId = currentSelectionMap[currentKey]; - setSelectedCredential(selectedId); - }, [currentIndex, currentSelectionMap, keys]); + console.log("Detected change of popup state inside the SelectCredentialsPopup") + console.log(popupState) + }, [popupState]) + + useEffect(() => { + if (popupState?.options) { + const currentKey = keys[currentIndex]; + const selectedId = currentSelectionMap[currentKey]; + setSelectedCredential(selectedId); + } + }, [currentIndex, currentSelectionMap, keys, popupState]); const goToNextSelection = () => { setShowAllFields(false); @@ -147,11 +155,13 @@ function SelectCredentialsPopup({ isOpen, setIsOpen, setSelectionMap, conformant }; const onClose = () => { - setIsOpen(false); - navigate('/'); + // setIsOpen(false); + setPopupState({ isOpen: false }); + popupState.reject(); + // navigate('/'); } - if (!isOpen) { + if (!popupState?.isOpen) { return null; }; @@ -196,7 +206,7 @@ function SelectCredentialsPopup({ isOpen, setIsOpen, setSelectionMap, conformant })(); return ( - +
{stepTitles && ( @@ -210,13 +220,13 @@ function SelectCredentialsPopup({ isOpen, setIsOpen, setSelectionMap, conformant )}
- {requestedFieldsText && requestedFields.length > 0 && verifierDomainName && ( + {requestedFieldsText && requestedFields.length > 0 && popupState.options.verifierDomainName && ( <>

}} /> diff --git a/src/context/ContainerContext.tsx b/src/context/ContainerContext.tsx index 9b4cd52dc..149726676 100644 --- a/src/context/ContainerContext.tsx +++ b/src/context/ContainerContext.tsx @@ -25,6 +25,7 @@ import defaultCredentialImage from "../assets/images/cred.png"; import renderSvgTemplate from "../components/Credentials/RenderSvgTemplate"; import renderCustomSvgTemplate from "../components/Credentials/RenderCustomSvgTemplate"; import StatusContext from "./StatusContext"; +import SelectCredentialsPopup from "../components/Popups/SelectCredentialsPopup"; export type ContainerContextValue = { httpProxy: IHttpProxy, @@ -47,11 +48,35 @@ const defaultLocale = 'en-US'; export const ContainerContextProvider = ({ children }) => { const { isOnline } = useContext(StatusContext); const { isLoggedIn, api, keystore } = useContext(SessionContext); - const [container, setContainer] = useState(null); const [isInitialized, setIsInitialized] = useState(false); // New flag const [shouldUseCache, setShouldUseCache] = useState(true) + + const [popupState, setPopupState] = useState({ + isOpen: false, + options: null, + resolve: (value: unknown) => { }, + reject: () => { }, + }); + + const showPopup = (options): Promise> => + new Promise((resolve, reject) => { + setPopupState({ + isOpen: true, + options, + resolve, + reject, + }); + }); + + const hidePopup = () => { + setPopupState((prevState) => ({ + ...prevState, + isOpen: false, + })); + }; + useEffect(() => { window.addEventListener('generatedProof', (e) => { setIsInitialized(false); @@ -127,7 +152,7 @@ export const ContainerContextProvider = ({ children }) => { || credentialConfigurationSupportedObj?.display?.[0]?.description || "Credential"; - const svgContent = await renderSvgTemplate({ beautifiedForm: result.beautifiedForm, credentialImageSvgTemplateURL: credentialImageSvgTemplateURL,claims:credentialHeader?.vctm?.claims }); + const svgContent = await renderSvgTemplate({ beautifiedForm: result.beautifiedForm, credentialImageSvgTemplateURL: credentialImageSvgTemplateURL, claims: credentialHeader?.vctm?.claims }); const simple = credentialHeader?.vctm?.display?.[0]?.[defaultLocale]?.rendering?.simple; const issuerMetadata = credentialConfigurationSupportedObj?.display?.[0]; @@ -210,12 +235,17 @@ export const ContainerContextProvider = ({ children }) => { audience, issuanceDate: new Date().toISOString(), }); + }, + + async function showCredentialSelectionPopup(conformantCredentialsMap: Map, verifierDomainName: string): Promise> { + return showPopup({ conformantCredentialsMap, verifierDomainName }); } ); cont.register('OpenID4VCIClientFactory', OpenID4VCIClientFactory, cont.resolve('HttpProxy'), cont.resolve('OpenID4VCIClientStateRepository'), + cont.resolve('OpenID4VPRelyingParty'), async (cNonce: string, audience: string, clientId: string): Promise<{ jws: string }> => { const [{ proof_jwts: [proof_jwt] }, newPrivateData, keystoreCommit] = await keystore.generateOpenid4vciProofs([{ nonce: cNonce, audience, issuer: clientId }]); await api.updatePrivateData(newPrivateData); @@ -284,6 +314,7 @@ export const ContainerContextProvider = ({ children }) => { return ( {children} + ); } diff --git a/src/lib/interfaces/IOpenID4VCIClient.ts b/src/lib/interfaces/IOpenID4VCIClient.ts index 0186311b0..0c78563d9 100644 --- a/src/lib/interfaces/IOpenID4VCIClient.ts +++ b/src/lib/interfaces/IOpenID4VCIClient.ts @@ -3,6 +3,6 @@ import { CredentialConfigurationSupported } from "../schemas/CredentialConfigura export interface IOpenID4VCIClient { handleCredentialOffer(credentialOfferURL: string, userHandleB64u: string): Promise<{ credentialIssuer: string, selectedCredentialConfigurationId: string; issuer_state?: string }>; getAvailableCredentialConfigurations(): Promise>; - generateAuthorizationRequest(credentialConfigurationId: string, userHandleB64u: string, issuer_state?: string): Promise<{ url?: string, client_id?: string, request_uri?: string }>; + generateAuthorizationRequest(credentialConfigurationId: string, userHandleB64u: string, issuer_state?: string): Promise<{ url?: string }>; handleAuthorizationResponse(url: string, userHandleB64U: string, dpopNonceHeader?: string): Promise; } diff --git a/src/lib/interfaces/IOpenID4VPRelyingParty.ts b/src/lib/interfaces/IOpenID4VPRelyingParty.ts index 85ea702fb..105536524 100644 --- a/src/lib/interfaces/IOpenID4VPRelyingParty.ts +++ b/src/lib/interfaces/IOpenID4VPRelyingParty.ts @@ -1,5 +1,6 @@ export interface IOpenID4VPRelyingParty { handleAuthorizationRequest(url: string): Promise<{ conformantCredentialsMap: Map, verifierDomainName: string } | { err: HandleAuthorizationRequestError }>; + promptForCredentialSelection(conformantCredentialsMap: any, verifierDomainName: string): Promise>; sendAuthorizationResponse(selectionMap: Map): Promise<{ url?: string }>; } diff --git a/src/lib/services/OpenID4VCIClient.ts b/src/lib/services/OpenID4VCIClient.ts index 307015ce1..7545b556d 100644 --- a/src/lib/services/OpenID4VCIClient.ts +++ b/src/lib/services/OpenID4VCIClient.ts @@ -1,7 +1,6 @@ import { IOpenID4VCIClient } from '../interfaces/IOpenID4VCIClient'; import { IHttpProxy } from '../interfaces/IHttpProxy'; import { ClientConfig } from '../types/ClientConfig'; -import pkce from 'pkce-challenge'; import { IOpenID4VCIClientStateRepository } from '../interfaces/IOpenID4VCIClientStateRepository'; import { CredentialConfigurationSupported } from '../schemas/CredentialConfigurationSupportedSchema'; import { OpenID4VCIClientState } from '../types/OpenID4VCIClientState'; @@ -12,18 +11,28 @@ import * as jose from 'jose'; import { generateRandomIdentifier } from '../utils/generateRandomIdentifier'; import * as config from '../../config'; import { VerifiableCredentialFormat } from '../schemas/vc'; +import { IOpenID4VCIAuthorizationRequest } from '../interfaces/IOpenID4VCIAuthorizationRequest'; +import { OpenID4VCIPushedAuthorizationRequest } from './OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest'; +import { OpenID4VCIAuthorizationRequestForFirstPartyApplications } from './OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications'; +import { IOpenID4VPRelyingParty } from '../interfaces/IOpenID4VPRelyingParty'; const redirectUri = config.OPENID4VCI_REDIRECT_URI as string; export class OpenID4VCIClient implements IOpenID4VCIClient { + private openID4VCIPushedAuthorizationRequest: IOpenID4VCIAuthorizationRequest; + private openID4VCIAuthorizationRequestForFirstPartyApplications: IOpenID4VCIAuthorizationRequest; + constructor(private config: ClientConfig, private httpProxy: IHttpProxy, private openID4VCIClientStateRepository: IOpenID4VCIClientStateRepository, + private openID4VPRelyingParty: IOpenID4VPRelyingParty, private generateNonceProof: (cNonce: string, audience: string, clientId: string) => Promise<{ jws: string }>, private storeCredential: (c: StorableCredential) => Promise, - private authorizationRequestModifier: (credentialIssuerIdentifier: string, url: string, request_uri?: string, client_id?: string) => Promise<{ url: string }> = async (_credentialIssuerIdentifier: string, url: string) => ({ url }), - ) { } + ) { + this.openID4VCIPushedAuthorizationRequest = new OpenID4VCIPushedAuthorizationRequest(this.httpProxy, this.openID4VCIClientStateRepository); + this.openID4VCIAuthorizationRequestForFirstPartyApplications = new OpenID4VCIAuthorizationRequestForFirstPartyApplications(this.httpProxy, this.openID4VCIClientStateRepository, this.openID4VPRelyingParty); + } async handleCredentialOffer(credentialOfferURL: string, userHandleB64u: string): Promise<{ credentialIssuer: string, selectedCredentialConfigurationId: string; issuer_state?: string }> { const parsedUrl = new URL(credentialOfferURL); @@ -70,7 +79,7 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { return this.config.credentialIssuerMetadata.credential_configurations_supported } - async generateAuthorizationRequest(credentialConfigurationId: string, userHandleB64u: string, issuer_state?: string): Promise<{ url?: string; client_id?: string; request_uri?: string; }> { + async generateAuthorizationRequest(credentialConfigurationId: string, userHandleB64u: string, issuer_state?: string): Promise<{ url?: string; }> { await this.openID4VCIClientStateRepository.cleanupExpired(userHandleB64u); try { // attempt to get credentials using active session @@ -84,51 +93,30 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { } catch (err) { console.error(err) } - const { code_challenge, code_verifier } = await pkce(); - - const formData = new URLSearchParams(); - - const selectedCredentialConfigurationSupported = this.config.credentialIssuerMetadata.credential_configurations_supported[credentialConfigurationId]; - formData.append("scope", selectedCredentialConfigurationSupported.scope); - - formData.append("response_type", "code"); - - formData.append("client_id", this.config.clientId); - formData.append("code_challenge", code_challenge); - - formData.append("code_challenge_method", "S256"); - - // the purpose of the "id" is to provide the "state" a random factor for unlinkability and to make OpenID4VCIClientState instances unique - const state = btoa(JSON.stringify({ userHandleB64u: userHandleB64u, id: generateRandomIdentifier(12) })).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); - formData.append("state", state); - - if (issuer_state) { - formData.append("issuer_state", issuer_state); - } - - formData.append("redirect_uri", redirectUri); - let res; - try { - res = await this.httpProxy.post(this.config.authorizationServerMetadata.pushed_authorization_request_endpoint, formData.toString(), { - 'Content-Type': 'application/x-www-form-urlencoded' - }); - } - catch (err) { - throw new Error("Pushed authorization request failed ", err.response.data) + let url = null; + if (this.config.authorizationServerMetadata.require_pushed_authorization_requests && this.config.authorizationServerMetadata.pushed_authorization_request_endpoint) { + url = await this.openID4VCIPushedAuthorizationRequest.generate( + credentialConfigurationId, + userHandleB64u, + issuer_state, + { + ...this.config, + redirectUri: redirectUri + } + ); } - - const { request_uri } = res.data; - const authorizationRequestURL = `${this.config.authorizationServerMetadata.authorization_endpoint}?request_uri=${request_uri}&client_id=${this.config.clientId}` - - await this.openID4VCIClientStateRepository.create(new OpenID4VCIClientState(userHandleB64u, this.config.credentialIssuerIdentifier, state, code_verifier, credentialConfigurationId)) - - const modifiedAuthorizationRequest = await this.authorizationRequestModifier(this.config.credentialIssuerIdentifier, authorizationRequestURL, request_uri, this.config.clientId); - - return { - url: modifiedAuthorizationRequest.url, - request_uri, - client_id: this.config.clientId, + else if (this.config.authorizationServerMetadata.authorization_challenge_endpoint) { + url = await this.openID4VCIAuthorizationRequestForFirstPartyApplications.generate( + credentialConfigurationId, + userHandleB64u, + issuer_state, + { + ...this.config, + redirectUri: redirectUri + } + ); } + return { url: url } } async handleAuthorizationResponse(url: string, userHandleB64U: string, dpopNonceHeader?: string) { diff --git a/src/lib/services/OpenID4VCIClientFactory.ts b/src/lib/services/OpenID4VCIClientFactory.ts index 5d6819f35..0004cd4a1 100644 --- a/src/lib/services/OpenID4VCIClientFactory.ts +++ b/src/lib/services/OpenID4VCIClientFactory.ts @@ -3,17 +3,18 @@ import { IHttpProxy } from '../interfaces/IHttpProxy'; import { ClientConfig } from '../types/ClientConfig'; import { IOpenID4VCIClientStateRepository } from '../interfaces/IOpenID4VCIClientStateRepository'; import { StorableCredential } from '../types/StorableCredential'; +import { IOpenID4VPRelyingParty } from '../interfaces/IOpenID4VPRelyingParty'; export class OpenID4VCIClientFactory { constructor(private httpProxy: IHttpProxy, private openID4VCIClientStateRepository: IOpenID4VCIClientStateRepository, + private openID4VPRelyingParty: IOpenID4VPRelyingParty, private generateNonceProof: (cNonce: string, audience: string, clientId: string) => Promise<{ jws: string }>, private storeCredential: (c: StorableCredential) => Promise, - private authorizationRequestModifier: (credentialIssuerIdentifier: string, url: string, request_uri?: string, client_id?: string) => Promise<{ url: string }>, ) { } createClient(config: ClientConfig): OpenID4VCIClient { - return new OpenID4VCIClient(config, this.httpProxy, this.openID4VCIClientStateRepository, this.generateNonceProof, this.storeCredential, this.authorizationRequestModifier); + return new OpenID4VCIClient(config, this.httpProxy, this.openID4VCIClientStateRepository, this.openID4VPRelyingParty, this.generateNonceProof, this.storeCredential); } } diff --git a/src/lib/services/OpenID4VPRelyingParty.ts b/src/lib/services/OpenID4VPRelyingParty.ts index d2a8fb882..46f482121 100644 --- a/src/lib/services/OpenID4VPRelyingParty.ts +++ b/src/lib/services/OpenID4VPRelyingParty.ts @@ -15,16 +15,19 @@ import { BACKEND_URL, OPENID4VP_SAN_DNS_CHECK_SSL_CERTS, OPENID4VP_SAN_DNS_CHECK export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { - constructor( private openID4VPRelyingPartyStateRepository: OpenID4VPRelyingPartyStateRepository, private httpProxy: IHttpProxy, private credentialParserRegistry: ICredentialParserRegistry, private getAllStoredVerifiableCredentials: () => Promise<{ verifiableCredentials: StorableCredential[] }>, private signJwtPresentationKeystoreFn: (nonce: string, audience: string, verifiableCredentials: any[]) => Promise<{ vpjwt: string }>, - private storeVerifiablePresentation: (presentation: string, format: string, identifiersOfIncludedCredentials: string[], presentationSubmission: any, audience: string) => Promise + private storeVerifiablePresentation: (presentation: string, format: string, identifiersOfIncludedCredentials: string[], presentationSubmission: any, audience: string) => Promise, + private showCredentialSelectionPopup: (conformantCredentialsMap: any, verifierDomainName: string) => Promise>, ) { } + async promptForCredentialSelection(conformantCredentialsMap: any, verifierDomainName: string): Promise> { + return this.showCredentialSelectionPopup(conformantCredentialsMap, verifierDomainName); + } async handleAuthorizationRequest(url: string): Promise<{ conformantCredentialsMap: Map, verifierDomainName: string; } | { err: HandleAuthorizationRequestError }> { const authorizationRequest = new URL(url); @@ -335,7 +338,7 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { console.log("JWE = ", jwe) } else { - formData.append('vp_token', generatedVPs.length == 1 ? generatedVPs[0] : JSON.stringify(generatedVPs) ); + 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); From abbbf39d12417c732eee768d9c4356d4e273c0ae Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 25 Nov 2024 12:50:22 +0200 Subject: [PATCH 047/162] Hotfix: force reload when find new content --- src/service-worker.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/service-worker.js b/src/service-worker.js index 626489d3f..fe8f3a828 100644 --- a/src/service-worker.js +++ b/src/service-worker.js @@ -60,9 +60,7 @@ self.addEventListener('activate', (event) => { return self.clients.matchAll().then((clients) => { clients.forEach((client) => { - client.postMessage({ - type: 'NEW_CONTENT_AVAILABLE', - }); + client.navigate(client.url); }); }); }) From 7fd59ff511711a4320c1a5002d16c0315ec28928 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 25 Nov 2024 13:06:11 +0200 Subject: [PATCH 048/162] removed SelectCredentialsPopup from App.js --- src/App.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/App.js b/src/App.js index 0f2a57a41..98a3460d9 100644 --- a/src/App.js +++ b/src/App.js @@ -164,9 +164,6 @@ function App() { } /> - {showSelectCredentialsPopup && - - } {showPinInputPopup && } From d4fbb7a128a01e5bd3b27d0aa7567d3f9e76474e Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 25 Nov 2024 13:11:34 +0200 Subject: [PATCH 049/162] separated AuthorizationRequest generators using the IOpenID4VCIAuthorizationRequest --- .gitignore | 1 + src/hooks/useCheckURL.ts | 14 ++-- .../IOpenID4VCIAuthorizationRequest.ts | 12 ++++ .../OpenID4VCIPushedAuthorizationRequest.ts | 69 +++++++++++++++++++ 4 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts create mode 100644 src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts diff --git a/.gitignore b/.gitignore index 48f9e0c19..774c908ad 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ package_lock.json /build .env +.env.prod # Logs logs diff --git a/src/hooks/useCheckURL.ts b/src/hooks/useCheckURL.ts index 502482e53..2dec4a26f 100644 --- a/src/hooks/useCheckURL.ts +++ b/src/hooks/useCheckURL.ts @@ -50,7 +50,7 @@ function useCheckURL(urlToCheck: string): { .then(({ credentialIssuer, selectedCredentialConfigurationId, issuer_state }) => { return container.openID4VCIClients[credentialIssuerIdentifier].generateAuthorizationRequest(selectedCredentialConfigurationId, userHandleB64u, issuer_state); }) - .then(({ url, client_id, request_uri }) => { + .then(({ url }) => { if (url) { window.location.href = url; } @@ -90,10 +90,14 @@ function useCheckURL(urlToCheck: string): { } const { conformantCredentialsMap, verifierDomainName } = result; const jsonedMap = Object.fromEntries(conformantCredentialsMap); - window.history.replaceState({}, '', `${window.location.pathname}`); - setVerifierDomainName(verifierDomainName); - setConformantCredentialsMap(jsonedMap); - setShowSelectCredentialsPopup(true); + return container.openID4VPRelyingParty.promptForCredentialSelection(jsonedMap, verifierDomainName); + }).then((selection) => { + console.log("Selection = ", selection); + return container.openID4VPRelyingParty.sendAuthorizationResponse(selection); + }).then((res) => { + if (res.url) { + window.location.href = res.url; + } }).catch(err => { console.log("Failed to handle authorization req"); console.error(err) diff --git a/src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts b/src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts new file mode 100644 index 000000000..334c04099 --- /dev/null +++ b/src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts @@ -0,0 +1,12 @@ +import { OpenidAuthorizationServerMetadata } from "../schemas/OpenidAuthorizationServerMetadataSchema"; +import { OpenidCredentialIssuerMetadata } from "../schemas/OpenidCredentialIssuerMetadataSchema"; + +export interface IOpenID4VCIAuthorizationRequest { + generate(credentialConfigurationId: string, userHandleB64u: string, issuer_state: string | undefined, config: { + credentialIssuerIdentifier: string, + redirectUri: string, + clientId: string, + authorizationServerMetadata: OpenidAuthorizationServerMetadata, + credentialIssuerMetadata: OpenidCredentialIssuerMetadata, + }): Promise +} diff --git a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts new file mode 100644 index 000000000..c710241c9 --- /dev/null +++ b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts @@ -0,0 +1,69 @@ +import { IOpenID4VCIAuthorizationRequest } from "../../interfaces/IOpenID4VCIAuthorizationRequest"; +import { OpenidAuthorizationServerMetadata } from "../../schemas/OpenidAuthorizationServerMetadataSchema"; +import pkce from 'pkce-challenge'; +import { OpenidCredentialIssuerMetadata } from "../../schemas/OpenidCredentialIssuerMetadataSchema"; +import { generateRandomIdentifier } from "../../utils/generateRandomIdentifier"; +import { IHttpProxy } from "../../interfaces/IHttpProxy"; +import { OpenID4VCIClientState } from "../../types/OpenID4VCIClientState"; +import { IOpenID4VCIClientStateRepository } from "../../interfaces/IOpenID4VCIClientStateRepository"; + +export class OpenID4VCIPushedAuthorizationRequest implements IOpenID4VCIAuthorizationRequest { + + constructor( + private httpProxy: IHttpProxy, + private openID4VCIClientStateRepository: IOpenID4VCIClientStateRepository, + ) { } + + async generate(credentialConfigurationId: string, userHandleB64u: string, issuer_state: string | undefined, config: { + credentialIssuerIdentifier: string, + redirectUri: string, + clientId: string, + authorizationServerMetadata: OpenidAuthorizationServerMetadata, + credentialIssuerMetadata: OpenidCredentialIssuerMetadata, + }): Promise { + const { code_challenge, code_verifier } = await pkce(); + + const formData = new URLSearchParams(); + + const selectedCredentialConfigurationSupported = config.credentialIssuerMetadata.credential_configurations_supported[credentialConfigurationId]; + formData.append("scope", selectedCredentialConfigurationSupported.scope); + + formData.append("response_type", "code"); + + formData.append("client_id", config.clientId); + formData.append("code_challenge", code_challenge); + + formData.append("code_challenge_method", "S256"); + + // the purpose of the "id" is to provide the "state" a random factor for unlinkability and to make OpenID4VCIClientState instances unique + const state = btoa(JSON.stringify({ userHandleB64u: userHandleB64u, id: generateRandomIdentifier(12) })).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); + formData.append("state", state); + + if (issuer_state) { + formData.append("issuer_state", issuer_state); + } + + formData.append("redirect_uri", config.redirectUri); + let res; + try { + res = await this.httpProxy.post(config.authorizationServerMetadata.pushed_authorization_request_endpoint, formData.toString(), { + 'Content-Type': 'application/x-www-form-urlencoded' + }); + } + catch (err) { + if (err?.response?.data) { + throw new Error("Pushed authorization request failed ", err.response.data) + } + else { + console.error(err); + throw new Error("Pushed authorization request failed") + } + } + + const { request_uri } = res.data; + const authorizationRequestURL = `${config.authorizationServerMetadata.authorization_endpoint}?request_uri=${request_uri}&client_id=${config.clientId}` + + await this.openID4VCIClientStateRepository.create(new OpenID4VCIClientState(userHandleB64u, config.credentialIssuerIdentifier, state, code_verifier, credentialConfigurationId)) + return authorizationRequestURL; + } +} From 0188bf97c192f07617a50f8cbcbd5f4f52622b25 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 25 Nov 2024 13:12:07 +0200 Subject: [PATCH 050/162] added OpenID4VCIAuthorizationRequestForFirstPartyApplications to implement IOpenID4VCIAuthorizationRequest --- src/lib/interfaces/IOpenID4VPRelyingParty.ts | 1 + ...OpenidAuthorizationServerMetadataSchema.ts | 1 + ...izationRequestForFirstPartyApplications.ts | 82 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts diff --git a/src/lib/interfaces/IOpenID4VPRelyingParty.ts b/src/lib/interfaces/IOpenID4VPRelyingParty.ts index 85ea702fb..076b62980 100644 --- a/src/lib/interfaces/IOpenID4VPRelyingParty.ts +++ b/src/lib/interfaces/IOpenID4VPRelyingParty.ts @@ -1,5 +1,6 @@ export interface IOpenID4VPRelyingParty { handleAuthorizationRequest(url: string): Promise<{ conformantCredentialsMap: Map, verifierDomainName: string } | { err: HandleAuthorizationRequestError }>; + promptForCredentialSelection(conformantCredentialsMap: {[x: string]: string[]}, verifierDomainName: string): Promise>; sendAuthorizationResponse(selectionMap: Map): Promise<{ url?: string }>; } diff --git a/src/lib/schemas/OpenidAuthorizationServerMetadataSchema.ts b/src/lib/schemas/OpenidAuthorizationServerMetadataSchema.ts index 37f03f9f4..2593ff412 100644 --- a/src/lib/schemas/OpenidAuthorizationServerMetadataSchema.ts +++ b/src/lib/schemas/OpenidAuthorizationServerMetadataSchema.ts @@ -5,6 +5,7 @@ export const OpenidAuthorizationServerMetadataSchema = z.object({ authorization_endpoint: z.string(), token_endpoint: z.string(), pushed_authorization_request_endpoint: z.string(), + authorization_challenge_endpoint: z.string().optional(), require_pushed_authorization_requests: z.boolean().optional(), token_endpoint_auth_methods_supported: z.array(z.string()), response_types_supported: z.array(z.string()), diff --git a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts new file mode 100644 index 000000000..f01107548 --- /dev/null +++ b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts @@ -0,0 +1,82 @@ +import { IOpenID4VCIAuthorizationRequest } from "../../interfaces/IOpenID4VCIAuthorizationRequest"; +import { OpenidAuthorizationServerMetadata } from "../../schemas/OpenidAuthorizationServerMetadataSchema"; +import pkce from 'pkce-challenge'; +import { OpenidCredentialIssuerMetadata } from "../../schemas/OpenidCredentialIssuerMetadataSchema"; +import { generateRandomIdentifier } from "../../utils/generateRandomIdentifier"; +import { IHttpProxy } from "../../interfaces/IHttpProxy"; +import { OpenID4VCIClientState } from "../../types/OpenID4VCIClientState"; +import { IOpenID4VCIClientStateRepository } from "../../interfaces/IOpenID4VCIClientStateRepository"; +import { IOpenID4VPRelyingParty } from "../../interfaces/IOpenID4VPRelyingParty"; + +export class OpenID4VCIAuthorizationRequestForFirstPartyApplications implements IOpenID4VCIAuthorizationRequest { + + constructor( + private httpProxy: IHttpProxy, + private openID4VCIClientStateRepository: IOpenID4VCIClientStateRepository, + private openID4VPRelyingParty: IOpenID4VPRelyingParty, + ) { } + + async generate(credentialConfigurationId: string, userHandleB64u: string, issuer_state: string | undefined, config: { + credentialIssuerIdentifier: string, + redirectUri: string, + clientId: string, + authorizationServerMetadata: OpenidAuthorizationServerMetadata, + credentialIssuerMetadata: OpenidCredentialIssuerMetadata, + }): Promise { + const { code_challenge, code_verifier } = await pkce(); + + const formData = new URLSearchParams(); + + const selectedCredentialConfigurationSupported = config.credentialIssuerMetadata.credential_configurations_supported[credentialConfigurationId]; + formData.append("scope", selectedCredentialConfigurationSupported.scope); + formData.append("client_id", config.clientId); + + formData.append("code_challenge", code_challenge); + + formData.append("code_challenge_method", "S256"); + + // the purpose of the "id" is to provide the "state" a random factor for unlinkability and to make OpenID4VCIClientState instances unique + const state = btoa(JSON.stringify({ userHandleB64u: userHandleB64u, id: generateRandomIdentifier(12) })).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); + formData.append("state", state); + + if (issuer_state) { + formData.append("issuer_state", issuer_state); + } + + formData.append("redirect_uri", config.redirectUri); + let res; + try { + res = await this.httpProxy.post(config.authorizationServerMetadata.authorization_challenge_endpoint, formData.toString(), { + 'Content-Type': 'application/x-www-form-urlencoded' + }); + } + catch (err) { + if (err?.response?.data && err?.response?.data?.error === "insufficient_authorization") { // Authorization Error Response + const { error, auth_session, presentation } = err?.response?.data; + + // this function should prompt the user for presentation selection + const generatedPresentation = await this.openID4VPRelyingParty.handleAuthorizationRequest("openid4vp:" + presentation).then((res) => { + if ('err' in res) { + return; + } + + return this.openID4VPRelyingParty.promptForCredentialSelection(res.conformantCredentialsMap, ""); + }).then((selectionMap) => { + return this.openID4VPRelyingParty.sendAuthorizationResponse(selectionMap); // returns presentation + }) + + + } + else { + console.error(err); + throw new Error("Pushed authorization request failed") + } + } + + const { request_uri } = res.data; + const authorizationRequestURL = `${config.authorizationServerMetadata.authorization_endpoint}?request_uri=${request_uri}&client_id=${config.clientId}` + + await this.openID4VCIClientStateRepository.create(new OpenID4VCIClientState(userHandleB64u, config.credentialIssuerIdentifier, state, code_verifier, credentialConfigurationId)) + return authorizationRequestURL; + } +} From fb86bbeb8d374dee7ded267ae1ad0be7541e8795 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 25 Nov 2024 15:06:49 +0200 Subject: [PATCH 051/162] fix the case where batch size is set to 1 on cred issuer --- src/lib/services/OpenID4VCIClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/services/OpenID4VCIClient.ts b/src/lib/services/OpenID4VCIClient.ts index 26150966b..231c839ce 100644 --- a/src/lib/services/OpenID4VCIClient.ts +++ b/src/lib/services/OpenID4VCIClient.ts @@ -458,7 +458,7 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { const credentialArray = []; - if (numberOfProofs == 1) { + if (numberOfProofs == 1 && credentialResponse.data.credential) { const { credential } = credentialResponse.data; credentialArray.push(credential); } From 7327b3db95278588878d4f85277569ec3833eaa2 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 25 Nov 2024 15:08:03 +0200 Subject: [PATCH 052/162] minor fix --- src/components/Popups/SelectCredentialsPopup.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Popups/SelectCredentialsPopup.js b/src/components/Popups/SelectCredentialsPopup.js index ea3de69c9..3ea4d5ec5 100644 --- a/src/components/Popups/SelectCredentialsPopup.js +++ b/src/components/Popups/SelectCredentialsPopup.js @@ -113,6 +113,7 @@ function SelectCredentialsPopup({ isOpen, setIsOpen, setSelectionMap, conformant currentIndex, currentSelectionMap, keys, + vcEntityList, setSelectionMap, setIsOpen, container.credentialParserRegistry, From f0e9126d0525a0c87b71fb6bae94c1908a2b965e Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 25 Nov 2024 18:01:24 +0200 Subject: [PATCH 053/162] Fix home vc batch display --- src/pages/Home/Home.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pages/Home/Home.js b/src/pages/Home/Home.js index 0053655c6..aac8b7441 100644 --- a/src/pages/Home/Home.js +++ b/src/pages/Home/Home.js @@ -90,15 +90,19 @@ const Home = () => { ) : (

- {vcEntityList.map((vcEntity) => ( + {vcEntityListInstances && vcEntityList.map((vcEntity) => ( ))} From 5bf3823c0dae06bca880e9d30d3a8ca6cb484853 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 25 Nov 2024 18:02:30 +0200 Subject: [PATCH 054/162] fix the credential filtering procedure based on the requested fields of a presentation definition --- src/lib/utils/Verify.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/utils/Verify.ts b/src/lib/utils/Verify.ts index eb3e18aea..e8498df71 100644 --- a/src/lib/utils/Verify.ts +++ b/src/lib/utils/Verify.ts @@ -117,6 +117,10 @@ export class Verify { // console.log("Path = ", path) // console.log("Json = ", vcJSON) const vcValueByPath = JSONPath({ path: path, json: vcJSON })[0]; + console.log(`Extracted value for path ${path} : ${vcValueByPath}`); + if (!vcValueByPath) { + return false; + } if (!filter) { // if filter is undefined return true; } From b8e776b7cb7a287bec5af288c56ee0da95f3f95d Mon Sep 17 00:00:00 2001 From: kkmanos Date: Tue, 26 Nov 2024 11:48:42 +0200 Subject: [PATCH 055/162] added withCredentialContext wrapper component --- src/App.js | 99 +++++++++---------- .../Popups/SelectCredentialsPopup.js | 13 ++- src/context/CredentialsContext.js | 6 ++ 3 files changed, 63 insertions(+), 55 deletions(-) diff --git a/src/App.js b/src/App.js index 2e30e3d64..532559f3f 100644 --- a/src/App.js +++ b/src/App.js @@ -5,7 +5,6 @@ import { I18nextProvider } from 'react-i18next'; import i18n from './i18n'; import useCheckURL from './hooks/useCheckURL'; -import { CredentialsProvider } from './context/CredentialsContext'; import { withSessionContext } from './context/SessionContext'; import { checkForUpdates } from './offlineRegistrationSW'; @@ -15,7 +14,7 @@ import Snowfalling from './components/ChristmasAnimation/Snowfalling'; import Spinner from './components/Shared/Spinner'; import { withContainerContext } from './context/ContainerContext'; - +import { withCredentialsContext } from './context/CredentialsContext'; import UpdateNotification from './components/Notifications/UpdateNotification'; import CredentialDetails from './pages/Home/CredentialDetails'; @@ -133,56 +132,54 @@ function App() { return ( - - - }> - - - - - - }> - - - - - - - - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - - - }> - } /> - } /> - } /> - - - {showPinInputPopup && - - } - {showMessagePopup && - setMessagePopup(false)} /> - } - - + + }> + + + + + + }> + + + + + + + + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + + + + }> + } /> + } /> + } /> + + + {showPinInputPopup && + + } + {showMessagePopup && + setMessagePopup(false)} /> + } + ); } -export default withSessionContext(withContainerContext(App)); +export default withSessionContext(withCredentialsContext(withContainerContext(App))); diff --git a/src/components/Popups/SelectCredentialsPopup.js b/src/components/Popups/SelectCredentialsPopup.js index b6e859441..356eea63e 100644 --- a/src/components/Popups/SelectCredentialsPopup.js +++ b/src/components/Popups/SelectCredentialsPopup.js @@ -58,10 +58,9 @@ const StepBar = ({ totalSteps, currentStep, stepTitles }) => { ); }; -function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopup }) { +function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopup, container }) { const { api } = useContext(SessionContext); - const container = useContext(ContainerContext); const [vcEntities, setVcEntities] = useState([]); const { vcEntityList, vcEntityListInstances } = useContext(CredentialsContext); const { t } = useTranslation(); @@ -99,6 +98,7 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu popupState.options.conformantCredentialsMap[keys[currentIndex]].credentials.includes(vcEntity.credentialIdentifier) ); + console.log("VC entities = ", vcEntities); setRequestedFields(popupState.options.conformantCredentialsMap[keys[currentIndex]].requestedFields); setVcEntities(filteredVcEntities); } catch (error) { @@ -108,6 +108,7 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu if (popupState?.options) { console.log("opts = ", popupState.options) + console.log("Vc entity list = ", vcEntityList) getData(); } }, [ @@ -118,10 +119,14 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu container, popupState, vcEntityList, - setIsOpen, - container.credentialParserRegistry, ]); + useEffect(() => { + if (vcEntityList) { + console.log("VC entity list mutated...", vcEntityList) + } + }, [vcEntityList]) + useEffect(() => { console.log("Detected change of popup state inside the SelectCredentialsPopup") console.log(popupState) diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js index e65725464..6d9cd9f47 100644 --- a/src/context/CredentialsContext.js +++ b/src/context/CredentialsContext.js @@ -114,4 +114,10 @@ export const CredentialsProvider = ({ children }) => { ); }; +export const withCredentialsContext = (Component) => + (props) => ( + + + + ); export default CredentialsContext; From feba6fd8d93082105833a945fb29131f002010a9 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Tue, 26 Nov 2024 17:10:22 +0200 Subject: [PATCH 056/162] Execute credential parsers in the order that the were executed --- src/lib/services/CredentialParserRegistry.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/lib/services/CredentialParserRegistry.ts b/src/lib/services/CredentialParserRegistry.ts index 20498c617..5f2a300ba 100644 --- a/src/lib/services/CredentialParserRegistry.ts +++ b/src/lib/services/CredentialParserRegistry.ts @@ -22,14 +22,13 @@ export class CredentialParserRegistry implements ICredentialParserRegistry { if (cacheResult) { return cacheResult; } - const promises = this.parserList.map((parser) => { - return parser.parse(rawCredential, presentationDefinitionFilter); - }); - - const results = await Promise.all(promises); - const first = results.filter((res) => ('beautifiedForm' in res))[0]; // get first successful parsing - this.parsedObjectsCache.set(hash, first); - return first ?? { error: "All parsings failed" }; + for (const p of this.parserList) { + const result = await p.parse(rawCredential, presentationDefinitionFilter).catch(() => null); + if (result && 'beautifiedForm' in result) { + return result + } + } + return { error: "All parsings failed" }; } } From 5754c71fe9979d8430aeaeef685fd9978164f1ee Mon Sep 17 00:00:00 2001 From: kkmanos Date: Tue, 26 Nov 2024 19:25:57 +0200 Subject: [PATCH 057/162] signed signed metadata if available --- .../OpenidCredentialIssuerMetadataSchema.ts | 3 ++- src/lib/services/OpenID4VCIHelper.ts | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts b/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts index ae8142dfe..e415af049 100644 --- a/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts +++ b/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts @@ -11,7 +11,8 @@ export const OpenidCredentialIssuerMetadataSchema = z.object({ batch_credential_issuance: z.object({ batch_size: z.number(), }).optional(), - credential_configurations_supported: z.record(CredentialConfigurationSupportedSchema) + credential_configurations_supported: z.record(CredentialConfigurationSupportedSchema), + signed_metadata: z.string().optional(), }) diff --git a/src/lib/services/OpenID4VCIHelper.ts b/src/lib/services/OpenID4VCIHelper.ts index 97201e782..f84d582a7 100644 --- a/src/lib/services/OpenID4VCIHelper.ts +++ b/src/lib/services/OpenID4VCIHelper.ts @@ -3,6 +3,8 @@ import { IOpenID4VCIHelper } from "../interfaces/IOpenID4VCIHelper"; import { OpenidAuthorizationServerMetadata, OpenidAuthorizationServerMetadataSchema } from "../schemas/OpenidAuthorizationServerMetadataSchema"; import { OpenidCredentialIssuerMetadata, OpenidCredentialIssuerMetadataSchema } from "../schemas/OpenidCredentialIssuerMetadataSchema"; import { addItem, getItem } from '../../indexedDB'; +import { base64url, importX509, jwtVerify } from "jose"; +import { getPublicKeyFromB64Cert } from "../utils/pki"; export class OpenID4VCIHelper implements IOpenID4VCIHelper { constructor(private httpProxy: IHttpProxy) { } @@ -67,6 +69,20 @@ export class OpenID4VCIHelper implements IOpenID4VCIHelper { isOnline, forceIndexDB ); + if (metadata.signed_metadata) { + try { + const parsedHeader = JSON.parse(new TextDecoder().decode(base64url.decode(metadata.signed_metadata.split('.')[0]))); + if (parsedHeader.x5c) { + const publicKey = await importX509(getPublicKeyFromB64Cert(parsedHeader.x5c[0]), parsedHeader.alg); + const { payload } = await jwtVerify(metadata.signed_metadata, publicKey); + return { metadata: payload as OpenidCredentialIssuerMetadata }; + } + return null; + } + catch(err) { + return null; + } + } return { metadata }; } catch(err) { From f7b4f06f1a2b7b4b3e591291724751f7155edef9 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Wed, 27 Nov 2024 01:22:50 +0200 Subject: [PATCH 058/162] use cached proofs in case of invalid dpop nonce proof --- src/lib/services/OpenID4VCIClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/services/OpenID4VCIClient.ts b/src/lib/services/OpenID4VCIClient.ts index 231c839ce..12f80607f 100644 --- a/src/lib/services/OpenID4VCIClient.ts +++ b/src/lib/services/OpenID4VCIClient.ts @@ -405,7 +405,7 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { audience: this.config.credentialIssuerIdentifier }) } - const generateProofsResult = await this.generateNonceProofs(inputs); + const generateProofsResult = cachedProofs ? { proof_jwts: cachedProofs } : await this.generateNonceProofs(inputs); proofsArray = generateProofsResult.proof_jwts; if (proofsArray) { dispatchEvent(new CustomEvent("generatedProof")); From 6bae2b015173e5604b95e5d1148e8c883425a3c9 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Fri, 29 Nov 2024 14:42:44 +0200 Subject: [PATCH 059/162] completed first implementation of first-party-app protocol --- src/hooks/useCheckURL.ts | 8 ++--- .../IOpenID4VCIAuthorizationRequest.ts | 2 +- src/lib/interfaces/IOpenID4VPRelyingParty.ts | 2 +- ...izationRequestForFirstPartyApplications.ts | 31 +++++++++++++------ .../OpenID4VCIPushedAuthorizationRequest.ts | 4 +-- src/lib/services/OpenID4VCIClient.ts | 19 ++++++++---- src/lib/services/OpenID4VPRelyingParty.ts | 5 ++- src/lib/types/OpenID4VCIClientState.ts | 3 ++ 8 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/hooks/useCheckURL.ts b/src/hooks/useCheckURL.ts index 2dec4a26f..820024dcb 100644 --- a/src/hooks/useCheckURL.ts +++ b/src/hooks/useCheckURL.ts @@ -95,7 +95,7 @@ function useCheckURL(urlToCheck: string): { console.log("Selection = ", selection); return container.openID4VPRelyingParty.sendAuthorizationResponse(selection); }).then((res) => { - if (res.url) { + if ('url' in res && res.url) { window.location.href = res.url; } }).catch(err => { @@ -122,9 +122,9 @@ function useCheckURL(urlToCheck: string): { useEffect(() => { if (selectionMap) { console.log("Selection map was mutated..."); - container.openID4VPRelyingParty.sendAuthorizationResponse(new Map(Object.entries(selectionMap))).then(({ url }) => { - if (url) { - window.location.href = url; + container.openID4VPRelyingParty.sendAuthorizationResponse(new Map(Object.entries(selectionMap))).then((result) => { + if ('url' in result && result.url) { + window.location.href = result.url; } }).catch((err) => console.error(err)); } diff --git a/src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts b/src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts index 334c04099..ee25c31ca 100644 --- a/src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts +++ b/src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts @@ -8,5 +8,5 @@ export interface IOpenID4VCIAuthorizationRequest { clientId: string, authorizationServerMetadata: OpenidAuthorizationServerMetadata, credentialIssuerMetadata: OpenidCredentialIssuerMetadata, - }): Promise + }): Promise<{ authorizationRequestURL: string } | { authorization_code: string }> } diff --git a/src/lib/interfaces/IOpenID4VPRelyingParty.ts b/src/lib/interfaces/IOpenID4VPRelyingParty.ts index 076b62980..b7a0b9e95 100644 --- a/src/lib/interfaces/IOpenID4VPRelyingParty.ts +++ b/src/lib/interfaces/IOpenID4VPRelyingParty.ts @@ -1,7 +1,7 @@ export interface IOpenID4VPRelyingParty { handleAuthorizationRequest(url: string): Promise<{ conformantCredentialsMap: Map, verifierDomainName: string } | { err: HandleAuthorizationRequestError }>; promptForCredentialSelection(conformantCredentialsMap: {[x: string]: string[]}, verifierDomainName: string): Promise>; - sendAuthorizationResponse(selectionMap: Map): Promise<{ url?: string }>; + sendAuthorizationResponse(selectionMap: Map): Promise<{ url?: string } | { presentation_during_issuance_session: string }>; } export enum HandleAuthorizationRequestError { diff --git a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts index 32182cbc2..9fe7f3d2c 100644 --- a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts +++ b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts @@ -22,7 +22,7 @@ export class OpenID4VCIAuthorizationRequestForFirstPartyApplications implements clientId: string, authorizationServerMetadata: OpenidAuthorizationServerMetadata, credentialIssuerMetadata: OpenidCredentialIssuerMetadata, - }): Promise { + }): Promise<{ authorizationRequestURL: string } | { authorization_code: string }> { const { code_challenge, code_verifier } = await pkce(); const formData = new URLSearchParams(); @@ -55,18 +55,34 @@ export class OpenID4VCIAuthorizationRequestForFirstPartyApplications implements const { error, auth_session, presentation } = err?.response?.data; // this function should prompt the user for presentation selection - const generatedPresentation = await this.openID4VPRelyingParty.handleAuthorizationRequest("openid4vp:" + presentation).then((res) => { + const result = await this.openID4VPRelyingParty.handleAuthorizationRequest("openid4vp:" + presentation).then((res) => { if ('err' in res) { return; } const jsonedMap = Object.fromEntries(res.conformantCredentialsMap); - return this.openID4VPRelyingParty.promptForCredentialSelection(jsonedMap, ""); + return this.openID4VPRelyingParty.promptForCredentialSelection(jsonedMap, config.credentialIssuerMetadata.credential_issuer); }).then((selectionMap) => { - return this.openID4VPRelyingParty.sendAuthorizationResponse(selectionMap); // returns presentation - }) + return this.openID4VPRelyingParty.sendAuthorizationResponse(selectionMap); + }); + if (!('presentation_during_issuance_session' in result)) { + throw new Error("presentation_during_issuance_session is not present in the result of the presentation sending phase"); + } + const presentation_during_issuance_session = result.presentation_during_issuance_session; + // add auth_session and presentation_during_issuance_session params on authorization_challenge_endpoint POST request + formData.append("auth_session", auth_session); + formData.append("presentation_during_issuance_session", presentation_during_issuance_session); + res = await this.httpProxy.post(config.authorizationServerMetadata.authorization_challenge_endpoint, formData.toString(), { + 'Content-Type': 'application/x-www-form-urlencoded' + }); + if (!res.data.authorization_code) { + throw new Error("authorization_code not present on the authorization response"); + } + await this.openID4VCIClientStateRepository.create(new OpenID4VCIClientState(userHandleB64u, config.credentialIssuerIdentifier, state, code_verifier, credentialConfigurationId, undefined, undefined, { auth_session: auth_session })); + + return { authorization_code: res.data.authorization_code }; } else { console.error(err); @@ -74,10 +90,5 @@ export class OpenID4VCIAuthorizationRequestForFirstPartyApplications implements } } - const { request_uri } = res.data; - const authorizationRequestURL = `${config.authorizationServerMetadata.authorization_endpoint}?request_uri=${request_uri}&client_id=${config.clientId}` - - await this.openID4VCIClientStateRepository.create(new OpenID4VCIClientState(userHandleB64u, config.credentialIssuerIdentifier, state, code_verifier, credentialConfigurationId)) - return authorizationRequestURL; } } diff --git a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts index c710241c9..1b826682b 100644 --- a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts +++ b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts @@ -20,7 +20,7 @@ export class OpenID4VCIPushedAuthorizationRequest implements IOpenID4VCIAuthoriz clientId: string, authorizationServerMetadata: OpenidAuthorizationServerMetadata, credentialIssuerMetadata: OpenidCredentialIssuerMetadata, - }): Promise { + }): Promise<{ authorizationRequestURL: string } | { authorization_code: string }> { const { code_challenge, code_verifier } = await pkce(); const formData = new URLSearchParams(); @@ -64,6 +64,6 @@ export class OpenID4VCIPushedAuthorizationRequest implements IOpenID4VCIAuthoriz const authorizationRequestURL = `${config.authorizationServerMetadata.authorization_endpoint}?request_uri=${request_uri}&client_id=${config.clientId}` await this.openID4VCIClientStateRepository.create(new OpenID4VCIClientState(userHandleB64u, config.credentialIssuerIdentifier, state, code_verifier, credentialConfigurationId)) - return authorizationRequestURL; + return { authorizationRequestURL }; } } diff --git a/src/lib/services/OpenID4VCIClient.ts b/src/lib/services/OpenID4VCIClient.ts index 7bc941626..750585250 100644 --- a/src/lib/services/OpenID4VCIClient.ts +++ b/src/lib/services/OpenID4VCIClient.ts @@ -93,9 +93,8 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { } catch (err) { console.error(err) } - let url = null; - if (this.config.authorizationServerMetadata.require_pushed_authorization_requests && this.config.authorizationServerMetadata.pushed_authorization_request_endpoint) { - url = await this.openID4VCIPushedAuthorizationRequest.generate( + if (this.config.authorizationServerMetadata.pushed_authorization_request_endpoint) { + const res = await this.openID4VCIPushedAuthorizationRequest.generate( credentialConfigurationId, userHandleB64u, issuer_state, @@ -104,9 +103,12 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { redirectUri: redirectUri } ); + if ('authorizationRequestURL' in res) { + return { url: res.authorizationRequestURL }; + } } else if (this.config.authorizationServerMetadata.authorization_challenge_endpoint) { - url = await this.openID4VCIAuthorizationRequestForFirstPartyApplications.generate( + await this.openID4VCIAuthorizationRequestForFirstPartyApplications.generate( credentialConfigurationId, userHandleB64u, issuer_state, @@ -114,9 +116,14 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { ...this.config, redirectUri: redirectUri } - ); + ).then((result) => { + if (!('authorization_code' in result)) { + console.error("authorization_code was not found in the result"); + return; + } + return this.handleAuthorizationResponse(`openid://?code=${result.authorization_code}`, userHandleB64u); + }); } - return { url: url } } async handleAuthorizationResponse(url: string, userHandleB64U: string, dpopNonceHeader?: string) { diff --git a/src/lib/services/OpenID4VPRelyingParty.ts b/src/lib/services/OpenID4VPRelyingParty.ts index 2c3870845..9ca0b7f41 100644 --- a/src/lib/services/OpenID4VPRelyingParty.ts +++ b/src/lib/services/OpenID4VPRelyingParty.ts @@ -186,7 +186,7 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { } - async sendAuthorizationResponse(selectionMap: Map): Promise<{ url?: string }> { + async sendAuthorizationResponse(selectionMap: Map): Promise<{ url?: string } | { presentation_during_issuance_session: string }> { const S = await this.openID4VPRelyingPartyStateRepository.retrieve(); console.log("send AuthorizationResponse: S = ", S) console.log("send AuthorizationResponse: Sess = ", sessionStorage.getItem('last_used_nonce')); @@ -370,6 +370,9 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { console.log("Direct post response = ", JSON.stringify(res.data)); + if (res.data.presentation_during_issuance_session) { + return { presentation_during_issuance_session: res.data.presentation_during_issuance_session } + } if (res.data.redirect_uri) { return { url: res.data.redirect_uri }; } diff --git a/src/lib/types/OpenID4VCIClientState.ts b/src/lib/types/OpenID4VCIClientState.ts index a94ddc4ab..a07fb9954 100644 --- a/src/lib/types/OpenID4VCIClientState.ts +++ b/src/lib/types/OpenID4VCIClientState.ts @@ -29,6 +29,9 @@ export class OpenID4VCIClientState { dpopPublicKeyJwk?: JWK, dpopAlg: string, }, + public firstPartyAuthorization?: { + auth_session: string; + }, public created: number = Math.floor(Date.now() / 1000), ) { } From 2038f1f0101e27e7db57ff25841b240fd123e9a4 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 2 Dec 2024 10:18:31 +0200 Subject: [PATCH 060/162] made toBase64 function iterative instead of calling String.fromCharCode.apply() --- src/util.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/util.ts b/src/util.ts index 8201512f5..78f6bd257 100644 --- a/src/util.ts +++ b/src/util.ts @@ -7,7 +7,14 @@ function toU8(b: BufferSource) { } export function toBase64(binary: BufferSource): string { - return btoa(String.fromCharCode.apply(String, toU8(binary))); + const uint8Array = toU8(binary); + const chunkSize = 0x8000; // 32KB + let result = ''; + for (let i = 0; i < uint8Array.length; i += chunkSize) { + const chunk = uint8Array.subarray(i, i + chunkSize); + result += String.fromCharCode(...chunk); + } + return btoa(result); } export function toBase64Url(binary: BufferSource): string { From 7fb66b0f84aeeca2b4d2b4692d643a9d3d5f537e Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 2 Dec 2024 11:02:14 +0200 Subject: [PATCH 061/162] minor fix --- src/lib/services/OpenID4VCIClient.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/services/OpenID4VCIClient.ts b/src/lib/services/OpenID4VCIClient.ts index 12f80607f..6e18e1e8c 100644 --- a/src/lib/services/OpenID4VCIClient.ts +++ b/src/lib/services/OpenID4VCIClient.ts @@ -405,11 +405,11 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { audience: this.config.credentialIssuerIdentifier }) } - const generateProofsResult = cachedProofs ? { proof_jwts: cachedProofs } : await this.generateNonceProofs(inputs); - proofsArray = generateProofsResult.proof_jwts; - if (proofsArray) { + const generateProofsResult = cachedProofs ? { proof_jwts: cachedProofs } : await this.generateNonceProofs(inputs).then((res) => { dispatchEvent(new CustomEvent("generatedProof")); - } + return res; + }); + proofsArray = generateProofsResult.proof_jwts; } catch (err) { console.error(err); From 7951ef0180bbbb10b0b0ec3cfe7f50cd02cbac7b Mon Sep 17 00:00:00 2001 From: kkmanos Date: Tue, 3 Dec 2024 12:00:21 +0200 Subject: [PATCH 062/162] multi presentation view --- src/components/History/HistoryList.js | 3 ++- src/lib/services/OpenID4VPRelyingParty.ts | 4 +++- src/pages/History/HistoryDetail.js | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/History/HistoryList.js b/src/components/History/HistoryList.js index e43059f0d..cd71fa7ff 100644 --- a/src/components/History/HistoryList.js +++ b/src/components/History/HistoryList.js @@ -4,6 +4,7 @@ import useScreenType from '../../hooks/useScreenType'; import { formatDate } from '../../functions/DateFormat'; import { H3 } from '../Shared/Heading'; import HistoryDetailPopup from '../Popups/HistoryDetailPopup'; +import { fromBase64 } from '../../util'; const HistoryList = ({ credentialId = null, history, title = '', limit = null }) => { @@ -21,7 +22,7 @@ const HistoryList = ({ credentialId = null, history, title = '', limit = null }) }, [history, credentialId, limit]); const handleHistoryItemClick = async (item) => { - setMatchingCredentials([item.presentation]); + setMatchingCredentials(item.presentation.startsWith("b64:") ? JSON.parse(new TextDecoder().decode(fromBase64(item.presentation.replace("b64:", "")))) : [ item.presentation ] ); if (screenType === 'mobile') { navigate(`/history/${item.id}`); } diff --git a/src/lib/services/OpenID4VPRelyingParty.ts b/src/lib/services/OpenID4VPRelyingParty.ts index f17fbc527..3b1d64a92 100644 --- a/src/lib/services/OpenID4VPRelyingParty.ts +++ b/src/lib/services/OpenID4VPRelyingParty.ts @@ -13,6 +13,7 @@ import { extractSAN, getPublicKeyFromB64Cert } from "../utils/pki"; import axios from "axios"; import { BACKEND_URL, OPENID4VP_SAN_DNS_CHECK_SSL_CERTS, OPENID4VP_SAN_DNS_CHECK } from "../../config"; import { CredentialBatchHelper } from "./CredentialBatchHelper"; +import { toBase64 } from "../../util"; export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { @@ -354,7 +355,8 @@ export class OpenID4VPRelyingParty implements IOpenID4VPRelyingParty { const credentialIdentifiers = originalVCs.map((vc) => vc.credentialIdentifier); - const storePresentationPromise = this.storeVerifiablePresentation(generatedVPs[0], presentationSubmission.descriptor_map[0].format, credentialIdentifiers, presentationSubmission, client_id); + const presentations = "b64:" + toBase64(new TextEncoder().encode(generatedVPs.length == 1 ? generatedVPs[0] : JSON.stringify(generatedVPs))); + const storePresentationPromise = this.storeVerifiablePresentation(presentations, "", credentialIdentifiers, presentationSubmission, client_id); const updateCredentialPromise = filteredVCEntities.map(async (cred) => this.credentialBatchHelper.useCredential(cred)) const updateRepositoryPromise = this.openID4VPRelyingPartyStateRepository.store(S); diff --git a/src/pages/History/HistoryDetail.js b/src/pages/History/HistoryDetail.js index 1d1f877ca..e7831c2ce 100644 --- a/src/pages/History/HistoryDetail.js +++ b/src/pages/History/HistoryDetail.js @@ -10,6 +10,7 @@ import SessionContext from '../../context/SessionContext'; // Utility functions import { formatDate } from '../../functions/DateFormat'; +import { fromBase64 } from '../../util'; // Hooks import useFetchPresentations from '../../hooks/useFetchPresentations'; @@ -28,8 +29,7 @@ const HistoryDetail = () => { useEffect(() => { if (history.length > 0) { - const verifiableCredentials = [history[0].presentation]; - setMatchingCredentials(verifiableCredentials); + setMatchingCredentials(history[0].startsWith("b64:") ? JSON.parse(new TextDecoder().decode(fromBase64(history[0].replace("b64:", "")))) : [ history[0] ] ); } }, [history]); From a085622f51f9b00b10bd168eb3f74b260fda89ea Mon Sep 17 00:00:00 2001 From: kkmanos Date: Fri, 29 Nov 2024 14:36:29 +0200 Subject: [PATCH 063/162] fix cross compatibility of expiry date --- src/components/Credentials/CredentialLayout.js | 2 +- src/components/Credentials/ExpiredRibbon.js | 4 ++-- src/components/Credentials/RenderCustomSvgTemplate.js | 2 +- src/functions/CheckExpired.js | 7 ++++++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/Credentials/CredentialLayout.js b/src/components/Credentials/CredentialLayout.js index 04f166831..413b78e15 100644 --- a/src/components/Credentials/CredentialLayout.js +++ b/src/components/Credentials/CredentialLayout.js @@ -61,7 +61,7 @@ const CredentialLayout = ({ children, title = null }) => { if ('error' in c) { return; } - setIsExpired(CheckExpired(c.beautifiedForm.expiry_date)) + setIsExpired(CheckExpired(c.beautifiedForm.expiry_date ?? c.beautifiedForm.exp)) setCredentialFriendlyName(c.credentialFriendlyName); }); }, [vcEntity, container]); diff --git a/src/components/Credentials/ExpiredRibbon.js b/src/components/Credentials/ExpiredRibbon.js index b2372d863..2d982832f 100644 --- a/src/components/Credentials/ExpiredRibbon.js +++ b/src/components/Credentials/ExpiredRibbon.js @@ -8,8 +8,8 @@ const ExpiredRibbon = ({ parsedCredential }) => { return ( <> - {parsedCredential && CheckExpired(parsedCredential.expiry_date) && -
+ {parsedCredential && CheckExpired(parsedCredential.exp ?? parsedCredential.expiry_date) && +
{t('expiredRibbon.expired')}
} diff --git a/src/components/Credentials/RenderCustomSvgTemplate.js b/src/components/Credentials/RenderCustomSvgTemplate.js index 64dfa96d0..3f243688f 100644 --- a/src/components/Credentials/RenderCustomSvgTemplate.js +++ b/src/components/Credentials/RenderCustomSvgTemplate.js @@ -49,7 +49,7 @@ const renderCustomSvgTemplate = async ({ beautifiedForm, name, description, logo .replace(/{{textColor}}/g, textColor) .replace(/{{description}}/g, description); - const expiryDate = jsonpointer.get(beautifiedForm, "/expiry_date"); + const expiryDate = jsonpointer.get(beautifiedForm, "/expiry_date") ?? new Date(jsonpointer.get(beautifiedForm, "/exp") * 1000).toISOString(); svgContent = svgContent.replace(/{{\/expiry_date}}/g, expiryDate ? `Expiry Date: ${formatDate(expiryDate, 'date')}` : ''); return `data:image/svg+xml;utf8,${encodeURIComponent(svgContent)}`; diff --git a/src/functions/CheckExpired.js b/src/functions/CheckExpired.js index 587bccfa1..c3b7cd566 100644 --- a/src/functions/CheckExpired.js +++ b/src/functions/CheckExpired.js @@ -1,6 +1,11 @@ // CheckExpired.js export function CheckExpired(expiry_date) { + if (!expiry_date) { + return false; + } + + const parsedExpiryDate = typeof expiry_date == 'string' ? expiry_date : new Date(expiry_date * 1000).toISOString(); const today = new Date(); - const expirationDate = new Date(expiry_date); + const expirationDate = new Date(parsedExpiryDate); return expirationDate < today; }; From 54d8b1a1e746e621d7ccdd23690be92a5cd90d4a Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 29 Nov 2024 15:56:22 +0200 Subject: [PATCH 064/162] Fix Expiration ribbon display --- src/components/Credentials/CredentialImage.js | 2 +- src/components/Credentials/CredentialLayout.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Credentials/CredentialImage.js b/src/components/Credentials/CredentialImage.js index 3051fa10c..401f37e2a 100644 --- a/src/components/Credentials/CredentialImage.js +++ b/src/components/Credentials/CredentialImage.js @@ -25,7 +25,7 @@ const CredentialImage = ({ credential, className, onClick, showRibbon = true, vc {"Credential"} )} {parsedCredential && showRibbon && - + } {vcEntityInstances && showRibbon && diff --git a/src/components/Credentials/CredentialLayout.js b/src/components/Credentials/CredentialLayout.js index 413b78e15..7acbf2f80 100644 --- a/src/components/Credentials/CredentialLayout.js +++ b/src/components/Credentials/CredentialLayout.js @@ -61,7 +61,7 @@ const CredentialLayout = ({ children, title = null }) => { if ('error' in c) { return; } - setIsExpired(CheckExpired(c.beautifiedForm.expiry_date ?? c.beautifiedForm.exp)) + setIsExpired(CheckExpired(c.beautifiedForm.exp ?? c.beautifiedForm.expiry_date )) setCredentialFriendlyName(c.credentialFriendlyName); }); }, [vcEntity, container]); From d6205bd5ee0b99b85319762a5b9aee3a153f3e22 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 29 Nov 2024 15:04:50 +0200 Subject: [PATCH 065/162] Handle all date format cases --- src/functions/DateFormat.js | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/functions/DateFormat.js b/src/functions/DateFormat.js index 1784c3e02..b34840bf6 100644 --- a/src/functions/DateFormat.js +++ b/src/functions/DateFormat.js @@ -3,15 +3,36 @@ export function formatDate(value, format = 'datetime') { const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/; // Regex for simple YYYY-MM-DD format const simpleDateRegex = /^\d{4}-\d{2}-\d{2}$/; + // Regex for long-form date strings like 'Wed Dec 11 2024 14:46:19 GMT+0200' + const longFormDateRegex = /^[A-Z][a-z]{2} [A-Z][a-z]{2} \d{2} \d{4} \d{2}:\d{2}:\d{2} GMT[+-]\d{4}/; let date; - if (iso8601Regex.test(value)) { - date = new Date(value); - } else if (simpleDateRegex.test(value)) { - date = new Date(value); + + if (typeof value === 'number' && value.toString().length === 10) { + // Handle Unix timestamp (seconds) by converting to milliseconds + date = new Date(value * 1000); + } else if (typeof value === 'string') { + if (iso8601Regex.test(value)) { + // Handle ISO 8601 format + date = new Date(value); + } else if (simpleDateRegex.test(value)) { + // Handle YYYY-MM-DD format + date = new Date(value); + } else if (longFormDateRegex.test(value)) { + // Handle long-form date string + date = new Date(value); + } else { + // Non-date strings, including IDs, are returned as-is + return value; + } + } else if (value instanceof Date) { + // Handle Date objects directly + date = value; } else { + // For unsupported types, return the original value return value; } + const options = format === 'datetime' ? { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' } : { day: '2-digit', month: '2-digit', year: 'numeric' }; From acbda63fd617d8d05bb33fa17ffd8cb99a4a9c20 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 3 Dec 2024 16:01:02 +0200 Subject: [PATCH 066/162] Add scrollbar on History details credential info on not mobile screen --- src/components/History/HistoryDetailContent.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/History/HistoryDetailContent.js b/src/components/History/HistoryDetailContent.js index 46d54d31d..dd605f9a5 100644 --- a/src/components/History/HistoryDetailContent.js +++ b/src/components/History/HistoryDetailContent.js @@ -7,9 +7,12 @@ import Slider from '../Shared/Slider'; import CredentialImage from '../Credentials/CredentialImage'; import CredentialInfo from '../Credentials/CredentialInfo'; +import useScreenType from '../../hooks/useScreenType'; + const HistoryDetailContent = ({ historyItem }) => { const { t } = useTranslation(); const [currentSlide, setCurrentSlide] = React.useState(1); + const screenType = useScreenType(); const renderSlideContent = (credential) => (
{ {/* Render details of the currently selected credential */} {historyItem[currentSlide - 1] && ( -
+
)} From 90656edacef9f3c17dc27e3e9db7dc300900f5ba Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Thu, 28 Nov 2024 16:26:18 +0200 Subject: [PATCH 067/162] fetch vc data on listen notification --- src/components/Notifications/HandlerNotification.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/Notifications/HandlerNotification.js b/src/components/Notifications/HandlerNotification.js index 3c394f6cd..3ab177b1f 100644 --- a/src/components/Notifications/HandlerNotification.js +++ b/src/components/Notifications/HandlerNotification.js @@ -1,8 +1,9 @@ -import React, { useState, useEffect, useCallback } from 'react'; +import React, { useState, useEffect, useCallback, useContext } from 'react'; import toast, { Toaster } from 'react-hot-toast'; import { onMessageListener } from '../../firebase'; import { AiOutlineClose } from 'react-icons/ai'; import logo from '../../assets/images/logo.png'; +import CredentialsContext from '../../context/CredentialsContext'; const ToastDisplay = ({ id, notification }) => { return ( @@ -31,6 +32,7 @@ const ToastDisplay = ({ id, notification }) => { const HandlerNotification = () => { const [notification, setNotification] = useState({ title: '', body: '' }); + const { getData } = useContext(CredentialsContext); const showToast = useCallback( () => toast((t) => ), @@ -50,6 +52,7 @@ const HandlerNotification = () => { title: payload?.notification?.title, body: payload?.notification?.body, }); + getData(); }) .catch((err) => { console.log('Failed to receive message:', err); @@ -60,10 +63,10 @@ const HandlerNotification = () => { messageListener(); } }; - }, []); + }, [getData]); return ( - + ); }; From 3f66769e4f26649dd1de3a3a2216962e9ebf0787 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 3 Dec 2024 16:04:33 +0100 Subject: [PATCH 068/162] Fix corruption data race in cached users The cause of this data corruption is: after successfully logging in and unlocking the keystore, the `useEffect` in `LocalStorageKeystore` calls `setCachedUsers` to update the cached users (to copy the `prfKeys` from the logged-in user's `privateData` to the matching cached user). But when there are two tabs open simultaneously, that code runs simultaneously in both tabs, and the `globalUserHandleB64u` is different between the two tabs. The user1 tab has `globalUserHandleB64u` set to the user handle of user1, and the user2 tab has `globalUserHandleB64u` set to the user handle of user2. So the result is that both cached users get updated with user2's `prfKeys`, which then causes the user to be logged into user2 even if they press the cache button labeled "Log in as user1". --- src/services/LocalStorageKeystore.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/services/LocalStorageKeystore.ts b/src/services/LocalStorageKeystore.ts index 6033a557d..11865682f 100644 --- a/src/services/LocalStorageKeystore.ts +++ b/src/services/LocalStorageKeystore.ts @@ -181,9 +181,6 @@ export function useLocalStorageKeystore(): LocalStorageKeystore { { exportedMainKey, privateData }: UnlockSuccess, user: CachedUser | UserData | null, ): Promise => { - setMainKey(exportedMainKey); - setPrivateData(privateData); - if (user) { const userHandleB64u = ("prfKeys" in user ? user.userHandleB64u @@ -199,13 +196,21 @@ export function useLocalStorageKeystore(): LocalStorageKeystore { ); setUserHandleB64u(userHandleB64u); + + // This must happen before setPrivateData in order to prevent the + // useEffect updating cachedUsers from corrupting cache entries for other + // users logged in in other tabs. setGlobalUserHandleB64u(userHandleB64u); + setCachedUsers((cachedUsers) => { // Move most recently used user to front of list const otherUsers = (cachedUsers || []).filter((cu) => cu.userHandleB64u !== newUser.userHandleB64u); return [newUser, ...otherUsers]; }); } + + setMainKey(exportedMainKey); + setPrivateData(privateData); }; const init = async ( From e122daf2f168abbe129d433a15de00d9f8ab8287 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 3 Dec 2024 12:35:31 +0100 Subject: [PATCH 069/162] Extract named logout function --- src/context/SessionContext.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/context/SessionContext.tsx b/src/context/SessionContext.tsx index a2eed4e22..0ec5c08a4 100644 --- a/src/context/SessionContext.tsx +++ b/src/context/SessionContext.tsx @@ -25,18 +25,18 @@ export const SessionContextProvider = ({ children }) => { const api = useApi(isOnline); const keystore = useLocalStorageKeystore(); + const logout = async () => { + // Clear URL parameters + sessionStorage.setItem('freshLogin', 'true'); + api.clearSession(); + await keystore.close(); + }; + const value: SessionContextValue = { api, isLoggedIn: api.isLoggedIn() && keystore.isOpen(), keystore, - logout: async () => { - - // Clear URL parameters - sessionStorage.setItem('freshLogin', 'true'); - api.clearSession(); - await keystore.close(); - - }, + logout, }; return ( From 9cc6dac5f7bae516dd640fa87f15d9558823b05f Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 3 Dec 2024 18:12:43 +0100 Subject: [PATCH 070/162] Send keystore.close event to log out api module too --- src/context/SessionContext.tsx | 7 +++++-- src/services/LocalStorageKeystore.ts | 11 ++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/context/SessionContext.tsx b/src/context/SessionContext.tsx index 0ec5c08a4..225002967 100644 --- a/src/context/SessionContext.tsx +++ b/src/context/SessionContext.tsx @@ -2,7 +2,7 @@ import React, { createContext, useContext } from 'react'; import StatusContext from './StatusContext'; import { BackendApi, useApi } from '../api'; -import { useLocalStorageKeystore } from '../services/LocalStorageKeystore'; +import { KeystoreEvent, useLocalStorageKeystore } from '../services/LocalStorageKeystore'; import type { LocalStorageKeystore } from '../services/LocalStorageKeystore'; @@ -23,7 +23,8 @@ const SessionContext: React.Context = createContext({ export const SessionContextProvider = ({ children }) => { const { isOnline } = useContext(StatusContext); const api = useApi(isOnline); - const keystore = useLocalStorageKeystore(); + const keystoreEvents = new EventTarget(); + const keystore = useLocalStorageKeystore(keystoreEvents); const logout = async () => { // Clear URL parameters @@ -32,6 +33,8 @@ export const SessionContextProvider = ({ children }) => { await keystore.close(); }; + keystoreEvents.addEventListener(KeystoreEvent.Close, logout, { once: true }); + const value: SessionContextValue = { api, isLoggedIn: api.isLoggedIn() && keystore.isOpen(), diff --git a/src/services/LocalStorageKeystore.ts b/src/services/LocalStorageKeystore.ts index 11865682f..46715f83f 100644 --- a/src/services/LocalStorageKeystore.ts +++ b/src/services/LocalStorageKeystore.ts @@ -27,6 +27,13 @@ export type CachedUser = { prfKeys: WebauthnPrfSaltInfo[]; } +export enum KeystoreEvent { + /** The keystore has been closed. This event should be propagated to all tabs. */ + Close = 'keystore.close', + /** The keystore has been closed. This event should not be propagated to other tabs. */ + CloseTabLocal = 'keystore.closeTabLocal', +} + export type CommitCallback = () => Promise; export interface LocalStorageKeystore { isOpen(): boolean, @@ -75,7 +82,7 @@ export interface LocalStorageKeystore { } /** A stateful wrapper around the keystore module, storing state in the browser's localStorage and sessionStorage. */ -export function useLocalStorageKeystore(): LocalStorageKeystore { +export function useLocalStorageKeystore(eventTarget: EventTarget): LocalStorageKeystore { const [cachedUsers, setCachedUsers,] = useLocalStorage("cachedUsers", []); const [privateData, setPrivateData, clearPrivateData] = useLocalStorage("privateData", null); const [globalUserHandleB64u, setGlobalUserHandleB64u, clearGlobalUserHandleB64u] = useLocalStorage("userHandle", null); @@ -97,6 +104,7 @@ export function useLocalStorageKeystore(): LocalStorageKeystore { const closeTabLocal = useCallback( () => { clearSessionStorage(); + eventTarget.dispatchEvent(new CustomEvent(KeystoreEvent.CloseTabLocal)); }, [clearSessionStorage], ); @@ -107,6 +115,7 @@ export function useLocalStorageKeystore(): LocalStorageKeystore { clearPrivateData(); clearGlobalUserHandleB64u(); closeTabLocal(); + eventTarget.dispatchEvent(new CustomEvent(KeystoreEvent.Close)); }, [closeTabLocal, idb, clearGlobalUserHandleB64u, clearPrivateData], ); From 6c49b0428357c2b0ccb4cabcfe16e77bf5cd58fb Mon Sep 17 00:00:00 2001 From: kkmanos Date: Tue, 3 Dec 2024 19:39:26 +0200 Subject: [PATCH 071/162] reinitialize SelectCredentialsPopup + fixes --- .../Popups/SelectCredentialsPopup.js | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/components/Popups/SelectCredentialsPopup.js b/src/components/Popups/SelectCredentialsPopup.js index 356eea63e..58db5e0a7 100644 --- a/src/components/Popups/SelectCredentialsPopup.js +++ b/src/components/Popups/SelectCredentialsPopup.js @@ -58,11 +58,11 @@ const StepBar = ({ totalSteps, currentStep, stepTitles }) => { ); }; -function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopup, container }) { +function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopup, vcEntityList, vcEntityListInstances, container }) { const { api } = useContext(SessionContext); const [vcEntities, setVcEntities] = useState([]); - const { vcEntityList, vcEntityListInstances } = useContext(CredentialsContext); + // const { vcEntityList, vcEntityListInstances } = useContext(CredentialsContext); const { t } = useTranslation(); const keys = useMemo(() => popupState?.options ? Object.keys(popupState.options.conformantCredentialsMap) : null, [popupState]); const stepTitles = useMemo(() => popupState?.options ? Object.keys(popupState.options.conformantCredentialsMap).map(key => key) : null, [popupState]); @@ -77,7 +77,7 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu useEffect(() => { const getData = async () => { if (currentIndex === Object.keys(popupState.options.conformantCredentialsMap).length) { - setPopupState({ isOpen: false }); + reinitialize(); popupState.resolve(new Map(Object.entries(currentSelectionMap))); return; } @@ -98,7 +98,6 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu popupState.options.conformantCredentialsMap[keys[currentIndex]].credentials.includes(vcEntity.credentialIdentifier) ); - console.log("VC entities = ", vcEntities); setRequestedFields(popupState.options.conformantCredentialsMap[keys[currentIndex]].requestedFields); setVcEntities(filteredVcEntities); } catch (error) { @@ -106,9 +105,8 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu } }; - if (popupState?.options) { + if (popupState?.options && container && vcEntityList) { console.log("opts = ", popupState.options) - console.log("Vc entity list = ", vcEntityList) getData(); } }, [ @@ -121,16 +119,6 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu vcEntityList, ]); - useEffect(() => { - if (vcEntityList) { - console.log("VC entity list mutated...", vcEntityList) - } - }, [vcEntityList]) - - useEffect(() => { - console.log("Detected change of popup state inside the SelectCredentialsPopup") - console.log(popupState) - }, [popupState]) useEffect(() => { if (popupState?.options) { @@ -163,10 +151,19 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu } }; + const reinitialize = () => { + setCurrentIndex(0); + setCurrentSlide(1); + setCurrentSelectionMap({}); + setRequestedFields([]); + setSelectedCredential(null); + setPopupState({ isOpen: false }); + } + const onClose = () => { // setIsOpen(false); - setPopupState({ isOpen: false }); popupState.reject(); + reinitialize(); // navigate('/'); } From bc82022fc638acebf71ddbd15cc1229b30cf05bc Mon Sep 17 00:00:00 2001 From: kkmanos Date: Tue, 3 Dec 2024 19:40:09 +0200 Subject: [PATCH 072/162] pass credentials from context to SelectCredentialsPopup component --- src/context/ContainerContext.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/context/ContainerContext.tsx b/src/context/ContainerContext.tsx index 2dc528eb2..0948cf3c5 100644 --- a/src/context/ContainerContext.tsx +++ b/src/context/ContainerContext.tsx @@ -26,6 +26,7 @@ import StatusContext from "./StatusContext"; import SelectCredentialsPopup from "../components/Popups/SelectCredentialsPopup"; import { getSdJwtVcMetadata } from "../lib/utils/getSdJwtVcMetadata"; import { CredentialBatchHelper } from "../lib/services/CredentialBatchHelper"; +import CredentialsContext from '../context/CredentialsContext'; export type ContainerContextValue = { httpProxy: IHttpProxy, @@ -51,6 +52,11 @@ export const ContainerContextProvider = ({ children }) => { const [container, setContainer] = useState(null); const [isInitialized, setIsInitialized] = useState(false); // New flag const [shouldUseCache, setShouldUseCache] = useState(true) + const { vcEntityList, vcEntityListInstances, latestCredentials, getData, currentSlide, setCurrentSlide } = useContext(CredentialsContext); + + useEffect(() => { + getData(); + }, [getData]); const [popupState, setPopupState] = useState({ isOpen: false, @@ -324,12 +330,12 @@ export const ContainerContextProvider = ({ children }) => { }; initialize(); - }, [isLoggedIn, api, container, isInitialized, keystore, isOnline, shouldUseCache]); + }, [isLoggedIn, api, container, isInitialized, keystore, isOnline, shouldUseCache, vcEntityList]); return ( {children} - + ); } From c3114216bc1d609471b0ec9e586e251257c6085c Mon Sep 17 00:00:00 2001 From: kkmanos Date: Tue, 3 Dec 2024 19:41:02 +0200 Subject: [PATCH 073/162] first-party app implementation improvements for cross-compatibility with pushed authorization request --- .../IOpenID4VCIAuthorizationRequest.ts | 2 +- ...izationRequestForFirstPartyApplications.ts | 79 ++++++++++--------- .../OpenID4VCIPushedAuthorizationRequest.ts | 2 +- src/lib/services/OpenID4VCIClient.ts | 31 ++++---- src/pages/AddCredentials/AddCredentials.js | 5 +- 5 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts b/src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts index ee25c31ca..c1c5a9e99 100644 --- a/src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts +++ b/src/lib/interfaces/IOpenID4VCIAuthorizationRequest.ts @@ -8,5 +8,5 @@ export interface IOpenID4VCIAuthorizationRequest { clientId: string, authorizationServerMetadata: OpenidAuthorizationServerMetadata, credentialIssuerMetadata: OpenidCredentialIssuerMetadata, - }): Promise<{ authorizationRequestURL: string } | { authorization_code: string }> + }): Promise<{ authorizationRequestURL: string } | { authorization_code: string; state: string; }> } diff --git a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts index 9fe7f3d2c..2d0c1ddd7 100644 --- a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts +++ b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts @@ -22,7 +22,7 @@ export class OpenID4VCIAuthorizationRequestForFirstPartyApplications implements clientId: string, authorizationServerMetadata: OpenidAuthorizationServerMetadata, credentialIssuerMetadata: OpenidCredentialIssuerMetadata, - }): Promise<{ authorizationRequestURL: string } | { authorization_code: string }> { + }): Promise<{ authorizationRequestURL: string } | { authorization_code: string; state: string; }> { const { code_challenge, code_verifier } = await pkce(); const formData = new URLSearchParams(); @@ -49,46 +49,53 @@ export class OpenID4VCIAuthorizationRequestForFirstPartyApplications implements res = await this.httpProxy.post(config.authorizationServerMetadata.authorization_challenge_endpoint, formData.toString(), { 'Content-Type': 'application/x-www-form-urlencoded' }); - } - catch (err) { - if (err?.response?.data && err?.response?.data?.error === "insufficient_authorization") { // Authorization Error Response - const { error, auth_session, presentation } = err?.response?.data; - - // this function should prompt the user for presentation selection - const result = await this.openID4VPRelyingParty.handleAuthorizationRequest("openid4vp:" + presentation).then((res) => { - if ('err' in res) { - return; + console.log("Res = ", res) + const err = res.err; + if (err) { + if (err?.data && err?.data?.error === "insufficient_authorization") { // Authorization Error Response + const { error, auth_session, presentation } = err?.data; + + // this function should prompt the user for presentation selection + const result = await this.openID4VPRelyingParty.handleAuthorizationRequest("openid4vp:" + presentation).then((res) => { + if ('err' in res) { + return; + } + + const jsonedMap = Object.fromEntries(res.conformantCredentialsMap); + return this.openID4VPRelyingParty.promptForCredentialSelection(jsonedMap, config.credentialIssuerMetadata.credential_issuer); + }).then((selectionMap) => { + return this.openID4VPRelyingParty.sendAuthorizationResponse(selectionMap); + }); + + if (!('presentation_during_issuance_session' in result)) { + throw new Error("presentation_during_issuance_session is not present in the result of the presentation sending phase"); } - - const jsonedMap = Object.fromEntries(res.conformantCredentialsMap); - return this.openID4VPRelyingParty.promptForCredentialSelection(jsonedMap, config.credentialIssuerMetadata.credential_issuer); - }).then((selectionMap) => { - return this.openID4VPRelyingParty.sendAuthorizationResponse(selectionMap); - }); - - if (!('presentation_during_issuance_session' in result)) { - throw new Error("presentation_during_issuance_session is not present in the result of the presentation sending phase"); + const presentation_during_issuance_session = result.presentation_during_issuance_session; + // add auth_session and presentation_during_issuance_session params on authorization_challenge_endpoint POST request + formData.append("auth_session", auth_session); + formData.append("presentation_during_issuance_session", presentation_during_issuance_session); + res = await this.httpProxy.post(config.authorizationServerMetadata.authorization_challenge_endpoint, formData.toString(), { + 'Content-Type': 'application/x-www-form-urlencoded' + }); + + if (!res.data.authorization_code) { + throw new Error("authorization_code not present on the authorization response"); + } + await this.openID4VCIClientStateRepository.create(new OpenID4VCIClientState(userHandleB64u, config.credentialIssuerIdentifier, state, code_verifier, credentialConfigurationId, undefined, undefined, { auth_session: auth_session })); + + return { authorization_code: res.data.authorization_code, state: state }; } - const presentation_during_issuance_session = result.presentation_during_issuance_session; - // add auth_session and presentation_during_issuance_session params on authorization_challenge_endpoint POST request - formData.append("auth_session", auth_session); - formData.append("presentation_during_issuance_session", presentation_during_issuance_session); - res = await this.httpProxy.post(config.authorizationServerMetadata.authorization_challenge_endpoint, formData.toString(), { - 'Content-Type': 'application/x-www-form-urlencoded' - }); - - if (!res.data.authorization_code) { - throw new Error("authorization_code not present on the authorization response"); + else { + console.error(err); + throw new Error("First party app authorization failed"); } - await this.openID4VCIClientStateRepository.create(new OpenID4VCIClientState(userHandleB64u, config.credentialIssuerIdentifier, state, code_verifier, credentialConfigurationId, undefined, undefined, { auth_session: auth_session })); - - return { authorization_code: res.data.authorization_code }; - } - else { - console.error(err); - throw new Error("Pushed authorization request failed") } } + catch (err) { + + } + + throw new Error("First party app authorization failed"); } } diff --git a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts index 1b826682b..19c7d469c 100644 --- a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts +++ b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.ts @@ -20,7 +20,7 @@ export class OpenID4VCIPushedAuthorizationRequest implements IOpenID4VCIAuthoriz clientId: string, authorizationServerMetadata: OpenidAuthorizationServerMetadata, credentialIssuerMetadata: OpenidCredentialIssuerMetadata, - }): Promise<{ authorizationRequestURL: string } | { authorization_code: string }> { + }): Promise<{ authorizationRequestURL: string } | { authorization_code: string; state: string; }> { const { code_challenge, code_verifier } = await pkce(); const formData = new URLSearchParams(); diff --git a/src/lib/services/OpenID4VCIClient.ts b/src/lib/services/OpenID4VCIClient.ts index 750585250..cf9a1e666 100644 --- a/src/lib/services/OpenID4VCIClient.ts +++ b/src/lib/services/OpenID4VCIClient.ts @@ -93,8 +93,8 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { } catch (err) { console.error(err) } - if (this.config.authorizationServerMetadata.pushed_authorization_request_endpoint) { - const res = await this.openID4VCIPushedAuthorizationRequest.generate( + if (this.config.authorizationServerMetadata.authorization_challenge_endpoint) { + await this.openID4VCIAuthorizationRequestForFirstPartyApplications.generate( credentialConfigurationId, userHandleB64u, issuer_state, @@ -102,13 +102,17 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { ...this.config, redirectUri: redirectUri } - ); - if ('authorizationRequestURL' in res) { - return { url: res.authorizationRequestURL }; - } + ).then((result) => { + if (!('authorization_code' in result)) { + console.error("authorization_code was not found in the result"); + return; + } + return this.handleAuthorizationResponse(`openid://?code=${result.authorization_code}&state=${result.state}`, userHandleB64u); + }); + return { } } - else if (this.config.authorizationServerMetadata.authorization_challenge_endpoint) { - await this.openID4VCIAuthorizationRequestForFirstPartyApplications.generate( + else if (this.config.authorizationServerMetadata.pushed_authorization_request_endpoint) { + const res = await this.openID4VCIPushedAuthorizationRequest.generate( credentialConfigurationId, userHandleB64u, issuer_state, @@ -116,13 +120,10 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { ...this.config, redirectUri: redirectUri } - ).then((result) => { - if (!('authorization_code' in result)) { - console.error("authorization_code was not found in the result"); - return; - } - return this.handleAuthorizationResponse(`openid://?code=${result.authorization_code}`, userHandleB64u); - }); + ); + if ('authorizationRequestURL' in res) { + return { url: res.authorizationRequestURL }; + } } } diff --git a/src/pages/AddCredentials/AddCredentials.js b/src/pages/AddCredentials/AddCredentials.js index c18708dab..07cb62f5b 100644 --- a/src/pages/AddCredentials/AddCredentials.js +++ b/src/pages/AddCredentials/AddCredentials.js @@ -83,8 +83,9 @@ const Issuers = () => { console.error("Could not generate authorization request because user handle is null"); return; } - cl.generateAuthorizationRequest(selectedConfigurationId, userHandleB64u).then(({ url }) => { - if (url) { + cl.generateAuthorizationRequest(selectedConfigurationId, userHandleB64u).then((result) => { + if ('url' in result) { + const { url } = result; window.location.href = url; } }).catch((err) => { From 3ca75141bb78fbe1887a827eb0430087e1285496 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Thu, 5 Dec 2024 11:56:01 +0200 Subject: [PATCH 074/162] Restore credential caching --- src/lib/services/CredentialParserRegistry.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/services/CredentialParserRegistry.ts b/src/lib/services/CredentialParserRegistry.ts index 5f2a300ba..99f05216e 100644 --- a/src/lib/services/CredentialParserRegistry.ts +++ b/src/lib/services/CredentialParserRegistry.ts @@ -25,7 +25,8 @@ export class CredentialParserRegistry implements ICredentialParserRegistry { for (const p of this.parserList) { const result = await p.parse(rawCredential, presentationDefinitionFilter).catch(() => null); if (result && 'beautifiedForm' in result) { - return result + this.parsedObjectsCache.set(hash, result); + return result; } } return { error: "All parsings failed" }; From 6fb4f5bf72e9c8ebc836f9e2ba658d1e2e8a52e8 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Thu, 5 Dec 2024 17:01:12 +0200 Subject: [PATCH 075/162] Fix cleanSessionStorage on every logout way --- src/context/SessionContext.tsx | 14 ++++++++------ src/services/LocalStorageKeystore.ts | 7 +++---- src/services/keystoreEvents.ts | 3 +++ 3 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 src/services/keystoreEvents.ts diff --git a/src/context/SessionContext.tsx b/src/context/SessionContext.tsx index 225002967..da54c6ec7 100644 --- a/src/context/SessionContext.tsx +++ b/src/context/SessionContext.tsx @@ -1,10 +1,10 @@ -import React, { createContext, useContext } from 'react'; +import React, { createContext, useContext, useEffect } from 'react'; import StatusContext from './StatusContext'; import { BackendApi, useApi } from '../api'; import { KeystoreEvent, useLocalStorageKeystore } from '../services/LocalStorageKeystore'; import type { LocalStorageKeystore } from '../services/LocalStorageKeystore'; - +import keystoreEvents from '../services/keystoreEvents'; type SessionContextValue = { api: BackendApi, @@ -23,17 +23,19 @@ const SessionContext: React.Context = createContext({ export const SessionContextProvider = ({ children }) => { const { isOnline } = useContext(StatusContext); const api = useApi(isOnline); - const keystoreEvents = new EventTarget(); const keystore = useLocalStorageKeystore(keystoreEvents); - const logout = async () => { - // Clear URL parameters + const clearSession = async () => { sessionStorage.setItem('freshLogin', 'true'); api.clearSession(); + }; + + const logout = async () => { + clearSession(); await keystore.close(); }; - keystoreEvents.addEventListener(KeystoreEvent.Close, logout, { once: true }); + keystoreEvents.addEventListener(KeystoreEvent.CloseTabLocal, clearSession, {once: true}); const value: SessionContextValue = { api, diff --git a/src/services/LocalStorageKeystore.ts b/src/services/LocalStorageKeystore.ts index 46715f83f..2d6af6354 100644 --- a/src/services/LocalStorageKeystore.ts +++ b/src/services/LocalStorageKeystore.ts @@ -102,11 +102,11 @@ export function useLocalStorageKeystore(eventTarget: EventTarget): LocalStorageK }, [])); const closeTabLocal = useCallback( - () => { - clearSessionStorage(); + async (): Promise => { eventTarget.dispatchEvent(new CustomEvent(KeystoreEvent.CloseTabLocal)); + clearSessionStorage(); }, - [clearSessionStorage], + [clearSessionStorage, eventTarget], ); const close = useCallback( @@ -115,7 +115,6 @@ export function useLocalStorageKeystore(eventTarget: EventTarget): LocalStorageK clearPrivateData(); clearGlobalUserHandleB64u(); closeTabLocal(); - eventTarget.dispatchEvent(new CustomEvent(KeystoreEvent.Close)); }, [closeTabLocal, idb, clearGlobalUserHandleB64u, clearPrivateData], ); diff --git a/src/services/keystoreEvents.ts b/src/services/keystoreEvents.ts new file mode 100644 index 000000000..45317d02d --- /dev/null +++ b/src/services/keystoreEvents.ts @@ -0,0 +1,3 @@ +// keystoreEvents.js +const keystoreEvents = new EventTarget(); +export default keystoreEvents; From 4d0f70d60dfe8add82869dfbeeb2db8e5b548d1d Mon Sep 17 00:00:00 2001 From: kkmanos Date: Thu, 5 Dec 2024 18:18:41 +0200 Subject: [PATCH 076/162] prioritize pushed authorization endpoint if supported --- src/lib/services/OpenID4VCIClient.ts | 31 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/lib/services/OpenID4VCIClient.ts b/src/lib/services/OpenID4VCIClient.ts index a924ec135..d9b221542 100644 --- a/src/lib/services/OpenID4VCIClient.ts +++ b/src/lib/services/OpenID4VCIClient.ts @@ -93,7 +93,22 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { } catch (err) { console.error(err) } - if (this.config.authorizationServerMetadata.authorization_challenge_endpoint) { + + if (this.config.authorizationServerMetadata.pushed_authorization_request_endpoint) { + const res = await this.openID4VCIPushedAuthorizationRequest.generate( + credentialConfigurationId, + userHandleB64u, + issuer_state, + { + ...this.config, + redirectUri: redirectUri + } + ); + if ('authorizationRequestURL' in res) { + return { url: res.authorizationRequestURL }; + } + } + else if (this.config.authorizationServerMetadata.authorization_challenge_endpoint) { await this.openID4VCIAuthorizationRequestForFirstPartyApplications.generate( credentialConfigurationId, userHandleB64u, @@ -111,20 +126,6 @@ export class OpenID4VCIClient implements IOpenID4VCIClient { }); return { } } - else if (this.config.authorizationServerMetadata.pushed_authorization_request_endpoint) { - const res = await this.openID4VCIPushedAuthorizationRequest.generate( - credentialConfigurationId, - userHandleB64u, - issuer_state, - { - ...this.config, - redirectUri: redirectUri - } - ); - if ('authorizationRequestURL' in res) { - return { url: res.authorizationRequestURL }; - } - } } async handleAuthorizationResponse(url: string, userHandleB64U: string, dpopNonceHeader?: string) { From 06bc0ed8649d5ce2ad86b635b4ec3da14817de4c Mon Sep 17 00:00:00 2001 From: kkmanos Date: Thu, 5 Dec 2024 18:23:19 +0200 Subject: [PATCH 077/162] formatting fixes --- ...VCIAuthorizationRequestForFirstPartyApplications.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts index 2d0c1ddd7..35ba1db07 100644 --- a/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts +++ b/src/lib/services/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.ts @@ -54,19 +54,19 @@ export class OpenID4VCIAuthorizationRequestForFirstPartyApplications implements if (err) { if (err?.data && err?.data?.error === "insufficient_authorization") { // Authorization Error Response const { error, auth_session, presentation } = err?.data; - + // this function should prompt the user for presentation selection const result = await this.openID4VPRelyingParty.handleAuthorizationRequest("openid4vp:" + presentation).then((res) => { if ('err' in res) { return; } - + const jsonedMap = Object.fromEntries(res.conformantCredentialsMap); return this.openID4VPRelyingParty.promptForCredentialSelection(jsonedMap, config.credentialIssuerMetadata.credential_issuer); }).then((selectionMap) => { return this.openID4VPRelyingParty.sendAuthorizationResponse(selectionMap); }); - + if (!('presentation_during_issuance_session' in result)) { throw new Error("presentation_during_issuance_session is not present in the result of the presentation sending phase"); } @@ -77,12 +77,12 @@ export class OpenID4VCIAuthorizationRequestForFirstPartyApplications implements res = await this.httpProxy.post(config.authorizationServerMetadata.authorization_challenge_endpoint, formData.toString(), { 'Content-Type': 'application/x-www-form-urlencoded' }); - + if (!res.data.authorization_code) { throw new Error("authorization_code not present on the authorization response"); } await this.openID4VCIClientStateRepository.create(new OpenID4VCIClientState(userHandleB64u, config.credentialIssuerIdentifier, state, code_verifier, credentialConfigurationId, undefined, undefined, { auth_session: auth_session })); - + return { authorization_code: res.data.authorization_code, state: state }; } else { From 1b09b5233efc0a779b42e5b3072dfad37cc2d555 Mon Sep 17 00:00:00 2001 From: jlsOsorio <61560186+jlsOsorio@users.noreply.github.com> Date: Mon, 9 Dec 2024 12:54:28 +0000 Subject: [PATCH 078/162] refactor: change selector to dropdown layout Set language selector back to dropdown layout. The options are now available in the Login page, with only the alpha-2 code (flag) and in Settings with the full label. The Login page is not displaying the full label because it would turn the layout messy, overlapping the main description. --- .../LanguageSelector/LanguageOption.tsx | 37 -------------- .../LanguageSelector/LanguageSelector.tsx | 49 +++++++++---------- src/components/LanguageSelector/languages.ts | 2 +- src/components/Layout/Navigation/Sidebar.js | 2 - src/locales/en.json | 1 + src/pages/Login/Login.tsx | 5 +- src/pages/Settings/Settings.tsx | 12 +++++ 7 files changed, 38 insertions(+), 70 deletions(-) delete mode 100644 src/components/LanguageSelector/LanguageOption.tsx diff --git a/src/components/LanguageSelector/LanguageOption.tsx b/src/components/LanguageSelector/LanguageOption.tsx deleted file mode 100644 index 9c3e711ac..000000000 --- a/src/components/LanguageSelector/LanguageOption.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; - -import Button from "../Buttons/Button"; -import { languageOptions } from "./languages"; - -type LanguageOptionProps = { - onClose: () => void; -}; - -const LanguageOption = ({ onClose }: LanguageOptionProps) => { - const { i18n } = useTranslation(); - const { language } = i18n; - - const handleLanguageChange = (value: string) => { - i18n.changeLanguage(value); - onClose(); - }; - - return ( -
- {languageOptions.map((lang) => ( - - ))} -
- ); -}; - -export default LanguageOption; diff --git a/src/components/LanguageSelector/LanguageSelector.tsx b/src/components/LanguageSelector/LanguageSelector.tsx index f34b02561..e117b3fbb 100644 --- a/src/components/LanguageSelector/LanguageSelector.tsx +++ b/src/components/LanguageSelector/LanguageSelector.tsx @@ -1,40 +1,37 @@ -import React, { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { FaLanguage } from "react-icons/fa"; +import React from "react"; -import PopupLayout from "../Popups/PopupLayout"; -import LanguageOption from "./LanguageOption"; +import { useTranslation } from "react-i18next"; +import { languageOptions } from "./languages"; type LanguageSelectorProps = { className: string; - iconSize?: number; - hasLabel: boolean; + showFullLabel: boolean; }; const LanguageSelector = ({ className, - iconSize, - hasLabel = true, + showFullLabel = true, }: LanguageSelectorProps) => { - const { t } = useTranslation(); - const [isOpenLanguageOptions, setIsOpenLanguageOptions] = useState(false); + const { i18n } = useTranslation(); + const { language } = i18n; + + const handleChangeLanguage = (event) => { + const selectedLanguage = event.target.value; + i18n.changeLanguage(selectedLanguage); + }; return ( - <> - - setIsOpenLanguageOptions(false)} - > - setIsOpenLanguageOptions(false)} /> - - + ); }; diff --git a/src/components/LanguageSelector/languages.ts b/src/components/LanguageSelector/languages.ts index 0d3b8731e..ee9e76487 100644 --- a/src/components/LanguageSelector/languages.ts +++ b/src/components/LanguageSelector/languages.ts @@ -5,5 +5,5 @@ type Option = { export const languageOptions: Option[] = [ { value: "en", label: "🇺🇸 English" }, - // { value: 'el', label: '🇬🇷 Ελληνικά' }, + // { value: "el", label: "🇬🇷 Ελληνικά" }, ]; diff --git a/src/components/Layout/Navigation/Sidebar.js b/src/components/Layout/Navigation/Sidebar.js index 9a1986d60..a560464f5 100644 --- a/src/components/Layout/Navigation/Sidebar.js +++ b/src/components/Layout/Navigation/Sidebar.js @@ -10,7 +10,6 @@ import StatusContext from '../../../context/StatusContext'; import SessionContext from '../../../context/SessionContext'; import { MdNotifications } from "react-icons/md"; import ConnectionStatusIcon from './ConnectionStatusIcon'; -import LanguageSelector from '../../LanguageSelector/LanguageSelector'; const NavItem = ({ children, @@ -154,7 +153,6 @@ const Sidebar = ({ isOpen, toggle }) => {
- + {t('common.walletName')} diff --git a/src/components/Layout/Navigation/Sidebar.js b/src/components/Layout/Navigation/Sidebar.js index a560464f5..669e2d69e 100644 --- a/src/components/Layout/Navigation/Sidebar.js +++ b/src/components/Layout/Navigation/Sidebar.js @@ -4,7 +4,7 @@ import { FaWallet, FaUserCircle } from "react-icons/fa"; import { IoIosTime, IoIosAddCircle, IoIosSend, IoMdSettings } from "react-icons/io"; import { useLocation, useNavigate } from 'react-router-dom'; import useScreenType from '../../../hooks/useScreenType'; -import logo from '../../../assets/images/wallet_white.png'; +import Logo from '../../Logo/Logo'; import { Trans, useTranslation } from 'react-i18next'; import StatusContext from '../../../context/StatusContext'; import SessionContext from '../../../context/SessionContext'; @@ -65,9 +65,7 @@ const Sidebar = ({ isOpen, toggle }) => {
- + diff --git a/src/components/Logo/Logo.tsx b/src/components/Logo/Logo.tsx new file mode 100644 index 000000000..5611c888b --- /dev/null +++ b/src/components/Logo/Logo.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import logoClassic from '../../assets/images/logo.png'; +import logoWhite from '../../assets/images/wallet_white.png'; + +interface LogoProps { + type?: string; // Determines the type of logo (classic or white) + aClassName?: string; // Class for the element + imglassName?: string; // Class for the element + alt?: string; // Alt text for the logo +} + +const Logo: React.FC = ({ + type = 'classic', + aClassName = '', + imglassName = '', + alt = 'Logo', +}) => { + // Determine which logo to use + const logoSrc = type === 'white' ? logoWhite : logoClassic; + + return ( + + {alt} + + ); +}; + +export default Logo; diff --git a/src/components/Notifications/HandlerNotification.js b/src/components/Notifications/HandlerNotification.js index 3ab177b1f..111927c26 100644 --- a/src/components/Notifications/HandlerNotification.js +++ b/src/components/Notifications/HandlerNotification.js @@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback, useContext } from 'react'; import toast, { Toaster } from 'react-hot-toast'; import { onMessageListener } from '../../firebase'; import { AiOutlineClose } from 'react-icons/ai'; -import logo from '../../assets/images/logo.png'; +import Logo from '../Logo/Logo'; import CredentialsContext from '../../context/CredentialsContext'; const ToastDisplay = ({ id, notification }) => { @@ -12,7 +12,7 @@ const ToastDisplay = ({ id, notification }) => { onClick={() => window.location.href = '/'} >
- Logo +

{notification?.title}

diff --git a/src/pages/NotFound/NotFound.js b/src/pages/NotFound/NotFound.js index 17993b083..f6e8a6338 100644 --- a/src/pages/NotFound/NotFound.js +++ b/src/pages/NotFound/NotFound.js @@ -1,5 +1,5 @@ import React from 'react'; -import logo from '../../assets/images/logo.png'; +import Logo from '../../components/Logo/Logo'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import Button from '../../components/Buttons/Button'; @@ -16,9 +16,7 @@ const NotFound = () => { return (
- - logo - +

{t('common.walletName')}

From 0891eeb7ed3df02dfee3db42cc0017991f350926 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 7 Jan 2025 12:55:56 +0200 Subject: [PATCH 083/162] Feat: add dynamic logo switching based on Christmas season --- src/assets/images/logo_christmas.png | Bin 0 -> 368543 bytes src/assets/images/wallet_white_christmas.png | Bin 0 -> 334086 bytes src/components/Logo/Logo.tsx | 25 +++++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/assets/images/logo_christmas.png create mode 100644 src/assets/images/wallet_white_christmas.png diff --git a/src/assets/images/logo_christmas.png b/src/assets/images/logo_christmas.png new file mode 100644 index 0000000000000000000000000000000000000000..119f5ecaad3307ccd3a97ad2336cdde9b88494bb GIT binary patch literal 368543 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 SCdweN%*y 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

t=I6h!qm- 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 K1LZD9zWFCOzA$nC literal 0 HcmV?d00001 diff --git a/src/assets/images/wallet_white_christmas.png b/src/assets/images/wallet_white_christmas.png new file mode 100644 index 0000000000000000000000000000000000000000..f401a198618a810b044e39325e67ddd14feeee00 GIT binary patch literal 334086 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 +Iy%~a@GPSQ$WMlWF*>l< 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 z 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 z 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ⅈ%(TN};ugoDBOA^Hsw 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 P|H(a2l+L?n=<|O7@R+(9 literal 0 HcmV?d00001 diff --git a/src/components/Logo/Logo.tsx b/src/components/Logo/Logo.tsx index 5611c888b..e1e817dd5 100644 --- a/src/components/Logo/Logo.tsx +++ b/src/components/Logo/Logo.tsx @@ -1,6 +1,8 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import logoClassic from '../../assets/images/logo.png'; import logoWhite from '../../assets/images/wallet_white.png'; +import logoClassicChristmas from '../../assets/images/logo_christmas.png'; +import logoWhiteChristmas from '../../assets/images/wallet_white_christmas.png'; interface LogoProps { type?: string; // Determines the type of logo (classic or white) @@ -15,8 +17,27 @@ const Logo: React.FC = ({ imglassName = '', alt = 'Logo', }) => { + const [isChristmasSeason, setIsChristmasSeason] = useState(false); + + useEffect(() => { + const checkSeason = () => { + const today = new Date(); + const currentYear = today.getFullYear(); + const start = new Date(currentYear, 11, 1); // December 1 + const end = new Date(currentYear + 1, 0, 2); // January 2 + return today >= start && today <= end; + }; + + setIsChristmasSeason(checkSeason()); + }, []); + // Determine which logo to use - const logoSrc = type === 'white' ? logoWhite : logoClassic; + const logoSrc = (() => { + if (isChristmasSeason) { + return type === 'white' ? logoWhiteChristmas : logoClassicChristmas; + } + return type === 'white' ? logoWhite : logoClassic; + })(); return ( From ea37ad9b00fa4b09abb6b73e6d337136064d4f67 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 7 Jan 2025 13:46:00 +0200 Subject: [PATCH 084/162] Refine Christmas season handling to ensure continuity across year change --- .../ChristmasAnimation/Snowfalling.js | 15 ++++++++++---- src/components/Logo/Logo.tsx | 20 ++++++++++++++----- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/components/ChristmasAnimation/Snowfalling.js b/src/components/ChristmasAnimation/Snowfalling.js index 0c8ec8691..16402d52c 100644 --- a/src/components/ChristmasAnimation/Snowfalling.js +++ b/src/components/ChristmasAnimation/Snowfalling.js @@ -6,13 +6,20 @@ const Snowfalling = () => { useEffect(() => { const checkSeason = () => { - const today = new Date(); + const today = new Date(); // Use new Date() for real-time or new Date(new Date().getFullYear(), 0, 1) for testing January 1st const currentYear = today.getFullYear(); - const start = new Date(currentYear, 11, 20); - const end = new Date(currentYear + 1, 0, 6); + // Christmas season part 1: December 1st to December 20th of the current year + const christmasStart = new Date(currentYear, 11, 20); // December 20 + const christmasEnd = new Date(currentYear, 11, 31); // December 31 - return today >= start && today <= end; + // Christmas season part 2: January 1st to January 6th of the next year + const newYearStart = new Date(currentYear, 0, 1); // January 1 + const newYearEnd = new Date(currentYear, 0, 6); // January 6 + + // Check if today is within either part of the Christmas season + return (today >= christmasStart && today <= christmasEnd) || + (today >= newYearStart && today <= newYearEnd); }; setIsChristmasSeason(checkSeason()); diff --git a/src/components/Logo/Logo.tsx b/src/components/Logo/Logo.tsx index e1e817dd5..19405ff42 100644 --- a/src/components/Logo/Logo.tsx +++ b/src/components/Logo/Logo.tsx @@ -21,14 +21,24 @@ const Logo: React.FC = ({ useEffect(() => { const checkSeason = () => { - const today = new Date(); + const today = new Date(); // Use new Date() for real-time or new Date(new Date().getFullYear(), 0, 1) for testing January 1st const currentYear = today.getFullYear(); - const start = new Date(currentYear, 11, 1); // December 1 - const end = new Date(currentYear + 1, 0, 2); // January 2 - return today >= start && today <= end; + + // Christmas season part 1: December 1st to December 31st of the current year + const christmasStart = new Date(currentYear, 11, 1); // December 1 + const christmasEnd = new Date(currentYear, 11, 31); // December 31 + + // Christmas season part 2: January 1st to January 2nd of the next year + const newYearStart = new Date(currentYear, 0, 1); // January 1 + const newYearEnd = new Date(currentYear, 0, 2); // January 2 + + // Check if today is within either part of the Christmas season + return (today >= christmasStart && today <= christmasEnd) || + (today >= newYearStart && today <= newYearEnd); }; - setIsChristmasSeason(checkSeason()); + const seasonActive = checkSeason(); + setIsChristmasSeason(seasonActive); }, []); // Determine which logo to use From 030725b42beacbc5ab8caf54dcdf6dfe7d72f1f0 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 7 Jan 2025 15:00:46 +0200 Subject: [PATCH 085/162] Remove alt prop on Logo.tsx and add aria-label on --- src/components/Logo/Logo.tsx | 8 ++++---- src/pages/NotFound/NotFound.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/Logo/Logo.tsx b/src/components/Logo/Logo.tsx index 19405ff42..0d5f98f3c 100644 --- a/src/components/Logo/Logo.tsx +++ b/src/components/Logo/Logo.tsx @@ -3,21 +3,21 @@ import logoClassic from '../../assets/images/logo.png'; import logoWhite from '../../assets/images/wallet_white.png'; import logoClassicChristmas from '../../assets/images/logo_christmas.png'; import logoWhiteChristmas from '../../assets/images/wallet_white_christmas.png'; +import { useTranslation } from 'react-i18next'; interface LogoProps { type?: string; // Determines the type of logo (classic or white) aClassName?: string; // Class for the element imglassName?: string; // Class for the element - alt?: string; // Alt text for the logo } const Logo: React.FC = ({ type = 'classic', aClassName = '', imglassName = '', - alt = 'Logo', }) => { const [isChristmasSeason, setIsChristmasSeason] = useState(false); + const { t } = useTranslation(); useEffect(() => { const checkSeason = () => { @@ -50,8 +50,8 @@ const Logo: React.FC = ({ })(); return ( - - {alt} + + {t('common.walletName')} ); }; diff --git a/src/pages/NotFound/NotFound.js b/src/pages/NotFound/NotFound.js index f6e8a6338..80609b183 100644 --- a/src/pages/NotFound/NotFound.js +++ b/src/pages/NotFound/NotFound.js @@ -16,7 +16,7 @@ const NotFound = () => { return (

- +

{t('common.walletName')}

From 24aaca7577ae800c70ad9dc17778a882c3ce0d64 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 7 Jan 2025 17:22:45 +0200 Subject: [PATCH 086/162] Fix imgClassName typo --- src/components/Auth/LoginLayout.tsx | 2 +- src/components/Layout/Header.js | 2 +- src/components/Layout/Navigation/Sidebar.js | 4 ++-- src/components/Logo/Logo.tsx | 6 +++--- src/pages/NotFound/NotFound.js | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/Auth/LoginLayout.tsx b/src/components/Auth/LoginLayout.tsx index 262166e17..ba29453ef 100644 --- a/src/components/Auth/LoginLayout.tsx +++ b/src/components/Auth/LoginLayout.tsx @@ -9,7 +9,7 @@ export default function LoginLayout({ children, heading }: { children: React.Rea return (
- +

{heading} diff --git a/src/components/Layout/Header.js b/src/components/Layout/Header.js index 4898569bf..afee5ad95 100644 --- a/src/components/Layout/Header.js +++ b/src/components/Layout/Header.js @@ -27,7 +27,7 @@ const Header = () => {
- + {t('common.walletName')} diff --git a/src/components/Layout/Navigation/Sidebar.js b/src/components/Layout/Navigation/Sidebar.js index 669e2d69e..9d56a6e18 100644 --- a/src/components/Layout/Navigation/Sidebar.js +++ b/src/components/Layout/Navigation/Sidebar.js @@ -65,7 +65,7 @@ const Sidebar = ({ isOpen, toggle }) => {
- + diff --git a/src/components/Logo/Logo.tsx b/src/components/Logo/Logo.tsx index 0d5f98f3c..56b0a501a 100644 --- a/src/components/Logo/Logo.tsx +++ b/src/components/Logo/Logo.tsx @@ -8,13 +8,13 @@ import { useTranslation } from 'react-i18next'; interface LogoProps { type?: string; // Determines the type of logo (classic or white) aClassName?: string; // Class for the element - imglassName?: string; // Class for the element + imgClassName?: string; // Class for the element } const Logo: React.FC = ({ type = 'classic', aClassName = '', - imglassName = '', + imgClassName = '', }) => { const [isChristmasSeason, setIsChristmasSeason] = useState(false); const { t } = useTranslation(); @@ -51,7 +51,7 @@ const Logo: React.FC = ({ return ( - {t('common.walletName')} + {t('common.walletName')} ); }; diff --git a/src/pages/NotFound/NotFound.js b/src/pages/NotFound/NotFound.js index 80609b183..16fa2b5e7 100644 --- a/src/pages/NotFound/NotFound.js +++ b/src/pages/NotFound/NotFound.js @@ -16,7 +16,7 @@ const NotFound = () => { return (
- +

{t('common.walletName')}

From f59f415246a8d1a5e17c36ffefd77bc2fed93685 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Wed, 8 Jan 2025 10:25:48 +0200 Subject: [PATCH 087/162] cleanup redundant classes --- src/lib/DIContainer.ts | 18 -------- .../AccessTokenManager/AccessTokenManager.tsx | 45 ------------------- .../CredentialEndpoint/CredentialEndpoint.tsx | 20 --------- 3 files changed, 83 deletions(-) delete mode 100644 src/lib/DIContainer.ts delete mode 100644 src/lib/services/OpenID4VCI/AccessTokenManager/AccessTokenManager.tsx delete mode 100644 src/lib/services/OpenID4VCI/CredentialEndpoint/CredentialEndpoint.tsx diff --git a/src/lib/DIContainer.ts b/src/lib/DIContainer.ts deleted file mode 100644 index 6f9298c7e..000000000 --- a/src/lib/DIContainer.ts +++ /dev/null @@ -1,18 +0,0 @@ -type Constructor = new (...args: any[]) => T; - -export class DIContainer { - private services = new Map(); - - register(name: string, service: Constructor, ...args: any[]): void { - this.services.set(name, new service(...args)); - } - - resolve(name: string): T { - const service = this.services.get(name); - if (!service) { - throw new Error(`Service not found: ${name}`); - } - return service; - } -} - diff --git a/src/lib/services/OpenID4VCI/AccessTokenManager/AccessTokenManager.tsx b/src/lib/services/OpenID4VCI/AccessTokenManager/AccessTokenManager.tsx deleted file mode 100644 index 4617f3a81..000000000 --- a/src/lib/services/OpenID4VCI/AccessTokenManager/AccessTokenManager.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useContext } from "react" -import SessionContext from "../../../../context/SessionContext" - - -export type AccessToken = { - access_token: string; - expires_in: number; - c_nonce: string; - c_nonce_expires_in: number; - refresh_token?: string; -} - -export enum GetAccessTokenErr { - NO_TOK_AVAILABLE -} - -export function useAccessTokenManager() { - - const { keystore } = useContext(SessionContext); - - - async function getAccessToken(credentialIssuerIdentifier: string): Promise<{ at: AccessToken } | { err: GetAccessTokenErr }> { - // get active access token for keystore.getUserHandle and this credentialIssuerIdentifier by searching the openid4vci client state repo - // if current access token is valid, return it from the flow state - // else if refresh token is available - // then getAccessTokenWithRefreshTokenGrant() and return the token - // else if authorizatio code currently available then execute getAccessTokenWithAuthorizationCodeGrant() and return it - // else return GetAccessTokenErr - } - - function getAccessTokenUsingAuthorizationCodeGrant(credentialIssuerIdentifier: string) { - // request token using authorization code grant - // the request will be constructed using the current flowstate - } - - - function getAccessTokenUsingRefreshTokenGrant(credentialIssuerIdentifier: string) { - // request token using refrhes token grant - // the request will be constructed using the current flowstate - } - - return { - getAccessToken - } -} \ No newline at end of file diff --git a/src/lib/services/OpenID4VCI/CredentialEndpoint/CredentialEndpoint.tsx b/src/lib/services/OpenID4VCI/CredentialEndpoint/CredentialEndpoint.tsx deleted file mode 100644 index d578a75b4..000000000 --- a/src/lib/services/OpenID4VCI/CredentialEndpoint/CredentialEndpoint.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useContext } from "react"; -import { AccessToken } from "../AccessTokenManager/AccessTokenManager"; -import SessionContext from "../../../../context/SessionContext"; -import { useHttpProxy } from "../../HttpProxy/HttpProxy"; - - -export function useCredentialEndpoint() { - - const { keystore } = useContext(SessionContext); - const httpProxy = useHttpProxy(); - - async function sendCredentialRequest(at: AccessToken) { - // manage cached proofs etc.... - // if credential request fails due to dpop nonce issue, then request again - } - - return { - sendCredentialRequest - } -} \ No newline at end of file From 778c119986425e3fd2a5055773b235bb63eb607e Mon Sep 17 00:00:00 2001 From: kkmanos Date: Wed, 8 Jan 2025 12:03:58 +0200 Subject: [PATCH 088/162] fix: history display --- src/components/History/HistoryList.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/History/HistoryList.js b/src/components/History/HistoryList.js index cd71fa7ff..6d351d124 100644 --- a/src/components/History/HistoryList.js +++ b/src/components/History/HistoryList.js @@ -22,7 +22,18 @@ const HistoryList = ({ credentialId = null, history, title = '', limit = null }) }, [history, credentialId, limit]); const handleHistoryItemClick = async (item) => { - setMatchingCredentials(item.presentation.startsWith("b64:") ? JSON.parse(new TextDecoder().decode(fromBase64(item.presentation.replace("b64:", "")))) : [ item.presentation ] ); + const extractPresentations = (item) => { + if (item.presentation.startsWith("b64:") && (new TextDecoder().decode(fromBase64(item.presentation.replace("b64:", "")))).includes("[")) { + return JSON.parse(new TextDecoder().decode(fromBase64(item.presentation.replace("b64:", "")))); + } + else if (item.presentation.startsWith("b64:")) { + return [ new TextDecoder().decode(fromBase64(item.presentation.replace("b64:", ""))) ]; + } + else { + return [ item.presentation ]; + } + } + setMatchingCredentials(extractPresentations(item)); if (screenType === 'mobile') { navigate(`/history/${item.id}`); } From b359f57112785a9cfb1d2890101b26ee59a43a6e Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Wed, 8 Jan 2025 17:55:55 +0200 Subject: [PATCH 089/162] Fix base lint warnings --- src/App.js | 5 +---- src/UriHandler.tsx | 2 +- src/components/Shared/Slider.js | 2 +- src/context/CredentialParserContext.tsx | 2 +- src/context/CredentialsContext.js | 2 +- src/context/OpenID4VPContext.tsx | 4 ++-- src/lib/services/OpenID4VCI/OpenID4VCI.tsx | 20 +++++++------------ ...zationRequestForFirstPartyApplications.tsx | 2 +- src/lib/services/OpenID4VCIHelper.tsx | 3 +-- src/lib/services/OpenID4VP/OpenID4VP.tsx | 7 +++---- src/pages/AddCredentials/AddCredentials.js | 2 +- 11 files changed, 20 insertions(+), 31 deletions(-) diff --git a/src/App.js b/src/App.js index 6a9bcda51..6e4c4c681 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,4 @@ -import React, { useEffect, Suspense, useState, useContext } from 'react'; +import React, { useEffect, Suspense } from 'react'; import { Routes, Route, Outlet, useLocation } from 'react-router-dom'; // Import i18next and set up translations import { I18nextProvider } from 'react-i18next'; @@ -11,7 +11,6 @@ import HandlerNotification from './components/Notifications/HandlerNotification' import Snowfalling from './components/ChristmasAnimation/Snowfalling'; import Spinner from './components/Shared/Spinner'; -import { withContainerContext } from './context/ContainerContext'; import { withCredentialsContext } from './context/CredentialsContext'; import UpdateNotification from './components/Notifications/UpdateNotification'; @@ -67,8 +66,6 @@ const lazyWithDelay = (importFunction, delay = 1000) => { ); }; -const MessagePopup = React.lazy(() => import('./components/Popups/MessagePopup')); -const PinInputPopup = React.lazy(() => import('./components/Popups/PinInput')); const PrivateRoute = reactLazyWithNonDefaultExports( () => import('./components/Auth/PrivateRoute'), 'NotificationPermissionWarning', diff --git a/src/UriHandler.tsx b/src/UriHandler.tsx index 6537f79cf..cf4b48a3d 100644 --- a/src/UriHandler.tsx +++ b/src/UriHandler.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, createContext, useState, useContext } from "react"; +import React, { useEffect, useState, useContext } from "react"; import { useLocation } from "react-router-dom"; import { checkForUpdates } from './offlineRegistrationSW'; import StatusContext from "./context/StatusContext"; diff --git a/src/components/Shared/Slider.js b/src/components/Shared/Slider.js index 4e250bd5a..c115e41d3 100644 --- a/src/components/Shared/Slider.js +++ b/src/components/Shared/Slider.js @@ -43,7 +43,7 @@ const Slider = ({ items, renderSlideContent, onSlideChange, initialSlide = 1 }) {items.map((item, index) => ( 1 && 'invisible pointer-events-none'} ${currentSlide == (index + 1) && 'overflow-visible-force'} `} + className={`rounded-xl ${Math.abs(currentSlide - (index + 1)) > 1 && 'invisible pointer-events-none'} ${currentSlide === (index + 1) && 'overflow-visible-force'} `} > {renderSlideContent(item, index)} diff --git a/src/context/CredentialParserContext.tsx b/src/context/CredentialParserContext.tsx index a1612266f..ea890b5ec 100644 --- a/src/context/CredentialParserContext.tsx +++ b/src/context/CredentialParserContext.tsx @@ -51,7 +51,7 @@ export const CredentialParserContextProvider = ({ children }) => { const isValidMetadata = !('error' in getSdJwtVcMetadataResult) && getSdJwtVcMetadataResult.credentialMetadata; // Extract metadata and claims - const metadata = isValidMetadata && getSdJwtVcMetadataResult.credentialMetadata?.display?.find((d) => d.lang === defaultLocale) || null; + const metadata = (isValidMetadata && getSdJwtVcMetadataResult.credentialMetadata?.display?.find((d) => d.lang === defaultLocale)) || null; const claims = isValidMetadata && getSdJwtVcMetadataResult.credentialMetadata?.claims?.length ? getSdJwtVcMetadataResult.credentialMetadata.claims : null; diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js index 6d9cd9f47..05243f7f7 100644 --- a/src/context/CredentialsContext.js +++ b/src/context/CredentialsContext.js @@ -18,7 +18,7 @@ export const CredentialsProvider = ({ children }) => { const vcEntityList = (await Promise.all(fetchedVcList.map(async (vcEntity) => { return { ...vcEntity }; - }))).filter((vcEntity) => vcEntity.instanceId == 0); // show only the first instance + }))).filter((vcEntity) => vcEntity.instanceId === 0); // show only the first instance vcEntityList.sort(reverse(compareBy(vc => vc.id))); diff --git a/src/context/OpenID4VPContext.tsx b/src/context/OpenID4VPContext.tsx index 3bc53c04c..f051a3303 100644 --- a/src/context/OpenID4VPContext.tsx +++ b/src/context/OpenID4VPContext.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useContext, createContext } from "react"; +import React, { useState, useContext, createContext } from "react"; import SelectCredentialsPopup from "../components/Popups/SelectCredentialsPopup"; import CredentialsContext from '../context/CredentialsContext'; import { useOpenID4VP } from "../lib/services/OpenID4VP/OpenID4VP"; @@ -13,7 +13,7 @@ const OpenID4VPContext: React.Context = createContext({ }); export const OpenID4VPContextProvider = ({ children }) => { - const { vcEntityList, vcEntityListInstances, latestCredentials, currentSlide, setCurrentSlide } = useContext(CredentialsContext); + const { vcEntityList, vcEntityListInstances } = useContext(CredentialsContext); const [popupState, setPopupState] = useState({ isOpen: false, diff --git a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx index 1b36da366..a99100968 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx @@ -10,7 +10,7 @@ import * as config from '../../../config'; import { VerifiableCredentialFormat } from '../../schemas/vc'; import { useHttpProxy } from '../HttpProxy/HttpProxy'; import { useOpenID4VCIClientStateRepository } from '../OpenID4VCIClientStateRepository'; -import { useContext, useEffect, useMemo } from 'react'; +import { useContext, useMemo } from 'react'; import SessionContext from '../../../context/SessionContext'; import { useOpenID4VCIPushedAuthorizationRequest } from './OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest'; import { useOpenID4VCIAuthorizationRequestForFirstPartyApplications } from './OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications'; @@ -174,7 +174,7 @@ export function useOpenID4VCI(): IOpenID4VCI { const credentialArray = []; - if (numberOfProofs == 1 && credentialResponse.data.credential) { + if (numberOfProofs === 1 && credentialResponse.data.credential) { const { credential } = credentialResponse.data; credentialArray.push(credential); } @@ -229,9 +229,8 @@ export function useOpenID4VCI(): IOpenID4VCI { } }) { - const [authzServerMetadata, credentialIssuerMetadata, clientId] = await Promise.all([ + const [authzServerMetadata, clientId] = await Promise.all([ openID4VCIHelper.getAuthorizationServerMetadata(credentialIssuerIdentifier), - openID4VCIHelper.getCredentialIssuerMetadata(credentialIssuerIdentifier), openID4VCIHelper.getClientId(credentialIssuerIdentifier) ]); if (requestCredentialsParams.usingActiveAccessToken) { @@ -291,7 +290,6 @@ export function useOpenID4VCI(): IOpenID4VCI { let dpopPrivateKey: jose.KeyLike | Uint8Array | null = null; let dpopPrivateKeyJwk: jose.JWK | null = null; - let dpopPublicKey: jose.KeyLike | Uint8Array | null = null; let dpopPublicKeyJwk: jose.JWK | null = null; if (!flowState.dpop) { // if DPoP keys have not been generated, then generate them @@ -302,15 +300,13 @@ export function useOpenID4VCI(): IOpenID4VCI { ]); dpopPrivateKey = privateKey; - dpopPublicKey = publicKey; } else { // if already generated, then reuse them dpopPrivateKeyJwk = flowState.dpop.dpopPrivateKeyJwk; dpopPublicKeyJwk = flowState.dpop.dpopPublicKeyJwk; - [dpopPrivateKey, dpopPublicKey] = await Promise.all([ - jose.importJWK(flowState.dpop.dpopPrivateKeyJwk, flowState.dpop.dpopAlg), - jose.importJWK(flowState.dpop.dpopPublicKeyJwk, flowState.dpop.dpopAlg) + [dpopPrivateKey] = await Promise.all([ + jose.importJWK(flowState.dpop.dpopPrivateKeyJwk, flowState.dpop.dpopAlg) ]) } const jti = generateRandomIdentifier(8); @@ -434,8 +430,7 @@ export function useOpenID4VCI(): IOpenID4VCI { throw new Error("Only authorization_code grant is supported"); } - const [authzServerMetadata, credentialIssuerMetadata] = await Promise.all([ - openID4VCIHelper.getAuthorizationServerMetadata(offer.credential_issuer), + const [credentialIssuerMetadata] = await Promise.all([ openID4VCIHelper.getCredentialIssuerMetadata(offer.credential_issuer) ]); @@ -454,8 +449,7 @@ export function useOpenID4VCI(): IOpenID4VCI { } async function getAvailableCredentialConfigurations(credentialIssuerIdentifier: string): Promise> { - const [authzServerMetadata, credentialIssuerMetadata] = await Promise.all([ - openID4VCIHelper.getAuthorizationServerMetadata(credentialIssuerIdentifier), + const [credentialIssuerMetadata] = await Promise.all([ openID4VCIHelper.getCredentialIssuerMetadata(credentialIssuerIdentifier) ]); if (!credentialIssuerMetadata.metadata?.credential_configurations_supported) { diff --git a/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx b/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx index 4109677a9..b81a4df23 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx @@ -57,7 +57,7 @@ export function useOpenID4VCIAuthorizationRequestForFirstPartyApplications(): IO const err = res.err; if (err) { if (err?.data && err?.data?.error === "insufficient_authorization") { // Authorization Error Response - const { error, auth_session, presentation } = err?.data; + const { auth_session, presentation } = err?.data; // this function should prompt the user for presentation selection const result = await openID4VP.handleAuthorizationRequest("openid4vp:" + presentation).then((res) => { diff --git a/src/lib/services/OpenID4VCIHelper.tsx b/src/lib/services/OpenID4VCIHelper.tsx index d5c5f536d..5125bbd46 100644 --- a/src/lib/services/OpenID4VCIHelper.tsx +++ b/src/lib/services/OpenID4VCIHelper.tsx @@ -1,4 +1,3 @@ -import { IHttpProxy } from "../interfaces/IHttpProxy"; import { IOpenID4VCIHelper } from "../interfaces/IOpenID4VCIHelper"; import { OpenidAuthorizationServerMetadata, OpenidAuthorizationServerMetadataSchema } from "../schemas/OpenidAuthorizationServerMetadataSchema"; import { OpenidCredentialIssuerMetadata, OpenidCredentialIssuerMetadataSchema } from "../schemas/OpenidCredentialIssuerMetadataSchema"; @@ -50,7 +49,7 @@ export function useOpenID4VCIHelper(): IOpenID4VCIHelper { try { const issuerResponse = await api.getExternalEntity('/issuer/all', undefined, true); const trustedCredentialIssuers = issuerResponse.data; - const issuer = trustedCredentialIssuers.filter((issuer: any) => issuer.credentialIssuerIdentifier == credentialIssuerIdentifier)[0]; + const issuer = trustedCredentialIssuers.filter((issuer: any) => issuer.credentialIssuerIdentifier === credentialIssuerIdentifier)[0]; if (issuer) { return { client_id: issuer.clientId }; } diff --git a/src/lib/services/OpenID4VP/OpenID4VP.tsx b/src/lib/services/OpenID4VP/OpenID4VP.tsx index d21b2cd86..11d86993d 100644 --- a/src/lib/services/OpenID4VP/OpenID4VP.tsx +++ b/src/lib/services/OpenID4VP/OpenID4VP.tsx @@ -12,7 +12,6 @@ import { BACKEND_URL, OPENID4VP_SAN_DNS_CHECK_SSL_CERTS, OPENID4VP_SAN_DNS_CHECK import { useCredentialBatchHelper } from "../CredentialBatchHelper"; import { toBase64 } from "../../../util"; import { useHttpProxy } from "../HttpProxy/HttpProxy"; -import { useCredentialParserRegistry } from "../CredentialParserRegistry"; import { useContext } from "react"; import SessionContext from "../../../context/SessionContext"; import CredentialParserContext from "../../../context/CredentialParserContext"; @@ -348,7 +347,7 @@ export function useOpenID4VP({ showCredentialSelectionPopup }: { showCredentialS 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.length == 1 ? generatedVPs[0] : generatedVPs, + vp_token: generatedVPs.length === 1 ? generatedVPs[0] : generatedVPs, presentation_submission: presentationSubmission, state: S.state ?? undefined }) @@ -359,7 +358,7 @@ export function useOpenID4VP({ showCredentialSelectionPopup }: { showCredentialS console.log("JWE = ", jwe) } else { - formData.append('vp_token', generatedVPs.length == 1 ? generatedVPs[0] : JSON.stringify(generatedVPs)); + 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); @@ -369,7 +368,7 @@ export function useOpenID4VP({ showCredentialSelectionPopup }: { showCredentialS const credentialIdentifiers = originalVCs.map((vc) => vc.credentialIdentifier); - const presentations = "b64:" + toBase64(new TextEncoder().encode(generatedVPs.length == 1 ? generatedVPs[0] : JSON.stringify(generatedVPs))); + const presentations = "b64:" + toBase64(new TextEncoder().encode(generatedVPs.length === 1 ? generatedVPs[0] : JSON.stringify(generatedVPs))); const storePresentationPromise = storeVerifiablePresentation(presentations, presentationSubmission, credentialIdentifiers, client_id); const updateCredentialPromise = filteredVCEntities.map(async (cred) => credentialBatchHelper.useCredential(cred)) diff --git a/src/pages/AddCredentials/AddCredentials.js b/src/pages/AddCredentials/AddCredentials.js index f1f462ff3..4e1f43edf 100644 --- a/src/pages/AddCredentials/AddCredentials.js +++ b/src/pages/AddCredentials/AddCredentials.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useContext, useCallback } from 'react'; +import React, { useState, useEffect, useContext } from 'react'; import { useTranslation } from 'react-i18next'; import StatusContext from '../../context/StatusContext'; From 7bfd6a29ddeb1d675af86065d666c108dd6f3d8c Mon Sep 17 00:00:00 2001 From: kkmanos Date: Thu, 9 Jan 2025 11:43:00 +0200 Subject: [PATCH 090/162] exposed OpenID4VCI on context + isolated the token request logic --- src/App.js | 7 +- src/context/OpenID4VCIContext.tsx | 34 ++++ src/context/OpenID4VPContext.tsx | 6 +- src/lib/services/OpenID4VCI/OpenID4VCI.tsx | 82 +++------ ...zationRequestForFirstPartyApplications.tsx | 5 +- src/lib/services/OpenID4VCI/TokenRequest.tsx | 159 ++++++++++++++++++ .../OpenID4VCIClientStateRepository.tsx | 7 +- src/lib/services/OpenID4VP/OpenID4VP.tsx | 14 +- 8 files changed, 248 insertions(+), 66 deletions(-) create mode 100644 src/context/OpenID4VCIContext.tsx create mode 100644 src/lib/services/OpenID4VCI/TokenRequest.tsx diff --git a/src/App.js b/src/App.js index 6a9bcda51..2a2ffda2f 100644 --- a/src/App.js +++ b/src/App.js @@ -19,6 +19,7 @@ import CredentialDetails from './pages/Home/CredentialDetails'; import { withUriHandler } from './UriHandler'; import { withCredentialParserContext } from './context/CredentialParserContext'; import { withOpenID4VPContext } from './context/OpenID4VPContext'; +import { withOpenID4VCIContext } from './context/OpenID4VCIContext'; const reactLazyWithNonDefaultExports = (load, ...names) => { const nonDefaults = (names ?? []).map(name => { @@ -161,8 +162,10 @@ export default withSessionContext( withCredentialsContext( withCredentialParserContext( withOpenID4VPContext( - withUriHandler( - App + withOpenID4VCIContext( + withUriHandler( + App + ) ) ) ) diff --git a/src/context/OpenID4VCIContext.tsx b/src/context/OpenID4VCIContext.tsx new file mode 100644 index 000000000..cfe6ff2e7 --- /dev/null +++ b/src/context/OpenID4VCIContext.tsx @@ -0,0 +1,34 @@ +import React, { createContext } from "react"; +import { IOpenID4VCI } from "../lib/interfaces/IOpenID4VCI"; +import { OpenID4VCI } from "../lib/services/OpenID4VCI/OpenID4VCI"; + + +export type OpenID4VPContextValue = { + openID4VCI: IOpenID4VCI; +} + +const OpenID4VCIContext: React.Context = createContext({ + openID4VCI: null +}); + +export const OpenID4VCIContextProvider = ({ children }) => { + + const errorCallback = (title: string, msg: string) => { + throw new Error("Not implemented"); + } + + const openID4VCI = OpenID4VCI({ errorCallback }); + return ( + + {children} + + ); +} + +export const withOpenID4VCIContext:

(component: React.ComponentType

) => React.ComponentType

= (Component) => + (props) => ( + + + + ); +export default OpenID4VCIContext; diff --git a/src/context/OpenID4VPContext.tsx b/src/context/OpenID4VPContext.tsx index 3bc53c04c..6e6c791a3 100644 --- a/src/context/OpenID4VPContext.tsx +++ b/src/context/OpenID4VPContext.tsx @@ -1,7 +1,7 @@ -import React, { useEffect, useState, useContext, createContext } from "react"; +import React, { useState, useContext, createContext } from "react"; import SelectCredentialsPopup from "../components/Popups/SelectCredentialsPopup"; import CredentialsContext from '../context/CredentialsContext'; -import { useOpenID4VP } from "../lib/services/OpenID4VP/OpenID4VP"; +import { OpenID4VP } from "../lib/services/OpenID4VP/OpenID4VP"; import { IOpenID4VP } from "../lib/interfaces/IOpenID4VP"; export type OpenID4VPContextValue = { @@ -45,7 +45,7 @@ export const OpenID4VPContextProvider = ({ children }) => { return showPopup({ conformantCredentialsMap, verifierDomainName }); } - const openID4VP = useOpenID4VP({ showCredentialSelectionPopup }); + const openID4VP = OpenID4VP({ showCredentialSelectionPopup }); return ( diff --git a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx index 1b36da366..3bfcdd5ca 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx @@ -15,10 +15,21 @@ import SessionContext from '../../../context/SessionContext'; import { useOpenID4VCIPushedAuthorizationRequest } from './OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest'; import { useOpenID4VCIAuthorizationRequestForFirstPartyApplications } from './OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications'; import { useOpenID4VCIHelper } from '../OpenID4VCIHelper'; +import { GrantType, useTokenRequest } from './TokenRequest'; +import OpenID4VCIContext from '../../../context/OpenID4VCIContext'; const redirectUri = config.OPENID4VCI_REDIRECT_URI as string; -export function useOpenID4VCI(): IOpenID4VCI { + +export function useOpenID4VCI() { + const openID4VCI = useContext(OpenID4VCIContext); + if (!openID4VCI.openID4VCI) { + throw new Error("OpenID4VCIContext is not defined in the context"); + } + return openID4VCI.openID4VCI; +} + +export function OpenID4VCI({ errorCallback }: { errorCallback: (title: string, message: string) => void }): IOpenID4VCI { const httpProxy = useHttpProxy(); const openID4VCIClientStateRepository = useOpenID4VCIClientStateRepository(); @@ -29,6 +40,7 @@ export function useOpenID4VCI(): IOpenID4VCI { const openID4VCIPushedAuthorizationRequest = useOpenID4VCIPushedAuthorizationRequest(); const openID4VCIAuthorizationRequestForFirstPartyApplications = useOpenID4VCIAuthorizationRequestForFirstPartyApplications(); + const tokenRequestBuilder = useTokenRequest(); async function handleAuthorizationResponse(url: string, dpopNonceHeader?: string) { @@ -315,74 +327,36 @@ export function useOpenID4VCI(): IOpenID4VCI { } const jti = generateRandomIdentifier(8); - let tokenRequestHeaders = { - 'Content-Type': 'application/x-www-form-urlencoded', - }; + tokenRequestBuilder.setTokenEndpoint(tokenEndpoint); if (authzServerMetadata.authzServeMetadata.dpop_signing_alg_values_supported) { - const dpop = await generateDPoP( - dpopPrivateKey as jose.KeyLike, - dpopPublicKeyJwk, - jti, - "POST", - tokenEndpoint, - requestCredentialsParams.dpopNonceHeader - ); + await tokenRequestBuilder.setDpopHeader(dpopPrivateKey as jose.KeyLike, dpopPublicKeyJwk, jti); flowState.dpop = { dpopAlg: 'ES256', dpopJti: jti, dpopPrivateKeyJwk: dpopPrivateKeyJwk, dpopPublicKeyJwk: dpopPublicKeyJwk, } - tokenRequestHeaders['DPoP'] = dpop; } + tokenRequestBuilder.setClientId(clientId.client_id); + tokenRequestBuilder.setGrantType(requestCredentialsParams.authorizationCodeGrant ? GrantType.AUTHORIZATION_CODE : GrantType.REFRESH); + tokenRequestBuilder.setAuthorizationCode(requestCredentialsParams?.authorizationCodeGrant?.code); + tokenRequestBuilder.setCodeVerifier(flowState?.code_verifier); - const formData = new URLSearchParams(); - formData.append('client_id', clientId.client_id); - if (requestCredentialsParams.authorizationCodeGrant) { - formData.append('grant_type', 'authorization_code'); - formData.append('code', requestCredentialsParams.authorizationCodeGrant.code); - formData.append('code_verifier', flowState.code_verifier); - } - else if (requestCredentialsParams.refreshTokenGrant) { - if (!flowState?.tokenResponse?.data.refresh_token) { - console.info("Found no refresh_token to execute refesh_token grant") - throw new Error("Found no refresh_token to execute refesh_token grant"); - } - formData.append('grant_type', 'refresh_token'); - formData.append('refresh_token', flowState.tokenResponse.data.refresh_token); - } - else { - throw new Error("No grant type selected in requestCredentials()"); - } - formData.append('redirect_uri', redirectUri); + tokenRequestBuilder.setRefreshToken(flowState?.tokenResponse?.data?.refresh_token); - const response = await httpProxy.post(tokenEndpoint, formData.toString(), tokenRequestHeaders); + tokenRequestBuilder.setRedirectUri(redirectUri); - if (response.err) { - const { err } = response; - console.log("failed token request") - console.log(JSON.stringify(err)); - console.log("Dpop nonce found = ", err.headers['dpop-nonce']) - if (err.headers['dpop-nonce']) { - requestCredentialsParams.dpopNonceHeader = err.headers['dpop-nonce']; - if (requestCredentialsParams.dpopNonceHeader) { - await requestCredentials(credentialIssuerIdentifier, requestCredentialsParams); - return; - } - } - else if (err.data.error) { - console.error("OID4VCI Token Response Error: ", JSON.stringify(err.data)) - } - return; + + const result = await tokenRequestBuilder.execute(); + + if ('error' in result) { + throw new Error("Token request failed"); } - console.log("== response = ", response) try { // try to extract the response and update the OpenID4VCIClientStateRepository - const { - data: { access_token, c_nonce, expires_in, c_nonce_expires_in, refresh_token }, - } = response; + const { access_token, c_nonce, expires_in, c_nonce_expires_in, refresh_token } = result.response; if (!access_token) { console.log("Missing access_token from response"); @@ -393,7 +367,7 @@ export function useOpenID4VCI(): IOpenID4VCI { data: { access_token, c_nonce, expiration_timestamp: Math.floor(Date.now() / 1000) + expires_in, c_nonce_expiration_timestamp: Math.floor(Date.now() / 1000) + c_nonce_expires_in, refresh_token }, - headers: { ...response.headers } + headers: { ...result.response.httpResponseHeaders } } await openID4VCIClientStateRepository.updateState(flowState); diff --git a/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx b/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx index 4109677a9..d6383f258 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx @@ -7,14 +7,15 @@ import { OpenID4VCIClientState } from "../../../types/OpenID4VCIClientState"; import { useOpenID4VCIClientStateRepository } from "../../OpenID4VCIClientStateRepository"; import { useHttpProxy } from "../../HttpProxy/HttpProxy"; import { useContext } from "react"; -import OpenID4VPContext from "../../../../context/OpenID4VPContext"; import SessionContext from "../../../../context/SessionContext"; +import { useOpenID4VP } from "../../OpenID4VP/OpenID4VP"; export function useOpenID4VCIAuthorizationRequestForFirstPartyApplications(): IOpenID4VCIAuthorizationRequest { const httpProxy = useHttpProxy(); const openID4VCIClientStateRepository = useOpenID4VCIClientStateRepository(); - const { openID4VP } = useContext(OpenID4VPContext); + const openID4VP = useOpenID4VP(); + const { keystore } = useContext(SessionContext); return { diff --git a/src/lib/services/OpenID4VCI/TokenRequest.tsx b/src/lib/services/OpenID4VCI/TokenRequest.tsx new file mode 100644 index 000000000..adc4a89bd --- /dev/null +++ b/src/lib/services/OpenID4VCI/TokenRequest.tsx @@ -0,0 +1,159 @@ +import { JWK, KeyLike } from 'jose'; +import { useHttpProxy } from '../HttpProxy/HttpProxy'; +import { generateDPoP } from '../../utils/dpop'; + +export type AccessToken = { + access_token: string; + c_nonce: string; + expires_in: number; + c_nonce_expires_in: number; + refresh_token?: string; + + httpResponseHeaders: { + "dpop-nonce"?: string + } +} + +export enum GrantType { + AUTHORIZATION_CODE = "code", + REFRESH = "refresh_token", +} + + +export enum TokenRequestError { + FAILED, +} + +export function useTokenRequest() { + + const httpProxy = useHttpProxy(); + + let tokenEndpointURL = null; + + let grant_type: GrantType = GrantType.AUTHORIZATION_CODE; + let refresh_token = null; + let code = null; + let code_verifier = null; + let redirect_uri = null; + let client_id = null; + + const httpHeaders = { + 'Content-Type': 'application/x-www-form-urlencoded', + }; + + function setClientId(clientId: string) { + client_id = clientId; + } + + function setGrantType(grant: GrantType) { + grant_type = grant; + } + + function setAuthorizationCode(authzCode: string) { + code = authzCode; + } + + function setCodeVerifier(codeVerifier: string) { + code_verifier = codeVerifier; + } + + function setRefreshToken(tok: string) { + refresh_token = tok; + } + + function setRedirectUri(redirectUri: string) { + redirect_uri = redirectUri; + } + + function setTokenEndpoint(tokenEndpoint: string) { + tokenEndpointURL = tokenEndpoint; + } + + async function setDpopHeader(dpopPrivateKey: KeyLike, dpopPublicKeyJwk: JWK, jti: string) { + if (!tokenEndpointURL) { + throw new Error("tokenEndpointURL was not defined"); + } + const dpop = await generateDPoP( + dpopPrivateKey as KeyLike, + dpopPublicKeyJwk, + jti, + "POST", + tokenEndpointURL, + httpHeaders['dpop-nonce'] + ); + + httpHeaders['DPoP'] = dpop; + } + + + async function execute(): Promise<{ response: AccessToken} | { error: TokenRequestError }> { + const formData = new URLSearchParams(); + + formData.append('client_id', client_id); + if (grant_type == GrantType.AUTHORIZATION_CODE) { + console.log("Executing authorization code grant..."); + + formData.append('grant_type', 'authorization_code'); + formData.append('code', code); + formData.append('code_verifier', code_verifier); + } + else if (grant_type == GrantType.REFRESH) { + console.log("Executing refresh token grant..."); + if (!refresh_token) { + console.info("Found no refresh_token to execute refesh_token grant") + throw new Error("Found no refresh_token to execute refesh_token grant"); + } + formData.append('grant_type', 'refresh_token'); + formData.append('refresh_token', refresh_token); + } + else { + throw new Error("No grant type selected in requestCredentials()"); + } + formData.append('redirect_uri', redirect_uri); + + const response = await httpProxy.post(tokenEndpointURL, formData.toString(), httpHeaders); + + if (response.err) { + const { err } = response; + console.log("failed token request") + console.log(JSON.stringify(err)); + console.log("Dpop nonce found = ", err.headers['dpop-nonce']) + if (err.headers['dpop-nonce']) { + httpHeaders['dpop-nonce'] = err.headers['dpop-nonce']; + if (httpHeaders['dpop-nonce']) { + return execute(); + } + } + else if (err.data.error) { + console.error("OID4VCI Token Response Error: ", JSON.stringify(err.data)) + } + return { error: TokenRequestError.FAILED }; + } + + return { + response: { + access_token: response.data.access_token, + c_nonce: response.data.c_nonce, + c_nonce_expires_in: response.data.c_nonce_expires_in, + expires_in: response.data.expires_in, + refresh_token: response.data?.refresh_token, + httpResponseHeaders: { + ...response.headers + } + } + } + } + + return { + setClientId, + setGrantType, + setAuthorizationCode, + setCodeVerifier, + setRefreshToken, + setRedirectUri, + setTokenEndpoint, + setDpopHeader, + + execute, + } +} \ No newline at end of file diff --git a/src/lib/services/OpenID4VCIClientStateRepository.tsx b/src/lib/services/OpenID4VCIClientStateRepository.tsx index 72bab8161..c4f10c20a 100644 --- a/src/lib/services/OpenID4VCIClientStateRepository.tsx +++ b/src/lib/services/OpenID4VCIClientStateRepository.tsx @@ -3,11 +3,10 @@ import { IOpenID4VCIClientStateRepository } from "../interfaces/IOpenID4VCIClien import { OpenID4VCIClientState } from "../types/OpenID4VCIClientState"; import SessionContext from "../../context/SessionContext"; - export function useOpenID4VCIClientStateRepository(): IOpenID4VCIClientStateRepository { const key = "openid4vci_client_state"; - const [rememberIssuerForSeconds, setRememberIssuerForSeconds] = useState(0); + const [rememberIssuerForSeconds, setRememberIssuerForSeconds] = useState(null); const { api, isLoggedIn, keystore } = useContext(SessionContext); const data = localStorage.getItem(key); @@ -22,7 +21,6 @@ export function useOpenID4VCIClientStateRepository(): IOpenID4VCIClientStateRepo if (rememberIssuerForSeconds == null) { api.get('/user/session/account-info').then((response) => { const userData = response.data; - console.log('userdata = ', userData) setRememberIssuerForSeconds(userData.settings.openidRefreshTokenMaxAgeInSeconds); }); } @@ -45,6 +43,9 @@ export function useOpenID4VCIClientStateRepository(): IOpenID4VCIClientStateRepo getByStateAndUserHandle, async cleanupExpired() { + if (rememberIssuerForSeconds == null) { + return; + } const array = JSON.parse(localStorage.getItem(key)) as Array; const results = array.filter((s) => s.userHandleB64U === keystore.getUserHandleB64u()); const statesToBeRemoved: string[] = []; diff --git a/src/lib/services/OpenID4VP/OpenID4VP.tsx b/src/lib/services/OpenID4VP/OpenID4VP.tsx index d21b2cd86..384a8c403 100644 --- a/src/lib/services/OpenID4VP/OpenID4VP.tsx +++ b/src/lib/services/OpenID4VP/OpenID4VP.tsx @@ -12,12 +12,22 @@ import { BACKEND_URL, OPENID4VP_SAN_DNS_CHECK_SSL_CERTS, OPENID4VP_SAN_DNS_CHECK import { useCredentialBatchHelper } from "../CredentialBatchHelper"; import { toBase64 } from "../../../util"; import { useHttpProxy } from "../HttpProxy/HttpProxy"; -import { useCredentialParserRegistry } from "../CredentialParserRegistry"; import { useContext } from "react"; import SessionContext from "../../../context/SessionContext"; import CredentialParserContext from "../../../context/CredentialParserContext"; +import OpenID4VPContext from "../../../context/OpenID4VPContext"; -export function useOpenID4VP({ showCredentialSelectionPopup }: { showCredentialSelectionPopup: (conformantCredentialsMap: any, verifierDomainName: string) => Promise> }): IOpenID4VP { + +export function useOpenID4VP() { + const openID4VP = useContext(OpenID4VPContext); + if (!openID4VP.openID4VP) { + throw new Error("OpenID4VPContext is not defined in the context"); + } + return openID4VP.openID4VP; +} + + +export function OpenID4VP({ showCredentialSelectionPopup }: { showCredentialSelectionPopup: (conformantCredentialsMap: any, verifierDomainName: string) => Promise> }): IOpenID4VP { const openID4VPRelyingPartyStateRepository = useOpenID4VPRelyingPartyStateRepository(); const httpProxy = useHttpProxy(); From 72de0cb8d552ef6397f277c08c6c8ad32a47e10e Mon Sep 17 00:00:00 2001 From: pstamatop Date: Thu, 9 Jan 2025 13:30:57 +0200 Subject: [PATCH 091/162] Update contribution guidelines --- README.md | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/README.md b/README.md index 655a6d040..7e0b3b5e2 100644 --- a/README.md +++ b/README.md @@ -313,31 +313,4 @@ Tailwind CSS provides an extensive set of default styles, but you can also custo Explore the [Tailwind CSS documentation](https://tailwindcss.com/docs/installation) to learn about all the utility classes, configuration options, and techniques for building beautiful UIs efficiently. ## 💡Contributing - -We welcome contributions from the community to help improve the wwWallet Frontend repository. If you'd like to contribute, follow these steps: - -1. **Create a New Branch:** - Create a new branch for your feature or bug fix - ```bash - git checkout -b my-feature - ``` - Replace my-feature with a descriptive name. - -2. **Make Changes:** - Make the necessary changes in your code editor. - -3. **Commit Changes:** - Commit your changes with a descriptive commit message: - ```bash - git commit -m "Add new feature" - ``` -4. **Push Changes:** - Push your changes to your new branrch: - ```bash - git push --set-upstream origin my-feature - ``` -5. **Create a Pull Request:** - Open a pull request on the original repository. Provide a detailed description of your changes and their purpose. - -6. **Review and Merge:** - Your pull request will be reviewed by the maintainers. Make any requested changes and address feedback. Once approved, your changes will be merged into master branch of the project. +Want to contribute? Check out our [Contribution Guidelines](https://github.com/wwWallet/.github/blob/main/CONTRIBUTING.md) for more details! \ No newline at end of file From c77eb09028704175d7f441a8cba88267b7054367 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Fri, 10 Jan 2025 11:31:48 +0200 Subject: [PATCH 092/162] request authorization in case it is required --- src/lib/services/OpenID4VCI/TokenRequest.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/services/OpenID4VCI/TokenRequest.tsx b/src/lib/services/OpenID4VCI/TokenRequest.tsx index adc4a89bd..bede8cbf7 100644 --- a/src/lib/services/OpenID4VCI/TokenRequest.tsx +++ b/src/lib/services/OpenID4VCI/TokenRequest.tsx @@ -22,6 +22,7 @@ export enum GrantType { export enum TokenRequestError { FAILED, + AUTHORIZATION_REQUIRED, } export function useTokenRequest() { @@ -86,7 +87,7 @@ export function useTokenRequest() { } - async function execute(): Promise<{ response: AccessToken} | { error: TokenRequestError }> { + async function execute(): Promise<{ response: AccessToken } | { error: TokenRequestError, response?: any }> { const formData = new URLSearchParams(); formData.append('client_id', client_id); @@ -124,6 +125,9 @@ export function useTokenRequest() { return execute(); } } + else if (err.data.error == "authorization_required") { + return { error: TokenRequestError.AUTHORIZATION_REQUIRED, response: err.data }; + } else if (err.data.error) { console.error("OID4VCI Token Response Error: ", JSON.stringify(err.data)) } From c5f12c1877d89b3f635acba647bec585dc09e433 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Fri, 10 Jan 2025 15:29:56 +0200 Subject: [PATCH 093/162] render each issuer if the metadata are loaded and not wait for all issuers --- src/components/QueryableList.tsx | 13 +++++-------- src/pages/AddCredentials/AddCredentials.js | 21 +++++++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/components/QueryableList.tsx b/src/components/QueryableList.tsx index 5436d1812..341f873ad 100644 --- a/src/components/QueryableList.tsx +++ b/src/components/QueryableList.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import SearchInput from "./Inputs/SearchInput"; import Button from "../components/Buttons/Button"; import { useTranslation } from "react-i18next"; @@ -52,13 +52,10 @@ const QueryableList = ({ setFilteredList(filtered); }; - if (list.length === 0) { - return ( -

- {t(translationPrefix + ".noFound")} -

- ); - } + useEffect(() => { + setFilteredList([...list]); + }, [list]); + return ( <> diff --git a/src/pages/AddCredentials/AddCredentials.js b/src/pages/AddCredentials/AddCredentials.js index f1f462ff3..e862ca579 100644 --- a/src/pages/AddCredentials/AddCredentials.js +++ b/src/pages/AddCredentials/AddCredentials.js @@ -13,7 +13,7 @@ import { useOpenID4VCI } from '../../lib/services/OpenID4VCI/OpenID4VCI'; const Issuers = () => { const { isOnline } = useContext(StatusContext); const { api, keystore } = useContext(SessionContext); - const [issuers, setIssuers] = useState(null); + const [issuers, setIssuers] = useState([]); const [showRedirectPopup, setShowRedirectPopup] = useState(false); const [selectedIssuer, setSelectedIssuer] = useState(null); const [loading, setLoading] = useState(false); @@ -29,24 +29,29 @@ const Issuers = () => { try { const response = await api.getExternalEntity('/issuer/all', undefined, true); let fetchedIssuers = response.data; - fetchedIssuers = await Promise.all(fetchedIssuers.map(async (issuer) => { + fetchedIssuers.map(async (issuer) => { try { const metadata = (await openID4VCIHelper.getCredentialIssuerMetadata(issuer.credentialIssuerIdentifier)).metadata; - return { + const issuerObject = { ...issuer, selectedDisplay: metadata?.display?.filter((display) => display.locale === 'en-US')[0] ? metadata.display.filter((display) => display.locale === 'en-US')[0] : null, credentialIssuerMetadata: metadata, + }; + + if (issuerObject.visible) { + setIssuers((currentArray) => { + if (currentArray.filter((iss) => iss.credentialIssuerMetadata.credential_issuer == issuerObject.credentialIssuerMetadata.credential_issuer).length == 0) { + return [...currentArray, issuerObject]; + } + return [...currentArray]; + }); } } catch (err) { console.error(err); return null; } - - })); - fetchedIssuers = fetchedIssuers.filter((issuer) => issuer !== null); - fetchedIssuers = fetchedIssuers.filter((issuer) => issuer.visible === 1); // show only visible issuers - setIssuers(fetchedIssuers); + }) } catch (error) { console.error('Error fetching issuers:', error); } From 5b9df0812fa699f19368623baa5d3883b985f7b1 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Fri, 10 Jan 2025 15:32:12 +0200 Subject: [PATCH 094/162] minor fixes --- src/UriHandler.tsx | 4 ++-- src/lib/services/OpenID4VCI/OpenID4VCI.tsx | 21 +++++++++++---------- src/lib/services/OpenID4VP/OpenID4VP.tsx | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/UriHandler.tsx b/src/UriHandler.tsx index 6537f79cf..d96400772 100644 --- a/src/UriHandler.tsx +++ b/src/UriHandler.tsx @@ -3,11 +3,11 @@ import { useLocation } from "react-router-dom"; import { checkForUpdates } from './offlineRegistrationSW'; import StatusContext from "./context/StatusContext"; import { useOpenID4VCI } from "./lib/services/OpenID4VCI/OpenID4VCI"; -import OpenID4VPContext from "./context/OpenID4VPContext"; import SessionContext from "./context/SessionContext"; import { BackgroundTasksContext } from "./context/BackgroundTasksContext"; import { useTranslation } from "react-i18next"; import { HandleAuthorizationRequestError } from "./lib/interfaces/IOpenID4VP"; +import { useOpenID4VP } from "./lib/services/OpenID4VP/OpenID4VP"; const MessagePopup = React.lazy(() => import('./components/Popups/MessagePopup')); const PinInputPopup = React.lazy(() => import('./components/Popups/PinInput')); @@ -22,7 +22,7 @@ export const UriHandler = ({ children }) => { const [url, setUrl] = useState(window.location.href); const openID4VCI = useOpenID4VCI(); - const { openID4VP } = useContext(OpenID4VPContext); + const openID4VP = useOpenID4VP(); const [showPinInputPopup, setShowPinInputPopup] = useState(false); diff --git a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx index 3bfcdd5ca..f47c8ca70 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx @@ -10,12 +10,12 @@ import * as config from '../../../config'; import { VerifiableCredentialFormat } from '../../schemas/vc'; import { useHttpProxy } from '../HttpProxy/HttpProxy'; import { useOpenID4VCIClientStateRepository } from '../OpenID4VCIClientStateRepository'; -import { useContext, useEffect, useMemo } from 'react'; +import { useContext } from 'react'; import SessionContext from '../../../context/SessionContext'; import { useOpenID4VCIPushedAuthorizationRequest } from './OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest'; import { useOpenID4VCIAuthorizationRequestForFirstPartyApplications } from './OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications'; import { useOpenID4VCIHelper } from '../OpenID4VCIHelper'; -import { GrantType, useTokenRequest } from './TokenRequest'; +import { GrantType, TokenRequestError, useTokenRequest } from './TokenRequest'; import OpenID4VCIContext from '../../../context/OpenID4VCIContext'; const redirectUri = config.OPENID4VCI_REDIRECT_URI as string; @@ -352,6 +352,9 @@ export function OpenID4VCI({ errorCallback }: { errorCallback: (title: string, m const result = await tokenRequestBuilder.execute(); if ('error' in result) { + if (result.error == TokenRequestError.AUTHORIZATION_REQUIRED) { + return generateAuthorizationRequest(flowState.credentialIssuerIdentifier, flowState.credentialConfigurationId); + } throw new Error("Token request failed"); } @@ -496,13 +499,11 @@ export function OpenID4VCI({ errorCallback }: { errorCallback: (title: string, m } - return useMemo(() => { - return { - generateAuthorizationRequest, - getAvailableCredentialConfigurations, - handleCredentialOffer, - handleAuthorizationResponse - } - }, [httpProxy, openID4VCIHelper, openID4VCIClientStateRepository, api, keystore]) + return { + generateAuthorizationRequest, + getAvailableCredentialConfigurations, + handleCredentialOffer, + handleAuthorizationResponse + } } diff --git a/src/lib/services/OpenID4VP/OpenID4VP.tsx b/src/lib/services/OpenID4VP/OpenID4VP.tsx index 384a8c403..4de010fe5 100644 --- a/src/lib/services/OpenID4VP/OpenID4VP.tsx +++ b/src/lib/services/OpenID4VP/OpenID4VP.tsx @@ -12,7 +12,7 @@ import { BACKEND_URL, OPENID4VP_SAN_DNS_CHECK_SSL_CERTS, OPENID4VP_SAN_DNS_CHECK import { useCredentialBatchHelper } from "../CredentialBatchHelper"; import { toBase64 } from "../../../util"; import { useHttpProxy } from "../HttpProxy/HttpProxy"; -import { useContext } from "react"; +import { useContext, useEffect } from "react"; import SessionContext from "../../../context/SessionContext"; import CredentialParserContext from "../../../context/CredentialParserContext"; import OpenID4VPContext from "../../../context/OpenID4VPContext"; From 6146dfb2e462eaeb2fba0a0b31e46be3eff1095c Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Fri, 10 Jan 2025 17:15:03 +0200 Subject: [PATCH 095/162] Resolve missing dependencies in useEffect to fix lint warnings --- src/UriHandler.tsx | 6 +- .../Popups/SelectCredentialsPopup.js | 22 +- src/context/CredentialParserContext.tsx | 14 +- src/context/OpenID4VPContext.tsx | 22 +- src/lib/services/CredentialBatchHelper.tsx | 45 +- src/lib/services/HttpProxy/HttpProxy.tsx | 6 +- src/lib/services/OpenID4VCI/OpenID4VCI.tsx | 865 +++++++++--------- ...zationRequestForFirstPartyApplications.tsx | 29 +- .../OpenID4VCIPushedAuthorizationRequest.tsx | 29 +- .../OpenID4VCIClientStateRepository.tsx | 129 +-- src/lib/services/OpenID4VCIHelper.tsx | 225 ++--- src/lib/services/OpenID4VP/OpenID4VP.tsx | 68 +- .../OpenID4VPRelyingPartyStateRepository.tsx | 31 +- src/pages/AddCredentials/AddCredentials.js | 3 +- 14 files changed, 800 insertions(+), 694 deletions(-) diff --git a/src/UriHandler.tsx b/src/UriHandler.tsx index cf4b48a3d..98461ea5a 100644 --- a/src/UriHandler.tsx +++ b/src/UriHandler.tsx @@ -36,9 +36,7 @@ export const UriHandler = ({ children }) => { setUrl(window.location.href); checkForUpdates(); updateOnlineStatus(false); - }, [location]); - - + }, [location, updateOnlineStatus]); useEffect(() => { if (!isLoggedIn || !url || !keystore || !t || !openID4VCI || !openID4VP) { @@ -125,7 +123,7 @@ export const UriHandler = ({ children }) => { } } handle(url); - }, [url]); + }, [url, addLoader, removeLoader, t, keystore, isLoggedIn, openID4VCI, openID4VP]); return ( <> diff --git a/src/components/Popups/SelectCredentialsPopup.js b/src/components/Popups/SelectCredentialsPopup.js index e48e4a0f9..a53f76cb7 100644 --- a/src/components/Popups/SelectCredentialsPopup.js +++ b/src/components/Popups/SelectCredentialsPopup.js @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo, useState, useContext } from 'react'; +import React, { useEffect, useMemo, useState, useContext, useCallback } from 'react'; import PopupLayout from './PopupLayout'; import { FaShare, FaRegCircle, FaCheckCircle } from 'react-icons/fa'; import { useTranslation, Trans } from 'react-i18next'; @@ -72,6 +72,15 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu const screenType = useScreenType(); const [currentSlide, setCurrentSlide] = useState(1); + const reinitialize = useCallback(() => { + setCurrentIndex(0); + setCurrentSlide(1); + setCurrentSelectionMap({}); + setRequestedFields([]); + setSelectedCredential(null); + setPopupState({ isOpen: false }); + }, [setPopupState]); + useEffect(() => { const getData = async () => { if (currentIndex === Object.keys(popupState.options.conformantCredentialsMap).length) { @@ -114,6 +123,8 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu keys, popupState, vcEntityList, + credentialParserContext.credentialParserRegistry, + reinitialize ]); @@ -148,15 +159,6 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu } }; - const reinitialize = () => { - setCurrentIndex(0); - setCurrentSlide(1); - setCurrentSelectionMap({}); - setRequestedFields([]); - setSelectedCredential(null); - setPopupState({ isOpen: false }); - } - const onClose = () => { // setIsOpen(false); popupState.reject(); diff --git a/src/context/CredentialParserContext.tsx b/src/context/CredentialParserContext.tsx index ea890b5ec..b44fefd1d 100644 --- a/src/context/CredentialParserContext.tsx +++ b/src/context/CredentialParserContext.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, createContext } from "react"; +import React, { useEffect, createContext, useMemo } from "react"; import { ICredentialParser, ICredentialParserRegistry } from "../lib/interfaces/ICredentialParser"; import { useCredentialParserRegistry } from "../lib/services/CredentialParserRegistry"; import { parseSdJwtCredential } from "../functions/parseSdJwtCredential"; @@ -8,7 +8,6 @@ import defaultCredentialImage from "../assets/images/cred.png"; import renderSvgTemplate from "../components/Credentials/RenderSvgTemplate"; import renderCustomSvgTemplate from "../components/Credentials/RenderCustomSvgTemplate"; - export type CredentialParserContextValue = { credentialParserRegistry: ICredentialParserRegistry; } @@ -19,13 +18,12 @@ const CredentialParserContext: React.Context = cre const defaultLocale = 'en-US'; - export const CredentialParserContextProvider = ({ children }) => { const credentialParserRegistry = useCredentialParserRegistry(); const openID4VCIHelper = useOpenID4VCIHelper(); - const parser1: ICredentialParser = { + const parser1: ICredentialParser = useMemo(() => ({ async parse(rawCredential) { if (typeof rawCredential != 'string') { @@ -126,10 +124,11 @@ export const CredentialParserContextProvider = ({ children }) => { } }, - } + }), [openID4VCIHelper]); + useEffect(() => { - credentialParserRegistry.setParsers([ parser1 ]); - }, [openID4VCIHelper]) + credentialParserRegistry.setParsers([parser1]); + }, [credentialParserRegistry, parser1]); return ( @@ -139,7 +138,6 @@ export const CredentialParserContextProvider = ({ children }) => { ); } - export const withCredentialParserContext:

(component: React.ComponentType

) => React.ComponentType

= (Component) => (props) => ( diff --git a/src/context/OpenID4VPContext.tsx b/src/context/OpenID4VPContext.tsx index f051a3303..10decffb2 100644 --- a/src/context/OpenID4VPContext.tsx +++ b/src/context/OpenID4VPContext.tsx @@ -1,4 +1,4 @@ -import React, { useState, useContext, createContext } from "react"; +import React, { useState, useContext, createContext, useCallback } from "react"; import SelectCredentialsPopup from "../components/Popups/SelectCredentialsPopup"; import CredentialsContext from '../context/CredentialsContext'; import { useOpenID4VP } from "../lib/services/OpenID4VP/OpenID4VP"; @@ -22,9 +22,7 @@ export const OpenID4VPContextProvider = ({ children }) => { reject: () => { }, }); - - - const showPopup = (options): Promise> => + const showPopup = useCallback((options): Promise> => new Promise((resolve, reject) => { setPopupState({ isOpen: true, @@ -32,18 +30,21 @@ export const OpenID4VPContextProvider = ({ children }) => { resolve, reject, }); - }); + }), []); - const hidePopup = () => { + const hidePopup = useCallback(() => { setPopupState((prevState) => ({ ...prevState, isOpen: false, })); - }; + }, []); - async function showCredentialSelectionPopup(conformantCredentialsMap: Map, verifierDomainName: string): Promise> { - return showPopup({ conformantCredentialsMap, verifierDomainName }); - } + const showCredentialSelectionPopup = useCallback( + async (conformantCredentialsMap: Map, verifierDomainName: string): Promise> => { + return showPopup({ conformantCredentialsMap, verifierDomainName }); + }, + [showPopup] + ); const openID4VP = useOpenID4VP({ showCredentialSelectionPopup }); @@ -55,7 +56,6 @@ export const OpenID4VPContextProvider = ({ children }) => { ); } - export const withOpenID4VPContext:

(component: React.ComponentType

) => React.ComponentType

= (Component) => (props) => ( diff --git a/src/lib/services/CredentialBatchHelper.tsx b/src/lib/services/CredentialBatchHelper.tsx index 4ccb41261..ed46d991b 100644 --- a/src/lib/services/CredentialBatchHelper.tsx +++ b/src/lib/services/CredentialBatchHelper.tsx @@ -1,38 +1,37 @@ -import { useContext } from "react"; +import { useContext, useCallback, useMemo } from "react"; import { compareBy } from "../../util"; import { StorableCredential } from "../types/StorableCredential"; import SessionContext from "../../context/SessionContext"; export function useCredentialBatchHelper() { - const { api } = useContext(SessionContext); - async function updateCredential(storableCredential: StorableCredential) { - await api.post('/storage/vc/update', { - credential: storableCredential + const updateCredential = useCallback(async (storableCredential: StorableCredential) => { + await api.post("/storage/vc/update", { + credential: storableCredential, }); - } - - /** - * - * @param credentialIdentifier - * @param cList all verifiable credentials of the wallet - * @returns - * Always return credential with the least amount of usages - */ + }, [api]); - return { - async getLeastUsedCredential(credentialIdentifier: string, cList: StorableCredential[]): Promise<{ credential: StorableCredential }> { + const getLeastUsedCredential = useCallback( + async (credentialIdentifier: string, cList: StorableCredential[]): Promise<{ credential: StorableCredential }> => { const creds = cList.filter((c) => c.credentialIdentifier === credentialIdentifier); creds.sort(compareBy((c) => c.sigCount)); - console.log("Ordered by sigCount = ", creds) - return { credential: creds[0] } + console.log("Ordered by sigCount = ", creds); + return { credential: creds[0] }; }, + [] + ); - async useCredential(storableCredential: StorableCredential): Promise { - storableCredential.sigCount = storableCredential.sigCount + 1; - await updateCredential(storableCredential); - } - } + const useCredential = useCallback(async (storableCredential: StorableCredential): Promise => { + storableCredential.sigCount += 1; + await updateCredential(storableCredential); + }, [updateCredential]); + return useMemo( + () => ({ + getLeastUsedCredential, + useCredential, + }), + [getLeastUsedCredential, useCredential] + ); } diff --git a/src/lib/services/HttpProxy/HttpProxy.tsx b/src/lib/services/HttpProxy/HttpProxy.tsx index 908f8fa19..2acbfd5ab 100644 --- a/src/lib/services/HttpProxy/HttpProxy.tsx +++ b/src/lib/services/HttpProxy/HttpProxy.tsx @@ -1,3 +1,4 @@ +import { useMemo } from 'react'; import axios from 'axios'; import { IHttpProxy } from '../../interfaces/IHttpProxy'; @@ -5,7 +6,7 @@ import { IHttpProxy } from '../../interfaces/IHttpProxy'; const walletBackendServerUrl = process.env.REACT_APP_WALLET_BACKEND_URL; export function useHttpProxy(): IHttpProxy { - return { + const proxy = useMemo(() => ({ async get(url: string, headers: any): Promise { try { const response = await axios.post(`${walletBackendServerUrl}/proxy`, { @@ -51,6 +52,7 @@ export function useHttpProxy(): IHttpProxy { } } } - } + }), []); + return proxy; } diff --git a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx index a99100968..234a6d68e 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx @@ -10,7 +10,7 @@ import * as config from '../../../config'; import { VerifiableCredentialFormat } from '../../schemas/vc'; import { useHttpProxy } from '../HttpProxy/HttpProxy'; import { useOpenID4VCIClientStateRepository } from '../OpenID4VCIClientStateRepository'; -import { useContext, useMemo } from 'react'; +import { useContext, useMemo, useCallback } from 'react'; import SessionContext from '../../../context/SessionContext'; import { useOpenID4VCIPushedAuthorizationRequest } from './OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest'; import { useOpenID4VCIAuthorizationRequestForFirstPartyApplications } from './OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications'; @@ -19,7 +19,7 @@ import { useOpenID4VCIHelper } from '../OpenID4VCIHelper'; const redirectUri = config.OPENID4VCI_REDIRECT_URI as string; export function useOpenID4VCI(): IOpenID4VCI { - + console.log('useOpenID4VCI'); const httpProxy = useHttpProxy(); const openID4VCIClientStateRepository = useOpenID4VCIClientStateRepository(); const { keystore, api } = useContext(SessionContext); @@ -29,492 +29,515 @@ export function useOpenID4VCI(): IOpenID4VCI { const openID4VCIPushedAuthorizationRequest = useOpenID4VCIPushedAuthorizationRequest(); const openID4VCIAuthorizationRequestForFirstPartyApplications = useOpenID4VCIAuthorizationRequestForFirstPartyApplications(); + const credentialRequest = useCallback( + async (response: any, flowState: OpenID4VCIClientState, cachedProofs?: string[]) => { + console.log('credentialRequest') + const { + data: { access_token, c_nonce }, + } = response; - async function handleAuthorizationResponse(url: string, dpopNonceHeader?: string) { + const [authzServerMetadata, credentialIssuerMetadata, clientId] = await Promise.all([ + openID4VCIHelper.getAuthorizationServerMetadata(flowState.credentialIssuerIdentifier), + openID4VCIHelper.getCredentialIssuerMetadata(flowState.credentialIssuerIdentifier), + openID4VCIHelper.getClientId(flowState.credentialIssuerIdentifier) + ]); - const parsedUrl = new URL(url); + const credentialEndpoint = credentialIssuerMetadata.metadata.credential_endpoint; - const code = parsedUrl.searchParams.get('code'); - const state = parsedUrl.searchParams.get('state'); + let credentialRequestHeaders = { + "Authorization": `Bearer ${access_token}`, + }; - if (!code) { - return; - } + if (authzServerMetadata.authzServeMetadata.dpop_signing_alg_values_supported) { + const privateKey = await jose.importJWK(flowState.dpop.dpopPrivateKeyJwk, flowState.dpop.dpopAlg); - const s = await openID4VCIClientStateRepository.getByStateAndUserHandle(state); - console.log("S = ", s) - if (!s || !s.credentialIssuerIdentifier) { - console.log("No credential issuer identifier was found in the issuance flow state"); - return; - } - if (sessionStorage.getItem('oid4vci_last_used_state') === state) { - return; - } + const newDPoPNonce = response.headers['dpop-nonce']; + const credentialEndpointDPoP = await generateDPoP( + privateKey as jose.KeyLike, + flowState.dpop.dpopPublicKeyJwk, + flowState.dpop.dpopJti, + "POST", + credentialEndpoint, + newDPoPNonce, + access_token + ); - sessionStorage.setItem('oid4vci_last_used_state', state); - console.log("Handling authorization response..."); - await requestCredentials(s.credentialIssuerIdentifier, { - dpopNonceHeader: dpopNonceHeader, - authorizationCodeGrant: { - authorizationResponseUrl: url, - code: code, - state: state, - } - }); - } - /** - * - * @param response - * @param flowState - * @param cachedProof cachedProof is used in case a failure due to invalid dpop-nonce is caused and the last proof can be re-used. - * @returns - */ - async function credentialRequest(response: any, flowState: OpenID4VCIClientState, cachedProofs?: string[]) { - const { - data: { access_token, c_nonce }, - } = response; - - - const [authzServerMetadata, credentialIssuerMetadata, clientId] = await Promise.all([ - openID4VCIHelper.getAuthorizationServerMetadata(flowState.credentialIssuerIdentifier), - openID4VCIHelper.getCredentialIssuerMetadata(flowState.credentialIssuerIdentifier), - openID4VCIHelper.getClientId(flowState.credentialIssuerIdentifier) - ]); - - const credentialEndpoint = credentialIssuerMetadata.metadata.credential_endpoint; - - let credentialRequestHeaders = { - "Authorization": `Bearer ${access_token}`, - }; - - if (authzServerMetadata.authzServeMetadata.dpop_signing_alg_values_supported) { - const privateKey = await jose.importJWK(flowState.dpop.dpopPrivateKeyJwk, flowState.dpop.dpopAlg); - - const newDPoPNonce = response.headers['dpop-nonce']; - const credentialEndpointDPoP = await generateDPoP( - privateKey as jose.KeyLike, - flowState.dpop.dpopPublicKeyJwk, - flowState.dpop.dpopJti, - "POST", - credentialEndpoint, - newDPoPNonce, - access_token - ); - - credentialRequestHeaders['Authorization'] = `DPoP ${access_token}`; - credentialRequestHeaders['dpop'] = credentialEndpointDPoP; - } - - let proofsArray: string[] = []; - const numberOfProofs = credentialIssuerMetadata.metadata.batch_credential_issuance?.batch_size ?? 1; - try { - const inputs = []; - for (let i = 0; i < numberOfProofs; i++) { - inputs.push({ - nonce: c_nonce, - issuer: clientId.client_id, - audience: credentialIssuerMetadata.metadata.credential_issuer - }) + credentialRequestHeaders['Authorization'] = `DPoP ${access_token}`; + credentialRequestHeaders['dpop'] = credentialEndpointDPoP; } - if (cachedProofs) { - proofsArray = cachedProofs; + let proofsArray: string[] = []; + const numberOfProofs = credentialIssuerMetadata.metadata.batch_credential_issuance?.batch_size ?? 1; + try { + const inputs = []; + for (let i = 0; i < numberOfProofs; i++) { + inputs.push({ + nonce: c_nonce, + issuer: clientId.client_id, + audience: credentialIssuerMetadata.metadata.credential_issuer + }) + } + + if (cachedProofs) { + proofsArray = cachedProofs; + } + else { + const [{ proof_jwts }, newPrivateData, keystoreCommit] = await keystore.generateOpenid4vciProofs(inputs); + await api.updatePrivateData(newPrivateData); + await keystoreCommit(); + proofsArray = proof_jwts; + } } - else { - const [{ proof_jwts }, newPrivateData, keystoreCommit] = await keystore.generateOpenid4vciProofs(inputs); - await api.updatePrivateData(newPrivateData); - await keystoreCommit(); - proofsArray = proof_jwts; + catch (err) { + console.error(err); + throw new Error("Failed to generate proof"); } - } - catch (err) { - console.error(err); - throw new Error("Failed to generate proof"); - } - const credentialConfigurationSupported = credentialIssuerMetadata.metadata.credential_configurations_supported[flowState.credentialConfigurationId]; + const credentialConfigurationSupported = credentialIssuerMetadata.metadata.credential_configurations_supported[flowState.credentialConfigurationId]; - const credentialEndpointBody = { - "format": credentialIssuerMetadata.metadata.credential_configurations_supported[flowState.credentialConfigurationId].format, - } as any; + const credentialEndpointBody = { + "format": credentialIssuerMetadata.metadata.credential_configurations_supported[flowState.credentialConfigurationId].format, + } as any; - if (credentialIssuerMetadata.metadata?.batch_credential_issuance?.batch_size) { - credentialEndpointBody.proofs = { - jwt: proofsArray + if (credentialIssuerMetadata.metadata?.batch_credential_issuance?.batch_size) { + credentialEndpointBody.proofs = { + jwt: proofsArray + } } - } - else { - credentialEndpointBody.proof = { - proof_type: "jwt", - jwt: proofsArray[0], + else { + credentialEndpointBody.proof = { + proof_type: "jwt", + jwt: proofsArray[0], + } } - } - if (credentialConfigurationSupported.format === VerifiableCredentialFormat.SD_JWT_VC && credentialConfigurationSupported.vct) { - credentialEndpointBody.vct = credentialConfigurationSupported.vct; - } - else if (credentialConfigurationSupported.format === VerifiableCredentialFormat.MSO_MDOC && credentialConfigurationSupported.doctype) { - credentialEndpointBody.doctype = credentialConfigurationSupported.doctype; - } - - const credentialResponse = await httpProxy.post(credentialEndpoint, credentialEndpointBody, credentialRequestHeaders); - - if (credentialResponse.err) { - console.log("Error: Credential response = ", JSON.stringify(credentialResponse.err)); - if (credentialResponse.err.headers["www-authenticate"].includes("invalid_dpop_proof") && "dpop-nonce" in credentialResponse.err.headers) { - console.log("Calling credentialRequest with new dpop-nonce....") - - response.headers['dpop-nonce'] = credentialResponse.err.headers["dpop-nonce"]; - await credentialRequest(response, flowState, proofsArray); - return; + if (credentialConfigurationSupported.format === VerifiableCredentialFormat.SD_JWT_VC && credentialConfigurationSupported.vct) { + credentialEndpointBody.vct = credentialConfigurationSupported.vct; + } + else if (credentialConfigurationSupported.format === VerifiableCredentialFormat.MSO_MDOC && credentialConfigurationSupported.doctype) { + credentialEndpointBody.doctype = credentialConfigurationSupported.doctype; } - throw new Error("Credential Request failed"); - } - console.log("Credential response = ", credentialResponse) + const credentialResponse = await httpProxy.post(credentialEndpoint, credentialEndpointBody, credentialRequestHeaders); - const credentialArray = []; - if (numberOfProofs === 1 && credentialResponse.data.credential) { - const { credential } = credentialResponse.data; - credentialArray.push(credential); - } - else { - credentialArray.push(...credentialResponse.data.credentials); - } - const new_c_nonce = credentialResponse.data.c_nonce; - const new_c_nonce_expires_in = credentialResponse.data.c_nonce_expires_in; + if (credentialResponse.err) { + console.log("Error: Credential response = ", JSON.stringify(credentialResponse.err)); + if (credentialResponse.err.headers["www-authenticate"].includes("invalid_dpop_proof") && "dpop-nonce" in credentialResponse.err.headers) { + console.log("Calling credentialRequest with new dpop-nonce....") - if (new_c_nonce && new_c_nonce_expires_in) { - flowState.tokenResponse.data.c_nonce = new_c_nonce; - flowState.tokenResponse.data.c_nonce_expiration_timestamp = Math.floor(Date.now() / 1000) + new_c_nonce_expires_in; - await openID4VCIClientStateRepository.updateState(flowState); - } - - await openID4VCIClientStateRepository.cleanupExpired(); + response.headers['dpop-nonce'] = credentialResponse.err.headers["dpop-nonce"]; + await credentialRequest(response, flowState, proofsArray); + return; + } + throw new Error("Credential Request failed"); + } + console.log("Credential response = ", credentialResponse) - const identifier = generateRandomIdentifier(32); - const storableCredentials: StorableCredential[] = credentialArray.map((credential, index) => ({ - credentialIdentifier: identifier, - credential: credential, - format: credentialIssuerMetadata.metadata.credential_configurations_supported[flowState.credentialConfigurationId].format, - credentialConfigurationId: flowState.credentialConfigurationId, - credentialIssuerIdentifier: credentialIssuerMetadata.metadata.credential_issuer, - sigCount: 0, - instanceId: index, - })); - await api.post('/storage/vc', { - credentials: storableCredentials - }); - return; + const credentialArray = []; + if (numberOfProofs === 1 && credentialResponse.data.credential) { + const { credential } = credentialResponse.data; + credentialArray.push(credential); + } + else { + credentialArray.push(...credentialResponse.data.credentials); + } + const new_c_nonce = credentialResponse.data.c_nonce; + const new_c_nonce_expires_in = credentialResponse.data.c_nonce_expires_in; - } + if (new_c_nonce && new_c_nonce_expires_in) { + flowState.tokenResponse.data.c_nonce = new_c_nonce; + flowState.tokenResponse.data.c_nonce_expiration_timestamp = Math.floor(Date.now() / 1000) + new_c_nonce_expires_in; + await openID4VCIClientStateRepository.updateState(flowState); + } + await openID4VCIClientStateRepository.cleanupExpired(); + + const identifier = generateRandomIdentifier(32); + const storableCredentials: StorableCredential[] = credentialArray.map((credential, index) => ({ + credentialIdentifier: identifier, + credential: credential, + format: credentialIssuerMetadata.metadata.credential_configurations_supported[flowState.credentialConfigurationId].format, + credentialConfigurationId: flowState.credentialConfigurationId, + credentialIssuerIdentifier: credentialIssuerMetadata.metadata.credential_issuer, + sigCount: 0, + instanceId: index, + })); + + await api.post('/storage/vc', { + credentials: storableCredentials + }); + return; - async function requestCredentials(credentialIssuerIdentifier: string, requestCredentialsParams: { - dpopNonceHeader?: string, - preAuthorizedCodeGrant?: { - pre_authorized_code: string; - }, - authorizationCodeGrant?: { - state: string; - authorizationResponseUrl: string; - code: string; }, - usingActiveAccessToken?: { - credentialConfigurationId: string; - }, - refreshTokenGrant?: { - credentialConfigurationId: string; - } - }) { - - const [authzServerMetadata, clientId] = await Promise.all([ - openID4VCIHelper.getAuthorizationServerMetadata(credentialIssuerIdentifier), - openID4VCIHelper.getClientId(credentialIssuerIdentifier) - ]); - if (requestCredentialsParams.usingActiveAccessToken) { - console.log("Attempting with active access token") - - const flowState = await openID4VCIClientStateRepository.getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle(credentialIssuerIdentifier, requestCredentialsParams.usingActiveAccessToken.credentialConfigurationId) - if (!flowState) { - throw new Error("Using active access token: No flowstate"); + [openID4VCIHelper, api, httpProxy, keystore, openID4VCIClientStateRepository] + ); + + const requestCredentials = useCallback( + async (credentialIssuerIdentifier: string, requestCredentialsParams: { + dpopNonceHeader?: string, + preAuthorizedCodeGrant?: { + pre_authorized_code: string; + }, + authorizationCodeGrant?: { + state: string; + authorizationResponseUrl: string; + code: string; + }, + usingActiveAccessToken?: { + credentialConfigurationId: string; + }, + refreshTokenGrant?: { + credentialConfigurationId: string; } + }) => { + console.log('requestCredentials') + const [authzServerMetadata, clientId] = await Promise.all([ + openID4VCIHelper.getAuthorizationServerMetadata(credentialIssuerIdentifier), + openID4VCIHelper.getClientId(credentialIssuerIdentifier) + ]); + if (requestCredentialsParams.usingActiveAccessToken) { + console.log("Attempting with active access token") - // if c_nonce and access_token are not expired - if (flowState.tokenResponse && Math.floor(Date.now() / 1000) < flowState.tokenResponse.data.c_nonce_expiration_timestamp && Math.floor(Date.now() / 1000) < flowState.tokenResponse.data.expiration_timestamp) { - // attempt credential request - if (!flowState.dpop) { - throw new Error("Using active access token: No dpop in flowstate"); + const flowState = await openID4VCIClientStateRepository.getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle(credentialIssuerIdentifier, requestCredentialsParams.usingActiveAccessToken.credentialConfigurationId) + if (!flowState) { + throw new Error("Using active access token: No flowstate"); } - await credentialRequest(flowState.tokenResponse, flowState); - return; - } - else { - console.log("Using active access token: c_nonce or access_token are expired"); - } - - // if access_token is expired - if (flowState.tokenResponse && Math.floor(Date.now() / 1000) > flowState.tokenResponse.data.expiration_timestamp && flowState.tokenResponse.data.refresh_token) { - // refresh token grant - await requestCredentials(credentialIssuerIdentifier, { - dpopNonceHeader: requestCredentialsParams.dpopNonceHeader, - refreshTokenGrant: { - credentialConfigurationId: requestCredentialsParams.usingActiveAccessToken.credentialConfigurationId + // if c_nonce and access_token are not expired + if (flowState.tokenResponse && Math.floor(Date.now() / 1000) < flowState.tokenResponse.data.c_nonce_expiration_timestamp && Math.floor(Date.now() / 1000) < flowState.tokenResponse.data.expiration_timestamp) { + // attempt credential request + if (!flowState.dpop) { + throw new Error("Using active access token: No dpop in flowstate"); } - }) - return; - } - throw new Error("Couldn't hande using active access token"); - } - // Token Request - const tokenEndpoint = authzServerMetadata.authzServeMetadata.token_endpoint; + await credentialRequest(flowState.tokenResponse, flowState); + return; + } + else { + console.log("Using active access token: c_nonce or access_token are expired"); + } - let flowState: OpenID4VCIClientState | null = null; + // if access_token is expired + if (flowState.tokenResponse && Math.floor(Date.now() / 1000) > flowState.tokenResponse.data.expiration_timestamp && flowState.tokenResponse.data.refresh_token) { + // refresh token grant + await requestCredentials(credentialIssuerIdentifier, { + dpopNonceHeader: requestCredentialsParams.dpopNonceHeader, + refreshTokenGrant: { + credentialConfigurationId: requestCredentialsParams.usingActiveAccessToken.credentialConfigurationId + } + }) + return; + } + throw new Error("Couldn't hande using active access token"); + } + // Token Request + const tokenEndpoint = authzServerMetadata.authzServeMetadata.token_endpoint; - if (requestCredentialsParams?.authorizationCodeGrant) { - flowState = await openID4VCIClientStateRepository.getByStateAndUserHandle(requestCredentialsParams.authorizationCodeGrant.state) - } - else if (requestCredentialsParams?.refreshTokenGrant) { - flowState = await openID4VCIClientStateRepository.getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle(credentialIssuerIdentifier, requestCredentialsParams.refreshTokenGrant.credentialConfigurationId) - } + let flowState: OpenID4VCIClientState | null = null; + if (requestCredentialsParams?.authorizationCodeGrant) { + flowState = await openID4VCIClientStateRepository.getByStateAndUserHandle(requestCredentialsParams.authorizationCodeGrant.state) + } + else if (requestCredentialsParams?.refreshTokenGrant) { + flowState = await openID4VCIClientStateRepository.getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle(credentialIssuerIdentifier, requestCredentialsParams.refreshTokenGrant.credentialConfigurationId) + } - if (!flowState) { - throw new Error("No flowstate"); - } - let dpopPrivateKey: jose.KeyLike | Uint8Array | null = null; - let dpopPrivateKeyJwk: jose.JWK | null = null; - let dpopPublicKeyJwk: jose.JWK | null = null; - if (!flowState.dpop) { // if DPoP keys have not been generated, then generate them - const { privateKey, publicKey } = await jose.generateKeyPair('ES256', { extractable: true }); // keypair for dpop if used - [dpopPrivateKeyJwk, dpopPublicKeyJwk] = await Promise.all([ - jose.exportJWK(privateKey), - jose.exportJWK(publicKey) - ]); + if (!flowState) { + throw new Error("No flowstate"); + } - dpopPrivateKey = privateKey; - } - else { // if already generated, then reuse them - dpopPrivateKeyJwk = flowState.dpop.dpopPrivateKeyJwk; - dpopPublicKeyJwk = flowState.dpop.dpopPublicKeyJwk; + let dpopPrivateKey: jose.KeyLike | Uint8Array | null = null; + let dpopPrivateKeyJwk: jose.JWK | null = null; + let dpopPublicKeyJwk: jose.JWK | null = null; - [dpopPrivateKey] = await Promise.all([ - jose.importJWK(flowState.dpop.dpopPrivateKeyJwk, flowState.dpop.dpopAlg) - ]) - } - const jti = generateRandomIdentifier(8); - - let tokenRequestHeaders = { - 'Content-Type': 'application/x-www-form-urlencoded', - }; - - if (authzServerMetadata.authzServeMetadata.dpop_signing_alg_values_supported) { - const dpop = await generateDPoP( - dpopPrivateKey as jose.KeyLike, - dpopPublicKeyJwk, - jti, - "POST", - tokenEndpoint, - requestCredentialsParams.dpopNonceHeader - ); - flowState.dpop = { - dpopAlg: 'ES256', - dpopJti: jti, - dpopPrivateKeyJwk: dpopPrivateKeyJwk, - dpopPublicKeyJwk: dpopPublicKeyJwk, - } - tokenRequestHeaders['DPoP'] = dpop; - } + if (!flowState.dpop) { // if DPoP keys have not been generated, then generate them + const { privateKey, publicKey } = await jose.generateKeyPair('ES256', { extractable: true }); // keypair for dpop if used + [dpopPrivateKeyJwk, dpopPublicKeyJwk] = await Promise.all([ + jose.exportJWK(privateKey), + jose.exportJWK(publicKey) + ]); + dpopPrivateKey = privateKey; + } + else { // if already generated, then reuse them + dpopPrivateKeyJwk = flowState.dpop.dpopPrivateKeyJwk; + dpopPublicKeyJwk = flowState.dpop.dpopPublicKeyJwk; - const formData = new URLSearchParams(); - formData.append('client_id', clientId.client_id); - if (requestCredentialsParams.authorizationCodeGrant) { - formData.append('grant_type', 'authorization_code'); - formData.append('code', requestCredentialsParams.authorizationCodeGrant.code); - formData.append('code_verifier', flowState.code_verifier); - } - else if (requestCredentialsParams.refreshTokenGrant) { - if (!flowState?.tokenResponse?.data.refresh_token) { - console.info("Found no refresh_token to execute refesh_token grant") - throw new Error("Found no refresh_token to execute refesh_token grant"); + [dpopPrivateKey] = await Promise.all([ + jose.importJWK(flowState.dpop.dpopPrivateKeyJwk, flowState.dpop.dpopAlg) + ]) } - formData.append('grant_type', 'refresh_token'); - formData.append('refresh_token', flowState.tokenResponse.data.refresh_token); - } - else { - throw new Error("No grant type selected in requestCredentials()"); - } - formData.append('redirect_uri', redirectUri); - - const response = await httpProxy.post(tokenEndpoint, formData.toString(), tokenRequestHeaders); - - if (response.err) { - const { err } = response; - console.log("failed token request") - console.log(JSON.stringify(err)); - console.log("Dpop nonce found = ", err.headers['dpop-nonce']) - if (err.headers['dpop-nonce']) { - requestCredentialsParams.dpopNonceHeader = err.headers['dpop-nonce']; - if (requestCredentialsParams.dpopNonceHeader) { - await requestCredentials(credentialIssuerIdentifier, requestCredentialsParams); - return; + const jti = generateRandomIdentifier(8); + + let tokenRequestHeaders = { + 'Content-Type': 'application/x-www-form-urlencoded', + }; + + if (authzServerMetadata.authzServeMetadata.dpop_signing_alg_values_supported) { + const dpop = await generateDPoP( + dpopPrivateKey as jose.KeyLike, + dpopPublicKeyJwk, + jti, + "POST", + tokenEndpoint, + requestCredentialsParams.dpopNonceHeader + ); + flowState.dpop = { + dpopAlg: 'ES256', + dpopJti: jti, + dpopPrivateKeyJwk: dpopPrivateKeyJwk, + dpopPublicKeyJwk: dpopPublicKeyJwk, } + tokenRequestHeaders['DPoP'] = dpop; } - else if (err.data.error) { - console.error("OID4VCI Token Response Error: ", JSON.stringify(err.data)) - } - return; - } - console.log("== response = ", response) - try { // try to extract the response and update the OpenID4VCIClientStateRepository - const { - data: { access_token, c_nonce, expires_in, c_nonce_expires_in, refresh_token }, - } = response; - if (!access_token) { - console.log("Missing access_token from response"); + const formData = new URLSearchParams(); + formData.append('client_id', clientId.client_id); + if (requestCredentialsParams.authorizationCodeGrant) { + formData.append('grant_type', 'authorization_code'); + formData.append('code', requestCredentialsParams.authorizationCodeGrant.code); + formData.append('code_verifier', flowState.code_verifier); + } + else if (requestCredentialsParams.refreshTokenGrant) { + if (!flowState?.tokenResponse?.data.refresh_token) { + console.info("Found no refresh_token to execute refesh_token grant") + throw new Error("Found no refresh_token to execute refesh_token grant"); + } + formData.append('grant_type', 'refresh_token'); + formData.append('refresh_token', flowState.tokenResponse.data.refresh_token); + } + else { + throw new Error("No grant type selected in requestCredentials()"); + } + formData.append('redirect_uri', redirectUri); + + const response = await httpProxy.post(tokenEndpoint, formData.toString(), tokenRequestHeaders); + + if (response.err) { + const { err } = response; + console.log("failed token request") + console.log(JSON.stringify(err)); + console.log("Dpop nonce found = ", err.headers['dpop-nonce']) + if (err.headers['dpop-nonce']) { + requestCredentialsParams.dpopNonceHeader = err.headers['dpop-nonce']; + if (requestCredentialsParams.dpopNonceHeader) { + await requestCredentials(credentialIssuerIdentifier, requestCredentialsParams); + return; + } + } + else if (err.data.error) { + console.error("OID4VCI Token Response Error: ", JSON.stringify(err.data)) + } return; } - flowState.tokenResponse = { - data: { - access_token, c_nonce, expiration_timestamp: Math.floor(Date.now() / 1000) + expires_in, c_nonce_expiration_timestamp: Math.floor(Date.now() / 1000) + c_nonce_expires_in, refresh_token - }, - headers: { ...response.headers } - } + console.log("== response = ", response) + try { // try to extract the response and update the OpenID4VCIClientStateRepository + const { + data: { access_token, c_nonce, expires_in, c_nonce_expires_in, refresh_token }, + } = response; - await openID4VCIClientStateRepository.updateState(flowState); - } - catch (err) { - console.error(err); - throw new Error("Failed to extract the response and update the OpenID4VCIClientStateRepository"); - } + if (!access_token) { + console.log("Missing access_token from response"); + return; + } - try { - // Credential Request - await credentialRequest(flowState.tokenResponse, flowState); - } - catch (err) { - console.error("Error handling authrozation response ", err); - throw new Error("Credential request failed"); - } - } + flowState.tokenResponse = { + data: { + access_token, c_nonce, expiration_timestamp: Math.floor(Date.now() / 1000) + expires_in, c_nonce_expiration_timestamp: Math.floor(Date.now() / 1000) + c_nonce_expires_in, refresh_token + }, + headers: { ...response.headers } + } + await openID4VCIClientStateRepository.updateState(flowState); + } + catch (err) { + console.error(err); + throw new Error("Failed to extract the response and update the OpenID4VCIClientStateRepository"); + } - async function handleCredentialOffer(credentialOfferURL: string): Promise<{ credentialIssuer: string, selectedCredentialConfigurationId: string; issuer_state?: string }> { - const parsedUrl = new URL(credentialOfferURL); - let offer; - if (parsedUrl.searchParams.get("credential_offer")) { - offer = CredentialOfferSchema.parse(JSON.parse(parsedUrl.searchParams.get("credential_offer"))); - } else { try { - let response = await httpProxy.get(parsedUrl.searchParams.get("credential_offer_uri"), {}) - offer = response.data; + // Credential Request + await credentialRequest(flowState.tokenResponse, flowState); } catch (err) { - console.error(err); + console.error("Error handling authrozation response ", err); + throw new Error("Credential request failed"); + } + }, + [ + openID4VCIClientStateRepository, + openID4VCIHelper, + httpProxy, + credentialRequest, + ] + ); + + const handleAuthorizationResponse = useCallback( + async (url: string, dpopNonceHeader?: string) => { + console.log('handleAuthorizationResponse'); + const parsedUrl = new URL(url); + + const code = parsedUrl.searchParams.get('code'); + const state = parsedUrl.searchParams.get('state'); + + if (!code) { return; } - } - if (!offer.grants.authorization_code) { - throw new Error("Only authorization_code grant is supported"); - } + const s = await openID4VCIClientStateRepository.getByStateAndUserHandle(state); + console.log("S = ", s) + if (!s || !s.credentialIssuerIdentifier) { + console.log("No credential issuer identifier was found in the issuance flow state"); + return; + } + if (sessionStorage.getItem('oid4vci_last_used_state') === state) { + return; + } - const [credentialIssuerMetadata] = await Promise.all([ - openID4VCIHelper.getCredentialIssuerMetadata(offer.credential_issuer) - ]); + sessionStorage.setItem('oid4vci_last_used_state', state); + console.log("Handling authorization response..."); + await requestCredentials(s.credentialIssuerIdentifier, { + dpopNonceHeader: dpopNonceHeader, + authorizationCodeGrant: { + authorizationResponseUrl: url, + code: code, + state: state, + } + }); + }, + [openID4VCIClientStateRepository, requestCredentials] + ); + /** + * + * @param response + * @param flowState + * @param cachedProof cachedProof is used in case a failure due to invalid dpop-nonce is caused and the last proof can be re-used. + * @returns + */ - const selectedConfigurationId = offer.credential_configuration_ids[0]; - const selectedConfiguration = credentialIssuerMetadata.metadata.credential_configurations_supported[selectedConfigurationId]; - if (!selectedConfiguration) { - throw new Error("Credential configuration not found"); - } + const handleCredentialOffer = useCallback( + async (credentialOfferURL: string): Promise<{ credentialIssuer: string, selectedCredentialConfigurationId: string; issuer_state?: string }> => { + console.log('handleCredentialOffer') + const parsedUrl = new URL(credentialOfferURL); + let offer; + if (parsedUrl.searchParams.get("credential_offer")) { + offer = CredentialOfferSchema.parse(JSON.parse(parsedUrl.searchParams.get("credential_offer"))); + } else { + try { + let response = await httpProxy.get(parsedUrl.searchParams.get("credential_offer_uri"), {}) + offer = response.data; + } + catch (err) { + console.error(err); + return; + } + } - let issuer_state = undefined; - if (offer.grants?.authorization_code?.issuer_state) { - issuer_state = offer.grants.authorization_code.issuer_state; - } + if (!offer.grants.authorization_code) { + throw new Error("Only authorization_code grant is supported"); + } - return { credentialIssuer: offer.credential_issuer, selectedCredentialConfigurationId: selectedConfigurationId, issuer_state }; - } + const [credentialIssuerMetadata] = await Promise.all([ + openID4VCIHelper.getCredentialIssuerMetadata(offer.credential_issuer) + ]); - async function getAvailableCredentialConfigurations(credentialIssuerIdentifier: string): Promise> { - const [credentialIssuerMetadata] = await Promise.all([ - openID4VCIHelper.getCredentialIssuerMetadata(credentialIssuerIdentifier) - ]); - if (!credentialIssuerMetadata.metadata?.credential_configurations_supported) { - throw new Error("Credential configuration supported not found") - } - return credentialIssuerMetadata.metadata?.credential_configurations_supported; - } + const selectedConfigurationId = offer.credential_configuration_ids[0]; + const selectedConfiguration = credentialIssuerMetadata.metadata.credential_configurations_supported[selectedConfigurationId]; + if (!selectedConfiguration) { + throw new Error("Credential configuration not found"); + } - async function generateAuthorizationRequest(credentialIssuerIdentifier: string, credentialConfigurationId: string, issuer_state?: string): Promise<{ url?: string; }> { - await openID4VCIClientStateRepository.cleanupExpired(); + let issuer_state = undefined; + if (offer.grants?.authorization_code?.issuer_state) { + issuer_state = offer.grants.authorization_code.issuer_state; + } - try { // attempt to get credentials using active session - await requestCredentials(credentialIssuerIdentifier, { - usingActiveAccessToken: { - credentialConfigurationId - } - }); - return { url: "/" }; - } - catch (err) { console.error(err) } - - const [authzServerMetadata, credentialIssuerMetadata, clientId] = await Promise.all([ - openID4VCIHelper.getAuthorizationServerMetadata(credentialIssuerIdentifier), - openID4VCIHelper.getCredentialIssuerMetadata(credentialIssuerIdentifier), - openID4VCIHelper.getClientId(credentialIssuerIdentifier) - ]); - - if (authzServerMetadata.authzServeMetadata.pushed_authorization_request_endpoint) { - const res = await openID4VCIPushedAuthorizationRequest.generate( - credentialConfigurationId, - issuer_state, - { - authorizationServerMetadata: authzServerMetadata.authzServeMetadata, - credentialIssuerMetadata: credentialIssuerMetadata.metadata, - credentialIssuerIdentifier: credentialIssuerMetadata.metadata.credential_issuer, - clientId: clientId.client_id, - redirectUri: redirectUri - } - ); - if ('authorizationRequestURL' in res) { - return { url: res.authorizationRequestURL }; + return { credentialIssuer: offer.credential_issuer, selectedCredentialConfigurationId: selectedConfigurationId, issuer_state }; + }, + [httpProxy, openID4VCIHelper] + ); + + const getAvailableCredentialConfigurations = useCallback( + async (credentialIssuerIdentifier: string): Promise> => { + console.log('getAvailableCredentialConfigurations') + const [credentialIssuerMetadata] = await Promise.all([ + openID4VCIHelper.getCredentialIssuerMetadata(credentialIssuerIdentifier) + ]); + if (!credentialIssuerMetadata.metadata?.credential_configurations_supported) { + throw new Error("Credential configuration supported not found") } - } - else if (authzServerMetadata.authzServeMetadata.authorization_challenge_endpoint) { - await openID4VCIAuthorizationRequestForFirstPartyApplications.generate( - credentialConfigurationId, - issuer_state, - { - authorizationServerMetadata: authzServerMetadata.authzServeMetadata, - credentialIssuerMetadata: credentialIssuerMetadata.metadata, - credentialIssuerIdentifier: credentialIssuerMetadata.metadata.credential_issuer, - clientId: clientId.client_id, - redirectUri: redirectUri - } - ).then((result) => { - if (!('authorization_code' in result)) { - console.error("authorization_code was not found in the result"); - return; - } - return handleAuthorizationResponse(`openid://?code=${result.authorization_code}&state=${result.state}`); - }); - return {} - } - } + return credentialIssuerMetadata.metadata?.credential_configurations_supported; + }, + [openID4VCIHelper] + ); + + const generateAuthorizationRequest = useCallback( + async (credentialIssuerIdentifier: string, credentialConfigurationId: string, issuer_state?: string) => { + console.log('generateAuthorizationRequest') + await openID4VCIClientStateRepository.cleanupExpired(); + + try { // attempt to get credentials using active session + await requestCredentials(credentialIssuerIdentifier, { + usingActiveAccessToken: { + credentialConfigurationId + } + }); + return { url: "/" }; + } + catch (err) { console.error(err) } + const [authzServerMetadata, credentialIssuerMetadata, clientId] = await Promise.all([ + openID4VCIHelper.getAuthorizationServerMetadata(credentialIssuerIdentifier), + openID4VCIHelper.getCredentialIssuerMetadata(credentialIssuerIdentifier), + openID4VCIHelper.getClientId(credentialIssuerIdentifier) + ]); + + if (authzServerMetadata.authzServeMetadata.pushed_authorization_request_endpoint) { + const res = await openID4VCIPushedAuthorizationRequest.generate( + credentialConfigurationId, + issuer_state, + { + authorizationServerMetadata: authzServerMetadata.authzServeMetadata, + credentialIssuerMetadata: credentialIssuerMetadata.metadata, + credentialIssuerIdentifier: credentialIssuerMetadata.metadata.credential_issuer, + clientId: clientId.client_id, + redirectUri: redirectUri + } + ); + if ('authorizationRequestURL' in res) { + return { url: res.authorizationRequestURL }; + } + } + else if (authzServerMetadata.authzServeMetadata.authorization_challenge_endpoint) { + await openID4VCIAuthorizationRequestForFirstPartyApplications.generate( + credentialConfigurationId, + issuer_state, + { + authorizationServerMetadata: authzServerMetadata.authzServeMetadata, + credentialIssuerMetadata: credentialIssuerMetadata.metadata, + credentialIssuerIdentifier: credentialIssuerMetadata.metadata.credential_issuer, + clientId: clientId.client_id, + redirectUri: redirectUri + } + ).then((result) => { + if (!('authorization_code' in result)) { + console.error("authorization_code was not found in the result"); + return; + } + return handleAuthorizationResponse(`openid://?code=${result.authorization_code}&state=${result.state}`); + }); + return {} + } + }, + [openID4VCIClientStateRepository,openID4VCIHelper, handleAuthorizationResponse, openID4VCIAuthorizationRequestForFirstPartyApplications,openID4VCIPushedAuthorizationRequest, requestCredentials] + ); return useMemo(() => { return { @@ -523,6 +546,10 @@ export function useOpenID4VCI(): IOpenID4VCI { handleCredentialOffer, handleAuthorizationResponse } - }, [httpProxy, openID4VCIHelper, openID4VCIClientStateRepository, api, keystore]) - + }, [ + generateAuthorizationRequest, + getAvailableCredentialConfigurations, + handleCredentialOffer, + handleAuthorizationResponse + ]); } diff --git a/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx b/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx index b81a4df23..ffd469981 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx @@ -6,7 +6,7 @@ import { generateRandomIdentifier } from "../../../utils/generateRandomIdentifie import { OpenID4VCIClientState } from "../../../types/OpenID4VCIClientState"; import { useOpenID4VCIClientStateRepository } from "../../OpenID4VCIClientStateRepository"; import { useHttpProxy } from "../../HttpProxy/HttpProxy"; -import { useContext } from "react"; +import { useCallback, useMemo, useContext } from "react"; import OpenID4VPContext from "../../../../context/OpenID4VPContext"; import SessionContext from "../../../../context/SessionContext"; @@ -17,15 +17,18 @@ export function useOpenID4VCIAuthorizationRequestForFirstPartyApplications(): IO const { openID4VP } = useContext(OpenID4VPContext); const { keystore } = useContext(SessionContext); - return { - async generate(credentialConfigurationId: string, issuer_state: string | undefined, config: { - credentialIssuerIdentifier: string, - redirectUri: string, - clientId: string, - authorizationServerMetadata: OpenidAuthorizationServerMetadata, - credentialIssuerMetadata: OpenidCredentialIssuerMetadata, - }): Promise<{ authorizationRequestURL: string } | { authorization_code: string; state: string; }> { - + const generate = useCallback( + async ( + credentialConfigurationId: string, + issuer_state: string | undefined, + config: { + credentialIssuerIdentifier: string; + redirectUri: string; + clientId: string; + authorizationServerMetadata: OpenidAuthorizationServerMetadata; + credentialIssuerMetadata: OpenidCredentialIssuerMetadata; + } + ): Promise<{ authorizationRequestURL: string } | { authorization_code: string; state: string }> => { const userHandleB64u = keystore.getUserHandleB64u(); const { code_challenge, code_verifier } = await pkce(); @@ -100,7 +103,9 @@ export function useOpenID4VCIAuthorizationRequestForFirstPartyApplications(): IO } throw new Error("First party app authorization failed"); + }, + [httpProxy, keystore, openID4VCIClientStateRepository, openID4VP] + ); - } - } + return useMemo(() => ({ generate }), [generate]); } diff --git a/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.tsx b/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.tsx index b8645dc28..dc89505d4 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest.tsx @@ -6,7 +6,7 @@ import { generateRandomIdentifier } from "../../../utils/generateRandomIdentifie import { OpenID4VCIClientState } from "../../../types/OpenID4VCIClientState"; import { useHttpProxy } from "../../HttpProxy/HttpProxy"; import { useOpenID4VCIClientStateRepository } from "../../OpenID4VCIClientStateRepository"; -import { useContext } from "react"; +import { useCallback, useMemo, useContext } from "react"; import SessionContext from "../../../../context/SessionContext"; export function useOpenID4VCIPushedAuthorizationRequest(): IOpenID4VCIAuthorizationRequest { @@ -15,15 +15,18 @@ export function useOpenID4VCIPushedAuthorizationRequest(): IOpenID4VCIAuthorizat const openID4VCIClientStateRepository = useOpenID4VCIClientStateRepository(); const { keystore } = useContext(SessionContext); - return { - async generate(credentialConfigurationId: string, issuer_state: string | undefined, config: { - credentialIssuerIdentifier: string, - redirectUri: string, - clientId: string, - authorizationServerMetadata: OpenidAuthorizationServerMetadata, - credentialIssuerMetadata: OpenidCredentialIssuerMetadata, - }): Promise<{ authorizationRequestURL: string } | { authorization_code: string; state: string; }> { - + const generate = useCallback( + async ( + credentialConfigurationId: string, + issuer_state: string | undefined, + config: { + credentialIssuerIdentifier: string; + redirectUri: string; + clientId: string; + authorizationServerMetadata: OpenidAuthorizationServerMetadata; + credentialIssuerMetadata: OpenidCredentialIssuerMetadata; + } + ): Promise<{ authorizationRequestURL: string }> => { const userHandleB64u = keystore.getUserHandleB64u(); const { code_challenge, code_verifier } = await pkce(); @@ -70,7 +73,9 @@ export function useOpenID4VCIPushedAuthorizationRequest(): IOpenID4VCIAuthorizat await openID4VCIClientStateRepository.create(new OpenID4VCIClientState(userHandleB64u, config.credentialIssuerIdentifier, state, code_verifier, credentialConfigurationId)) return { authorizationRequestURL }; - } - } + }, + [httpProxy, openID4VCIClientStateRepository, keystore] + ); + return useMemo(() => ({ generate }), [generate]); } diff --git a/src/lib/services/OpenID4VCIClientStateRepository.tsx b/src/lib/services/OpenID4VCIClientStateRepository.tsx index 72bab8161..078e4f8bc 100644 --- a/src/lib/services/OpenID4VCIClientStateRepository.tsx +++ b/src/lib/services/OpenID4VCIClientStateRepository.tsx @@ -1,9 +1,8 @@ -import { useContext, useEffect, useState } from "react"; +import { useContext, useEffect, useState, useCallback, useMemo } from "react"; import { IOpenID4VCIClientStateRepository } from "../interfaces/IOpenID4VCIClientStateRepository"; import { OpenID4VCIClientState } from "../types/OpenID4VCIClientState"; import SessionContext from "../../context/SessionContext"; - export function useOpenID4VCIClientStateRepository(): IOpenID4VCIClientStateRepository { const key = "openid4vci_client_state"; @@ -26,72 +25,73 @@ export function useOpenID4VCIClientStateRepository(): IOpenID4VCIClientStateRepo setRememberIssuerForSeconds(userData.settings.openidRefreshTokenMaxAgeInSeconds); }); } - }, [api, isLoggedIn]); - - async function getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle(credentialIssuer: string, credentialConfigurationId: string): Promise { - const array = JSON.parse(localStorage.getItem(key)) as Array; - const res = array.filter((s) => s.credentialIssuerIdentifier === credentialIssuer && s.credentialConfigurationId === credentialConfigurationId && s.userHandleB64U === keystore.getUserHandleB64u())[0]; - return res ? res : null; - } - - async function getByStateAndUserHandle(state: string): Promise { - const array = JSON.parse(localStorage.getItem(key)) as Array; - const res = array.filter((s) => s.state === state && s.userHandleB64U === keystore.getUserHandleB64u())[0]; - return res ? res : null; - } + }, [api, isLoggedIn, rememberIssuerForSeconds]); - return { - getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle, - getByStateAndUserHandle, + const getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle = useCallback( + async ( + credentialIssuer: string, + credentialConfigurationId: string + ): Promise => { - async cleanupExpired() { const array = JSON.parse(localStorage.getItem(key)) as Array; - const results = array.filter((s) => s.userHandleB64U === keystore.getUserHandleB64u()); - const statesToBeRemoved: string[] = []; - for (const res of results) { - if (!res.created || - typeof res.created !== 'number' || - Math.floor(Date.now() / 1000) - res.created > rememberIssuerForSeconds) { - - statesToBeRemoved.push(res.state); - } - } - - console.log("Cleanup states = ", statesToBeRemoved) - const filteredArray = array.filter((s) => !statesToBeRemoved.includes(s.state)); - localStorage.setItem(key, JSON.stringify(filteredArray)); + const res = array.filter((s) => s.credentialIssuerIdentifier === credentialIssuer && s.credentialConfigurationId === credentialConfigurationId && s.userHandleB64U === keystore.getUserHandleB64u())[0]; + return res ? res : null; }, + [keystore] + ); + const getByStateAndUserHandle = useCallback( + async (state: string): Promise => { + const array = JSON.parse(localStorage.getItem(key)) as Array; + const res = array.filter((s) => s.state === state && s.userHandleB64U === keystore.getUserHandleB64u())[0]; + return res ? res : null; + }, + [keystore] + ); + const cleanupExpired = useCallback(async (): Promise => { + const array = JSON.parse(localStorage.getItem(key)) as Array; + const results = array.filter((s) => s.userHandleB64U === keystore.getUserHandleB64u()); + const statesToBeRemoved: string[] = []; + for (const res of results) { + if (!res.created || + typeof res.created !== 'number' || + Math.floor(Date.now() / 1000) - res.created > rememberIssuerForSeconds) { + + statesToBeRemoved.push(res.state); + } + } - - async create(s: OpenID4VCIClientState): Promise { - const existingState = await getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle(s.credentialIssuerIdentifier, s.credentialConfigurationId); - if (existingState) { // remove the existing state for this configuration id - const array = JSON.parse(localStorage.getItem(key)) as Array; - const updatedArray = array.filter((x) => x.credentialConfigurationId !== s.credentialConfigurationId); + console.log("Cleanup states = ", statesToBeRemoved) + const filteredArray = array.filter((s) => !statesToBeRemoved.includes(s.state)); + localStorage.setItem(key, JSON.stringify(filteredArray)); + }, [keystore, rememberIssuerForSeconds]); + + const create = useCallback( + async (state: OpenID4VCIClientState): Promise => { + const existingState = await getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle( + state.credentialIssuerIdentifier, + state.credentialConfigurationId + ); + + const data = localStorage.getItem(key); + const array = data ? (JSON.parse(data) as OpenID4VCIClientState[]) : []; + + if (existingState) { + const updatedArray = array.filter( + (x) => x.credentialConfigurationId !== state.credentialConfigurationId + ); localStorage.setItem(key, JSON.stringify(updatedArray)); } - let data = localStorage.getItem(key); - if (!data) { - data = JSON.stringify('[]'); - } - let array; - try { - array = JSON.parse(data) as Array; - if (!(array instanceof Array)) { - throw new Error("Unable to parse as array") - } - } - catch (err) { // if parsing failed - array = []; // then clean up the array with no elements - } - array.push(s); + array.push(state); localStorage.setItem(key, JSON.stringify(array)); }, + [getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle] + ); - async updateState(newState: OpenID4VCIClientState): Promise { + const updateState = useCallback( + async (newState: OpenID4VCIClientState): Promise => { const fetched = await getByStateAndUserHandle(newState.state); if (!fetched) { return; @@ -101,6 +101,23 @@ export function useOpenID4VCIClientStateRepository(): IOpenID4VCIClientStateRepo updatedArray.push(newState); // commit changes localStorage.setItem(key, JSON.stringify(updatedArray)); + }, + [getByStateAndUserHandle] + ); + + return useMemo(() => { + return { + getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle, + getByStateAndUserHandle, + cleanupExpired, + create, + updateState } - } + }, [ + getByCredentialIssuerIdentifierAndCredentialConfigurationIdAndUserHandle, + getByStateAndUserHandle, + cleanupExpired, + create, + updateState + ]); } diff --git a/src/lib/services/OpenID4VCIHelper.tsx b/src/lib/services/OpenID4VCIHelper.tsx index 5125bbd46..154e3df95 100644 --- a/src/lib/services/OpenID4VCIHelper.tsx +++ b/src/lib/services/OpenID4VCIHelper.tsx @@ -5,7 +5,7 @@ import { addItem, getItem } from '../../indexedDB'; import { base64url, importX509, jwtVerify } from "jose"; import { getPublicKeyFromB64Cert } from "../utils/pki"; import { useHttpProxy } from "./HttpProxy/HttpProxy"; -import { useCallback, useContext, useEffect, useState } from "react"; +import { useCallback, useContext, useEffect, useState, useMemo } from "react"; import StatusContext from "../../context/StatusContext"; import SessionContext from "../../context/SessionContext"; @@ -16,118 +16,135 @@ export function useOpenID4VCIHelper(): IOpenID4VCIHelper { const { api } = useContext(SessionContext); useEffect(() => { - window.addEventListener('login', (e) => { - console.log("Should use cache") - setShouldUseCache(false) - }); - }, []); - - - - const fetchAndCache = useCallback(async function fetchAndCache(path: string, schema: any, isOnline: boolean, forceIndexDB: boolean): Promise { - if (!isOnline || forceIndexDB) { - const cachedData = await getItem(path, path); - if (cachedData) return cachedData; - } - - // Fetch from network if online - try { - const response = await httpProxy.get(path, {}); - if (!response) throw new Error("Couldn't get response"); - - const parsedData = schema.parse(response.data); - await addItem(path, path, parsedData); // Cache the fetched data - return parsedData; - } catch (err) { - console.error(`Error fetching from ${path}:`, err); - throw new Error(`Couldn't get data from ${path}`); - } - }, [isOnline]) + const handleLogin = () => setShouldUseCache(false); + window.addEventListener('login', handleLogin); + return () => { + window.removeEventListener('login', handleLogin); + }; + }, []); - async function getClientId(credentialIssuerIdentifier: string) { - try { - const issuerResponse = await api.getExternalEntity('/issuer/all', undefined, true); - const trustedCredentialIssuers = issuerResponse.data; - const issuer = trustedCredentialIssuers.filter((issuer: any) => issuer.credentialIssuerIdentifier === credentialIssuerIdentifier)[0]; - if (issuer) { - return { client_id: issuer.clientId }; + const fetchAndCache = useCallback( + async function fetchAndCache(path: string, schema: any, isOnline: boolean, forceIndexDB: boolean): Promise { + console.log('fetchAndCache') + if (!isOnline || forceIndexDB) { + const cachedData = await getItem(path, path); + if (cachedData) return cachedData; } - return null; - } - catch (err) { - console.log("Could not get client_id for issuer " + credentialIssuerIdentifier + " Details:"); - console.error(err); - return null; - } - } - - // Fetches authorization server metadata with fallback - async function getAuthorizationServerMetadata(credentialIssuerIdentifier: string): Promise<{ authzServeMetadata: OpenidAuthorizationServerMetadata } | null> { - const pathAuthorizationServer = `${credentialIssuerIdentifier}/.well-known/oauth-authorization-server`; - const pathConfiguration = `${credentialIssuerIdentifier}/.well-known/openid-configuration`; - - try { - const authzServeMetadata = await fetchAndCache( - pathAuthorizationServer, - OpenidAuthorizationServerMetadataSchema, - isOnline, - shouldUseCache - ); - return { authzServeMetadata }; - } catch { - // Fallback to openid-configuration if oauth-authorization-server fetch fails - const authzServeMetadata = await fetchAndCache( - pathConfiguration, - OpenidAuthorizationServerMetadataSchema, - isOnline, - shouldUseCache - ).catch(() => null); - - if (!authzServeMetadata) { + // Fetch from network if online + try { + const response = await httpProxy.get(path, {}); + if (!response) throw new Error("Couldn't get response"); + + const parsedData = schema.parse(response.data); + await addItem(path, path, parsedData); // Cache the fetched data + return parsedData; + } catch (err) { + console.error(`Error fetching from ${path}:`, err); + throw new Error(`Couldn't get data from ${path}`); + } + }, [httpProxy]) + + + const getClientId = useCallback( + async (credentialIssuerIdentifier: string) => { + console.log('getClientId'); + try { + const issuerResponse = await api.getExternalEntity('/issuer/all', undefined, true); + const trustedCredentialIssuers = issuerResponse.data; + const issuer = trustedCredentialIssuers.filter((issuer: any) => issuer.credentialIssuerIdentifier === credentialIssuerIdentifier)[0]; + if (issuer) { + return { client_id: issuer.clientId }; + } return null; } - return { authzServeMetadata }; - } - } - - async function getCredentialIssuerMetadata(credentialIssuerIdentifier: string): Promise<{ metadata: OpenidCredentialIssuerMetadata } | null> { - const pathCredentialIssuer = `${credentialIssuerIdentifier}/.well-known/openid-credential-issuer`; + catch (err) { + console.log("Could not get client_id for issuer " + credentialIssuerIdentifier + " Details:"); + console.error(err); + return null; + } + }, + [api] + ); - try { - const metadata = await fetchAndCache( - pathCredentialIssuer, - OpenidCredentialIssuerMetadataSchema, - isOnline, - shouldUseCache - ); - if (metadata.signed_metadata) { - try { - const parsedHeader = JSON.parse(new TextDecoder().decode(base64url.decode(metadata.signed_metadata.split('.')[0]))); - if (parsedHeader.x5c) { - const publicKey = await importX509(getPublicKeyFromB64Cert(parsedHeader.x5c[0]), parsedHeader.alg); - const { payload } = await jwtVerify(metadata.signed_metadata, publicKey); - return { metadata: payload as OpenidCredentialIssuerMetadata }; - } + // Fetches authorization server metadata with fallback + const getAuthorizationServerMetadata = useCallback( + async (credentialIssuerIdentifier: string): Promise<{ authzServeMetadata: OpenidAuthorizationServerMetadata } | null> => { + const pathAuthorizationServer = `${credentialIssuerIdentifier}/.well-known/oauth-authorization-server`; + const pathConfiguration = `${credentialIssuerIdentifier}/.well-known/openid-configuration`; + console.log('getAuthorizationServerMetadata'); + try { + const authzServeMetadata = await fetchAndCache( + pathAuthorizationServer, + OpenidAuthorizationServerMetadataSchema, + isOnline, + shouldUseCache + ); + return { authzServeMetadata }; + } catch { + // Fallback to openid-configuration if oauth-authorization-server fetch fails + const authzServeMetadata = await fetchAndCache( + pathConfiguration, + OpenidAuthorizationServerMetadataSchema, + isOnline, + shouldUseCache + ).catch(() => null); + + if (!authzServeMetadata) { return null; } - catch (err) { - return null; + return { authzServeMetadata }; + } + }, + [fetchAndCache, isOnline, shouldUseCache] + ); + + const getCredentialIssuerMetadata = useCallback( + async (credentialIssuerIdentifier: string): Promise<{ metadata: OpenidCredentialIssuerMetadata } | null> => { + const pathCredentialIssuer = `${credentialIssuerIdentifier}/.well-known/openid-credential-issuer`; + console.log('getCredentialIssuerMetadata'); + try { + const metadata = await fetchAndCache( + pathCredentialIssuer, + OpenidCredentialIssuerMetadataSchema, + isOnline, + shouldUseCache + ); + if (metadata.signed_metadata) { + try { + const parsedHeader = JSON.parse(new TextDecoder().decode(base64url.decode(metadata.signed_metadata.split('.')[0]))); + if (parsedHeader.x5c) { + const publicKey = await importX509(getPublicKeyFromB64Cert(parsedHeader.x5c[0]), parsedHeader.alg); + const { payload } = await jwtVerify(metadata.signed_metadata, publicKey); + return { metadata: payload as OpenidCredentialIssuerMetadata }; + } + return null; + } + catch (err) { + return null; + } } + return { metadata }; } - return { metadata }; - } - catch (err) { - console.error(err); - return null; - } - } - - return { - getClientId: useCallback(getClientId, [api]), - getAuthorizationServerMetadata: useCallback(getAuthorizationServerMetadata, [api, shouldUseCache]), - getCredentialIssuerMetadata: useCallback(getCredentialIssuerMetadata, [api, shouldUseCache]) - } - + catch (err) { + console.error(err); + return null; + } + }, + [fetchAndCache, isOnline, shouldUseCache] + ); + + return useMemo( + () => ({ + getClientId, + getAuthorizationServerMetadata, + getCredentialIssuerMetadata, + }), + [ + getClientId, + getAuthorizationServerMetadata, + getCredentialIssuerMetadata + ] + ); } diff --git a/src/lib/services/OpenID4VP/OpenID4VP.tsx b/src/lib/services/OpenID4VP/OpenID4VP.tsx index 11d86993d..c7659e5f6 100644 --- a/src/lib/services/OpenID4VP/OpenID4VP.tsx +++ b/src/lib/services/OpenID4VP/OpenID4VP.tsx @@ -12,39 +12,49 @@ import { BACKEND_URL, OPENID4VP_SAN_DNS_CHECK_SSL_CERTS, OPENID4VP_SAN_DNS_CHECK import { useCredentialBatchHelper } from "../CredentialBatchHelper"; import { toBase64 } from "../../../util"; import { useHttpProxy } from "../HttpProxy/HttpProxy"; -import { useContext } from "react"; +import { useCallback, useContext, useMemo } from "react"; import SessionContext from "../../../context/SessionContext"; import CredentialParserContext from "../../../context/CredentialParserContext"; export function useOpenID4VP({ showCredentialSelectionPopup }: { showCredentialSelectionPopup: (conformantCredentialsMap: any, verifierDomainName: string) => Promise> }): IOpenID4VP { + console.log('useOpenID4VP'); const openID4VPRelyingPartyStateRepository = useOpenID4VPRelyingPartyStateRepository(); const httpProxy = useHttpProxy(); const { credentialParserRegistry } = useContext(CredentialParserContext); const credentialBatchHelper = useCredentialBatchHelper(); const { keystore, api } = useContext(SessionContext); - async function storeVerifiablePresentation(presentation: string, presentationSubmission: any, identifiersOfIncludedCredentials: string[], audience: string) { - await api.post('/storage/vp', { - presentationIdentifier: generateRandomIdentifier(32), - presentation, - presentationSubmission, - includedVerifiableCredentialIdentifiers: identifiersOfIncludedCredentials, - audience, - issuanceDate: new Date().toISOString(), - }); - } - - async function getAllStoredVerifiableCredentials() { - const fetchAllCredentials = await api.get('/storage/vc'); + const storeVerifiablePresentation = useCallback( + async (presentation: string, presentationSubmission: any, identifiersOfIncludedCredentials: string[], audience: string) => { + await api.post('/storage/vp', { + presentationIdentifier: generateRandomIdentifier(32), + presentation, + presentationSubmission, + includedVerifiableCredentialIdentifiers: identifiersOfIncludedCredentials, + audience, + issuanceDate: new Date().toISOString(), + }); + }, + [api] + ); + + const getAllStoredVerifiableCredentials = useCallback(async () => { + const fetchAllCredentials = await api.get("/storage/vc"); return { verifiableCredentials: fetchAllCredentials.data.vc_list }; - } + }, + [api] + ); - return { - async promptForCredentialSelection(conformantCredentialsMap: any, verifierDomainName: string): Promise> { + const promptForCredentialSelection = useCallback( + async (conformantCredentialsMap: any, verifierDomainName: string): Promise> => { return showCredentialSelectionPopup(conformantCredentialsMap, verifierDomainName); }, - async handleAuthorizationRequest(url: string): Promise<{ conformantCredentialsMap: Map, verifierDomainName: string; } | { err: HandleAuthorizationRequestError }> { + [showCredentialSelectionPopup] + ); + + const handleAuthorizationRequest = useCallback( + async (url: string): Promise<{ conformantCredentialsMap: Map; verifierDomainName: string } | { err: HandleAuthorizationRequestError }> => { const authorizationRequest = new URL(url); let client_id = authorizationRequest.searchParams.get('client_id'); let response_uri = authorizationRequest.searchParams.get('response_uri'); @@ -196,9 +206,11 @@ export function useOpenID4VP({ showCredentialSelectionPopup }: { showCredentialS return { conformantCredentialsMap: mapping, verifierDomainName: verifierDomainName }; }, + [httpProxy, credentialParserRegistry, getAllStoredVerifiableCredentials, openID4VPRelyingPartyStateRepository] + ); - - async sendAuthorizationResponse(selectionMap: Map): Promise<{ url?: string } | { presentation_during_issuance_session: string }> { + const sendAuthorizationResponse = useCallback( + async (selectionMap: Map): Promise<{ url?: string } | { presentation_during_issuance_session: string }> => { const S = await openID4VPRelyingPartyStateRepository.retrieve(); console.log("send AuthorizationResponse: S = ", S) console.log("send AuthorizationResponse: Sess = ", sessionStorage.getItem('last_used_nonce')); @@ -388,7 +400,19 @@ export function useOpenID4VP({ showCredentialSelectionPopup }: { showCredentialS if (res.data.redirect_uri) { return { url: res.data.redirect_uri }; } + }, + [httpProxy, keystore, openID4VPRelyingPartyStateRepository, credentialBatchHelper, getAllStoredVerifiableCredentials, storeVerifiablePresentation] + ); + + return useMemo(() => { + return { + promptForCredentialSelection, + handleAuthorizationRequest, + sendAuthorizationResponse, } - - } + }, [ + promptForCredentialSelection, + handleAuthorizationRequest, + sendAuthorizationResponse, + ]); } diff --git a/src/lib/services/OpenID4VPRelyingPartyStateRepository.tsx b/src/lib/services/OpenID4VPRelyingPartyStateRepository.tsx index 79de1d644..0b84428c9 100644 --- a/src/lib/services/OpenID4VPRelyingPartyStateRepository.tsx +++ b/src/lib/services/OpenID4VPRelyingPartyStateRepository.tsx @@ -1,19 +1,30 @@ +import { useCallback, useMemo } from "react"; import { IOpenID4VPRelyingPartyStateRepository } from "../interfaces/IOpenID4VPRelyingPartyStateRepository"; import { OpenID4VPRelyingPartyState } from "../types/OpenID4VPRelyingPartyState"; - export function useOpenID4VPRelyingPartyStateRepository(): IOpenID4VPRelyingPartyStateRepository { - const key = "openid4vp_rp_state"; - return { - async store(s: OpenID4VPRelyingPartyState): Promise { - const x = s.serialize(); - localStorage.setItem(key, x); - }, + const store = useCallback(async (s: OpenID4VPRelyingPartyState): Promise => { + const x = s.serialize(); + localStorage.setItem(key, x); + }, [key]); + + const retrieve = useCallback(async (): Promise => { + const serializedState = localStorage.getItem(key); + if (!serializedState) { + throw new Error("No state found in localStorage"); + } + return OpenID4VPRelyingPartyState.deserialize(serializedState); + }, [key]); - async retrieve(): Promise { - return OpenID4VPRelyingPartyState.deserialize(localStorage.getItem(key)) + return useMemo(() => { + return { + store, + retrieve } - } + }, [ + store, + retrieve + ]); } diff --git a/src/pages/AddCredentials/AddCredentials.js b/src/pages/AddCredentials/AddCredentials.js index 4e1f43edf..4b08a156a 100644 --- a/src/pages/AddCredentials/AddCredentials.js +++ b/src/pages/AddCredentials/AddCredentials.js @@ -25,6 +25,7 @@ const Issuers = () => { const { t } = useTranslation(); useEffect(() => { + console.log("Starting to fetch issuers",openID4VCIHelper); const fetchIssuers = async () => { try { const response = await api.getExternalEntity('/issuer/all', undefined, true); @@ -56,7 +57,7 @@ const Issuers = () => { console.log("Fetching issuers...") fetchIssuers(); } - }, [api, isOnline]); + }, [api, isOnline, openID4VCIHelper]); const handleIssuerClick = async (credentialIssuerIdentifier) => { const clickedIssuer = issuers.find((issuer) => issuer.credentialIssuerIdentifier === credentialIssuerIdentifier); From b668ff4d4998b191b3dd7b3237b8ab138b3243ac Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 13 Jan 2025 13:02:38 +0200 Subject: [PATCH 096/162] formatting fix --- src/lib/services/OpenID4VCI/TokenRequest.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/services/OpenID4VCI/TokenRequest.tsx b/src/lib/services/OpenID4VCI/TokenRequest.tsx index bede8cbf7..adbb649d0 100644 --- a/src/lib/services/OpenID4VCI/TokenRequest.tsx +++ b/src/lib/services/OpenID4VCI/TokenRequest.tsx @@ -160,4 +160,4 @@ export function useTokenRequest() { execute, } -} \ No newline at end of file +} From 3212fa03d9bfec3f450af1a3696629d7c64478a8 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 13 Jan 2025 13:03:37 +0200 Subject: [PATCH 097/162] formatting fix --- src/lib/services/OpenID4VCI/TokenRequest.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/services/OpenID4VCI/TokenRequest.tsx b/src/lib/services/OpenID4VCI/TokenRequest.tsx index adbb649d0..1de14b456 100644 --- a/src/lib/services/OpenID4VCI/TokenRequest.tsx +++ b/src/lib/services/OpenID4VCI/TokenRequest.tsx @@ -8,7 +8,7 @@ export type AccessToken = { expires_in: number; c_nonce_expires_in: number; refresh_token?: string; - + httpResponseHeaders: { "dpop-nonce"?: string } From 6766a608f30cf020bf294f79554beb6ab35efe22 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 13 Jan 2025 13:19:42 +0200 Subject: [PATCH 098/162] Fix: update equality operator to '===' in AddCredentials.js --- src/pages/AddCredentials/AddCredentials.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/AddCredentials/AddCredentials.js b/src/pages/AddCredentials/AddCredentials.js index e59913cec..b4de8bea8 100644 --- a/src/pages/AddCredentials/AddCredentials.js +++ b/src/pages/AddCredentials/AddCredentials.js @@ -41,7 +41,7 @@ const Issuers = () => { if (issuerObject.visible) { setIssuers((currentArray) => { - if (currentArray.filter((iss) => iss.credentialIssuerMetadata.credential_issuer == issuerObject.credentialIssuerMetadata.credential_issuer).length == 0) { + if (currentArray.filter((iss) => iss.credentialIssuerMetadata.credential_issuer === issuerObject.credentialIssuerMetadata.credential_issuer).length === 0) { return [...currentArray, issuerObject]; } return [...currentArray]; From ec6a6f6308455a36bbbf789d10adeeb944ef33d6 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 13 Jan 2025 23:37:33 +0200 Subject: [PATCH 099/162] Extract VC entity fetching logic into reusable hook --- .../Credentials/CredentialLayout.js | 24 +++------- src/context/CredentialsContext.js | 17 ++++--- src/hooks/useVcEntity.js | 44 +++++++++++++++++++ src/pages/Home/Credential.js | 21 +++------ src/pages/Home/CredentialDetails.js | 25 +++-------- 5 files changed, 76 insertions(+), 55 deletions(-) create mode 100644 src/hooks/useVcEntity.js diff --git a/src/components/Credentials/CredentialLayout.js b/src/components/Credentials/CredentialLayout.js index 84762ed36..16ea6d4bb 100644 --- a/src/components/Credentials/CredentialLayout.js +++ b/src/components/Credentials/CredentialLayout.js @@ -7,9 +7,10 @@ import { PiCardsBold } from "react-icons/pi"; // Hooks import useScreenType from '../../hooks/useScreenType'; +import { useVcEntity } from '../../hooks/useVcEntity'; // Contexts -import SessionContext from '../../context/SessionContext'; +import CredentialsContext from '../../context/CredentialsContext'; //Functions import { CheckExpired } from '../../functions/CheckExpired'; @@ -23,9 +24,7 @@ import CredentialParserContext from '../../context/CredentialParserContext'; const CredentialLayout = ({ children, title = null }) => { const { credentialId } = useParams(); - const { api } = useContext(SessionContext); const screenType = useScreenType(); - const [vcEntity, setVcEntity] = useState(null); const [showFullscreenImgPopup, setShowFullscreenImgPopup] = useState(false); const [credentialFiendlyName, setCredentialFriendlyName] = useState(null); const { t } = useTranslation(); @@ -35,24 +34,15 @@ const CredentialLayout = ({ children, title = null }) => { const [sigTotal, setSigTotal] = useState(null); const { credentialParserRegistry } = useContext(CredentialParserContext); + const { vcEntityList, vcEntityListInstances, fetchVcData } = useContext(CredentialsContext); + const { vcEntity, vcEntityInstances } = useVcEntity(fetchVcData, vcEntityList, vcEntityListInstances, credentialId); useEffect(() => { - const getData = async () => { - const response = await api.get('/storage/vc'); - const vcEntity = response.data.vc_list - .filter((vcEntity) => vcEntity.credentialIdentifier === credentialId)[0]; - const vcEntityInstances = response.data.vc_list - .filter((vcEntity) => vcEntity.credentialIdentifier === credentialId); + if (vcEntity && vcEntityInstances) { setZeroSigCount(vcEntityInstances.filter(instance => instance.sigCount === 0).length || 0); setSigTotal(vcEntityInstances.length); - if (!vcEntity) { - throw new Error("Credential not found"); - } - setVcEntity(vcEntity); - }; - - getData(); - }, [api, credentialId]); + } + }, [vcEntity, vcEntityInstances]); useEffect(() => { if (!vcEntity) { diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js index 05243f7f7..0ca24028f 100644 --- a/src/context/CredentialsContext.js +++ b/src/context/CredentialsContext.js @@ -12,16 +12,23 @@ export const CredentialsProvider = ({ children }) => { const [latestCredentials, setLatestCredentials] = useState(new Set()); const [currentSlide, setCurrentSlide] = useState(1); - const fetchVcData = useCallback(async () => { + const fetchVcData = useCallback(async (credentialId = null) => { const response = await api.get('/storage/vc'); const fetchedVcList = response.data.vc_list; - const vcEntityList = (await Promise.all(fetchedVcList.map(async (vcEntity) => { - return { ...vcEntity }; - }))).filter((vcEntity) => vcEntity.instanceId === 0); // show only the first instance + const vcEntityList = ( + await Promise.all( + fetchedVcList.map(async (vcEntity) => { + return { ...vcEntity }; + }) + ) + ).filter((vcEntity) => + credentialId ? vcEntity.credentialIdentifier === credentialId : vcEntity.instanceId === 0 + ); // show only the first instance vcEntityList.sort(reverse(compareBy(vc => vc.id))); + console.log('--->',vcEntityList, fetchedVcList) return { vcEntityList, fetchedVcList }; }, [api]); @@ -108,7 +115,7 @@ export const CredentialsProvider = ({ children }) => { }, [getData]); return ( - + {children} ); diff --git a/src/hooks/useVcEntity.js b/src/hooks/useVcEntity.js new file mode 100644 index 000000000..d3ac956a0 --- /dev/null +++ b/src/hooks/useVcEntity.js @@ -0,0 +1,44 @@ +import { useState, useEffect, useCallback } from 'react'; + +export const useVcEntity = (fetchVcData, vcEntityList, vcEntityListInstances = null, credentialId) => { + const [vcEntity, setVcEntity] = useState(null); + const [vcEntityInstances, setVcEntityInstances] = useState(null); + + const fetchAndSetVcEntity = useCallback(async () => { + try { + if (vcEntityList && vcEntityListInstances) { + const vcEntity = vcEntityList.find( + (vcEntity) => vcEntity.credentialIdentifier === credentialId + ); + if (!vcEntity) { + throw new Error("Credential not found"); + } + const vcEntityInstances = vcEntityListInstances.filter( + (vc) => vc.credentialIdentifier === credentialId + ); + + if (!vcEntityInstances) { + throw new Error("Credential not found"); + } + + setVcEntity(vcEntity); + setVcEntityInstances(vcEntityInstances); + } else { + const { vcEntityList, fetchedVcList } = await fetchVcData(credentialId); + setVcEntity(vcEntityList[0]); + setVcEntityInstances(fetchedVcList); + + } + } catch (err) { + console.error('Error fetching VC entity:', err); + setVcEntity(null); // Clear the state on error + setVcEntityInstances(null) + } + }, [fetchVcData, vcEntityList, vcEntityListInstances, credentialId]); + + useEffect(() => { + fetchAndSetVcEntity(); + }, [fetchAndSetVcEntity]); + + return { vcEntity, vcEntityInstances }; +}; diff --git a/src/pages/Home/Credential.js b/src/pages/Home/Credential.js index 3ec7bb69b..440876ab8 100644 --- a/src/pages/Home/Credential.js +++ b/src/pages/Home/Credential.js @@ -5,10 +5,12 @@ import { useTranslation, Trans } from 'react-i18next'; // Contexts import SessionContext from '../../context/SessionContext'; +import CredentialsContext from '../../context/CredentialsContext'; // Hooks import useFetchPresentations from '../../hooks/useFetchPresentations'; import useScreenType from '../../hooks/useScreenType'; +import { useVcEntity } from '../../hooks/useVcEntity'; // Components import CredentialTabs from '../../components/Credentials/CredentialTabs'; @@ -25,8 +27,6 @@ const Credential = () => { const { credentialId } = useParams(); const { api } = useContext(SessionContext); const history = useFetchPresentations(api, credentialId, null); - - const [vcEntity, setVcEntity] = useState(null); const [showDeletePopup, setShowDeletePopup] = useState(false); const [loading, setLoading] = useState(false); const [credentialFiendlyName, setCredentialFriendlyName] = useState(null); @@ -36,21 +36,12 @@ const Credential = () => { const { t } = useTranslation(); const { credentialParserRegistry } = useContext(CredentialParserContext); + const { vcEntityList, vcEntityListInstances, fetchVcData } = useContext(CredentialsContext); - useEffect(() => { - const getData = async () => { - const response = await api.get('/storage/vc'); - const vcEntity = response.data.vc_list - .filter((vcEntity) => vcEntity.credentialIdentifier === credentialId)[0]; - if (!vcEntity) { - throw new Error("Credential not found"); - } - setVcEntity(vcEntity); - }; - - getData(); - }, [api, credentialId]); + const {vcEntity, vcEntityInstances} = useVcEntity(fetchVcData, vcEntityList, vcEntityListInstances, credentialId); + console.log('-> vcEntity',vcEntity) + console.log('-> vcEntityInstances',vcEntityInstances) useEffect(() => { if (!vcEntity) { return; diff --git a/src/pages/Home/CredentialDetails.js b/src/pages/Home/CredentialDetails.js index cad9be788..84e9be9e5 100644 --- a/src/pages/Home/CredentialDetails.js +++ b/src/pages/Home/CredentialDetails.js @@ -1,10 +1,13 @@ // External libraries -import React, { useContext, useState, useEffect } from 'react'; +import React, { useContext } from 'react'; import { useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; +// Hooks +import { useVcEntity } from '../../hooks/useVcEntity'; + // Contexts -import SessionContext from '../../context/SessionContext'; +import CredentialsContext from '../../context/CredentialsContext'; // Components import CredentialLayout from '../../components/Credentials/CredentialLayout'; @@ -12,24 +15,10 @@ import CredentialJson from '../../components/Credentials/CredentialJson'; const CredentialDetails = () => { const { credentialId } = useParams(); - const { api } = useContext(SessionContext); - const [vcEntity, setVcEntity] = useState(null); const { t } = useTranslation(); - useEffect(() => { - const getData = async () => { - const response = await api.get('/storage/vc'); - const vcEntity = response.data.vc_list - .filter((vcEntity) => vcEntity.credentialIdentifier === credentialId)[0]; - if (!vcEntity) { - throw new Error("Credential not found"); - } - console.log('details', vcEntity) - setVcEntity(vcEntity); - }; - - getData(); - }, [api, credentialId]); + const { vcEntityList, fetchVcData } = useContext(CredentialsContext); + const { vcEntity } = useVcEntity(fetchVcData, vcEntityList, credentialId); return ( <> From 8d58aab626cb1b85200ddc6dc306ed0d52759187 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Tue, 14 Jan 2025 10:42:35 +0200 Subject: [PATCH 100/162] simplifications --- README.md | 1 + src/UriHandler.tsx | 8 ++++---- src/context/OpenID4VCIContext.tsx | 4 ++-- src/context/OpenID4VPContext.tsx | 4 ++-- src/lib/services/OpenID4VCI/OpenID4VCI.tsx | 11 +---------- ...horizationRequestForFirstPartyApplications.tsx | 4 ++-- src/lib/services/OpenID4VP/OpenID4VP.tsx | 15 ++------------- src/pages/AddCredentials/AddCredentials.js | 4 ++-- 8 files changed, 16 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 655a6d040..f978908a0 100644 --- a/README.md +++ b/README.md @@ -341,3 +341,4 @@ We welcome contributions from the community to help improve the wwWallet Fronten 6. **Review and Merge:** Your pull request will be reviewed by the maintainers. Make any requested changes and address feedback. Once approved, your changes will be merged into master branch of the project. + diff --git a/src/UriHandler.tsx b/src/UriHandler.tsx index d96400772..170dbcfb1 100644 --- a/src/UriHandler.tsx +++ b/src/UriHandler.tsx @@ -2,12 +2,12 @@ import React, { useEffect, createContext, useState, useContext } from "react"; import { useLocation } from "react-router-dom"; import { checkForUpdates } from './offlineRegistrationSW'; import StatusContext from "./context/StatusContext"; -import { useOpenID4VCI } from "./lib/services/OpenID4VCI/OpenID4VCI"; import SessionContext from "./context/SessionContext"; import { BackgroundTasksContext } from "./context/BackgroundTasksContext"; import { useTranslation } from "react-i18next"; import { HandleAuthorizationRequestError } from "./lib/interfaces/IOpenID4VP"; -import { useOpenID4VP } from "./lib/services/OpenID4VP/OpenID4VP"; +import OpenID4VCIContext from "./context/OpenID4VCIContext"; +import OpenID4VPContext from "./context/OpenID4VPContext"; const MessagePopup = React.lazy(() => import('./components/Popups/MessagePopup')); const PinInputPopup = React.lazy(() => import('./components/Popups/PinInput')); @@ -21,8 +21,8 @@ export const UriHandler = ({ children }) => { const location = useLocation(); const [url, setUrl] = useState(window.location.href); - const openID4VCI = useOpenID4VCI(); - const openID4VP = useOpenID4VP(); + const { openID4VCI } = useContext(OpenID4VCIContext); + const { openID4VP } = useContext(OpenID4VPContext); const [showPinInputPopup, setShowPinInputPopup] = useState(false); diff --git a/src/context/OpenID4VCIContext.tsx b/src/context/OpenID4VCIContext.tsx index cfe6ff2e7..ffd0aff1f 100644 --- a/src/context/OpenID4VCIContext.tsx +++ b/src/context/OpenID4VCIContext.tsx @@ -1,6 +1,6 @@ import React, { createContext } from "react"; import { IOpenID4VCI } from "../lib/interfaces/IOpenID4VCI"; -import { OpenID4VCI } from "../lib/services/OpenID4VCI/OpenID4VCI"; +import { useOpenID4VCI } from "../lib/services/OpenID4VCI/OpenID4VCI"; export type OpenID4VPContextValue = { @@ -17,7 +17,7 @@ export const OpenID4VCIContextProvider = ({ children }) => { throw new Error("Not implemented"); } - const openID4VCI = OpenID4VCI({ errorCallback }); + const openID4VCI = useOpenID4VCI({ errorCallback }); return ( {children} diff --git a/src/context/OpenID4VPContext.tsx b/src/context/OpenID4VPContext.tsx index 6e6c791a3..0518ba6d1 100644 --- a/src/context/OpenID4VPContext.tsx +++ b/src/context/OpenID4VPContext.tsx @@ -1,7 +1,7 @@ import React, { useState, useContext, createContext } from "react"; import SelectCredentialsPopup from "../components/Popups/SelectCredentialsPopup"; import CredentialsContext from '../context/CredentialsContext'; -import { OpenID4VP } from "../lib/services/OpenID4VP/OpenID4VP"; +import { useOpenID4VP } from "../lib/services/OpenID4VP/OpenID4VP"; import { IOpenID4VP } from "../lib/interfaces/IOpenID4VP"; export type OpenID4VPContextValue = { @@ -45,7 +45,7 @@ export const OpenID4VPContextProvider = ({ children }) => { return showPopup({ conformantCredentialsMap, verifierDomainName }); } - const openID4VP = OpenID4VP({ showCredentialSelectionPopup }); + const openID4VP = useOpenID4VP({ showCredentialSelectionPopup }); return ( diff --git a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx index f47c8ca70..8a20cf79b 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx @@ -16,20 +16,11 @@ import { useOpenID4VCIPushedAuthorizationRequest } from './OpenID4VCIAuthorizati import { useOpenID4VCIAuthorizationRequestForFirstPartyApplications } from './OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications'; import { useOpenID4VCIHelper } from '../OpenID4VCIHelper'; import { GrantType, TokenRequestError, useTokenRequest } from './TokenRequest'; -import OpenID4VCIContext from '../../../context/OpenID4VCIContext'; const redirectUri = config.OPENID4VCI_REDIRECT_URI as string; -export function useOpenID4VCI() { - const openID4VCI = useContext(OpenID4VCIContext); - if (!openID4VCI.openID4VCI) { - throw new Error("OpenID4VCIContext is not defined in the context"); - } - return openID4VCI.openID4VCI; -} - -export function OpenID4VCI({ errorCallback }: { errorCallback: (title: string, message: string) => void }): IOpenID4VCI { +export function useOpenID4VCI({ errorCallback }: { errorCallback: (title: string, message: string) => void }): IOpenID4VCI { const httpProxy = useHttpProxy(); const openID4VCIClientStateRepository = useOpenID4VCIClientStateRepository(); diff --git a/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx b/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx index d6383f258..ca26017b3 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications.tsx @@ -8,13 +8,13 @@ import { useOpenID4VCIClientStateRepository } from "../../OpenID4VCIClientStateR import { useHttpProxy } from "../../HttpProxy/HttpProxy"; import { useContext } from "react"; import SessionContext from "../../../../context/SessionContext"; -import { useOpenID4VP } from "../../OpenID4VP/OpenID4VP"; +import OpenID4VPContext from "../../../../context/OpenID4VPContext"; export function useOpenID4VCIAuthorizationRequestForFirstPartyApplications(): IOpenID4VCIAuthorizationRequest { const httpProxy = useHttpProxy(); const openID4VCIClientStateRepository = useOpenID4VCIClientStateRepository(); - const openID4VP = useOpenID4VP(); + const { openID4VP } = useContext(OpenID4VPContext); const { keystore } = useContext(SessionContext); diff --git a/src/lib/services/OpenID4VP/OpenID4VP.tsx b/src/lib/services/OpenID4VP/OpenID4VP.tsx index 4de010fe5..7a5649c17 100644 --- a/src/lib/services/OpenID4VP/OpenID4VP.tsx +++ b/src/lib/services/OpenID4VP/OpenID4VP.tsx @@ -12,22 +12,11 @@ import { BACKEND_URL, OPENID4VP_SAN_DNS_CHECK_SSL_CERTS, OPENID4VP_SAN_DNS_CHECK import { useCredentialBatchHelper } from "../CredentialBatchHelper"; import { toBase64 } from "../../../util"; import { useHttpProxy } from "../HttpProxy/HttpProxy"; -import { useContext, useEffect } from "react"; +import { useContext } from "react"; import SessionContext from "../../../context/SessionContext"; import CredentialParserContext from "../../../context/CredentialParserContext"; -import OpenID4VPContext from "../../../context/OpenID4VPContext"; - -export function useOpenID4VP() { - const openID4VP = useContext(OpenID4VPContext); - if (!openID4VP.openID4VP) { - throw new Error("OpenID4VPContext is not defined in the context"); - } - return openID4VP.openID4VP; -} - - -export function OpenID4VP({ showCredentialSelectionPopup }: { showCredentialSelectionPopup: (conformantCredentialsMap: any, verifierDomainName: string) => Promise> }): IOpenID4VP { +export function useOpenID4VP({ showCredentialSelectionPopup }: { showCredentialSelectionPopup: (conformantCredentialsMap: any, verifierDomainName: string) => Promise> }): IOpenID4VP { const openID4VPRelyingPartyStateRepository = useOpenID4VPRelyingPartyStateRepository(); const httpProxy = useHttpProxy(); diff --git a/src/pages/AddCredentials/AddCredentials.js b/src/pages/AddCredentials/AddCredentials.js index e862ca579..0692e67fd 100644 --- a/src/pages/AddCredentials/AddCredentials.js +++ b/src/pages/AddCredentials/AddCredentials.js @@ -8,7 +8,7 @@ import { H1 } from '../../components/Shared/Heading'; import PageDescription from '../../components/Shared/PageDescription'; import QueryableList from '../../components/QueryableList'; import { useOpenID4VCIHelper } from '../../lib/services/OpenID4VCIHelper'; -import { useOpenID4VCI } from '../../lib/services/OpenID4VCI/OpenID4VCI'; +import OpenID4VCIContext from '../../context/OpenID4VCIContext'; const Issuers = () => { const { isOnline } = useContext(StatusContext); @@ -20,7 +20,7 @@ const Issuers = () => { const [availableCredentialConfigurations, setAvailableCredentialConfigurations] = useState(null); const openID4VCIHelper = useOpenID4VCIHelper(); - const openID4VCI = useOpenID4VCI(); + const { openID4VCI } = useContext(OpenID4VCIContext); const { t } = useTranslation(); From 4f2ef4d27d6c5946c014613ce34705b333d4afe6 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Tue, 14 Jan 2025 11:40:30 +0200 Subject: [PATCH 101/162] fallback client id --- src/lib/services/OpenID4VCI/OpenID4VCI.tsx | 11 ++++++----- src/lib/services/OpenID4VCIHelper.tsx | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx index 8a20cf79b..7386adfdf 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx @@ -10,7 +10,7 @@ import * as config from '../../../config'; import { VerifiableCredentialFormat } from '../../schemas/vc'; import { useHttpProxy } from '../HttpProxy/HttpProxy'; import { useOpenID4VCIClientStateRepository } from '../OpenID4VCIClientStateRepository'; -import { useContext } from 'react'; +import { useContext, useState } from 'react'; import SessionContext from '../../../context/SessionContext'; import { useOpenID4VCIPushedAuthorizationRequest } from './OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest'; import { useOpenID4VCIAuthorizationRequestForFirstPartyApplications } from './OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications'; @@ -115,7 +115,7 @@ export function useOpenID4VCI({ errorCallback }: { errorCallback: (title: string for (let i = 0; i < numberOfProofs; i++) { inputs.push({ nonce: c_nonce, - issuer: clientId.client_id, + issuer: clientId ? clientId.client_id : null, audience: credentialIssuerMetadata.metadata.credential_issuer }) } @@ -330,7 +330,8 @@ export function useOpenID4VCI({ errorCallback }: { errorCallback: (title: string } } - tokenRequestBuilder.setClientId(clientId.client_id); + + tokenRequestBuilder.setClientId(clientId ? clientId?.client_id : null); tokenRequestBuilder.setGrantType(requestCredentialsParams.authorizationCodeGrant ? GrantType.AUTHORIZATION_CODE : GrantType.REFRESH); tokenRequestBuilder.setAuthorizationCode(requestCredentialsParams?.authorizationCodeGrant?.code); tokenRequestBuilder.setCodeVerifier(flowState?.code_verifier); @@ -459,7 +460,7 @@ export function useOpenID4VCI({ errorCallback }: { errorCallback: (title: string authorizationServerMetadata: authzServerMetadata.authzServeMetadata, credentialIssuerMetadata: credentialIssuerMetadata.metadata, credentialIssuerIdentifier: credentialIssuerMetadata.metadata.credential_issuer, - clientId: clientId.client_id, + clientId: clientId ? clientId.client_id : null, redirectUri: redirectUri } ); @@ -475,7 +476,7 @@ export function useOpenID4VCI({ errorCallback }: { errorCallback: (title: string authorizationServerMetadata: authzServerMetadata.authzServeMetadata, credentialIssuerMetadata: credentialIssuerMetadata.metadata, credentialIssuerIdentifier: credentialIssuerMetadata.metadata.credential_issuer, - clientId: clientId.client_id, + clientId: clientId ? clientId.client_id : null, redirectUri: redirectUri } ).then((result) => { diff --git a/src/lib/services/OpenID4VCIHelper.tsx b/src/lib/services/OpenID4VCIHelper.tsx index d5c5f536d..ce9c1d67d 100644 --- a/src/lib/services/OpenID4VCIHelper.tsx +++ b/src/lib/services/OpenID4VCIHelper.tsx @@ -54,12 +54,12 @@ export function useOpenID4VCIHelper(): IOpenID4VCIHelper { if (issuer) { return { client_id: issuer.clientId }; } - return null; + return { client_id: "CLIENT123" }; } catch (err) { console.log("Could not get client_id for issuer " + credentialIssuerIdentifier + " Details:"); console.error(err); - return null; + return { client_id: "CLIENT123" }; } } From e5ff744a91141122ee9f5000488b833c13330bc8 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Tue, 14 Jan 2025 11:44:45 +0200 Subject: [PATCH 102/162] zod schema re-alignment --- src/lib/schemas/CredentialConfigurationSupportedSchema.ts | 4 ++-- src/lib/schemas/OpenidAuthorizationServerMetadataSchema.ts | 4 ++-- src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib/schemas/CredentialConfigurationSupportedSchema.ts b/src/lib/schemas/CredentialConfigurationSupportedSchema.ts index 3d82118e5..9f798e9eb 100644 --- a/src/lib/schemas/CredentialConfigurationSupportedSchema.ts +++ b/src/lib/schemas/CredentialConfigurationSupportedSchema.ts @@ -24,8 +24,8 @@ const commonSchema = z.object({ }).optional(), })).optional(), scope: z.string(), - cryptographic_binding_methods_supported: z.array(z.string().nonempty()), - credential_signing_alg_values_supported: z.array(z.string().nonempty()), + cryptographic_binding_methods_supported: z.array(z.string()), + credential_signing_alg_values_supported: z.array(z.string()), proof_types_supported: proofTypesSupportedSchema, }); diff --git a/src/lib/schemas/OpenidAuthorizationServerMetadataSchema.ts b/src/lib/schemas/OpenidAuthorizationServerMetadataSchema.ts index 2593ff412..700ae202f 100644 --- a/src/lib/schemas/OpenidAuthorizationServerMetadataSchema.ts +++ b/src/lib/schemas/OpenidAuthorizationServerMetadataSchema.ts @@ -7,9 +7,9 @@ export const OpenidAuthorizationServerMetadataSchema = z.object({ pushed_authorization_request_endpoint: z.string(), authorization_challenge_endpoint: z.string().optional(), require_pushed_authorization_requests: z.boolean().optional(), - token_endpoint_auth_methods_supported: z.array(z.string()), + token_endpoint_auth_methods_supported: z.array(z.string()).optional(), response_types_supported: z.array(z.string()), - code_challenge_methods_supported: z.array(z.string()), + code_challenge_methods_supported: z.array(z.string()).optional(), dpop_signing_alg_values_supported: z.array(z.string()).optional(), }); diff --git a/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts b/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts index e415af049..aa0647494 100644 --- a/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts +++ b/src/lib/schemas/OpenidCredentialIssuerMetadataSchema.ts @@ -4,6 +4,7 @@ import { CredentialConfigurationSupportedSchema } from './CredentialConfiguratio export const OpenidCredentialIssuerMetadataSchema = z.object({ credential_issuer: z.string(), credential_endpoint: z.string(), + authorization_servers: z.array(z.string()).optional(), display: z.array(z.object({ name: z.string(), locale: z.string(), From 68920b67681005239e73e4cc5a8e43fb4c7a8d4a Mon Sep 17 00:00:00 2001 From: kkmanos Date: Tue, 14 Jan 2025 12:45:36 +0200 Subject: [PATCH 103/162] minor adaptations --- src/lib/services/OpenID4VCI/OpenID4VCI.tsx | 75 ++++++-------------- src/lib/services/OpenID4VCI/TokenRequest.tsx | 6 +- 2 files changed, 25 insertions(+), 56 deletions(-) diff --git a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx index 7e97932d2..b91fbada5 100644 --- a/src/lib/services/OpenID4VCI/OpenID4VCI.tsx +++ b/src/lib/services/OpenID4VCI/OpenID4VCI.tsx @@ -15,6 +15,7 @@ import SessionContext from '../../../context/SessionContext'; import { useOpenID4VCIPushedAuthorizationRequest } from './OpenID4VCIAuthorizationRequest/OpenID4VCIPushedAuthorizationRequest'; import { useOpenID4VCIAuthorizationRequestForFirstPartyApplications } from './OpenID4VCIAuthorizationRequest/OpenID4VCIAuthorizationRequestForFirstPartyApplications'; import { useOpenID4VCIHelper } from '../OpenID4VCIHelper'; +import { GrantType, TokenRequestError, useTokenRequest } from './TokenRequest'; const redirectUri = config.OPENID4VCI_REDIRECT_URI as string; @@ -30,6 +31,8 @@ export function useOpenID4VCI({ errorCallback }: { errorCallback: (title: string const openID4VCIPushedAuthorizationRequest = useOpenID4VCIPushedAuthorizationRequest(); const openID4VCIAuthorizationRequestForFirstPartyApplications = useOpenID4VCIAuthorizationRequestForFirstPartyApplications(); + const tokenRequestBuilder = useTokenRequest(); + const credentialRequest = useCallback( async (response: any, flowState: OpenID4VCIClientState, cachedProofs?: string[]) => { console.log('credentialRequest') @@ -275,74 +278,40 @@ export function useOpenID4VCI({ errorCallback }: { errorCallback: (title: string } const jti = generateRandomIdentifier(8); - let tokenRequestHeaders = { - 'Content-Type': 'application/x-www-form-urlencoded', - }; + tokenRequestBuilder.setTokenEndpoint(tokenEndpoint); if (authzServerMetadata.authzServeMetadata.dpop_signing_alg_values_supported) { - const dpop = await generateDPoP( - dpopPrivateKey as jose.KeyLike, - dpopPublicKeyJwk, - jti, - "POST", - tokenEndpoint, - requestCredentialsParams.dpopNonceHeader - ); + await tokenRequestBuilder.setDpopHeader(dpopPrivateKey as jose.KeyLike, dpopPublicKeyJwk, jti); flowState.dpop = { dpopAlg: 'ES256', dpopJti: jti, dpopPrivateKeyJwk: dpopPrivateKeyJwk, dpopPublicKeyJwk: dpopPublicKeyJwk, } - tokenRequestHeaders['DPoP'] = dpop; } - const formData = new URLSearchParams(); - formData.append('client_id', clientId.client_id); - if (requestCredentialsParams.authorizationCodeGrant) { - formData.append('grant_type', 'authorization_code'); - formData.append('code', requestCredentialsParams.authorizationCodeGrant.code); - formData.append('code_verifier', flowState.code_verifier); - } - else if (requestCredentialsParams.refreshTokenGrant) { - if (!flowState?.tokenResponse?.data.refresh_token) { - console.info("Found no refresh_token to execute refesh_token grant") - throw new Error("Found no refresh_token to execute refesh_token grant"); - } - formData.append('grant_type', 'refresh_token'); - formData.append('refresh_token', flowState.tokenResponse.data.refresh_token); - } - else { - throw new Error("No grant type selected in requestCredentials()"); - } - formData.append('redirect_uri', redirectUri); + tokenRequestBuilder.setClientId(clientId ? clientId?.client_id : null); + tokenRequestBuilder.setGrantType(requestCredentialsParams.authorizationCodeGrant ? GrantType.AUTHORIZATION_CODE : GrantType.REFRESH); + tokenRequestBuilder.setAuthorizationCode(requestCredentialsParams?.authorizationCodeGrant?.code); + tokenRequestBuilder.setCodeVerifier(flowState?.code_verifier); - const response = await httpProxy.post(tokenEndpoint, formData.toString(), tokenRequestHeaders); + tokenRequestBuilder.setRefreshToken(flowState?.tokenResponse?.data?.refresh_token); - if (response.err) { - const { err } = response; - console.log("failed token request") - console.log(JSON.stringify(err)); - console.log("Dpop nonce found = ", err.headers['dpop-nonce']) - if (err.headers['dpop-nonce']) { - requestCredentialsParams.dpopNonceHeader = err.headers['dpop-nonce']; - if (requestCredentialsParams.dpopNonceHeader) { - await requestCredentials(credentialIssuerIdentifier, requestCredentialsParams); - return; - } - } - else if (err.data.error) { - console.error("OID4VCI Token Response Error: ", JSON.stringify(err.data)) + tokenRequestBuilder.setRedirectUri(redirectUri); + + + const result = await tokenRequestBuilder.execute(); + + if ('error' in result) { + if (result.error == TokenRequestError.AUTHORIZATION_REQUIRED) { + return generateAuthorizationRequest(flowState.credentialIssuerIdentifier, flowState.credentialConfigurationId); } - return; + throw new Error("Token request failed"); } - console.log("== response = ", response) try { // try to extract the response and update the OpenID4VCIClientStateRepository - const { - data: { access_token, c_nonce, expires_in, c_nonce_expires_in, refresh_token }, - } = response; + const { access_token, c_nonce, expires_in, c_nonce_expires_in, refresh_token } = result.response; if (!access_token) { console.log("Missing access_token from response"); @@ -353,7 +322,7 @@ export function useOpenID4VCI({ errorCallback }: { errorCallback: (title: string data: { access_token, c_nonce, expiration_timestamp: Math.floor(Date.now() / 1000) + expires_in, c_nonce_expiration_timestamp: Math.floor(Date.now() / 1000) + c_nonce_expires_in, refresh_token }, - headers: { ...response.headers } + headers: { ...result.response.httpResponseHeaders } } await openID4VCIClientStateRepository.updateState(flowState); @@ -537,7 +506,7 @@ export function useOpenID4VCI({ errorCallback }: { errorCallback: (title: string return {} } }, - [openID4VCIClientStateRepository,openID4VCIHelper, handleAuthorizationResponse, openID4VCIAuthorizationRequestForFirstPartyApplications,openID4VCIPushedAuthorizationRequest, requestCredentials] + [openID4VCIClientStateRepository, openID4VCIHelper, handleAuthorizationResponse, openID4VCIAuthorizationRequestForFirstPartyApplications, openID4VCIPushedAuthorizationRequest, requestCredentials] ); return useMemo(() => { diff --git a/src/lib/services/OpenID4VCI/TokenRequest.tsx b/src/lib/services/OpenID4VCI/TokenRequest.tsx index 1de14b456..5341bdef2 100644 --- a/src/lib/services/OpenID4VCI/TokenRequest.tsx +++ b/src/lib/services/OpenID4VCI/TokenRequest.tsx @@ -91,14 +91,14 @@ export function useTokenRequest() { const formData = new URLSearchParams(); formData.append('client_id', client_id); - if (grant_type == GrantType.AUTHORIZATION_CODE) { + if (grant_type === GrantType.AUTHORIZATION_CODE) { console.log("Executing authorization code grant..."); formData.append('grant_type', 'authorization_code'); formData.append('code', code); formData.append('code_verifier', code_verifier); } - else if (grant_type == GrantType.REFRESH) { + else if (grant_type === GrantType.REFRESH) { console.log("Executing refresh token grant..."); if (!refresh_token) { console.info("Found no refresh_token to execute refesh_token grant") @@ -125,7 +125,7 @@ export function useTokenRequest() { return execute(); } } - else if (err.data.error == "authorization_required") { + else if (err.data.error === "authorization_required") { return { error: TokenRequestError.AUTHORIZATION_REQUIRED, response: err.data }; } else if (err.data.error) { From 9eb647b8ee1556bee6fcf70652e1bca73cbb4dc3 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Tue, 14 Jan 2025 13:11:06 +0200 Subject: [PATCH 104/162] Enhance credential filtering by grouping instances and adding 'instances' field --- .../Credentials/CredentialLayout.js | 12 ++-- .../Popups/SelectCredentialsPopup.js | 4 +- src/context/CredentialsContext.js | 63 ++++++++++++------- src/context/OpenID4VPContext.tsx | 4 +- src/hooks/useVcEntity.js | 21 ++----- src/pages/Home/Credential.js | 6 +- src/pages/Home/CredentialDetails.js | 2 +- src/pages/Home/Home.js | 42 ++++++++----- 8 files changed, 83 insertions(+), 71 deletions(-) diff --git a/src/components/Credentials/CredentialLayout.js b/src/components/Credentials/CredentialLayout.js index 16ea6d4bb..46bc5eed7 100644 --- a/src/components/Credentials/CredentialLayout.js +++ b/src/components/Credentials/CredentialLayout.js @@ -34,15 +34,15 @@ const CredentialLayout = ({ children, title = null }) => { const [sigTotal, setSigTotal] = useState(null); const { credentialParserRegistry } = useContext(CredentialParserContext); - const { vcEntityList, vcEntityListInstances, fetchVcData } = useContext(CredentialsContext); - const { vcEntity, vcEntityInstances } = useVcEntity(fetchVcData, vcEntityList, vcEntityListInstances, credentialId); + const { vcEntityList, fetchVcData } = useContext(CredentialsContext); + const vcEntity = useVcEntity(fetchVcData, vcEntityList, credentialId); useEffect(() => { - if (vcEntity && vcEntityInstances) { - setZeroSigCount(vcEntityInstances.filter(instance => instance.sigCount === 0).length || 0); - setSigTotal(vcEntityInstances.length); + if (vcEntity) { + setZeroSigCount(vcEntity.instances.filter(instance => instance.sigCount === 0).length || 0); + setSigTotal(vcEntity.instances.length); } - }, [vcEntity, vcEntityInstances]); + }, [vcEntity]); useEffect(() => { if (!vcEntity) { diff --git a/src/components/Popups/SelectCredentialsPopup.js b/src/components/Popups/SelectCredentialsPopup.js index a53f76cb7..7802c0afb 100644 --- a/src/components/Popups/SelectCredentialsPopup.js +++ b/src/components/Popups/SelectCredentialsPopup.js @@ -56,7 +56,7 @@ const StepBar = ({ totalSteps, currentStep, stepTitles }) => { ); }; -function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopup, vcEntityList, vcEntityListInstances }) { +function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopup, vcEntityList }) { const { api } = useContext(SessionContext); const credentialParserContext = useContext(CredentialParserContext); @@ -180,7 +180,7 @@ function SelectCredentialsPopup({ popupState, setPopupState, showPopup, hidePopu title={t('selectCredentialPopup.credentialSelectTitle', { friendlyName: vcEntity.friendlyName })} > vc.credentialIdentifier === vcEntity.credentialIdentifier)} + vcEntityInstances={vcEntity.instances} key={vcEntity.credentialIdentifier} credential={vcEntity.credential} className="w-full object-cover rounded-xl" diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js index 0ca24028f..d8f1782f6 100644 --- a/src/context/CredentialsContext.js +++ b/src/context/CredentialsContext.js @@ -8,7 +8,6 @@ const CredentialsContext = createContext(); export const CredentialsProvider = ({ children }) => { const { api } = useContext(SessionContext); const [vcEntityList, setVcEntityList] = useState(null); - const [vcEntityListInstances, setVcEntityListInstances] = useState(null); const [latestCredentials, setLatestCredentials] = useState(new Set()); const [currentSlide, setCurrentSlide] = useState(1); @@ -16,23 +15,42 @@ export const CredentialsProvider = ({ children }) => { const response = await api.get('/storage/vc'); const fetchedVcList = response.data.vc_list; - const vcEntityList = ( - await Promise.all( - fetchedVcList.map(async (vcEntity) => { - return { ...vcEntity }; - }) - ) - ).filter((vcEntity) => - credentialId ? vcEntity.credentialIdentifier === credentialId : vcEntity.instanceId === 0 - ); // show only the first instance - - vcEntityList.sort(reverse(compareBy(vc => vc.id))); - - console.log('--->',vcEntityList, fetchedVcList) - return { vcEntityList, fetchedVcList }; + // Group the fetched VC list by credentialIdentifier + const groupedByCredential = fetchedVcList.reduce((acc, vcEntity) => { + if (!acc[vcEntity.credentialIdentifier]) { + acc[vcEntity.credentialIdentifier] = []; + } + // Push the current vcEntity into the group + acc[vcEntity.credentialIdentifier].push(vcEntity); + return acc; + }, {}); + + // Map over each group to add the `instances` field + const vcEntityList = Object.values(groupedByCredential).map((group) => { + const firstInstance = group[0]; // First instance for each credentialIdentifier + + // Add the instances array with all instance details + const instances = group.map((vcEntity) => ({ + instanceId: vcEntity.instanceId, + sigCount: vcEntity.sigCount + })); + + // Return the first instance with the added `instances` field + return { ...firstInstance, instances }; + }); + + // If a specific credentialId is provided, filter based on it + const filteredVcEntityList = credentialId + ? vcEntityList.filter(vc => vc.credentialIdentifier === credentialId) + : vcEntityList; + + // Sorting the list as you did earlier + filteredVcEntityList.sort(reverse(compareBy(vc => vc.id))); + + return filteredVcEntityList; }, [api]); - const updateVcListAndLatestCredentials = (vcEntityList, fetchedVcList) => { + const updateVcListAndLatestCredentials = (vcEntityList) => { setLatestCredentials(new Set(vcEntityList.filter(vc => vc.id === vcEntityList[0].id).map(vc => vc.id))); setTimeout(() => { @@ -40,7 +58,6 @@ export const CredentialsProvider = ({ children }) => { }, 2000); setVcEntityList(vcEntityList); - setVcEntityListInstances(fetchedVcList); }; const pollForCredentials = useCallback(() => { @@ -57,13 +74,13 @@ export const CredentialsProvider = ({ children }) => { const previousVcList = await getItem("vc", userId); const previousSize = previousVcList.vc_list.length; - const { vcEntityList, fetchedVcList } = await fetchVcData(); + const vcEntityList = await fetchVcData(); if (previousSize < vcEntityList.length) { console.log('Found new credentials, stopping polling'); isPolling = false; clearInterval(intervalId); - updateVcListAndLatestCredentials(vcEntityList, fetchedVcList); + updateVcListAndLatestCredentials(vcEntityList); } if (attempts >= 5) { @@ -81,10 +98,9 @@ export const CredentialsProvider = ({ children }) => { const uniqueIdentifiers = new Set(previousVcList?.vc_list.map(vc => vc.credentialIdentifier)); const previousSize = uniqueIdentifiers.size; - const { vcEntityList, fetchedVcList } = await fetchVcData(); + const vcEntityList = await fetchVcData(); setVcEntityList(vcEntityList); - setVcEntityListInstances(fetchedVcList); const newCredentialsFound = previousSize < vcEntityList.length; if (shouldPoll && !newCredentialsFound) { @@ -94,10 +110,9 @@ export const CredentialsProvider = ({ children }) => { } else if (newCredentialsFound) { window.history.replaceState({}, '', `/`); console.log("Found new credentials, no need to poll"); - updateVcListAndLatestCredentials(vcEntityList, fetchedVcList); + updateVcListAndLatestCredentials(vcEntityList); } else { setVcEntityList(vcEntityList); - setVcEntityListInstances(fetchedVcList); } } catch (error) { console.error('Failed to fetch data', error); @@ -115,7 +130,7 @@ export const CredentialsProvider = ({ children }) => { }, [getData]); return ( - + {children} ); diff --git a/src/context/OpenID4VPContext.tsx b/src/context/OpenID4VPContext.tsx index d30254dec..3f6914009 100644 --- a/src/context/OpenID4VPContext.tsx +++ b/src/context/OpenID4VPContext.tsx @@ -13,7 +13,7 @@ const OpenID4VPContext: React.Context = createContext({ }); export const OpenID4VPContextProvider = ({ children }) => { - const { vcEntityList, vcEntityListInstances } = useContext(CredentialsContext); + const { vcEntityList } = useContext(CredentialsContext); const [popupState, setPopupState] = useState({ isOpen: false, @@ -51,7 +51,7 @@ export const OpenID4VPContextProvider = ({ children }) => { return ( {children} - + ); } diff --git a/src/hooks/useVcEntity.js b/src/hooks/useVcEntity.js index d3ac956a0..d0f79b0d5 100644 --- a/src/hooks/useVcEntity.js +++ b/src/hooks/useVcEntity.js @@ -1,44 +1,33 @@ import { useState, useEffect, useCallback } from 'react'; -export const useVcEntity = (fetchVcData, vcEntityList, vcEntityListInstances = null, credentialId) => { +export const useVcEntity = (fetchVcData, vcEntityList, credentialId) => { const [vcEntity, setVcEntity] = useState(null); - const [vcEntityInstances, setVcEntityInstances] = useState(null); const fetchAndSetVcEntity = useCallback(async () => { try { - if (vcEntityList && vcEntityListInstances) { + if (vcEntityList) { const vcEntity = vcEntityList.find( (vcEntity) => vcEntity.credentialIdentifier === credentialId ); if (!vcEntity) { throw new Error("Credential not found"); } - const vcEntityInstances = vcEntityListInstances.filter( - (vc) => vc.credentialIdentifier === credentialId - ); - - if (!vcEntityInstances) { - throw new Error("Credential not found"); - } setVcEntity(vcEntity); - setVcEntityInstances(vcEntityInstances); } else { - const { vcEntityList, fetchedVcList } = await fetchVcData(credentialId); + const vcEntityList = await fetchVcData(credentialId); setVcEntity(vcEntityList[0]); - setVcEntityInstances(fetchedVcList); } } catch (err) { console.error('Error fetching VC entity:', err); setVcEntity(null); // Clear the state on error - setVcEntityInstances(null) } - }, [fetchVcData, vcEntityList, vcEntityListInstances, credentialId]); + }, [fetchVcData, vcEntityList, credentialId]); useEffect(() => { fetchAndSetVcEntity(); }, [fetchAndSetVcEntity]); - return { vcEntity, vcEntityInstances }; + return vcEntity; }; diff --git a/src/pages/Home/Credential.js b/src/pages/Home/Credential.js index 440876ab8..e847ed7d1 100644 --- a/src/pages/Home/Credential.js +++ b/src/pages/Home/Credential.js @@ -36,12 +36,10 @@ const Credential = () => { const { t } = useTranslation(); const { credentialParserRegistry } = useContext(CredentialParserContext); - const { vcEntityList, vcEntityListInstances, fetchVcData } = useContext(CredentialsContext); + const { vcEntityList, fetchVcData } = useContext(CredentialsContext); - const {vcEntity, vcEntityInstances} = useVcEntity(fetchVcData, vcEntityList, vcEntityListInstances, credentialId); + const vcEntity = useVcEntity(fetchVcData, vcEntityList, credentialId); - console.log('-> vcEntity',vcEntity) - console.log('-> vcEntityInstances',vcEntityInstances) useEffect(() => { if (!vcEntity) { return; diff --git a/src/pages/Home/CredentialDetails.js b/src/pages/Home/CredentialDetails.js index 84e9be9e5..0dee02ba6 100644 --- a/src/pages/Home/CredentialDetails.js +++ b/src/pages/Home/CredentialDetails.js @@ -18,7 +18,7 @@ const CredentialDetails = () => { const { t } = useTranslation(); const { vcEntityList, fetchVcData } = useContext(CredentialsContext); - const { vcEntity } = useVcEntity(fetchVcData, vcEntityList, credentialId); + const vcEntity = useVcEntity(fetchVcData, vcEntityList, credentialId); return ( <> diff --git a/src/pages/Home/Home.js b/src/pages/Home/Home.js index aac8b7441..387c547ba 100644 --- a/src/pages/Home/Home.js +++ b/src/pages/Home/Home.js @@ -19,14 +19,13 @@ import HistoryList from '../../components/History/HistoryList'; import Slider from '../../components/Shared/Slider'; const Home = () => { - const { vcEntityList, vcEntityListInstances, latestCredentials, getData, currentSlide, setCurrentSlide } = useContext(CredentialsContext); + const { vcEntityList, latestCredentials, getData, currentSlide, setCurrentSlide } = useContext(CredentialsContext); const { api } = useContext(SessionContext); const history = useFetchPresentations(api); const screenType = useScreenType(); const navigate = useNavigate(); const { t } = useTranslation(); - useEffect(() => { getData(); }, [getData]); @@ -39,18 +38,29 @@ const Home = () => { navigate(`/credential/${vcEntity.credentialIdentifier}`); }; - const renderSlideContent = (vcEntity) => ( - - ); + const renderSlideContent = (vcEntity) => { + return ( + + ); + }; + return ( <> @@ -90,7 +100,7 @@ const Home = () => { ) : (

- {vcEntityListInstances && vcEntityList.map((vcEntity) => ( + {vcEntityList && vcEntityList.map((vcEntity) => (

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≷>&JSx9e5}9SA30Y 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 z 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