From da76c1ac3eb532b17e4af87e43133888cfcc2353 Mon Sep 17 00:00:00 2001 From: Sadrinho27 Date: Tue, 2 Dec 2025 00:25:41 +0100 Subject: [PATCH] refactor(iframe-controller): enhance async handling, improve error checks, and remove unnecessary comments for better code clarity --- src/services/iframe-controller.service.ts | 114 +++++++--------------- 1 file changed, 35 insertions(+), 79 deletions(-) diff --git a/src/services/iframe-controller.service.ts b/src/services/iframe-controller.service.ts index faf444c..c352716 100644 --- a/src/services/iframe-controller.service.ts +++ b/src/services/iframe-controller.service.ts @@ -6,12 +6,11 @@ import { splitPrivateData, isValid32ByteHex } from "../utils/service.utils"; import { MerkleProofResult } from "../../pkg/sdk_client"; export class IframeController { - private static isInitialized = false; // <--- VERROU + private static isInitialized = false; static async init() { - if (this.isInitialized) return; // On sort si déjà lancé + if (this.isInitialized) return; - // On ne lance l'écoute que si on est dans une iframe if (window.self !== window.top) { console.log( "[IframeController] 📡 Mode Iframe détecté. Démarrage des listeners API..." @@ -31,9 +30,6 @@ export class IframeController { const services = await Services.getInstance(); const tokenService = await TokenService.getInstance(); - /** - * Fonction centralisée pour envoyer des réponses d'erreur à la fenêtre parente (l'application A). - */ const errorResponse = ( errorMsg: string, origin: string, @@ -52,43 +48,35 @@ export class IframeController { ); }; - // Helper pour vérifier le token avant chaque action sensible const withToken = async ( event: MessageEvent, action: () => Promise ) => { const { accessToken } = event.data; - // On vérifie si le token est présent ET valide pour l'origine de l'iframe if ( !accessToken || !(await tokenService.validateToken(accessToken, event.origin)) ) { throw new Error("Invalid or expired session token"); } - // Si tout est bon, on exécute l'action await action(); }; - // --- Définitions des gestionnaires (Handlers) --- + // --- HANDLERS --- const handleRequestLink = async (event: MessageEvent) => { console.log( `[Router:API] 📨 Message ${MessageType.REQUEST_LINK} reçu de ${event.origin}` ); - // 1. Vérifier si l'appareil est DÉJÀ appairé (cas de la 2ème connexion) const device = await services.getDeviceFromDatabase(); if (device && device.pairing_process_commitment) { console.log( "[Router:API] Appareil déjà appairé. Pas besoin d'attendre home.ts." ); - // On saute l'attente et on passe directement à la suite. } else { - // 2. Cas de la 1ère connexion (appareil non appairé) - // On doit attendre que home.ts (auto-pairing) ait fini son travail. await new Promise((resolve, reject) => { - // Fonction de nettoyage pour éviter les fuites de mémoire const cleanup = () => { document.removeEventListener( "app:pairing-ready", @@ -97,7 +85,6 @@ export class IframeController { clearTimeout(timeoutId); }; - // Le gestionnaire de l'événement const handler = (e: CustomEvent) => { cleanup(); if (e.detail && e.detail.success) { @@ -107,13 +94,11 @@ export class IframeController { } }; - // Timeout de sécurité (5 secondes) const timeoutId = setTimeout(() => { cleanup(); reject(new Error("Auto-pairing timed out (Event not received)")); }, 5000); - // On écoute l'événement qu'on a créé dans Home.ts document.addEventListener( "app:pairing-ready", handler as EventListener @@ -124,7 +109,6 @@ export class IframeController { } console.log(`[Router:API] Traitement de la liaison...`); - const result = true; // Auto-confirmation const tokens = await tokenService.generateSessionToken(event.origin); window.parent.postMessage( @@ -144,7 +128,8 @@ export class IframeController { const handleCreatePairing = async (event: MessageEvent) => { console.log(`[Router:API] 📨 Message ${MessageType.CREATE_PAIRING} reçu`); - if (services.isPaired()) { + // 🔥 CORRECTION TS2801 : Ajout de await + if (await services.isPaired()) { throw new Error( "Device already paired — ignoring CREATE_PAIRING request" ); @@ -153,7 +138,9 @@ export class IframeController { await withToken(event, async () => { console.log("[Router:API] 🚀 Démarrage du processus d'appairage..."); - const myAddress = services.getDeviceAddress(); + // 🔥 CORRECTION TS2322 : Ajout de await pour récupérer la string + const myAddress = await services.getDeviceAddress(); + console.log("[Router:API] 1/7: Création du processus de pairing..."); const createPairingProcessReturn = await services.createPairingProcess( "", @@ -172,7 +159,8 @@ export class IframeController { console.log(`[Router:API] 2/7: Processus ${pairingId} créé.`); console.log("[Router:API] 3/7: Enregistrement local de l'appareil..."); - services.pairDevice(pairingId, [myAddress]); + // 🔥 CORRECTION TS2322 : myAddress est maintenant une string, plus une Promise + await services.pairDevice(pairingId, [myAddress]); console.log( "[Router:API] 4/7: Traitement du retour (handleApiReturn)..." @@ -194,7 +182,6 @@ export class IframeController { await services.handleApiReturn(approveChangeReturn); console.log("[Router:API] 7/7: Confirmation finale du pairing..."); - // await services.confirmPairing(); console.log("[Router:API] 🎉 Appairage terminé avec succès !"); @@ -211,7 +198,7 @@ export class IframeController { console.log( `[Router:API] 📨 Message ${MessageType.GET_MY_PROCESSES} reçu` ); - if (!services.isPaired()) throw new Error("Device not paired"); + if (!(await services.isPaired())) throw new Error("Device not paired"); await withToken(event, async () => { const myProcesses = await services.getMyProcesses(); @@ -229,7 +216,7 @@ export class IframeController { const handleGetProcesses = async (event: MessageEvent) => { console.log(`[Router:API] 📨 Message ${MessageType.GET_PROCESSES} reçu`); - if (!services.isPaired()) throw new Error("Device not paired"); + if (!(await services.isPaired())) throw new Error("Device not paired"); await withToken(event, async () => { const processes = await services.getProcesses(); @@ -247,7 +234,7 @@ export class IframeController { const handleDecryptState = async (event: MessageEvent) => { console.log(`[Router:API] 📨 Message ${MessageType.RETRIEVE_DATA} reçu`); - if (!services.isPaired()) throw new Error("Device not paired"); + if (!(await services.isPaired())) throw new Error("Device not paired"); const { processId, stateId } = event.data; @@ -255,7 +242,9 @@ export class IframeController { const process = await services.getProcess(processId); if (!process) throw new Error("Can't find process"); - const state = services.getStateFromId(process, stateId); + // 🔥 CORRECTION TS2339 & TS2345 : Ajout de await car getStateFromId est async + const state = await services.getStateFromId(process, stateId); + if (!state) throw new Error(`Unknown state ${stateId} for process ${processId}`); @@ -282,8 +271,7 @@ export class IframeController { } } console.log( - `[Router:API] ✅ Déchiffrement terminé pour ${processId}. ${ - Object.keys(res).length + `[Router:API] ✅ Déchiffrement terminé pour ${processId}. ${Object.keys(res).length } attribut(s) déchiffré(s).` ); @@ -299,6 +287,7 @@ export class IframeController { }; const handleValidateToken = async (event: MessageEvent) => { + // ... (Code identique, pas d'erreurs ici normalement) console.log(`[Router:API] 📨 Message ${MessageType.VALIDATE_TOKEN} reçu`); const accessToken = event.data.accessToken; const refreshToken = event.data.refreshToken; @@ -324,6 +313,7 @@ export class IframeController { }; const handleRenewToken = async (event: MessageEvent) => { + // ... (Code identique) console.log(`[Router:API] 📨 Message ${MessageType.RENEW_TOKEN} reçu`); const refreshToken = event.data.refreshToken; if (!refreshToken) throw new Error("No refresh token provided"); @@ -349,42 +339,24 @@ export class IframeController { const handleGetPairingId = async (event: MessageEvent) => { console.log(`[Router:API] 📨 Message ${MessageType.GET_PAIRING_ID} reçu`); - const maxRetries = 10; const retryDelay = 300; let pairingId: string | null = null; - // Boucle de polling for (let i = 0; i < maxRetries; i++) { - // On lit DIRECTEMENT la BDD (la "source de vérité") const device = await services.getDeviceFromDatabase(); - - // On vérifie si l'ID est maintenant présent dans la BDD if (device && device.pairing_process_commitment) { - // SUCCÈS ! L'ID est dans la BDD pairingId = device.pairing_process_commitment; console.log( - `[Router:API] GET_PAIRING_ID: ID trouvé en BDD (tentative ${ - i + 1 + `[Router:API] GET_PAIRING_ID: ID trouvé en BDD (tentative ${i + 1 }/${maxRetries})` ); - break; // On sort de la boucle + break; } - - // Si non trouvé, on patiente - console.warn( - `[Router:API] GET_PAIRING_ID: Non trouvé en BDD, nouvelle tentative... (${ - i + 1 - }/${maxRetries})` - ); await new Promise((resolve) => setTimeout(resolve, retryDelay)); } - // Si la boucle se termine sans succès if (!pairingId) { - console.error( - `[Router:API] GET_PAIRING_ID: Échec final, non trouvé en BDD après ${maxRetries} tentatives.` - ); throw new Error("Device not paired"); } @@ -402,20 +374,16 @@ export class IframeController { const handleCreateProcess = async (event: MessageEvent) => { console.log(`[Router:API] 📨 Message ${MessageType.CREATE_PROCESS} reçu`); - if (!services.isPaired()) throw new Error("Device not paired"); + if (!(await services.isPaired())) throw new Error("Device not paired"); const { processData, privateFields, roles } = event.data; await withToken(event, async () => { - console.log( - "[Router:API] 🚀 Démarrage de la création de processus standard..." - ); const { privateData, publicData } = splitPrivateData( processData, privateFields ); - console.log("[Router:API] 1/2: Création du processus..."); const createProcessReturn = await services.createProcess( privateData, publicData, @@ -427,12 +395,8 @@ export class IframeController { const processId = createProcessReturn.updated_process.process_id; const process = createProcessReturn.updated_process.current_process; - const stateId = process.states[0].state_id; - console.log( - `[Router:API] 2/2: Processus ${processId} créé. Traitement...` - ); - await services.handleApiReturn(createProcessReturn); + await services.handleApiReturn(createProcessReturn); console.log(`[Router:API] 🎉 Processus ${processId} créé.`); const res = { @@ -454,7 +418,7 @@ export class IframeController { const handleNotifyUpdate = async (event: MessageEvent) => { console.log(`[Router:API] 📨 Message ${MessageType.NOTIFY_UPDATE} reçu`); - if (!services.isPaired()) throw new Error("Device not paired"); + if (!(await services.isPaired())) throw new Error("Device not paired"); const { processId, stateId } = event.data; @@ -476,7 +440,7 @@ export class IframeController { const handleValidateState = async (event: MessageEvent) => { console.log(`[Router:API] 📨 Message ${MessageType.VALIDATE_STATE} reçu`); - if (!services.isPaired()) throw new Error("Device not paired"); + if (!(await services.isPaired())) throw new Error("Device not paired"); const { processId, stateId } = event.data; @@ -497,30 +461,23 @@ export class IframeController { const handleUpdateProcess = async (event: MessageEvent) => { console.log(`[Router:API] 📨 Message ${MessageType.UPDATE_PROCESS} reçu`); - if (!services.isPaired()) throw new Error("Device not paired"); + if (!(await services.isPaired())) throw new Error("Device not paired"); const { processId, newData, privateFields, roles } = event.data; await withToken(event, async () => { - console.log( - `[Router:API] 🔄 Transfert de la mise à jour de ${processId} au service...` - ); - - // Le service gère maintenant tout : récupération, réparation d'état, et mise à jour. const res = await services.updateProcess( processId, newData, privateFields, roles ); - - // Nous appelons handleApiReturn ici, comme avant. await services.handleApiReturn(res); window.parent.postMessage( { type: MessageType.PROCESS_UPDATED, - updatedProcess: res.updated_process, // res vient directement de l'appel service + updatedProcess: res.updated_process, messageId: event.data.messageId, }, event.origin @@ -532,12 +489,12 @@ export class IframeController { console.log( `[Router:API] 📨 Message ${MessageType.DECODE_PUBLIC_DATA} reçu` ); - if (!services.isPaired()) throw new Error("Device not paired"); + if (!(await services.isPaired())) throw new Error("Device not paired"); const { encodedData } = event.data; await withToken(event, async () => { - const decodedData = services.decodeValue(encodedData); + const decodedData = await services.decodeValue(encodedData); window.parent.postMessage( { type: MessageType.PUBLIC_DATA_DECODED, @@ -554,7 +511,7 @@ export class IframeController { const { commitedIn, label, fileBlob } = event.data; await withToken(event, async () => { - const hash = services.getHashForFile(commitedIn, label, fileBlob); + const hash = await services.getHashForFile(commitedIn, label, fileBlob); window.parent.postMessage( { type: MessageType.VALUE_HASHED, @@ -573,7 +530,7 @@ export class IframeController { const { processState, attributeName } = event.data; await withToken(event, async () => { - const proof = services.getMerkleProofForFile( + const proof = await services.getMerkleProofForFile( processState, attributeName ); @@ -602,7 +559,7 @@ export class IframeController { throw new Error("Provided merkleProof is not a valid json object"); } - const res = services.validateMerkleProof( + const res = await services.validateMerkleProof( parsedMerkleProof, documentHash ); @@ -617,13 +574,12 @@ export class IframeController { }); }; - // --- Le "Switchyard" : il reçoit tous les messages et les dispatche --- - window.removeEventListener("message", handleMessage); window.addEventListener("message", handleMessage); async function handleMessage(event: MessageEvent) { try { + // Switch/case inchangé ... switch (event.data.type) { case MessageType.REQUEST_LINK: await handleRequestLink(event); @@ -674,7 +630,7 @@ export class IframeController { await handleValidateMerkleProof(event); break; default: - console.warn("[Router:API] ⚠️ Message non géré reçu:", event.data); + // console.warn("[Router:API] ⚠️ Message non géré reçu:", event.data); } } catch (error: any) { const errorMsg = `[Router:API] 💥 Erreur de haut niveau: ${error}`; @@ -692,4 +648,4 @@ export class IframeController { "[Router:API] ✅ Tous les listeners sont actifs. Envoi du message LISTENING au parent." ); } -} +} \ No newline at end of file