Added withToken func to remove the duplicated code

This commit is contained in:
NicolasCantu 2025-11-25 09:57:57 +01:00
parent 740a29688d
commit 8512b90d36

View File

@ -6,7 +6,11 @@ import { splitPrivateData, isValid32ByteHex } from '../utils/service.utils';
import { MerkleProofResult } from '../../pkg/sdk_client';
export class IframeController {
private static isInitialized = false; // <--- VERROU
static async init() {
if (this.isInitialized) return; // On sort si déjà lancé
// 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...');
@ -36,6 +40,17 @@ export class IframeController {
);
};
// Helper pour vérifier le token avant chaque action sensible
const withToken = async (event: MessageEvent, action: () => Promise<void>) => {
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) ---
const handleRequestLink = async (event: MessageEvent) => {
@ -95,131 +110,121 @@ export class IframeController {
throw new Error('Device already paired — ignoring CREATE_PAIRING request');
}
const { accessToken } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
await withToken(event, async () => {
console.log("[Router:API] 🚀 Démarrage du processus d'appairage...");
console.log("[Router:API] 🚀 Démarrage du processus d'appairage...");
const myAddress = services.getDeviceAddress();
console.log('[Router:API] 1/7: Création du processus de pairing...');
const createPairingProcessReturn = await services.createPairingProcess('', [myAddress]);
const myAddress = services.getDeviceAddress();
console.log('[Router:API] 1/7: Création du processus de pairing...');
const createPairingProcessReturn = await services.createPairingProcess('', [myAddress]);
const pairingId = createPairingProcessReturn.updated_process?.process_id;
const stateId = createPairingProcessReturn.updated_process?.current_process?.states[0]?.state_id as string;
if (!pairingId || !stateId) {
throw new Error('Pairing process creation failed to return valid IDs');
}
console.log(`[Router:API] 2/7: Processus ${pairingId} créé.`);
const pairingId = createPairingProcessReturn.updated_process?.process_id;
const stateId = createPairingProcessReturn.updated_process?.current_process?.states[0]?.state_id as string;
if (!pairingId || !stateId) {
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...");
services.pairDevice(pairingId, [myAddress]);
console.log("[Router:API] 3/7: Enregistrement local de l'appareil...");
services.pairDevice(pairingId, [myAddress]);
console.log('[Router:API] 4/7: Traitement du retour (handleApiReturn)...');
await services.handleApiReturn(createPairingProcessReturn);
console.log('[Router:API] 4/7: Traitement du retour (handleApiReturn)...');
await services.handleApiReturn(createPairingProcessReturn);
console.log('[Router:API] 5/7: Création de la mise à jour PRD...');
const createPrdUpdateReturn = await services.createPrdUpdate(pairingId, stateId);
await services.handleApiReturn(createPrdUpdateReturn);
console.log('[Router:API] 5/7: Création de la mise à jour PRD...');
const createPrdUpdateReturn = await services.createPrdUpdate(pairingId, stateId);
await services.handleApiReturn(createPrdUpdateReturn);
console.log('[Router:API] 6/7: Approbation du changement...');
const approveChangeReturn = await services.approveChange(pairingId, stateId);
await services.handleApiReturn(approveChangeReturn);
console.log('[Router:API] 6/7: Approbation du changement...');
const approveChangeReturn = await services.approveChange(pairingId, stateId);
await services.handleApiReturn(approveChangeReturn);
console.log('[Router:API] 7/7: Confirmation finale du pairing...');
await services.confirmPairing();
console.log('[Router:API] 7/7: Confirmation finale du pairing...');
await services.confirmPairing();
console.log('[Router:API] 🎉 Appairage terminé avec succès !');
console.log('[Router:API] 🎉 Appairage terminé avec succès !');
const successMsg = {
type: MessageType.PAIRING_CREATED,
pairingId,
messageId: event.data.messageId,
};
window.parent.postMessage(successMsg, event.origin);
const successMsg = {
type: MessageType.PAIRING_CREATED,
pairingId,
messageId: event.data.messageId,
};
window.parent.postMessage(successMsg, event.origin);
});
};
const handleGetMyProcesses = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.GET_MY_PROCESSES} reçu`);
if (!services.isPaired()) throw new Error('Device not paired');
const { accessToken } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
await withToken(event, async () => {
const myProcesses = await services.getMyProcesses();
const myProcesses = await services.getMyProcesses();
window.parent.postMessage(
{
type: MessageType.GET_MY_PROCESSES,
myProcesses,
messageId: event.data.messageId,
},
event.origin,
);
window.parent.postMessage(
{
type: MessageType.GET_MY_PROCESSES,
myProcesses,
messageId: event.data.messageId,
},
event.origin,
);
});
};
const handleGetProcesses = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.GET_PROCESSES} reçu`);
if (!services.isPaired()) throw new Error('Device not paired');
const { accessToken } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
await withToken(event, async () => {
const processes = await services.getProcesses();
const processes = await services.getProcesses();
window.parent.postMessage(
{
type: MessageType.PROCESSES_RETRIEVED,
processes,
messageId: event.data.messageId,
},
event.origin,
);
window.parent.postMessage(
{
type: MessageType.PROCESSES_RETRIEVED,
processes,
messageId: event.data.messageId,
},
event.origin,
);
});
};
const handleDecryptState = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.RETRIEVE_DATA} reçu`);
if (!services.isPaired()) throw new Error('Device not paired');
const { processId, stateId, accessToken } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
const { processId, stateId } = event.data;
const process = await services.getProcess(processId);
if (!process) throw new Error("Can't find process");
await withToken(event, async () => {
const process = await services.getProcess(processId);
if (!process) throw new Error("Can't find process");
const state = services.getStateFromId(process, stateId);
if (!state) throw new Error(`Unknown state ${stateId} for process ${processId}`);
const state = services.getStateFromId(process, 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);
console.log(`[Router:API] 🔐 Démarrage du déchiffrement pour ${processId}`);
await services.ensureConnections(process, stateId);
const res: Record<string, any> = {};
for (const attribute of Object.keys(state.pcd_commitment)) {
if (attribute === 'roles' || (state.public_data && state.public_data[attribute])) {
continue;
const res: Record<string, any> = {};
for (const attribute of Object.keys(state.pcd_commitment)) {
if (attribute === 'roles' || (state.public_data && state.public_data[attribute])) {
continue;
}
const decryptedAttribute = await services.decryptAttribute(processId, state, attribute);
if (decryptedAttribute) {
res[attribute] = decryptedAttribute;
}
}
const decryptedAttribute = await services.decryptAttribute(processId, state, attribute);
if (decryptedAttribute) {
res[attribute] = decryptedAttribute;
}
}
console.log(`[Router:API] ✅ Déchiffrement terminé pour ${processId}. ${Object.keys(res).length} attribut(s) déchiffré(s).`);
console.log(`[Router:API] ✅ Déchiffrement terminé pour ${processId}. ${Object.keys(res).length} attribut(s) déchiffré(s).`);
window.parent.postMessage(
{
type: MessageType.DATA_RETRIEVED,
data: res,
messageId: event.data.messageId,
},
event.origin,
);
window.parent.postMessage(
{
type: MessageType.DATA_RETRIEVED,
data: res,
messageId: event.data.messageId,
},
event.origin,
);
});
};
const handleValidateToken = async (event: MessageEvent) => {
@ -295,214 +300,204 @@ export class IframeController {
throw new Error('Device not paired');
}
const { accessToken } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
window.parent.postMessage(
{
type: MessageType.GET_PAIRING_ID,
userPairingId: pairingId,
messageId: event.data.messageId,
},
event.origin,
);
await withToken(event, async () => {
window.parent.postMessage(
{
type: MessageType.GET_PAIRING_ID,
userPairingId: pairingId,
messageId: event.data.messageId,
},
event.origin,
);
});
};
const handleCreateProcess = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.CREATE_PROCESS} reçu`);
if (!services.isPaired()) throw new Error('Device not paired');
const { processData, privateFields, roles, accessToken } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
const { processData, privateFields, roles } = event.data;
console.log('[Router:API] 🚀 Démarrage de la création de processus standard...');
const { privateData, publicData } = splitPrivateData(processData, privateFields);
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, roles);
if (!createProcessReturn.updated_process) {
throw new Error('Empty updated_process in createProcessReturn');
}
console.log('[Router:API] 1/2: Création du processus...');
const createProcessReturn = await services.createProcess(privateData, publicData, roles);
if (!createProcessReturn.updated_process) {
throw new Error('Empty updated_process in createProcessReturn');
}
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);
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);
console.log(`[Router:API] 🎉 Processus ${processId} créé.`);
console.log(`[Router:API] 🎉 Processus ${processId} créé.`);
const res = {
processId,
process,
processData,
};
const res = {
processId,
process,
processData,
};
window.parent.postMessage(
{
type: MessageType.PROCESS_CREATED,
processCreated: res,
messageId: event.data.messageId,
},
event.origin,
);
window.parent.postMessage(
{
type: MessageType.PROCESS_CREATED,
processCreated: res,
messageId: event.data.messageId,
},
event.origin,
);
});
};
const handleNotifyUpdate = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.NOTIFY_UPDATE} reçu`);
if (!services.isPaired()) throw new Error('Device not paired');
const { processId, stateId, accessToken } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
if (!isValid32ByteHex(stateId)) throw new Error('Invalid state id');
const { processId, stateId } = event.data;
const res = await services.createPrdUpdate(processId, stateId);
await services.handleApiReturn(res);
await withToken(event, async () => {
if (!isValid32ByteHex(stateId)) throw new Error('Invalid state id');
window.parent.postMessage(
{
type: MessageType.UPDATE_NOTIFIED,
messageId: event.data.messageId,
},
event.origin,
);
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 (!services.isPaired()) throw new Error('Device not paired');
const { processId, stateId, accessToken } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
const { processId, stateId } = event.data;
const res = await services.approveChange(processId, stateId);
await services.handleApiReturn(res);
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,
);
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 (!services.isPaired()) throw new Error('Device not paired');
const { processId, newData, privateFields, roles, accessToken } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
const { processId, newData, privateFields, roles } = event.data;
console.log(`[Router:API] 🔄 Transfert de la mise à jour de ${processId} au service...`);
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);
// 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);
// --- FIN DE LA MODIFICATION ---
// Nous appelons handleApiReturn ici, comme avant.
await services.handleApiReturn(res);
// --- FIN DE LA MODIFICATION ---
window.parent.postMessage(
{
type: MessageType.PROCESS_UPDATED,
updatedProcess: res.updated_process, // res vient directement de l'appel service
messageId: event.data.messageId,
},
event.origin,
);
window.parent.postMessage(
{
type: MessageType.PROCESS_UPDATED,
updatedProcess: res.updated_process, // res vient directement de l'appel service
messageId: event.data.messageId,
},
event.origin,
);
});
};
const handleDecodePublicData = async (event: MessageEvent) => {
console.log(`[Router:API] 📨 Message ${MessageType.DECODE_PUBLIC_DATA} reçu`);
if (!services.isPaired()) throw new Error('Device not paired');
const { accessToken, encodedData } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
const { encodedData } = event.data;
const decodedData = services.decodeValue(encodedData);
window.parent.postMessage(
{
type: MessageType.PUBLIC_DATA_DECODED,
decodedData,
messageId: event.data.messageId,
},
event.origin,
);
await withToken(event, async () => {
const decodedData = 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 { accessToken, commitedIn, label, fileBlob } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
const { commitedIn, label, fileBlob } = event.data;
const hash = services.getHashForFile(commitedIn, label, fileBlob);
window.parent.postMessage(
{
type: MessageType.VALUE_HASHED,
hash,
messageId: event.data.messageId,
},
event.origin,
);
await withToken(event, async () => {
const hash = 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 { accessToken, processState, attributeName } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
const { processState, attributeName } = event.data;
const proof = services.getMerkleProofForFile(processState, attributeName);
window.parent.postMessage(
{
type: MessageType.MERKLE_PROOF_RETRIEVED,
proof,
messageId: event.data.messageId,
},
event.origin,
);
await withToken(event, async () => {
const proof = 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 { accessToken, merkleProof, documentHash } = event.data;
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
throw new Error('Invalid or expired session token');
}
const { merkleProof, documentHash } = event.data;
let parsedMerkleProof: MerkleProofResult;
try {
parsedMerkleProof = JSON.parse(merkleProof);
} catch (e) {
throw new Error('Provided merkleProof is not a valid json object');
}
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 = services.validateMerkleProof(parsedMerkleProof, documentHash);
window.parent.postMessage(
{
type: MessageType.MERKLE_PROOF_VALIDATED,
isValid: res,
messageId: event.data.messageId,
},
event.origin,
);
const res = services.validateMerkleProof(parsedMerkleProof, documentHash);
window.parent.postMessage(
{
type: MessageType.MERKLE_PROOF_VALIDATED,
isValid: res,
messageId: event.data.messageId,
},
event.origin,
);
});
};
// --- Le "Switchyard" : il reçoit tous les messages et les dispatche ---