diff --git a/app/src/screens/ProveFlow/ProofRequestStatusScreen.tsx b/app/src/screens/ProveFlow/ProofRequestStatusScreen.tsx index 6e6680337..d0a32d280 100644 --- a/app/src/screens/ProveFlow/ProofRequestStatusScreen.tsx +++ b/app/src/screens/ProveFlow/ProofRequestStatusScreen.tsx @@ -2,7 +2,7 @@ import React, { useEffect } from 'react'; import { StatusBar, StyleSheet, View } from 'react-native'; import LottieView from 'lottie-react-native'; -import { Spinner } from 'tamagui'; +import { ScrollView, Spinner } from 'tamagui'; import loadingAnimation from '../../assets/animations/loading/misc.json'; import failAnimation from '../../assets/animations/proof_failed.json'; @@ -23,7 +23,8 @@ import { } from '../../utils/haptic'; const SuccessScreen: React.FC = () => { - const { selectedApp, disclosureStatus, cleanSelfApp } = useProofInfo(); + const { selectedApp, disclosureStatus, discloseError, cleanSelfApp } = + useProofInfo(); const appName = selectedApp?.appName; const goHome = useHapticNavigation('Home'); @@ -69,6 +70,7 @@ const SuccessScreen: React.FC = () => { - Unable to prove your identity to{' '} - {appName} - {status === 'error' && '. Due to technical issues.'} - + + + Unable to prove your identity to{' '} + {appName} + {status === 'error' && '. Due to technical issues.'} + + {status === 'failure' && reason && ( + <> + + + Reason: + + + + + + + {reason} + + + + + + )} + ); } else { return ( diff --git a/app/src/screens/ProveFlow/ProveScreen.tsx b/app/src/screens/ProveFlow/ProveScreen.tsx index d5f22ea3b..ef152ed56 100644 --- a/app/src/screens/ProveFlow/ProveScreen.tsx +++ b/app/src/screens/ProveFlow/ProveScreen.tsx @@ -168,7 +168,9 @@ const ProveScreen: React.FC = () => { ); handleProofResult( currentApp.sessionId, - status === ProofStatusEnum.SUCCESS, + status?.status === ProofStatusEnum.SUCCESS, + status?.error_code, + status?.reason, ); } catch (e) { console.log('Error in verification process'); diff --git a/app/src/stores/appProvider.tsx b/app/src/stores/appProvider.tsx index 8ff2c32dc..ef017be59 100644 --- a/app/src/stores/appProvider.tsx +++ b/app/src/stores/appProvider.tsx @@ -28,7 +28,12 @@ interface IAppContext { * @param sessionId - The session ID from the scanned QR code. * @param success - Whether the proof was verified successfully. */ - handleProofResult: (sessionId: string, success: boolean) => void; + handleProofResult: ( + sessionId: string, + success: boolean, + error_code?: string, + reason?: string, + ) => void; } const AppContext = createContext({ @@ -120,7 +125,12 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ } }; - const handleProofResult = (sessionId: string, proof_verified: boolean) => { + const handleProofResult = ( + sessionId: string, + proof_verified: boolean, + error_code?: string, + reason?: string, + ) => { console.log( '[AppProvider] handleProofResult called with sessionId:', sessionId, @@ -143,11 +153,15 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ '[AppProvider] Emitting proof_generation_failed event with data:', { session_id: sessionId, + error_code, + reason, }, ); socketRef.current.emit('proof_generation_failed', { session_id: sessionId, + error_code, + reason, }); } }; diff --git a/app/src/stores/proofProvider.tsx b/app/src/stores/proofProvider.tsx index a4cd2c797..bfe278608 100644 --- a/app/src/stores/proofProvider.tsx +++ b/app/src/stores/proofProvider.tsx @@ -16,9 +16,15 @@ export enum ProofStatusEnum { ERROR = 'error', } +export type DiscloseError = { + error_code?: string; + reason?: string; +}; + interface IProofContext { registrationStatus: ProofStatusEnum; disclosureStatus: ProofStatusEnum; + discloseError: DiscloseError | undefined; selectedApp: SelfApp; setSelectedApp: (app: SelfApp) => void; cleanSelfApp: () => void; @@ -28,6 +34,7 @@ interface IProofContext { const defaults: IProofContext = { registrationStatus: ProofStatusEnum.PENDING, disclosureStatus: ProofStatusEnum.PENDING, + discloseError: undefined, selectedApp: { appName: '', logoBase64: '', @@ -52,7 +59,7 @@ export let globalSetRegistrationStatus: | ((status: ProofStatusEnum) => void) | null = null; export let globalSetDisclosureStatus: - | ((status: ProofStatusEnum) => void) + | ((status: ProofStatusEnum, error?: DiscloseError) => void) | null = null; /* @@ -66,6 +73,10 @@ export function ProofProvider({ children }: PropsWithChildren<{}>) { ProofStatusEnum.PENDING, ); + const [discloseError, setDiscloseError] = useState( + undefined, + ); + const [selectedApp, setSelectedAppInternal] = useState( defaults.selectedApp, ); @@ -75,6 +86,7 @@ export function ProofProvider({ children }: PropsWithChildren<{}>) { return; } setRegistrationStatus(ProofStatusEnum.PENDING); + setDiscloseError(undefined); setSelectedAppInternal(app); }, []); @@ -87,11 +99,15 @@ export function ProofProvider({ children }: PropsWithChildren<{}>) { const resetProof = useCallback(() => { setRegistrationStatus(ProofStatusEnum.PENDING); setDisclosureStatus(ProofStatusEnum.PENDING); + setDiscloseError(undefined); }, []); useEffect(() => { globalSetRegistrationStatus = setRegistrationStatus; - globalSetDisclosureStatus = setDisclosureStatus; + globalSetDisclosureStatus = (status, error) => { + setDisclosureStatus(status); + setDiscloseError(error); + }; return () => { globalSetRegistrationStatus = null; globalSetDisclosureStatus = null; @@ -102,6 +118,7 @@ export function ProofProvider({ children }: PropsWithChildren<{}>) { () => ({ registrationStatus, disclosureStatus, + discloseError, selectedApp, setSelectedApp, cleanSelfApp, @@ -110,8 +127,10 @@ export function ProofProvider({ children }: PropsWithChildren<{}>) { [ registrationStatus, disclosureStatus, + discloseError, selectedApp, setSelectedApp, + setDiscloseError, cleanSelfApp, resetProof, ], diff --git a/app/src/utils/proving/payload.ts b/app/src/utils/proving/payload.ts index 850f6fdf6..00241f791 100644 --- a/app/src/utils/proving/payload.ts +++ b/app/src/utils/proving/payload.ts @@ -120,7 +120,7 @@ async function checkIdPassportDscIsInTree( circuitDNSMapping, endpointType, ); - if (dscStatus !== ProofStatusEnum.SUCCESS) { + if (dscStatus.status !== ProofStatusEnum.SUCCESS) { console.log('DSC proof failed'); return false; } @@ -140,9 +140,9 @@ export async function sendDscPayload( passportData: PassportData, circuitDNSMapping: Record, endpointType: EndpointType, -): Promise { +): Promise<{ status: ProofStatusEnum; error_code?: string; reason?: string }> { if (!passportData) { - return false; + return { status: ProofStatusEnum.FAILURE }; } // const isSupported = checkPassportSupported(passportData); // if (!isSupported) { diff --git a/app/src/utils/proving/tee.ts b/app/src/utils/proving/tee.ts index dcd68b1c6..4f0a9a020 100644 --- a/app/src/utils/proving/tee.ts +++ b/app/src/utils/proving/tee.ts @@ -10,6 +10,7 @@ import { } from '../../../../common/src/constants/constants'; import { EndpointType } from '../../../../common/src/utils/appType'; import { + DiscloseError, ProofStatusEnum, globalSetDisclosureStatus, globalSetRegistrationStatus, @@ -67,7 +68,7 @@ export async function sendPayload( updateGlobalOnFailure?: boolean; flow?: 'registration' | 'disclosure'; }, -): Promise { +): Promise<{ status: ProofStatusEnum; error_code?: string; reason?: string }> { const opts = { updateGlobalOnSuccess: true, updateGlobalOnFailure: true, @@ -75,7 +76,11 @@ export async function sendPayload( }; return new Promise(resolve => { let finalized = false; - function finalize(status: ProofStatusEnum) { + function finalize( + status: ProofStatusEnum, + error_code?: string, + reason?: string, + ) { if (!finalized) { finalized = true; clearTimeout(timer); @@ -84,12 +89,15 @@ export async function sendPayload( (status !== ProofStatusEnum.SUCCESS && opts.updateGlobalOnFailure) ) { if (options?.flow === 'disclosure') { - globalSetDisclosureStatus && globalSetDisclosureStatus(status); + let discloseError: DiscloseError | undefined = + error_code || reason ? { error_code, reason } : undefined; + globalSetDisclosureStatus && + globalSetDisclosureStatus(status, discloseError); } else { globalSetRegistrationStatus && globalSetRegistrationStatus(status); } } - resolve(status); + resolve({ status, error_code, reason }); } } const uuid = v4(); @@ -201,7 +209,7 @@ export async function sendPayload( if (ws.readyState === WebSocket.OPEN) { ws.close(); } - finalize(ProofStatusEnum.FAILURE); + finalize(ProofStatusEnum.FAILURE, data.error_code, data.reason); } }); socket.on('disconnect', reason => { diff --git a/sdk/qrcode/SelfQRcode.tsx b/sdk/qrcode/SelfQRcode.tsx index 0cba341ee..e82ce93c6 100644 --- a/sdk/qrcode/SelfQRcode.tsx +++ b/sdk/qrcode/SelfQRcode.tsx @@ -15,6 +15,7 @@ import { getUniversalLink, SelfApp, SelfAppBuilder } from '../../common/src/util interface SelfQRcodeProps { selfApp: SelfApp; onSuccess: () => void; + onError: (data: {error_code?: string, reason?: string}) => void; type?: 'websocket' | 'deeplink'; websocketUrl?: string; size?: number; @@ -37,6 +38,7 @@ const SelfQRcodeWrapper = (props: SelfQRcodeProps) => { const SelfQRcode = ({ selfApp, onSuccess, + onError, type = 'websocket', websocketUrl = WS_DB_RELAYER, size = 300, @@ -58,7 +60,8 @@ const SelfQRcode = ({ }, type, setProofStep, - onSuccess + onSuccess, + onError, ); } diff --git a/sdk/qrcode/utils/websocket.ts b/sdk/qrcode/utils/websocket.ts index c36012ca9..202e80461 100644 --- a/sdk/qrcode/utils/websocket.ts +++ b/sdk/qrcode/utils/websocket.ts @@ -28,7 +28,8 @@ const handleWebSocketMessage = selfApp: SelfApp, type: 'websocket' | 'deeplink', setProofStep: (step: number) => void, - onSuccess: () => void + onSuccess: () => void, + onError: (data: {error_code?: string, reason?: string}) => void ) => async (data: any) => { console.log('[WebSocket] Received mobile status:', data.status, 'for session:', sessionId); @@ -55,6 +56,7 @@ const handleWebSocketMessage = case 'proof_generation_failed': console.log('[WebSocket] Proof generation failed.'); setProofStep(QRcodeSteps.PROOF_GENERATION_FAILED); + onError(data); break; case 'proof_verified': console.log('[WebSocket] Proof verified.'); @@ -73,7 +75,8 @@ export function initWebSocket( selfApp: SelfApp, type: 'websocket' | 'deeplink', setProofStep: (step: number) => void, - onSuccess: () => void + onSuccess: () => void, + onError: (data: {error_code?: string, reason?: string}) => void, ) { const sessionId = selfApp.sessionId; console.log(`[WebSocket] Initializing WebSocket connection for sessionId: ${sessionId}`); @@ -95,7 +98,8 @@ export function initWebSocket( selfApp, type, setProofStep, - onSuccess + onSuccess, + onError )(data); });