Compare commits
3 Commits
8cc016c2a5
...
bd0e3b9114
| Author | SHA1 | Date | |
|---|---|---|---|
| bd0e3b9114 | |||
| 129b7cf32e | |||
| 61c4c7c831 |
@ -529,8 +529,7 @@ export async function registerAllListeners() {
|
|||||||
console.log('[Router:API] 🚀 Démarrage de la création de processus standard...');
|
console.log('[Router:API] 🚀 Démarrage de la création de processus standard...');
|
||||||
const { privateData, publicData } = splitPrivateData(processData, privateFields);
|
const { privateData, publicData } = splitPrivateData(processData, privateFields);
|
||||||
|
|
||||||
// --- 1. CRÉATION DU PROCESSUS ---
|
console.log('[Router:API] 1/2: Création du processus...');
|
||||||
console.log('[Router:API] 1/4: 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');
|
||||||
@ -539,20 +538,10 @@ export async function registerAllListeners() {
|
|||||||
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/4: Processus ${processId} créé. Traitement...`);
|
console.log(`[Router:API] 2/2: Processus ${processId} créé. Traitement...`);
|
||||||
await services.handleApiReturn(createProcessReturn);
|
await services.handleApiReturn(createProcessReturn);
|
||||||
|
|
||||||
// --- 2. MISE À JOUR PRD ---
|
console.log(`[Router:API] 🎉 Processus ${processId} créé.`);
|
||||||
console.log('[Router:API] 3/4: Création de la mise à jour PRD...');
|
|
||||||
const createPrdUpdateReturn = await services.createPrdUpdate(processId, stateId);
|
|
||||||
await services.handleApiReturn(createPrdUpdateReturn);
|
|
||||||
|
|
||||||
// --- 3. APPROBATION DU CHANGEMENT ---
|
|
||||||
console.log('[Router:API] 4/4: Approbation du changement...');
|
|
||||||
const approveChangeReturn = await services.approveChange(processId, stateId);
|
|
||||||
await services.handleApiReturn(approveChangeReturn);
|
|
||||||
|
|
||||||
console.log(`[Router:API] 🎉 Processus ${processId} créé et auto-approuvé.`);
|
|
||||||
|
|
||||||
const res = {
|
const res = {
|
||||||
processId,
|
processId,
|
||||||
@ -779,12 +768,7 @@ export async function registerAllListeners() {
|
|||||||
window.addEventListener('message', handleMessage);
|
window.addEventListener('message', handleMessage);
|
||||||
|
|
||||||
async function handleMessage(event: MessageEvent) {
|
async function handleMessage(event: MessageEvent) {
|
||||||
// Le 'switch' est dans un 'try...catch'
|
|
||||||
// Grâce au 'await' sur chaque 'handle', si l'un d'eux échoue (throw),
|
|
||||||
// l'erreur sera interceptée ici et renvoyée proprement.
|
|
||||||
try {
|
try {
|
||||||
// AMÉLIORATION CRITIQUE: Ajout de 'await' à chaque appel
|
|
||||||
// pour que le try/catch puisse intercepter les erreurs.
|
|
||||||
switch (event.data.type) {
|
switch (event.data.type) {
|
||||||
case MessageType.REQUEST_LINK:
|
case MessageType.REQUEST_LINK:
|
||||||
await handleRequestLink(event);
|
await handleRequestLink(event);
|
||||||
@ -813,10 +797,6 @@ export async function registerAllListeners() {
|
|||||||
case MessageType.CREATE_PROCESS:
|
case MessageType.CREATE_PROCESS:
|
||||||
await handleCreateProcess(event);
|
await handleCreateProcess(event);
|
||||||
break;
|
break;
|
||||||
case MessageType.CREATE_CONVERSATION:
|
|
||||||
// @ts-ignore - 'handleCreateConversationProcess' n'est pas défini dans le fichier
|
|
||||||
await handleCreateConversationProcess(event);
|
|
||||||
break;
|
|
||||||
case MessageType.NOTIFY_UPDATE:
|
case MessageType.NOTIFY_UPDATE:
|
||||||
await handleNotifyUpdate(event);
|
await handleNotifyUpdate(event);
|
||||||
break;
|
break;
|
||||||
@ -839,16 +819,14 @@ export async function registerAllListeners() {
|
|||||||
await handleValidateMerkleProof(event);
|
await handleValidateMerkleProof(event);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`[Router:API] ⚠️ Message non géré reçu: ${event.data.type}`);
|
console.warn('[Router:API] ⚠️ Message non géré reçu:', event.data);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// C'est le "filet de sécurité" global
|
|
||||||
const errorMsg = `[Router:API] 💥 Erreur de haut niveau: ${error.message || error}`;
|
const errorMsg = `[Router:API] 💥 Erreur de haut niveau: ${error.message || error}`;
|
||||||
errorResponse(errorMsg, event.origin, event.data.messageId);
|
errorResponse(errorMsg, event.origin, event.data.messageId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notifie l'application parente que l'Iframe (le "serveur") est prête
|
|
||||||
window.parent.postMessage(
|
window.parent.postMessage(
|
||||||
{
|
{
|
||||||
type: MessageType.LISTENING,
|
type: MessageType.LISTENING,
|
||||||
|
|||||||
@ -809,7 +809,6 @@ export default class Services {
|
|||||||
console.error(`[Services:parseCipher] 💥 Échec critique du déchiffrement: ${e}`);
|
console.error(`[Services:parseCipher] 💥 Échec critique du déchiffrement: ${e}`);
|
||||||
console.warn(`[Services:parseCipher] Contrainte d'anonymat: L'expéditeur est inconnu.`);
|
console.warn(`[Services:parseCipher] Contrainte d'anonymat: L'expéditeur est inconnu.`);
|
||||||
|
|
||||||
// --- 🚨 NOUVELLE LOGIQUE 🚨 ---
|
|
||||||
// On ne supprime rien. On lève juste un drapeau pour
|
// On ne supprime rien. On lève juste un drapeau pour
|
||||||
// forcer 'ensureConnections' à se méfier de la BDD.
|
// forcer 'ensureConnections' à se méfier de la BDD.
|
||||||
console.warn(`[Services:parseCipher] 🚩 ACTION: Levée du drapeau 'secretsAreCompromised'.`);
|
console.warn(`[Services:parseCipher] 🚩 ACTION: Levée du drapeau 'secretsAreCompromised'.`);
|
||||||
@ -817,7 +816,6 @@ export default class Services {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- AMÉLIORATION: Refactorisé en sous-fonctions ---
|
|
||||||
async parseNewTx(newTxMsg: string) {
|
async parseNewTx(newTxMsg: string) {
|
||||||
console.log('[Services:parseNewTx] 📄 Nouveau message NewTx reçu.');
|
console.log('[Services:parseNewTx] 📄 Nouveau message NewTx reçu.');
|
||||||
const parsedMsg: NewTxMessage = JSON.parse(newTxMsg);
|
const parsedMsg: NewTxMessage = JSON.parse(newTxMsg);
|
||||||
@ -1714,99 +1712,119 @@ export default class Services {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async decryptAttribute(processId: string, state: ProcessState, attribute: string): Promise<any | null> {
|
async decryptAttribute(processId: string, state: ProcessState, attribute: string): Promise<any | null> {
|
||||||
console.log(`[Services:decryptAttribute] 🔑 Tentative de déchiffrement de l'attribut '${attribute}' pour le processus ${processId}`);
|
// Le groupe principal est "collapsed" pour ne pas polluer la console par défaut
|
||||||
let hash = state.pcd_commitment[attribute];
|
console.groupCollapsed(`[Services:decryptAttribute] 🔑 Déchiffrement de '${attribute}' (Process: ${processId})`);
|
||||||
if (!hash) {
|
|
||||||
console.warn(`[Services:decryptAttribute] ⚠️ L'attribut '${attribute}' n'existe pas (pas de hash).`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let key = state.keys[attribute];
|
|
||||||
const pairingProcessId = this.getPairingProcessId();
|
|
||||||
|
|
||||||
// If key is missing, request an update and then retry
|
try {
|
||||||
if (!key) {
|
let hash = state.pcd_commitment[attribute];
|
||||||
console.warn(`[Services:decryptAttribute] ⚠️ Clé manquante pour '${attribute}'. Vérification de l'accès et demande aux pairs...`);
|
if (!hash) {
|
||||||
const roles = state.roles;
|
console.warn(`⚠️ L'attribut n'existe pas (pas de hash).`);
|
||||||
let hasAccess = false;
|
return null; // Le 'finally' s'exécutera
|
||||||
// If we're not supposed to have access to this attribute, ignore
|
}
|
||||||
for (const role of Object.values(roles)) {
|
let key = state.keys[attribute];
|
||||||
for (const rule of Object.values(role.validation_rules)) {
|
const pairingProcessId = this.getPairingProcessId();
|
||||||
if (rule.fields.includes(attribute)) {
|
|
||||||
if (role.members.includes(pairingProcessId)) {
|
// If key is missing, request an update and then retry
|
||||||
// We have access to this attribute
|
if (!key) {
|
||||||
hasAccess = true;
|
// On crée un sous-groupe pour la logique de récupération de la clé
|
||||||
break;
|
console.group(`🔐 Gestion de la clé manquante pour '${attribute}'`);
|
||||||
|
|
||||||
|
console.warn(`Vérification de l'accès et demande aux pairs...`);
|
||||||
|
const roles = state.roles;
|
||||||
|
let hasAccess = false;
|
||||||
|
// If we're not supposed to have access to this attribute, ignore
|
||||||
|
for (const role of Object.values(roles)) {
|
||||||
|
for (const rule of Object.values(role.validation_rules)) {
|
||||||
|
if (rule.fields.includes(attribute)) {
|
||||||
|
if (role.members.includes(pairingProcessId)) {
|
||||||
|
// We have access to this attribute
|
||||||
|
hasAccess = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasAccess) {
|
if (!hasAccess) {
|
||||||
console.log(`[Services:decryptAttribute] ⛔ Accès non autorisé à '${attribute}'. Abandon.`);
|
console.log(`⛔ Accès non autorisé. Abandon.`);
|
||||||
return null;
|
console.groupEnd(); // Ferme le sous-groupe "Gestion de la clé manquante"
|
||||||
}
|
return null; // Le 'finally' principal s'exécutera
|
||||||
|
|
||||||
const process = await this.getProcess(processId);
|
|
||||||
if (!process) {
|
|
||||||
console.error(`[Services:decryptAttribute] 💥 Impossible de trouver le processus ${processId} pour ensureConnections.`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.ensureConnections(process);
|
|
||||||
// We should have the key, so we're going to ask other members for it
|
|
||||||
console.log(`[Services:decryptAttribute] 🗣️ Demande de données aux pairs pour '${attribute}'...`);
|
|
||||||
await this.requestDataFromPeers(processId, [state.state_id], [state.roles]);
|
|
||||||
|
|
||||||
const maxRetries = 5;
|
|
||||||
const retryDelay = 500; // delay in milliseconds
|
|
||||||
let retries = 0;
|
|
||||||
|
|
||||||
while ((!hash || !key) && retries < maxRetries) {
|
|
||||||
console.log(`[Services:decryptAttribute] ⏳ Attente de la clé... (Tentative ${retries + 1}/${maxRetries})`);
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
||||||
// Re-read hash and key after waiting
|
|
||||||
// AMÉLIORATION: On doit relire l'état complet depuis la BDD/cache, car 'state' est un instantané
|
|
||||||
const updatedProcess = await this.getProcess(processId);
|
|
||||||
const updatedState = this.getStateFromId(updatedProcess, state.state_id);
|
|
||||||
if (updatedState) {
|
|
||||||
hash = updatedState.pcd_commitment[attribute];
|
|
||||||
key = updatedState.keys[attribute];
|
|
||||||
}
|
}
|
||||||
retries++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hash && key) {
|
const process = await this.getProcess(processId);
|
||||||
console.log(`[Services:decryptAttribute] ℹ️ Clé et hash trouvés pour '${attribute}'. Tentative de déchiffrement...`);
|
if (!process) {
|
||||||
const blob = await this.getBlobFromDb(hash);
|
console.error(`💥 Impossible de trouver le processus ${processId} pour ensureConnections.`);
|
||||||
if (blob) {
|
console.groupEnd(); // Ferme le sous-groupe "Gestion de la clé manquante"
|
||||||
// Decrypt the data
|
return null;
|
||||||
const buf = await blob.arrayBuffer();
|
}
|
||||||
const cipher = new Uint8Array(buf);
|
|
||||||
|
|
||||||
const keyUIntArray = this.hexToUInt8Array(key);
|
await this.ensureConnections(process);
|
||||||
|
// We should have the key, so we're going to ask other members for it
|
||||||
|
console.log(`🗣️ Demande de données aux pairs...`);
|
||||||
|
await this.requestDataFromPeers(processId, [state.state_id], [state.roles]);
|
||||||
|
|
||||||
try {
|
const maxRetries = 5;
|
||||||
const clear = this.sdkClient.decrypt_data(keyUIntArray, cipher);
|
const retryDelay = 500; // delay in milliseconds
|
||||||
if (clear) {
|
let retries = 0;
|
||||||
// deserialize the result to get the actual data
|
|
||||||
const decoded = this.sdkClient.decode_value(clear);
|
// On crée un sous-groupe replié pour la boucle de réessai (potentiellement verbeuse)
|
||||||
console.log(`[Services:decryptAttribute] ✅ Attribut '${attribute}' déchiffré avec succès.`);
|
console.groupCollapsed(`⏳ Boucle d'attente de la clé (max ${maxRetries} tentatives)`);
|
||||||
return decoded;
|
while ((!hash || !key) && retries < maxRetries) {
|
||||||
} else {
|
console.log(`(Tentative ${retries + 1}/${maxRetries})...`);
|
||||||
throw new Error('decrypt_data returned null');
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
||||||
|
// Re-read hash and key after waiting
|
||||||
|
const updatedProcess = await this.getProcess(processId);
|
||||||
|
const updatedState = this.getStateFromId(updatedProcess, state.state_id);
|
||||||
|
if (updatedState) {
|
||||||
|
hash = updatedState.pcd_commitment[attribute];
|
||||||
|
key = updatedState.keys[attribute];
|
||||||
}
|
}
|
||||||
} catch (e) {
|
retries++;
|
||||||
console.error(`[Services:decryptAttribute] 💥 Échec du déchiffrement (decrypt_data): ${e}`);
|
}
|
||||||
|
console.groupEnd(); // Ferme le sous-groupe "Boucle d'attente"
|
||||||
|
|
||||||
|
console.groupEnd(); // Ferme le sous-groupe "Gestion de la clé manquante"
|
||||||
|
} // Fin de if (!key)
|
||||||
|
|
||||||
|
if (hash && key) {
|
||||||
|
console.log(`ℹ️ Clé et hash trouvés. Tentative de déchiffrement...`);
|
||||||
|
const blob = await this.getBlobFromDb(hash);
|
||||||
|
if (blob) {
|
||||||
|
// Decrypt the data
|
||||||
|
const buf = await blob.arrayBuffer();
|
||||||
|
const cipher = new Uint8Array(buf);
|
||||||
|
|
||||||
|
const keyUIntArray = this.hexToUInt8Array(key);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const clear = this.sdkClient.decrypt_data(keyUIntArray, cipher);
|
||||||
|
if (clear) {
|
||||||
|
// deserialize the result to get the actual data
|
||||||
|
const decoded = this.sdkClient.decode_value(clear);
|
||||||
|
console.log(`✅ Attribut '${attribute}' déchiffré avec succès.`);
|
||||||
|
return decoded; // Le 'finally' s'exécutera
|
||||||
|
} else {
|
||||||
|
throw new Error('decrypt_data returned null');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`💥 Échec du déchiffrement (decrypt_data): ${e}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error(`💥 Échec: Blob non trouvé en BDD pour le hash ${hash}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error(`[Services:decryptAttribute] 💥 Échec: Blob non trouvé en BDD pour le hash ${hash}`);
|
console.error(`💥 Échec: Clé ou hash manquant après ${maxRetries} tentatives pour '${attribute}'.`);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
console.error(`[Services:decryptAttribute] 💥 Échec: Clé ou hash manquant après ${maxRetries} tentatives pour '${attribute}'.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null; // Le 'finally' s'exécutera
|
||||||
|
} catch (error) {
|
||||||
|
// Intercepte les erreurs inattendues non gérées
|
||||||
|
console.error(`💥 Erreur inattendue dans decryptAttribute:`, error);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
// Ce bloc est TOUJOURS exécuté, assurant que le groupe est fermé.
|
||||||
|
console.groupEnd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getNotifications(): any[] | null {
|
getNotifications(): any[] | null {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user