Compare commits

..

No commits in common. "77dcb8b9ae18c5003231a05d0ba62cd8e2f8c7b8" and "633fd57793062f52f397eaa34fe538209c80f5fa" have entirely different histories.

3 changed files with 378 additions and 136 deletions

View File

@ -1,70 +1,60 @@
import Services from "./services/service"; import Services from './services/service';
import { Router } from "./router/index"; import { Router } from './router/index';
import "./components/header/Header"; import './components/header/Header';
import "./App"; import './App';
import { IframeController } from "./services/iframe-controller.service"; import { IframeController } from './services/iframe-controller.service';
async function bootstrap() { async function bootstrap() {
// Optionnel : Désactiver les logs verbeux en prod si nécessaire console.log("🚀 Démarrage de l'application 4NK (Multi-Worker Architecture)...");
console.log(
"🚀 Démarrage de l'application 4NK (Multi-Worker Architecture)..."
);
try { try {
// 1. Initialisation des Services & Workers // 1. Initialisation des Services (Proxy vers Core & Network Workers)
// Cela va lancer les workers en arrière-plan
const services = await Services.getInstance(); const services = await Services.getInstance();
// Injection du Header (Si le DOM est prêt) // Injection du Header
const headerSlot = document.getElementById("header-slot"); const headerSlot = document.getElementById('header-slot');
if (headerSlot) { if (headerSlot) {
headerSlot.innerHTML = "<app-header></app-header>"; headerSlot.innerHTML = '<app-header></app-header>';
} }
// 2. Gestion Appareil (Device) // 2. Vérification / Création de l'appareil (via le Worker)
const device = await services.getDeviceFromDatabase(); const device = await services.getDeviceFromDatabase();
if (!device) { if (!device) {
console.log( console.log('✨ Nouvel appareil détecté, création en cours via Worker...');
"✨ Nouvel appareil détecté, création en cours via Worker..."
);
await services.createNewDevice(); await services.createNewDevice();
} else { } else {
console.log("Restauration de l'appareil..."); console.log("Restauration de l'appareil...");
await services.restoreDevice(device); await services.restoreDevice(device);
} }
// 3. Iframe Controller // 3. Initialisation du contrôleur d'Iframe (Reste sur le Main Thread pour écouter window)
await IframeController.init(); await IframeController.init();
// 4. Restauration des données et secrets // 4. Restauration des données
await services.restoreProcessesFromDB(); await services.restoreProcessesFromDB();
await services.restoreSecretsFromDB();
if (services.restoreSecretsFromDB) {
await services.restoreSecretsFromDB();
} else {
console.warn("restoreSecretsFromDB non implémenté dans le proxy Services");
}
// 5. Gestion du Routing // 5. Gestion du Routing
const isIframe = window.self !== window.top; const isIframe = window.self !== window.top;
const isPaired = await services.isPaired(); const isPaired = await services.isPaired();
if (isPaired && !isIframe) { if (isPaired && !isIframe) {
console.log("✅ Mode Standalone & Appairé : Redirection vers Process."); console.log('✅ Mode Standalone & Appairé : Redirection vers Process.');
// Nettoyage de l'URL pour éviter de recharger sur une route intermédiaire window.history.replaceState({}, '', 'process');
window.history.replaceState({}, "", "process");
Router.handleLocation(); Router.handleLocation();
} else { } else {
console.log( console.log(isIframe ? '📡 Mode Iframe détecté : Attente API.' : '🆕 Non appairé : Démarrage sur Home.');
isIframe
? "📡 Mode Iframe détecté : Prêt."
: "🆕 Non appairé : Démarrage sur Home."
);
// En mode Iframe, on laisse souvent le parent piloter ou on charge la route par défaut
Router.init(); Router.init();
} }
} catch (error) { } catch (error) {
console.error("💥 Erreur critique au démarrage :", error); console.error('💥 Erreur critique au démarrage :', error);
if (window.self !== window.top) {
window.parent.postMessage(
{ type: "4NK_ERROR", error: String(error) },
"*"
);
}
} }
} }

