Compare commits
1 Commits
225dd27c2c
...
7310f49eb8
| Author | SHA1 | Date | |
|---|---|---|---|
| 7310f49eb8 |
@ -6,7 +6,11 @@ import { splitPrivateData, isValid32ByteHex } from '../utils/service.utils';
|
|||||||
import { MerkleProofResult } from '../../pkg/sdk_client';
|
import { MerkleProofResult } from '../../pkg/sdk_client';
|
||||||
|
|
||||||
export class IframeController {
|
export class IframeController {
|
||||||
|
private static isInitialized = false; // <--- VERROU
|
||||||
|
|
||||||
static async init() {
|
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
|
// On ne lance l'écoute que si on est dans une iframe
|
||||||
if (window.self !== window.top) {
|
if (window.self !== window.top) {
|
||||||
console.log('[IframeController] 📡 Mode Iframe détecté. Démarrage des listeners API...');
|
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) ---
|
// --- Définitions des gestionnaires (Handlers) ---
|
||||||
|
|
||||||
const handleRequestLink = async (event: MessageEvent) => {
|
const handleRequestLink = async (event: MessageEvent) => {
|
||||||
@ -95,131 +110,121 @@ export class IframeController {
|
|||||||
throw new Error('Device already paired — ignoring CREATE_PAIRING request');
|
throw new Error('Device already paired — ignoring CREATE_PAIRING request');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { accessToken } = event.data;
|
await withToken(event, async () => {
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
console.log("[Router:API] 🚀 Démarrage du processus d'appairage...");
|
||||||
throw new Error('Invalid or expired session token');
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
const pairingId = createPairingProcessReturn.updated_process?.process_id;
|
||||||
console.log('[Router:API] 1/7: Création du processus de pairing...');
|
const stateId = createPairingProcessReturn.updated_process?.current_process?.states[0]?.state_id as string;
|
||||||
const createPairingProcessReturn = await services.createPairingProcess('', [myAddress]);
|
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;
|
console.log("[Router:API] 3/7: Enregistrement local de l'appareil...");
|
||||||
const stateId = createPairingProcessReturn.updated_process?.current_process?.states[0]?.state_id as string;
|
services.pairDevice(pairingId, [myAddress]);
|
||||||
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...");
|
console.log('[Router:API] 4/7: Traitement du retour (handleApiReturn)...');
|
||||||
services.pairDevice(pairingId, [myAddress]);
|
await services.handleApiReturn(createPairingProcessReturn);
|
||||||
|
|
||||||
console.log('[Router:API] 4/7: Traitement du retour (handleApiReturn)...');
|
console.log('[Router:API] 5/7: Création de la mise à jour PRD...');
|
||||||
await services.handleApiReturn(createPairingProcessReturn);
|
const createPrdUpdateReturn = await services.createPrdUpdate(pairingId, stateId);
|
||||||
|
await services.handleApiReturn(createPrdUpdateReturn);
|
||||||
|
|
||||||
console.log('[Router:API] 5/7: Création de la mise à jour PRD...');
|
console.log('[Router:API] 6/7: Approbation du changement...');
|
||||||
const createPrdUpdateReturn = await services.createPrdUpdate(pairingId, stateId);
|
const approveChangeReturn = await services.approveChange(pairingId, stateId);
|
||||||
await services.handleApiReturn(createPrdUpdateReturn);
|
await services.handleApiReturn(approveChangeReturn);
|
||||||
|
|
||||||
console.log('[Router:API] 6/7: Approbation du changement...');
|
console.log('[Router:API] 7/7: Confirmation finale du pairing...');
|
||||||
const approveChangeReturn = await services.approveChange(pairingId, stateId);
|
await services.confirmPairing();
|
||||||
await services.handleApiReturn(approveChangeReturn);
|
|
||||||
|
|
||||||
console.log('[Router:API] 7/7: Confirmation finale du pairing...');
|
console.log('[Router:API] 🎉 Appairage terminé avec succès !');
|
||||||
await services.confirmPairing();
|
|
||||||
|
|
||||||
console.log('[Router:API] 🎉 Appairage terminé avec succès !');
|
const successMsg = {
|
||||||
|
type: MessageType.PAIRING_CREATED,
|
||||||
const successMsg = {
|
pairingId,
|
||||||
type: MessageType.PAIRING_CREATED,
|
messageId: event.data.messageId,
|
||||||
pairingId,
|
};
|
||||||
messageId: event.data.messageId,
|
window.parent.postMessage(successMsg, 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`);
|
console.log(`[Router:API] 📨 Message ${MessageType.GET_MY_PROCESSES} reçu`);
|
||||||
if (!services.isPaired()) throw new Error('Device not paired');
|
if (!services.isPaired()) throw new Error('Device not paired');
|
||||||
|
|
||||||
const { accessToken } = event.data;
|
await withToken(event, async () => {
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
const myProcesses = await services.getMyProcesses();
|
||||||
throw new Error('Invalid or expired session token');
|
|
||||||
}
|
|
||||||
|
|
||||||
const myProcesses = await services.getMyProcesses();
|
window.parent.postMessage(
|
||||||
|
{
|
||||||
window.parent.postMessage(
|
type: MessageType.GET_MY_PROCESSES,
|
||||||
{
|
myProcesses,
|
||||||
type: MessageType.GET_MY_PROCESSES,
|
messageId: event.data.messageId,
|
||||||
myProcesses,
|
},
|
||||||
messageId: event.data.messageId,
|
event.origin,
|
||||||
},
|
);
|
||||||
event.origin,
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGetProcesses = async (event: MessageEvent) => {
|
const handleGetProcesses = async (event: MessageEvent) => {
|
||||||
console.log(`[Router:API] 📨 Message ${MessageType.GET_PROCESSES} reçu`);
|
console.log(`[Router:API] 📨 Message ${MessageType.GET_PROCESSES} reçu`);
|
||||||
if (!services.isPaired()) throw new Error('Device not paired');
|
if (!services.isPaired()) throw new Error('Device not paired');
|
||||||
|
|
||||||
const { accessToken } = event.data;
|
await withToken(event, async () => {
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
const processes = await services.getProcesses();
|
||||||
throw new Error('Invalid or expired session token');
|
|
||||||
}
|
|
||||||
|
|
||||||
const processes = await services.getProcesses();
|
window.parent.postMessage(
|
||||||
|
{
|
||||||
window.parent.postMessage(
|
type: MessageType.PROCESSES_RETRIEVED,
|
||||||
{
|
processes,
|
||||||
type: MessageType.PROCESSES_RETRIEVED,
|
messageId: event.data.messageId,
|
||||||
processes,
|
},
|
||||||
messageId: event.data.messageId,
|
event.origin,
|
||||||
},
|
);
|
||||||
event.origin,
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDecryptState = async (event: MessageEvent) => {
|
const handleDecryptState = async (event: MessageEvent) => {
|
||||||
console.log(`[Router:API] 📨 Message ${MessageType.RETRIEVE_DATA} reçu`);
|
console.log(`[Router:API] 📨 Message ${MessageType.RETRIEVE_DATA} reçu`);
|
||||||
if (!services.isPaired()) throw new Error('Device not paired');
|
if (!services.isPaired()) throw new Error('Device not paired');
|
||||||
|
|
||||||
const { processId, stateId, accessToken } = event.data;
|
const { processId, stateId } = event.data;
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
|
||||||
throw new Error('Invalid or expired session token');
|
|
||||||
}
|
|
||||||
|
|
||||||
const process = await services.getProcess(processId);
|
await withToken(event, async () => {
|
||||||
if (!process) throw new Error("Can't find process");
|
const process = await services.getProcess(processId);
|
||||||
|
if (!process) throw new Error("Can't find process");
|
||||||
|
|
||||||
const state = services.getStateFromId(process, stateId);
|
const state = services.getStateFromId(process, stateId);
|
||||||
if (!state) throw new Error(`Unknown state ${stateId} for process ${processId}`);
|
if (!state) throw new Error(`Unknown state ${stateId} for process ${processId}`);
|
||||||
|
|
||||||
console.log(`[Router:API] 🔐 Démarrage du déchiffrement pour ${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> = {};
|
||||||
for (const attribute of Object.keys(state.pcd_commitment)) {
|
for (const attribute of Object.keys(state.pcd_commitment)) {
|
||||||
if (attribute === 'roles' || (state.public_data && state.public_data[attribute])) {
|
if (attribute === 'roles' || (state.public_data && state.public_data[attribute])) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
const decryptedAttribute = await services.decryptAttribute(processId, state, attribute);
|
||||||
|
if (decryptedAttribute) {
|
||||||
|
res[attribute] = decryptedAttribute;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const decryptedAttribute = await services.decryptAttribute(processId, state, attribute);
|
console.log(`[Router:API] ✅ Déchiffrement terminé pour ${processId}. ${Object.keys(res).length} attribut(s) déchiffré(s).`);
|
||||||
if (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(
|
||||||
{
|
{
|
||||||
type: MessageType.DATA_RETRIEVED,
|
type: MessageType.DATA_RETRIEVED,
|
||||||
data: res,
|
data: res,
|
||||||
messageId: event.data.messageId,
|
messageId: event.data.messageId,
|
||||||
},
|
},
|
||||||
event.origin,
|
event.origin,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleValidateToken = async (event: MessageEvent) => {
|
const handleValidateToken = async (event: MessageEvent) => {
|
||||||
@ -295,214 +300,204 @@ export class IframeController {
|
|||||||
throw new Error('Device not paired');
|
throw new Error('Device not paired');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { accessToken } = event.data;
|
await withToken(event, async () => {
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
window.parent.postMessage(
|
||||||
throw new Error('Invalid or expired session token');
|
{
|
||||||
}
|
type: MessageType.GET_PAIRING_ID,
|
||||||
|
userPairingId: pairingId,
|
||||||
window.parent.postMessage(
|
messageId: event.data.messageId,
|
||||||
{
|
},
|
||||||
type: MessageType.GET_PAIRING_ID,
|
event.origin,
|
||||||
userPairingId: pairingId,
|
);
|
||||||
messageId: event.data.messageId,
|
});
|
||||||
},
|
|
||||||
event.origin,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateProcess = async (event: MessageEvent) => {
|
const handleCreateProcess = async (event: MessageEvent) => {
|
||||||
console.log(`[Router:API] 📨 Message ${MessageType.CREATE_PROCESS} reçu`);
|
console.log(`[Router:API] 📨 Message ${MessageType.CREATE_PROCESS} reçu`);
|
||||||
if (!services.isPaired()) throw new Error('Device not paired');
|
if (!services.isPaired()) throw new Error('Device not paired');
|
||||||
|
|
||||||
const { processData, privateFields, roles, accessToken } = event.data;
|
const { processData, privateFields, roles } = event.data;
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
|
||||||
throw new Error('Invalid or expired session token');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[Router:API] 🚀 Démarrage de la création de processus standard...');
|
await withToken(event, async () => {
|
||||||
const { privateData, publicData } = splitPrivateData(processData, privateFields);
|
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...');
|
console.log('[Router:API] 1/2: Création du processus...');
|
||||||
const createProcessReturn = await services.createProcess(privateData, publicData, roles);
|
const createProcessReturn = await services.createProcess(privateData, publicData, roles);
|
||||||
if (!createProcessReturn.updated_process) {
|
if (!createProcessReturn.updated_process) {
|
||||||
throw new Error('Empty updated_process in createProcessReturn');
|
throw new Error('Empty updated_process in createProcessReturn');
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
const stateId = process.states[0].state_id;
|
const stateId = process.states[0].state_id;
|
||||||
console.log(`[Router:API] 2/2: Processus ${processId} créé. Traitement...`);
|
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éé.`);
|
console.log(`[Router:API] 🎉 Processus ${processId} créé.`);
|
||||||
|
|
||||||
const res = {
|
const res = {
|
||||||
processId,
|
processId,
|
||||||
process,
|
process,
|
||||||
processData,
|
processData,
|
||||||
};
|
};
|
||||||
|
|
||||||
window.parent.postMessage(
|
window.parent.postMessage(
|
||||||
{
|
{
|
||||||
type: MessageType.PROCESS_CREATED,
|
type: MessageType.PROCESS_CREATED,
|
||||||
processCreated: res,
|
processCreated: res,
|
||||||
messageId: event.data.messageId,
|
messageId: event.data.messageId,
|
||||||
},
|
},
|
||||||
event.origin,
|
event.origin,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNotifyUpdate = async (event: MessageEvent) => {
|
const handleNotifyUpdate = async (event: MessageEvent) => {
|
||||||
console.log(`[Router:API] 📨 Message ${MessageType.NOTIFY_UPDATE} reçu`);
|
console.log(`[Router:API] 📨 Message ${MessageType.NOTIFY_UPDATE} reçu`);
|
||||||
if (!services.isPaired()) throw new Error('Device not paired');
|
if (!services.isPaired()) throw new Error('Device not paired');
|
||||||
|
|
||||||
const { processId, stateId, accessToken } = event.data;
|
const { processId, stateId } = 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 res = await services.createPrdUpdate(processId, stateId);
|
await withToken(event, async () => {
|
||||||
await services.handleApiReturn(res);
|
if (!isValid32ByteHex(stateId)) throw new Error('Invalid state id');
|
||||||
|
|
||||||
window.parent.postMessage(
|
const res = await services.createPrdUpdate(processId, stateId);
|
||||||
{
|
await services.handleApiReturn(res);
|
||||||
type: MessageType.UPDATE_NOTIFIED,
|
|
||||||
messageId: event.data.messageId,
|
window.parent.postMessage(
|
||||||
},
|
{
|
||||||
event.origin,
|
type: MessageType.UPDATE_NOTIFIED,
|
||||||
);
|
messageId: event.data.messageId,
|
||||||
|
},
|
||||||
|
event.origin,
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleValidateState = async (event: MessageEvent) => {
|
const handleValidateState = async (event: MessageEvent) => {
|
||||||
console.log(`[Router:API] 📨 Message ${MessageType.VALIDATE_STATE} reçu`);
|
console.log(`[Router:API] 📨 Message ${MessageType.VALIDATE_STATE} reçu`);
|
||||||
if (!services.isPaired()) throw new Error('Device not paired');
|
if (!services.isPaired()) throw new Error('Device not paired');
|
||||||
|
|
||||||
const { processId, stateId, accessToken } = event.data;
|
const { processId, stateId } = event.data;
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
|
||||||
throw new Error('Invalid or expired session token');
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await services.approveChange(processId, stateId);
|
await withToken(event, async () => {
|
||||||
await services.handleApiReturn(res);
|
const res = await services.approveChange(processId, stateId);
|
||||||
|
await services.handleApiReturn(res);
|
||||||
|
|
||||||
window.parent.postMessage(
|
window.parent.postMessage(
|
||||||
{
|
{
|
||||||
type: MessageType.STATE_VALIDATED,
|
type: MessageType.STATE_VALIDATED,
|
||||||
validatedProcess: res.updated_process,
|
validatedProcess: res.updated_process,
|
||||||
messageId: event.data.messageId,
|
messageId: event.data.messageId,
|
||||||
},
|
},
|
||||||
event.origin,
|
event.origin,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdateProcess = async (event: MessageEvent) => {
|
const handleUpdateProcess = async (event: MessageEvent) => {
|
||||||
console.log(`[Router:API] 📨 Message ${MessageType.UPDATE_PROCESS} reçu`);
|
console.log(`[Router:API] 📨 Message ${MessageType.UPDATE_PROCESS} reçu`);
|
||||||
if (!services.isPaired()) throw new Error('Device not paired');
|
if (!services.isPaired()) throw new Error('Device not paired');
|
||||||
|
|
||||||
const { processId, newData, privateFields, roles, accessToken } = event.data;
|
const { processId, newData, privateFields, roles } = event.data;
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
|
||||||
throw new Error('Invalid or expired session token');
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
// 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);
|
const res = await services.updateProcess(processId, newData, privateFields, roles);
|
||||||
|
|
||||||
// Nous appelons handleApiReturn ici, comme avant.
|
// Nous appelons handleApiReturn ici, comme avant.
|
||||||
await services.handleApiReturn(res);
|
await services.handleApiReturn(res);
|
||||||
// --- FIN DE LA MODIFICATION ---
|
// --- FIN DE LA MODIFICATION ---
|
||||||
|
|
||||||
window.parent.postMessage(
|
window.parent.postMessage(
|
||||||
{
|
{
|
||||||
type: MessageType.PROCESS_UPDATED,
|
type: MessageType.PROCESS_UPDATED,
|
||||||
updatedProcess: res.updated_process, // res vient directement de l'appel service
|
updatedProcess: res.updated_process, // res vient directement de l'appel service
|
||||||
messageId: event.data.messageId,
|
messageId: event.data.messageId,
|
||||||
},
|
},
|
||||||
event.origin,
|
event.origin,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDecodePublicData = async (event: MessageEvent) => {
|
const handleDecodePublicData = async (event: MessageEvent) => {
|
||||||
console.log(`[Router:API] 📨 Message ${MessageType.DECODE_PUBLIC_DATA} reçu`);
|
console.log(`[Router:API] 📨 Message ${MessageType.DECODE_PUBLIC_DATA} reçu`);
|
||||||
if (!services.isPaired()) throw new Error('Device not paired');
|
if (!services.isPaired()) throw new Error('Device not paired');
|
||||||
|
|
||||||
const { accessToken, encodedData } = event.data;
|
const { encodedData } = event.data;
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
|
||||||
throw new Error('Invalid or expired session token');
|
|
||||||
}
|
|
||||||
|
|
||||||
const decodedData = services.decodeValue(encodedData);
|
await withToken(event, async () => {
|
||||||
window.parent.postMessage(
|
const decodedData = services.decodeValue(encodedData);
|
||||||
{
|
window.parent.postMessage(
|
||||||
type: MessageType.PUBLIC_DATA_DECODED,
|
{
|
||||||
decodedData,
|
type: MessageType.PUBLIC_DATA_DECODED,
|
||||||
messageId: event.data.messageId,
|
decodedData,
|
||||||
},
|
messageId: event.data.messageId,
|
||||||
event.origin,
|
},
|
||||||
);
|
event.origin,
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleHashValue = async (event: MessageEvent) => {
|
const handleHashValue = async (event: MessageEvent) => {
|
||||||
console.log(`[Router:API] 📨 Message ${MessageType.HASH_VALUE} reçu`);
|
console.log(`[Router:API] 📨 Message ${MessageType.HASH_VALUE} reçu`);
|
||||||
const { accessToken, commitedIn, label, fileBlob } = event.data;
|
const { commitedIn, label, fileBlob } = event.data;
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
|
||||||
throw new Error('Invalid or expired session token');
|
|
||||||
}
|
|
||||||
|
|
||||||
const hash = services.getHashForFile(commitedIn, label, fileBlob);
|
await withToken(event, async () => {
|
||||||
window.parent.postMessage(
|
const hash = services.getHashForFile(commitedIn, label, fileBlob);
|
||||||
{
|
window.parent.postMessage(
|
||||||
type: MessageType.VALUE_HASHED,
|
{
|
||||||
hash,
|
type: MessageType.VALUE_HASHED,
|
||||||
messageId: event.data.messageId,
|
hash,
|
||||||
},
|
messageId: event.data.messageId,
|
||||||
event.origin,
|
},
|
||||||
);
|
event.origin,
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGetMerkleProof = async (event: MessageEvent) => {
|
const handleGetMerkleProof = async (event: MessageEvent) => {
|
||||||
console.log(`[Router:API] 📨 Message ${MessageType.GET_MERKLE_PROOF} reçu`);
|
console.log(`[Router:API] 📨 Message ${MessageType.GET_MERKLE_PROOF} reçu`);
|
||||||
const { accessToken, processState, attributeName } = event.data;
|
const { processState, attributeName } = event.data;
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
|
||||||
throw new Error('Invalid or expired session token');
|
|
||||||
}
|
|
||||||
|
|
||||||
const proof = services.getMerkleProofForFile(processState, attributeName);
|
await withToken(event, async () => {
|
||||||
window.parent.postMessage(
|
const proof = services.getMerkleProofForFile(processState, attributeName);
|
||||||
{
|
window.parent.postMessage(
|
||||||
type: MessageType.MERKLE_PROOF_RETRIEVED,
|
{
|
||||||
proof,
|
type: MessageType.MERKLE_PROOF_RETRIEVED,
|
||||||
messageId: event.data.messageId,
|
proof,
|
||||||
},
|
messageId: event.data.messageId,
|
||||||
event.origin,
|
},
|
||||||
);
|
event.origin,
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleValidateMerkleProof = async (event: MessageEvent) => {
|
const handleValidateMerkleProof = async (event: MessageEvent) => {
|
||||||
console.log(`[Router:API] 📨 Message ${MessageType.VALIDATE_MERKLE_PROOF} reçu`);
|
console.log(`[Router:API] 📨 Message ${MessageType.VALIDATE_MERKLE_PROOF} reçu`);
|
||||||
const { accessToken, merkleProof, documentHash } = event.data;
|
const { merkleProof, documentHash } = event.data;
|
||||||
if (!accessToken || !(await tokenService.validateToken(accessToken, event.origin))) {
|
|
||||||
throw new Error('Invalid or expired session token');
|
|
||||||
}
|
|
||||||
|
|
||||||
let parsedMerkleProof: MerkleProofResult;
|
await withToken(event, async () => {
|
||||||
try {
|
let parsedMerkleProof: MerkleProofResult;
|
||||||
parsedMerkleProof = JSON.parse(merkleProof);
|
try {
|
||||||
} catch (e) {
|
parsedMerkleProof = JSON.parse(merkleProof);
|
||||||
throw new Error('Provided merkleProof is not a valid json object');
|
} catch (e) {
|
||||||
}
|
throw new Error('Provided merkleProof is not a valid json object');
|
||||||
|
}
|
||||||
|
|
||||||
const res = services.validateMerkleProof(parsedMerkleProof, documentHash);
|
const res = services.validateMerkleProof(parsedMerkleProof, documentHash);
|
||||||
window.parent.postMessage(
|
window.parent.postMessage(
|
||||||
{
|
{
|
||||||
type: MessageType.MERKLE_PROOF_VALIDATED,
|
type: MessageType.MERKLE_PROOF_VALIDATED,
|
||||||
isValid: res,
|
isValid: res,
|
||||||
messageId: event.data.messageId,
|
messageId: event.data.messageId,
|
||||||
},
|
},
|
||||||
event.origin,
|
event.origin,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Le "Switchyard" : il reçoit tous les messages et les dispatche ---
|
// --- Le "Switchyard" : il reçoit tous les messages et les dispatche ---
|
||||||
|
|||||||
@ -1,89 +1,135 @@
|
|||||||
import { AnkFlag } from 'pkg/sdk_client';
|
import { AnkFlag } from '../../pkg/sdk_client'; // Vérifie le chemin vers pkg
|
||||||
import Services from './service';
|
import Services from './service';
|
||||||
|
|
||||||
let ws: WebSocket;
|
let ws: WebSocket | null = null;
|
||||||
let messageQueue: string[] = [];
|
let messageQueue: string[] = [];
|
||||||
|
let reconnectInterval = 1000; // Délai initial de 1s avant reconnexion
|
||||||
|
const MAX_RECONNECT_INTERVAL = 30000; // Max 30s
|
||||||
|
let isConnecting = false;
|
||||||
|
let urlReference: string = '';
|
||||||
|
let pingIntervalId: any = null;
|
||||||
|
|
||||||
export async function initWebsocket(url: string) {
|
export async function initWebsocket(url: string) {
|
||||||
ws = new WebSocket(url);
|
urlReference = url;
|
||||||
|
connect();
|
||||||
if (ws !== null) {
|
}
|
||||||
ws.onopen = async (event) => {
|
|
||||||
console.log('WebSocket connection established');
|
function connect() {
|
||||||
|
if (isConnecting || (ws && ws.readyState === WebSocket.OPEN)) return;
|
||||||
while (messageQueue.length > 0) {
|
isConnecting = true;
|
||||||
const message = messageQueue.shift();
|
|
||||||
if (message) {
|
console.log(`[WS] 🔌 Tentative de connexion à ${urlReference}...`);
|
||||||
ws.send(message);
|
ws = new WebSocket(urlReference);
|
||||||
}
|
|
||||||
}
|
ws.onopen = async () => {
|
||||||
};
|
console.log('[WS] ✅ Connexion établie !');
|
||||||
|
isConnecting = false;
|
||||||
// Listen for messages
|
reconnectInterval = 1000; // Reset du délai
|
||||||
ws.onmessage = (event) => {
|
|
||||||
const msgData = event.data;
|
// Démarrer le Heartbeat (Ping pour garder la connexion vivante)
|
||||||
|
startHeartbeat();
|
||||||
// console.log("Received text message: ", msgData);
|
|
||||||
(async () => {
|
// Vider la file d'attente (messages envoyés pendant la coupure)
|
||||||
if (typeof msgData === 'string') {
|
while (messageQueue.length > 0) {
|
||||||
try {
|
const message = messageQueue.shift();
|
||||||
const parsedMessage = JSON.parse(msgData);
|
if (message) ws?.send(message);
|
||||||
const services = await Services.getInstance();
|
}
|
||||||
switch (parsedMessage.flag) {
|
};
|
||||||
case 'Handshake':
|
|
||||||
await services.handleHandshakeMsg(url, parsedMessage.content);
|
ws.onmessage = (event) => {
|
||||||
break;
|
const msgData = event.data;
|
||||||
case 'NewTx':
|
if (typeof msgData === 'string') {
|
||||||
await services.parseNewTx(parsedMessage.content);
|
(async () => {
|
||||||
break;
|
try {
|
||||||
case 'Cipher':
|
const parsedMessage = JSON.parse(msgData);
|
||||||
await services.parseCipher(parsedMessage.content);
|
const services = await Services.getInstance();
|
||||||
break;
|
|
||||||
case 'Commit':
|
// Gestion des messages
|
||||||
// Basically if we see this it means we have an error
|
switch (parsedMessage.flag) {
|
||||||
await services.handleCommitError(parsedMessage.content);
|
case 'Handshake':
|
||||||
break;
|
await services.handleHandshakeMsg(urlReference, parsedMessage.content);
|
||||||
}
|
break;
|
||||||
} catch (error) {
|
case 'NewTx':
|
||||||
console.error('Received an invalid message:', error);
|
await services.parseNewTx(parsedMessage.content);
|
||||||
}
|
break;
|
||||||
} else {
|
case 'Cipher':
|
||||||
console.error('Received a non-string message');
|
await services.parseCipher(parsedMessage.content);
|
||||||
}
|
break;
|
||||||
})();
|
case 'Commit':
|
||||||
};
|
await services.handleCommitError(parsedMessage.content);
|
||||||
|
break;
|
||||||
// Listen for possible errors
|
// Ajoute d'autres cas si nécessaire
|
||||||
ws.onerror = (event) => {
|
default:
|
||||||
console.error('WebSocket error:', event);
|
// console.log('[WS] Message reçu:', parsedMessage.flag);
|
||||||
};
|
}
|
||||||
|
} catch (error) {
|
||||||
// Listen for when the connection is closed
|
console.error('[WS] Erreur traitement message:', error);
|
||||||
ws.onclose = (event) => {
|
}
|
||||||
console.log('WebSocket is closed now.');
|
})();
|
||||||
};
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
ws.onerror = (event) => {
|
||||||
|
console.error('[WS] 💥 Erreur:', event);
|
||||||
|
// Pas besoin de reconnecter ici, onclose sera appelé juste après
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = (event) => {
|
||||||
|
isConnecting = false;
|
||||||
|
stopHeartbeat();
|
||||||
|
console.warn(`[WS] ⚠️ Déconnecté (Code: ${event.code}). Reconnexion dans ${reconnectInterval / 1000}s...`);
|
||||||
|
|
||||||
|
// Reconnexion exponentielle (1s, 1.5s, 2.25s...)
|
||||||
|
setTimeout(() => {
|
||||||
|
connect();
|
||||||
|
reconnectInterval = Math.min(reconnectInterval * 1.5, MAX_RECONNECT_INTERVAL);
|
||||||
|
}, reconnectInterval);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function startHeartbeat() {
|
||||||
|
stopHeartbeat();
|
||||||
|
// Envoie un ping toutes les 30 secondes pour éviter que le serveur ou le navigateur ne coupe la connexion
|
||||||
|
pingIntervalId = setInterval(() => {
|
||||||
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||||
|
// Adapter selon ce que ton serveur attend comme Ping, ou envoyer un message vide
|
||||||
|
// ws.send(JSON.stringify({ flag: 'Ping', content: '' }));
|
||||||
|
}
|
||||||
|
}, 30000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopHeartbeat() {
|
||||||
|
if (pingIntervalId) clearInterval(pingIntervalId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to send messages
|
|
||||||
export function sendMessage(flag: AnkFlag, message: string): void {
|
export function sendMessage(flag: AnkFlag, message: string): void {
|
||||||
if (ws.readyState === WebSocket.OPEN) {
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||||
const networkMessage = {
|
const networkMessage = {
|
||||||
flag: flag,
|
flag: flag,
|
||||||
content: message,
|
content: message,
|
||||||
};
|
};
|
||||||
console.log('Sending message of type:', flag);
|
|
||||||
ws.send(JSON.stringify(networkMessage));
|
ws.send(JSON.stringify(networkMessage));
|
||||||
} else {
|
} else {
|
||||||
console.error('WebSocket is not open. ReadyState:', ws.readyState);
|
console.warn(`[WS] Pas connecté. Message '${flag}' mis en file d'attente.`);
|
||||||
messageQueue.push(message);
|
const networkMessage = {
|
||||||
|
flag: flag,
|
||||||
|
content: message,
|
||||||
|
};
|
||||||
|
messageQueue.push(JSON.stringify(networkMessage));
|
||||||
|
|
||||||
|
// Si on n'est pas déjà en train de se connecter, on force une tentative
|
||||||
|
if (!isConnecting) connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUrl(): string {
|
export function getUrl(): string {
|
||||||
return ws.url;
|
return urlReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to close the WebSocket connection
|
|
||||||
export function close(): void {
|
export function close(): void {
|
||||||
ws.close();
|
if (ws) {
|
||||||
|
ws.onclose = null; // On évite la reconnexion auto si fermeture volontaire
|
||||||
|
stopHeartbeat();
|
||||||
|
ws.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user