Improved decrypAttribute func
This commit is contained in:
parent
6419e4e1c9
commit
b473ddeefe
@ -1709,118 +1709,160 @@ export default class Services {
|
||||
}
|
||||
}
|
||||
|
||||
// La fonction principale est maintenant beaucoup plus simple à lire.
|
||||
// Elle sert d'orchestrateur.
|
||||
async decryptAttribute(processId: string, state: ProcessState, attribute: string): Promise<any | null> {
|
||||
// Le groupe principal est "collapsed" pour ne pas polluer la console par défaut
|
||||
console.groupCollapsed(`[Services:decryptAttribute] 🔑 Déchiffrement de '${attribute}' (Process: ${processId})`);
|
||||
|
||||
try {
|
||||
let hash = state.pcd_commitment[attribute];
|
||||
if (!hash) {
|
||||
console.warn(`⚠️ L'attribut n'existe pas (pas de hash).`);
|
||||
return null; // Le 'finally' s'exécutera
|
||||
}
|
||||
let key = state.keys[attribute];
|
||||
const pairingProcessId = this.getPairingProcessId();
|
||||
|
||||
// If key is missing, request an update and then retry
|
||||
if (!key) {
|
||||
// On crée un sous-groupe pour la logique de récupération de la clé
|
||||
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) {
|
||||
console.log(`⛔ Accès non autorisé. Abandon.`);
|
||||
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(`💥 Impossible de trouver le processus ${processId} pour ensureConnections.`);
|
||||
console.groupEnd(); // Ferme le sous-groupe "Gestion de la clé manquante"
|
||||
// 1. Garde : A-t-on au moins le hash ?
|
||||
if (!hash) {
|
||||
console.warn(`⚠️ L'attribut n'existe pas (pas de hash).`);
|
||||
return null;
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
const maxRetries = 5;
|
||||
const retryDelay = 500; // delay in milliseconds
|
||||
let retries = 0;
|
||||
|
||||
// On crée un sous-groupe replié pour la boucle de réessai (potentiellement verbeuse)
|
||||
console.groupCollapsed(`⏳ Boucle d'attente de la clé (max ${maxRetries} tentatives)`);
|
||||
while ((!hash || !key) && retries < maxRetries) {
|
||||
console.log(`(Tentative ${retries + 1}/${maxRetries})...`);
|
||||
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];
|
||||
// 2. Si la clé est manquante, on la récupère
|
||||
if (!key) {
|
||||
// 2a. Vérifier l'accès (logique extraite)
|
||||
if (!this._checkAccess(state, attribute, pairingProcessId)) {
|
||||
console.log(`⛔ Accès non autorisé. Abandon.`);
|
||||
return null;
|
||||
}
|
||||
retries++;
|
||||
|
||||
// 2b. Tenter de récupérer la clé (logique extraite)
|
||||
const result = await this._fetchMissingKey(processId, state, attribute);
|
||||
hash = result.hash; // Mettre à jour le hash (il a pu être rafraîchi)
|
||||
key = result.key; // Mettre à jour la clé
|
||||
}
|
||||
console.groupEnd(); // Ferme le sous-groupe "Boucle d'attente"
|
||||
|
||||
console.groupEnd(); // Ferme le sous-groupe "Gestion de la clé manquante"
|
||||
} // Fin de if (!key)
|
||||
|
||||
// 3. Si on a tout (soit depuis le début, soit après récupération)
|
||||
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);
|
||||
if (!blob) {
|
||||
console.error(`💥 Échec: Blob non trouvé en BDD pour le hash ${hash}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const buf = await blob.arrayBuffer();
|
||||
const cipher = new Uint8Array(buf);
|
||||
const keyUIntArray = this.hexToUInt8Array(key);
|
||||
|
||||
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 {
|
||||
if (!clear) {
|
||||
throw new Error('decrypt_data returned null');
|
||||
}
|
||||
|
||||
const decoded = this.sdkClient.decode_value(clear);
|
||||
console.log(`✅ Attribut '${attribute}' déchiffré avec succès.`);
|
||||
return decoded;
|
||||
} catch (e) {
|
||||
console.error(`💥 Échec du déchiffrement (decrypt_data): ${e}`);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
console.error(`💥 Échec: Blob non trouvé en BDD pour le hash ${hash}`);
|
||||
}
|
||||
} else {
|
||||
console.error(`💥 Échec: Clé ou hash manquant après ${maxRetries} tentatives pour '${attribute}'.`);
|
||||
}
|
||||
|
||||
return null; // Le 'finally' s'exécutera
|
||||
// 4. Échec final si la clé ou le hash manque toujours
|
||||
console.error(`💥 Échec: Clé ou hash manquant après tentatives pour '${attribute}'.`);
|
||||
return null;
|
||||
} 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é.
|
||||
// Garantit que le groupe principal est TOUJOURS fermé
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOUVELLE MÉTHODE PRIVÉE
|
||||
* Vérifie si l'utilisateur courant a le droit d'accéder à cet attribut
|
||||
* en se basant sur les rôles du state.
|
||||
*/
|
||||
private _checkAccess(state: ProcessState, attribute: string, pairingProcessId: string): boolean {
|
||||
const roles = state.roles;
|
||||
|
||||
// Utilise .some() pour une lecture plus claire et un arrêt anticipé
|
||||
// "Existe-t-il AU MOINS UN rôle..."
|
||||
return Object.values(roles).some((role) => {
|
||||
// "...tel que l'utilisateur est membre..."
|
||||
const isMember = role.members.includes(pairingProcessId);
|
||||
if (!isMember) {
|
||||
return false; // Passe au rôle suivant
|
||||
}
|
||||
|
||||
// "...ET ce rôle a AU MOINS UNE règle de validation qui inclut cet attribut"
|
||||
return Object.values(role.validation_rules).some((rule) => rule.fields.includes(attribute));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* NOUVELLE MÉTHODE PRIVÉE
|
||||
* Gère la logique complexe de demande aux pairs et la boucle de retentative.
|
||||
*/
|
||||
private async _fetchMissingKey(processId: string, state: ProcessState, attribute: string): Promise<{ hash: string | null; key: string | null }> {
|
||||
console.group(`🔐 Gestion de la clé manquante pour '${attribute}'`);
|
||||
|
||||
try {
|
||||
const process = await this.getProcess(processId);
|
||||
if (!process) {
|
||||
console.error(`💥 Impossible de trouver le processus ${processId} pour ensureConnections.`);
|
||||
return { hash: null, key: null };
|
||||
}
|
||||
|
||||
await this.ensureConnections(process);
|
||||
console.log(`🗣️ Demande de données aux pairs...`);
|
||||
await this.requestDataFromPeers(processId, [state.state_id], [state.roles]);
|
||||
|
||||
// Boucle de retentative
|
||||
const maxRetries = 5;
|
||||
const retryDelay = 500;
|
||||
let retries = 0;
|
||||
let hash: string | null = null;
|
||||
let key: string | null = null;
|
||||
|
||||
console.groupCollapsed(`⏳ Boucle d'attente de la clé (max ${maxRetries} tentatives)`);
|
||||
try {
|
||||
while (retries < maxRetries) {
|
||||
console.log(`(Tentative ${retries + 1}/${maxRetries})...`);
|
||||
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
||||
|
||||
// On rafraîchit les données depuis la source
|
||||
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];
|
||||
|
||||
if (hash && key) {
|
||||
console.log('✅ Clé et hash reçus !');
|
||||
break; // Sortir de la boucle while
|
||||
}
|
||||
}
|
||||
retries++;
|
||||
}
|
||||
} finally {
|
||||
// Garantit la fermeture du groupe de la boucle
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
if (!hash || !key) {
|
||||
console.warn(`⌛ Clé ou hash toujours manquant après ${maxRetries} tentatives.`);
|
||||
}
|
||||
|
||||
return { hash, key };
|
||||
} catch (e) {
|
||||
console.error(`💥 Erreur durant _fetchMissingKey: ${e}`);
|
||||
return { hash: null, key: null };
|
||||
} finally {
|
||||
// Garantit la fermeture du groupe de gestion de clé
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user