View File

@ -10,7 +10,6 @@ export class IframeController {
static async init() { static async init() {
if (this.isInitialized) return; if (this.isInitialized) return;
this.isInitialized = true; // Marquage immédiat pour éviter les doubles appels
if (window.self !== window.top) { if (window.self !== window.top) {
console.log( console.log(
@ -19,24 +18,25 @@ export class IframeController {
await IframeController.registerAllListeners(); await IframeController.registerAllListeners();
} else { } else {
console.log( console.log(
"[IframeController] Mode Standalone. Listeners API inactifs." "[IframeController] Mode Standalone (pas d'iframe). Listeners API inactifs."
); );
} }
} }
private static async registerAllListeners() { private static async registerAllListeners() {
console.log(
"[Router:API] 🎧 Enregistrement des gestionnaires de messages (postMessage)..."
);
const services = await Services.getInstance(); const services = await Services.getInstance();
const tokenService = await TokenService.getInstance(); const tokenService = await TokenService.getInstance();
// --- UTILS ---
const errorResponse = ( const errorResponse = (
errorMsg: string, errorMsg: string,
origin: string, origin: string,
messageId?: string messageId?: string
) => { ) => {
console.error( console.error(
`[Router:API] 📤 Envoi Erreur: ${errorMsg} (Origine: ${origin})` `[Router:API] 📤 Envoi Erreur: ${errorMsg} (Origine: ${origin}, MsgID: ${messageId})`
); );
window.parent.postMessage( window.parent.postMessage(
{ {
@ -44,7 +44,7 @@ export class IframeController {
error: errorMsg, error: errorMsg,
messageId, messageId,
}, },
origin // On renvoie à l'origine exacte reçue, même en mode * origin
); );
}; };
@ -53,7 +53,6 @@ export class IframeController {
action: () => Promise<void> action: () => Promise<void>
) => { ) => {
const { accessToken } = event.data; const { accessToken } = event.data;
// Note: Pour la démo, on accepte souvent tout, mais la validation du token reste une bonne pratique
if ( if (
!accessToken || !accessToken ||
!(await tokenService.validateToken(accessToken, event.origin)) !(await tokenService.validateToken(accessToken, event.origin))
@ -72,11 +71,11 @@ export class IframeController {
const device = await services.getDeviceFromDatabase(); const device = await services.getDeviceFromDatabase();
// Si déjà appairé, on accepte immédiatement sans attendre l'événement UI
if (device && device.pairing_process_commitment) { if (device && device.pairing_process_commitment) {
console.log("[Router:API] Appareil déjà appairé. Liaison immédiate."); console.log(
"[Router:API] Appareil déjà appairé. Pas besoin d'attendre home.ts."
);
} else { } else {
// Sinon, on attend que l'utilisateur clique sur "Lier" dans l'interface (Home.ts)
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {
const cleanup = () => { const cleanup = () => {
document.removeEventListener( document.removeEventListener(
@ -97,19 +96,21 @@ export class IframeController {
const timeoutId = setTimeout(() => { const timeoutId = setTimeout(() => {
cleanup(); cleanup();
reject(new Error("Auto-pairing timed out (User action missing)")); reject(new Error("Auto-pairing timed out (Event not received)"));
}, 60000); // Augmenté à 60s pour laisser le temps à l'utilisateur de cliquer }, 5000);
document.addEventListener( document.addEventListener(
"app:pairing-ready", "app:pairing-ready",
handler as EventListener handler as EventListener
); );
}); });
console.log(`[Router:API] Feu vert de home.ts reçu !`);
} }
console.log(`[Router:API] Génération des tokens de session...`); console.log(`[Router:API] Traitement de la liaison...`);
const tokens = await tokenService.generateSessionToken(event.origin);
const tokens = await tokenService.generateSessionToken(event.origin);
window.parent.postMessage( window.parent.postMessage(
{ {
type: MessageType.LINK_ACCEPTED, type: MessageType.LINK_ACCEPTED,
@ -119,11 +120,15 @@ export class IframeController {
}, },
event.origin event.origin
); );
console.log(
`[Router:API] ✅ ${MessageType.REQUEST_LINK} accepté et jetons envoyés.`
);
}; };
const handleCreatePairing = async (event: MessageEvent) => { const handleCreatePairing = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.CREATE_PAIRING} reçu`); console.log(`[Router:API] 📨 Message ${MessageType.CREATE_PAIRING} reçu`);
// 🔥 CORRECTION TS2801 : Ajout de await
if (await services.isPaired()) { if (await services.isPaired()) {
throw new Error( throw new Error(
"Device already paired — ignoring CREATE_PAIRING request" "Device already paired — ignoring CREATE_PAIRING request"
@ -131,9 +136,12 @@ export class IframeController {
} }
await withToken(event, async () => { await withToken(event, async () => {
const myAddress = await services.getDeviceAddress(); // string console.log("[Router:API] 🚀 Démarrage du processus d'appairage...");
console.log("[Router:API] Création du processus de pairing..."); // 🔥 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( const createPairingProcessReturn = await services.createPairingProcess(
"", "",
[myAddress] [myAddress]
@ -143,44 +151,58 @@ export class IframeController {
createPairingProcessReturn.updated_process?.process_id; createPairingProcessReturn.updated_process?.process_id;
const stateId = createPairingProcessReturn.updated_process const stateId = createPairingProcessReturn.updated_process
?.current_process?.states[0]?.state_id as string; ?.current_process?.states[0]?.state_id as string;
if (!pairingId || !stateId) { if (!pairingId || !stateId) {
throw new Error("Pairing process creation failed (invalid IDs)"); throw new Error(
"Pairing process creation failed to return valid IDs"
);
} }
console.log(`[Router:API] 2/7: Processus ${pairingId} créé.`);
console.log("[Router:API] 3/7: Enregistrement local de l'appareil...");
// 🔥 CORRECTION TS2322 : myAddress est maintenant une string, plus une Promise
await services.pairDevice(pairingId, [myAddress]); await services.pairDevice(pairingId, [myAddress]);
console.log(
"[Router:API] 4/7: Traitement du retour (handleApiReturn)..."
);
await services.handleApiReturn(createPairingProcessReturn); await services.handleApiReturn(createPairingProcessReturn);
// Auto-approbation du premier état (PRD) console.log("[Router:API] 5/7: Création de la mise à jour PRD...");
const createPrdUpdateReturn = await services.createPrdUpdate( const createPrdUpdateReturn = await services.createPrdUpdate(
pairingId, pairingId,
stateId stateId
); );
await services.handleApiReturn(createPrdUpdateReturn); await services.handleApiReturn(createPrdUpdateReturn);
console.log("[Router:API] 6/7: Approbation du changement...");
const approveChangeReturn = await services.approveChange( const approveChangeReturn = await services.approveChange(
pairingId, pairingId,
stateId stateId
); );
await services.handleApiReturn(approveChangeReturn); await services.handleApiReturn(approveChangeReturn);
console.log("[Router:API] 🎉 Appairage terminé !"); console.log("[Router:API] 7/7: Confirmation finale du pairing...");
window.parent.postMessage( console.log("[Router:API] 🎉 Appairage terminé avec succès !");
{
type: MessageType.PAIRING_CREATED, const successMsg = {
pairingId, type: MessageType.PAIRING_CREATED,
messageId: event.data.messageId, pairingId,
}, messageId: event.data.messageId,
event.origin };
); window.parent.postMessage(successMsg, event.origin);
}); });
}; };
const handleGetMyProcesses = async (event: MessageEvent) => { const handleGetMyProcesses = async (event: MessageEvent) => {
console.log(
`[Router:API] 📨 Message ${MessageType.GET_MY_PROCESSES} reçu`
);
if (!(await services.isPaired())) throw new Error("Device not paired"); if (!(await services.isPaired())) throw new Error("Device not paired");
await withToken(event, async () => { await withToken(event, async () => {
const myProcesses = await services.getMyProcesses(); const myProcesses = await services.getMyProcesses();
window.parent.postMessage( window.parent.postMessage(
{ {
type: MessageType.GET_MY_PROCESSES, type: MessageType.GET_MY_PROCESSES,
@ -193,9 +215,12 @@ export class IframeController {
}; };
const handleGetProcesses = async (event: MessageEvent) => { const handleGetProcesses = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.GET_PROCESSES} reçu`);
if (!(await services.isPaired())) throw new Error("Device not paired"); if (!(await services.isPaired())) throw new Error("Device not paired");
await withToken(event, async () => { await withToken(event, async () => {
const processes = await services.getProcesses(); const processes = await services.getProcesses();
window.parent.postMessage( window.parent.postMessage(
{ {
type: MessageType.PROCESSES_RETRIEVED, type: MessageType.PROCESSES_RETRIEVED,
@ -208,21 +233,27 @@ export class IframeController {
}; };
const handleDecryptState = async (event: MessageEvent) => { const handleDecryptState = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.RETRIEVE_DATA} reçu`);
if (!(await services.isPaired())) throw new Error("Device not paired"); if (!(await services.isPaired())) throw new Error("Device not paired");
const { processId, stateId } = event.data; const { processId, stateId } = event.data;
await withToken(event, async () => { await withToken(event, async () => {
const process = await services.getProcess(processId); const process = await services.getProcess(processId);
if (!process) throw new Error("Can't find process"); if (!process) throw new Error("Can't find process");
// 🔥 CORRECTION TS2339 & TS2345 : Ajout de await car getStateFromId est async
const state = await services.getStateFromId(process, stateId); const state = await services.getStateFromId(process, stateId);
if (!state) throw new Error(`Unknown state ${stateId}`);
if (!state)
throw new Error(`Unknown state ${stateId} for process ${processId}`);
console.log(
`[Router:API] 🔐 Démarrage du déchiffrement pour ${processId}`
);
await services.ensureConnections(process, stateId); await services.ensureConnections(process, stateId);
const res: Record<string, any> = {}; const res: Record<string, any> = {};
// Déchiffrement des attributs privés
for (const attribute of Object.keys(state.pcd_commitment)) { for (const attribute of Object.keys(state.pcd_commitment)) {
if ( if (
attribute === "roles" || attribute === "roles" ||
@ -239,6 +270,10 @@ export class IframeController {
res[attribute] = decryptedAttribute; res[attribute] = decryptedAttribute;
} }
} }
console.log(
`[Router:API] ✅ Déchiffrement terminé pour ${processId}. ${Object.keys(res).length
} attribut(s) déchiffré(s).`
);
window.parent.postMessage( window.parent.postMessage(
{ {
@ -251,21 +286,79 @@ 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;
if (!accessToken || !refreshToken) {
throw new Error("Missing access, refresh token or both");
}
const isValid = await tokenService.validateToken(
accessToken,
event.origin
);
console.log(`[Router:API] 🔑 Validation Jeton: ${isValid}`);
window.parent.postMessage(
{
type: MessageType.VALIDATE_TOKEN,
accessToken: accessToken,
refreshToken: refreshToken,
isValid: isValid,
messageId: event.data.messageId,
},
event.origin
);
};
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");
const newAccessToken = await tokenService.refreshAccessToken(
refreshToken,
event.origin
);
if (!newAccessToken)
throw new Error("Failed to refresh token (invalid refresh token)");
console.log(`[Router:API] 🔑 Jeton d'accès renouvelé.`);
window.parent.postMessage(
{
type: MessageType.RENEW_TOKEN,
accessToken: newAccessToken,
refreshToken: refreshToken,
messageId: event.data.messageId,
},
event.origin
);
};
const handleGetPairingId = async (event: MessageEvent) => { const handleGetPairingId = async (event: MessageEvent) => {
// Logique de retry si la DB est lente au démarrage console.log(`[Router:API] 📨 Message ${MessageType.GET_PAIRING_ID} reçu`);
const maxRetries = 10; const maxRetries = 10;
const retryDelay = 300;
let pairingId: string | null = null; let pairingId: string | null = null;
for (let i = 0; i < maxRetries; i++) { for (let i = 0; i < maxRetries; i++) {
const device = await services.getDeviceFromDatabase(); const device = await services.getDeviceFromDatabase();
if (device && device.pairing_process_commitment) { if (device && device.pairing_process_commitment) {
pairingId = device.pairing_process_commitment; pairingId = device.pairing_process_commitment;
console.log(
`[Router:API] GET_PAIRING_ID: ID trouvé en BDD (tentative ${i + 1
}/${maxRetries})`
);
break; break;
} }
await new Promise((resolve) => setTimeout(resolve, 300)); await new Promise((resolve) => setTimeout(resolve, retryDelay));
} }
if (!pairingId) throw new Error("Device not paired (Timeout)"); if (!pairingId) {
throw new Error("Device not paired");
}
await withToken(event, async () => { await withToken(event, async () => {
window.parent.postMessage( window.parent.postMessage(
@ -280,7 +373,9 @@ export class IframeController {
}; };
const handleCreateProcess = async (event: MessageEvent) => { const handleCreateProcess = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.CREATE_PROCESS} reçu`);
if (!(await services.isPaired())) throw new Error("Device not paired"); if (!(await services.isPaired())) throw new Error("Device not paired");
const { processData, privateFields, roles } = event.data; const { processData, privateFields, roles } = event.data;
await withToken(event, async () => { await withToken(event, async () => {
@ -288,24 +383,32 @@ export class IframeController {
processData, processData,
privateFields privateFields
); );
const createProcessReturn = await services.createProcess( const createProcessReturn = await services.createProcess(
privateData, privateData,
publicData, publicData,
roles roles
); );
if (!createProcessReturn.updated_process) {
if (!createProcessReturn.updated_process) throw new Error("Empty updated_process in createProcessReturn");
throw new Error("Process creation failed"); }
const processId = createProcessReturn.updated_process.process_id; const processId = createProcessReturn.updated_process.process_id;
const process = createProcessReturn.updated_process.current_process; const process = createProcessReturn.updated_process.current_process;
await services.handleApiReturn(createProcessReturn); await services.handleApiReturn(createProcessReturn);
console.log(`[Router:API] 🎉 Processus ${processId} créé.`);
const res = {
processId,
process,
processData,
};
window.parent.postMessage( window.parent.postMessage(
{ {
type: MessageType.PROCESS_CREATED, type: MessageType.PROCESS_CREATED,
processCreated: { processId, process, processData }, processCreated: res,
messageId: event.data.messageId, messageId: event.data.messageId,
}, },
event.origin event.origin
@ -313,18 +416,170 @@ export class IframeController {
}); });
}; };
// --- MAIN MESSAGE DISPATCHER --- const handleNotifyUpdate = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.NOTIFY_UPDATE} reçu`);
if (!(await services.isPaired())) throw new Error("Device not paired");
const { processId, stateId } = event.data;
await withToken(event, async () => {
if (!isValid32ByteHex(stateId)) throw new Error("Invalid state id");
const res = await services.createPrdUpdate(processId, stateId);
await services.handleApiReturn(res);
window.parent.postMessage(
{
type: MessageType.UPDATE_NOTIFIED,
messageId: event.data.messageId,
},
event.origin
);
});
};
const handleValidateState = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.VALIDATE_STATE} reçu`);
if (!(await services.isPaired())) throw new Error("Device not paired");
const { processId, stateId } = event.data;
await withToken(event, async () => {
const res = await services.approveChange(processId, stateId);
await services.handleApiReturn(res);
window.parent.postMessage(
{
type: MessageType.STATE_VALIDATED,
validatedProcess: res.updated_process,
messageId: event.data.messageId,
},
event.origin
);
});
};
const handleUpdateProcess = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.UPDATE_PROCESS} reçu`);
if (!(await services.isPaired())) throw new Error("Device not paired");
const { processId, newData, privateFields, roles } = event.data;
await withToken(event, async () => {
const res = await services.updateProcess(
processId,
newData,
privateFields,
roles
);
await services.handleApiReturn(res);
window.parent.postMessage(
{
type: MessageType.PROCESS_UPDATED,
updatedProcess: res.updated_process,
messageId: event.data.messageId,
},
event.origin
);
});
};
const handleDecodePublicData = async (event: MessageEvent) => {
console.log(
`[Router:API] 📨 Message ${MessageType.DECODE_PUBLIC_DATA} reçu`
);
if (!(await services.isPaired())) throw new Error("Device not paired");
const { encodedData } = event.data;
await withToken(event, async () => {
const decodedData = await services.decodeValue(encodedData);
window.parent.postMessage(
{
type: MessageType.PUBLIC_DATA_DECODED,
decodedData,
messageId: event.data.messageId,
},
event.origin
);
});
};
const handleHashValue = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.HASH_VALUE} reçu`);
const { commitedIn, label, fileBlob } = event.data;
await withToken(event, async () => {
const hash = await services.getHashForFile(commitedIn, label, fileBlob);
window.parent.postMessage(
{
type: MessageType.VALUE_HASHED,
hash,
messageId: event.data.messageId,
},
event.origin
);
});
};
const handleGetMerkleProof = async (event: MessageEvent) => {
console.log(
`[Router:API] 📨 Message ${MessageType.GET_MERKLE_PROOF} reçu`
);
const { processState, attributeName } = event.data;
await withToken(event, async () => {
const proof = await services.getMerkleProofForFile(
processState,
attributeName
);
window.parent.postMessage(
{
type: MessageType.MERKLE_PROOF_RETRIEVED,
proof,
messageId: event.data.messageId,
},
event.origin
);
});
};
const handleValidateMerkleProof = async (event: MessageEvent) => {
console.log(
`[Router:API] 📨 Message ${MessageType.VALIDATE_MERKLE_PROOF} reçu`
);
const { merkleProof, documentHash } = event.data;
await withToken(event, async () => {
let parsedMerkleProof: MerkleProofResult;
try {
parsedMerkleProof = JSON.parse(merkleProof);
} catch (e) {
throw new Error("Provided merkleProof is not a valid json object");
}
const res = await services.validateMerkleProof(
parsedMerkleProof,
documentHash
);
window.parent.postMessage(
{
type: MessageType.MERKLE_PROOF_VALIDATED,
isValid: res,
messageId: event.data.messageId,
},
event.origin
);
});
};
window.removeEventListener("message", handleMessage);
window.addEventListener("message", handleMessage);
async function handleMessage(event: MessageEvent) { async function handleMessage(event: MessageEvent) {
// 🛡️ SÉCURITÉ : Ignorer les messages qui ne sont pas des objets (ex: extensions Chrome)
if (!event.data || typeof event.data !== "object") {
return;
}
// 🛡️ FILTRAGE : On ne traite que les messages avec un 'type' connu
if (!event.data.type) return;
try { try {
// Switch/case inchangé ...
switch (event.data.type) { switch (event.data.type) {
case MessageType.REQUEST_LINK: case MessageType.REQUEST_LINK:
await handleRequestLink(event); await handleRequestLink(event);
@ -341,70 +596,56 @@ export class IframeController {
case MessageType.RETRIEVE_DATA: case MessageType.RETRIEVE_DATA:
await handleDecryptState(event); await handleDecryptState(event);
break; break;
case MessageType.VALIDATE_TOKEN:
await handleValidateToken(event);
break;
case MessageType.RENEW_TOKEN:
await handleRenewToken(event);
break;
case MessageType.GET_PAIRING_ID: case MessageType.GET_PAIRING_ID:
await handleGetPairingId(event); await handleGetPairingId(event);
break; break;
case MessageType.CREATE_PROCESS: case MessageType.CREATE_PROCESS:
await handleCreateProcess(event); await handleCreateProcess(event);
break; break;
case MessageType.NOTIFY_UPDATE:
// Cas simples (tokens, notifications...) await handleNotifyUpdate(event);
case MessageType.VALIDATE_TOKEN:
const { accessToken, refreshToken } = event.data;
if (!accessToken || !refreshToken)
throw new Error("Tokens missing");
const isValid = await tokenService.validateToken(
accessToken,
event.origin
);
window.parent.postMessage(
{
type: MessageType.VALIDATE_TOKEN,
isValid,
accessToken,
refreshToken,
messageId: event.data.messageId,
},
event.origin
);
break; break;
case MessageType.VALIDATE_STATE:
case MessageType.RENEW_TOKEN: await handleValidateState(event);
if (!event.data.refreshToken) throw new Error("No refresh token"); break;
const newAccess = await tokenService.refreshAccessToken( case MessageType.UPDATE_PROCESS:
event.data.refreshToken, await handleUpdateProcess(event);
event.origin break;
); case MessageType.DECODE_PUBLIC_DATA:
if (!newAccess) throw new Error("Refresh failed"); await handleDecodePublicData(event);
window.parent.postMessage( break;
{ case MessageType.HASH_VALUE:
type: MessageType.RENEW_TOKEN, await handleHashValue(event);
accessToken: newAccess, break;
refreshToken: event.data.refreshToken, case MessageType.GET_MERKLE_PROOF:
messageId: event.data.messageId, await handleGetMerkleProof(event);
}, break;
event.origin case MessageType.VALIDATE_MERKLE_PROOF:
); await handleValidateMerkleProof(event);
break; break;
default: default:
// Silence sur les types inconnus (peut être un autre protocole) // console.warn("[Router:API] ⚠️ Message non géré reçu:", event.data);
break;
} }
} catch (error: any) { } catch (error: any) {
// En cas d'erreur métier, on prévient le parent const errorMsg = `[Router:API] 💥 Erreur de haut niveau: ${error}`;
errorResponse( errorResponse(errorMsg, event.origin, event.data.messageId);
String(error.message || error),
event.origin,
event.data?.messageId
);
} }
} }
// Ajout du listener unique window.parent.postMessage(
window.addEventListener("message", handleMessage); {
type: MessageType.LISTENING,
// Handshake final : "Je suis prêt" },
window.parent.postMessage({ type: MessageType.LISTENING }, "*"); "*"
console.log("[Router:API] ✅ Listeners actifs. Handshake envoyé."); );
console.log(
"[Router:API] ✅ Tous les listeners sont actifs. Envoi du message LISTENING au parent."
);
} }
} }

View File

@ -130,6 +130,12 @@ export default class Services {
return await this.coreWorker.getDevice2Ready(); return await this.coreWorker.getDevice2Ready();
} }
// NOTE: getSdkClient renvoie null car l'objet WASM n'est pas transférable hors du worker.
// Toute la logique utilisant le client doit être dans le worker.
public get sdkClient() {
return null;
}
public async setProcessId(id: string | null) { public async setProcessId(id: string | null) {
return await this.coreWorker.setProcessId(id); return await this.coreWorker.setProcessId(id);
} }
@ -164,6 +170,11 @@ export default class Services {
public getSpAddress(url: string) { public getSpAddress(url: string) {
return this.networkService.getAllRelays()[url]; return this.networkService.getAllRelays()[url];
} }
// Délégation directe au NetworkService
public printAllRelays() {
// Si NetworkService ne l'expose pas directement dans sa version proxy, on l'ajoute ou on log ici
console.log("Relays:", this.networkService.getAllRelays());
}
// ========================================== // ==========================================
// PROXY - WALLET // PROXY - WALLET