docs: update initialization flow documentation with verified checks

**Motivations :**
- La documentation doit refléter les améliorations récentes sur les vérifications réelles des logs
- Documenter le nouveau flux avec block-sync et les vérifications des prérequis
- Documenter le système de vérification réelle des logs pour faciliter la maintenance

**Modifications :**
- Ajout d'une section détaillée sur les vérifications des prérequis dans birthday-setup
- Documentation des vérifications réelles dans updateDeviceBlockHeight
- Documentation des vérifications réelles dans saveDeviceInDatabase
- Ajout de la section sur la redirection vers block-sync
- Mise à jour du diagramme de flux pour inclure block-sync et les vérifications
- Ajout d'une section complète sur le système de vérification réelle des logs
- Mise à jour de la gestion des erreurs avec les erreurs de vérification
- Ajout de points d'attention sur les vérifications réelles et block-sync

**Pages affectées :**
- docs/INITIALIZATION_FLOW.md (documentation complète mise à jour)
This commit is contained in:
NicolasCantu 2025-10-29 13:33:50 +01:00
parent 93ddfcbb76
commit 9b5e1b68b6
6 changed files with 270 additions and 37 deletions

View File

@ -3,3 +3,5 @@ alwaysApply: true
---
lire avec attention: docs/INITIALIZATION_FLOW.md
lire avec attention: docs/IA_agents/*
lire avec attention: docs/docs/*

View File

@ -79,6 +79,8 @@ voir les fichiers README.md
* **Centralisation des logs :** Centraliser les logs dans les répertoires `logs/` des applications et dans le répertoire `logs/` du projet pour les logs hors applications (déploiement par exemple)
* **Système de logging :** Implémenter une gestion d'erreurs robuste et utiliser le système de logging Winston pour toutes les sorties (info, warn, error, debug, etc.).
* **Traçabilité :** Logger toutes les valeurs, états clés et retours d'API.
* **Données vérifiées :** Vérifiant que les logs reflètent des vérifications réelles et non des déclarations.
* **Log abondamment :** Log les informations et étapes ou états clés ainsi que les identifiants clés.
#### 🌐 Interactions Externes (BDD, API, Emails)
* **APIs externes :** Gérer les interactions avec les API de manière appropriée, en respectant les limites d'utilisation et en gérant les erreurs.

View File

@ -56,11 +56,6 @@ voir docs/INITIALIZATION_FLOW.md
* **Lint :** Corrige les erreurs de lint, vérifie apres chaque fichier modifié
* **Fallbacks :** Ne fait pas et supprime les fallbacks
#### Logs
* **Données vérifiées :** Vérifiant que les logs reflètent des vérifications réelles et non des déclarations.
* **Log abondamment :** Log les informations et étapes ou états clés ainsi que les identifiants clés.
#### 🧪 Tests
* **Couverture des tests :** Rédiger des tests unitaires et d'intégration pour toute nouvelle fonctionnalité ou correction de bug.
@ -84,6 +79,9 @@ voir docs/INITIALIZATION_FLOW.md
* **Centralisation des logs :** Centraliser les logs dans les répertoires `logs/` des applications et dans le répertoire `logs/` du projet pour les logs hors applications (déploiement par exemple)
* **Système de logging :** Implémenter une gestion d'erreurs robuste et utiliser le système de logging Winston pour toutes les sorties (info, warn, error, debug, etc.).
* **Traçabilité :** Logger toutes les valeurs, états clés et retours d'API.
* **Données vérifiées :** Vérifiant que les logs reflètent des vérifications réelles et non des déclarations.
* **Log abondamment :** Log les informations et étapes ou états clés ainsi que les identifiants clés.
#### 🌐 Interactions Externes (BDD, API, Emails)
* **APIs externes :** Gérer les interactions avec les API de manière appropriée, en respectant les limites d'utilisation et en gérant les erreurs.

View File

@ -183,29 +183,202 @@ const walletObject = {
**Fichier :** `src/pages/birthday-setup/birthday-setup.ts`
#### 4.1 Connexion aux Relais
#### 4.1 Vérification des Prérequis
Avant de procéder, la page vérifie que tous les prérequis sont remplis :
```typescript
// Vérification de la clé PBKDF2 dans le store pbkdf2keys
const securityModes = ['none', 'otp', 'password', 'os', 'proton-pass'];
let pbkdf2KeyFound = false;
for (const mode of securityModes) {
const hasKey = await secureCredentials.hasPBKDF2Key(mode);
if (hasKey) {
const key = await secureCredentials.retrievePBKDF2Key(mode);
if (key) {
pbkdf2KeyFound = true;
break;
}
}
}
// Vérification du wallet en base de données (avec retry pour synchronisation)
let wallet = await services.getDeviceFromDatabase();
if (!wallet) {
// Retry jusqu'à 5 tentatives avec délai de 500ms
for (let attempt = 0; attempt < 5; attempt++) {
await new Promise(resolve => setTimeout(resolve, 500));
wallet = await services.getDeviceFromDatabase();
if (wallet) break;
}
}
// Vérification que le wallet contient les données attendues
if (wallet.sp_wallet && wallet.sp_wallet.birthday !== undefined) {
console.log('✅ Wallet found in database with birthday:', wallet.sp_wallet.birthday);
} else {
throw new Error('Wallet found but missing required data');
}
```
**Points importants :**
- Vérification réelle de la présence de la clé PBKDF2 dans le store `pbkdf2keys`
- Vérification réelle du wallet en base avec retry pour gérer les problèmes de synchronisation
- Validation que le wallet contient bien les données attendues (`sp_wallet`, `birthday`)
#### 4.2 Connexion aux Relais
```typescript
// Connexion aux relais Bitcoin
await services.connectToRelays();
await services.connectAllRelays();
// Vérification que les relais sont connectés en vérifiant chain_tip
const currentBlockHeight = services.getCurrentBlockHeight();
if (currentBlockHeight !== -1) {
console.log('✅ Relays connected successfully, chain_tip:', currentBlockHeight);
} else {
throw new Error('Relays connected but chain_tip not set');
}
// Vérification que le handshake a été reçu
if (currentBlockHeight > 0) {
console.log('✅ Communication handshake completed, chain_tip:', currentBlockHeight);
} else {
throw new Error('Handshake not received or chain_tip not set');
}
```
#### 4.2 Mise à Jour de la Date Anniversaire
**Vérifications réelles :**
- Vérification que `chain_tip` est défini (valeur != -1)
- Vérification que `chain_tip` est positif (indique que le handshake a été reçu)
#### 4.3 Mise à Jour de la Date Anniversaire
**Fichier :** `src/services/service.ts``updateDeviceBlockHeight()`
```typescript
// Récupération de la hauteur de bloc actuelle
const currentBlockHeight = await services.getCurrentBlockHeight();
// Mise à jour du birthday du device
await services.updateDeviceBirthday(currentBlockHeight);
await services.updateDeviceBlockHeight();
```
#### 4.3 Synchronisation des Processus
**Processus interne avec vérifications réelles :**
1. **Restauration en mémoire** :
```typescript
this.sdkClient.restore_device(device);
// Vérification que le device a été restauré en mémoire
const restoredDevice = this.dumpDeviceFromMemory();
if (restoredDevice?.sp_wallet?.birthday === device.sp_wallet.birthday) {
console.log('✅ Device restored in memory with updated birthday:', device.sp_wallet.birthday);
} else {
throw new Error('Device restoration failed');
}
```
2. **Sauvegarde en base de données** :
```typescript
await this.saveDeviceInDatabase(device);
// Vérification que le device a été sauvegardé en base de données
const savedDevice = await this.getDeviceFromDatabase();
if (savedDevice?.sp_wallet?.birthday === device.sp_wallet.birthday) {
console.log('✅ Device saved to database with updated birthday:', device.sp_wallet.birthday);
} else {
throw new Error('Device save verification failed');
}
```
3. **Vérification du scan initial** :
```typescript
await this.sdkClient.scan_blocks(this.currentBlockHeight, BLINDBITURL);
// Vérification que le scan est terminé en vérifiant last_scan
const deviceAfterScan = this.dumpDeviceFromMemory();
if (deviceAfterScan?.sp_wallet?.last_scan === this.currentBlockHeight) {
console.log('✅ Initial scan completed for new wallet');
} else {
console.warn('⚠️ Initial scan may not be complete');
}
```
4. **Vérification finale** :
```typescript
// Sauvegarde finale avec last_scan mis à jour
await this.saveDeviceInDatabase(device);
// Vérification que le device a été sauvegardé avec last_scan mis à jour
const finalDevice = await this.getDeviceFromDatabase();
if (finalDevice?.sp_wallet?.last_scan === this.currentBlockHeight) {
console.log('✅ New wallet initial scan completed and saved');
} else {
throw new Error('Final save verification failed');
}
```
**Vérification dans birthday-setup.ts :**
```typescript
// Vérifier que le birthday a bien été mis à jour en récupérant le wallet depuis la base
const updatedWallet = await services.getDeviceFromDatabase();
if (updatedWallet?.sp_wallet?.birthday && updatedWallet.sp_wallet.birthday > 0) {
console.log('✅ Birthday updated successfully:', updatedWallet.sp_wallet.birthday);
} else {
throw new Error('Birthday update verification failed');
}
```
#### 4.4 Sauvegarde du Device avec Vérification
**Fichier :** `src/services/service.ts``saveDeviceInDatabase()`
La méthode `saveDeviceInDatabase()` effectue maintenant une vérification réelle après la sauvegarde :
```typescript
// Restauration des processus depuis la base de données
await services.restoreProcessesFromDB();
// Sauvegarde du wallet chiffré
const putRequest = store.put(walletObject);
putRequest.onsuccess = () => {
console.log('✅ Device saved to database with encryption');
// La vérification se fera dans transaction.oncomplete
};
transaction.oncomplete = async () => {
// Vérifier que le wallet a bien été sauvegardé en le récupérant depuis la base
const verificationDb = await new Promise<IDBDatabase>((resolve, reject) => {
const request = indexedDB.open(DATABASE_CONFIG.name, DATABASE_CONFIG.version);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
const verificationTx = verificationDb.transaction([walletStore], 'readonly');
const verifyRequest = verificationStore.get('1');
verifyRequest.onsuccess = () => {
const savedData = verifyRequest.result;
if (savedData && savedData.encrypted_device === encryptedDevice) {
console.log('✅ Verified: Device correctly saved in database');
resolve();
} else {
throw new Error('Device save verification failed');
}
};
};
```
**Points importants :**
- Vérification réelle après la transaction pour confirmer que les données sont bien sauvegardées
- Comparaison de `encrypted_device` pour s'assurer que les données sont correctes
- Logs de succès uniquement après vérification réelle
#### 4.5 Redirection vers la Synchronisation des Blocs
Après la mise à jour réussie du birthday, l'application redirige vers la page de synchronisation des blocs :
```typescript
// Redirection vers la page de synchronisation des blocs
window.location.href = '/src/pages/block-sync/block-sync.html';
```
**Page :** `src/pages/block-sync/block-sync.html`
- Interface dédiée pour la synchronisation des blocs
- Affichage de la progression de la synchronisation
- Gestion de la synchronisation initiale du wallet avec le réseau Bitcoin
### 5. Processus de Pairing
**Fichier :** `src/pages/home/home.ts``handleMainPairing()`
@ -317,7 +490,7 @@ graph TD
B -->|Aucune config| C[Security Setup]
B -->|PBKDF2 existe| D[Wallet Setup]
B -->|Wallet existe| E[Birthday Setup]
B -->|Birthday configuré| F[Pairing]
B -->|Birthday configuré| F[Block Sync]
B -->|Appareil appairé| G[Account]
C --> C1[Sélection Mode Sécurité]
@ -328,19 +501,30 @@ graph TD
D --> D1[Récupération Clé PBKDF2]
D1 --> D2[Création Device SDK]
D2 --> D3[Génération Wallet]
D3 --> D4[Stockage Chiffré]
D3 --> D4[Stockage Chiffré avec Vérification]
D4 --> E
E --> E1[Connexion Relais]
E1 --> E2[Mise à Jour Birthday]
E2 --> E3[Synchronisation Processus]
E3 --> F
E --> E1[Vérification Prérequis]
E1 --> E2{Prérequis OK?}
E2 -->|Non| E3[Redirection vers Setup Précédent]
E2 -->|Oui| E4[Connexion Relais]
E4 --> E5[Vérification Handshake]
E5 --> E6[Mise à Jour Birthday]
E6 --> E7[Vérification Sauvegarde]
E7 --> E8[Vérification Birthday]
E8 --> F
F --> F1[Authentification Mode]
F1 --> F2[Génération Credentials]
F2 --> F3[Création Processus Pairing]
F3 --> F4[Récupération Processus]
F --> F1[Synchronisation Blocs]
F1 --> F2[Initialisation Services]
F2 --> F3[Scan des Blocs]
F3 --> F4[Mise à Jour last_scan]
F4 --> G
G --> G1[Pairing]
G1 --> G2[Authentification Mode]
G2 --> G3[Génération Credentials]
G3 --> G4[Création Processus Pairing]
G4 --> G5[Récupération Processus]
```
## Sécurité par Mode
@ -382,6 +566,48 @@ graph TD
- **OTP invalide** → Nouvelle demande
- **Mot de passe incorrect** → Nouvelle tentative
### Erreurs de Vérification
- **Vérification des prérequis échouée** → Redirection vers l'étape appropriée
- **Vérification de sauvegarde échouée** → Retry de la sauvegarde avec logs détaillés
- **Vérification de restauration échouée** → Retry de la restauration avec logs détaillés
- **Vérification de handshake échouée** → Retry de la connexion avec logs détaillés
## Système de Vérification Réelle des Logs
Tous les logs de succès sont maintenant émis uniquement après vérification réelle des résultats. Cela permet de :
1. **Détecter les échecs silencieux** : Les opérations qui échouent sans erreur sont détectées par les vérifications
2. **Avoir des logs fiables** : Les logs reflètent la réalité et non juste des déclarations
3. **Faciliter le diagnostic** : Les logs indiquent précisément où et pourquoi un processus échoue
### Vérifications Implémentées
#### Dans `birthday-setup.ts`
- ✅ Vérification réelle de la présence de la clé PBKDF2 dans le store `pbkdf2keys`
- ✅ Vérification réelle du wallet en base avec retry pour gérer les problèmes de synchronisation
- ✅ Validation que le wallet contient bien les données attendues (`sp_wallet`, `birthday`)
- ✅ Vérification que les relais sont connectés en vérifiant `chain_tip`
- ✅ Vérification que le handshake a été reçu (`chain_tip > 0`)
- ✅ Vérification que le birthday a bien été mis à jour en récupérant le wallet depuis la base
#### Dans `updateDeviceBlockHeight()`
- ✅ Vérification que le device est restauré en mémoire en comparant le birthday
- ✅ Vérification que le device est sauvegardé en base en le récupérant après l'opération
- ✅ Vérification que le scan est terminé en vérifiant `last_scan`
- ✅ Vérification que la sauvegarde finale est réussie
#### Dans `saveDeviceInDatabase()`
- ✅ Vérification que le wallet est bien sauvegardé en le récupérant depuis la base après la transaction
- ✅ Comparaison de `encrypted_device` pour confirmer que les données sont correctes
- ✅ Logs de succès uniquement après vérification réelle
### Avantages
- **Fiabilité** : Les logs reflètent la réalité et non juste des déclarations
- **Diagnostic** : Facilite le diagnostic en cas de problème
- **Détection** : Détecte les échecs silencieux qui passeraient inaperçus
- **Traçabilité** : Chaque étape est vérifiée et tracée avec des logs détaillés
## Points d'Attention
1. **Ordre des modes testés** : `['none', 'otp', 'password', 'os', 'proton-pass']`
@ -389,5 +615,10 @@ graph TD
3. **Clé PBKDF2** : Toujours stockée dans `pbkdf2keys` avec `security_mode` comme clé
4. **Wallet** : Toujours stocké chiffré dans le store `wallet`
5. **Redirection automatique** : 3 secondes après création du wallet vers `birthday-setup`
6. **Vérifications réelles** : Tous les logs de succès sont émis uniquement après vérification réelle des résultats
7. **Block Sync** : Nouvelle page intermédiaire entre `birthday-setup` et `pairing` pour la synchronisation des blocs
8. **Prérequis** : Chaque page vérifie ses prérequis en base de données avant de procéder
9. **Synchronisation IndexedDB** : Utilisation directe d'IndexedDB pour éviter les problèmes de synchronisation avec le service worker
10. **Retry automatique** : Retry automatique jusqu'à 5 tentatives avec délai de 500ms pour les vérifications de wallet en base
Cette documentation couvre l'ensemble du processus d'initialisation du système LeCoffre.io, depuis la configuration de sécurité jusqu'au pairing réussi et à la récupération des processus.

View File

@ -99,7 +99,7 @@ document.addEventListener('DOMContentLoaded', async () => {
} else {
throw new Error('Wallet found but missing required data (sp_wallet or birthday)');
}
// Vérifier que tous les prérequis sont remplis
const prerequisitesOk = wallet && pbkdf2KeyFound;
if (prerequisitesOk) {
@ -110,7 +110,7 @@ document.addEventListener('DOMContentLoaded', async () => {
// Connexion aux relais
await services.connectAllRelays();
// Vérifier que les relais sont connectés
const currentBlockHeight = services.getCurrentBlockHeight();
if (currentBlockHeight !== -1) {
@ -152,7 +152,7 @@ document.addEventListener('DOMContentLoaded', async () => {
// Mettre à jour la date anniversaire du wallet
await services.updateDeviceBlockHeight();
// Vérifier que le birthday a bien été mis à jour en récupérant le wallet depuis la base
const updatedWallet = await services.getDeviceFromDatabase();
if (updatedWallet?.sp_wallet?.birthday && updatedWallet.sp_wallet.birthday > 0) {

View File

@ -1915,7 +1915,7 @@ export default class Services {
// Définir les handlers de transaction avant le put
transaction.oncomplete = async () => {
console.log('✅ Transaction completed for wallet save');
// Vérifier que le wallet a bien été sauvegardé en le récupérant depuis la base
try {
const verificationDb = await new Promise<IDBDatabase>((resolveDb, rejectDb) => {
@ -1923,11 +1923,11 @@ export default class Services {
request.onsuccess = () => resolveDb(request.result);
request.onerror = () => rejectDb(request.error);
});
const verificationTx = verificationDb.transaction([walletStore], 'readonly');
const verificationStore = verificationTx.objectStore(walletStore);
const verifyRequest = verificationStore.get('1');
await new Promise<void>((resolveVerify, rejectVerify) => {
verifyRequest.onsuccess = () => {
const savedData = verifyRequest.result;
@ -1939,19 +1939,19 @@ export default class Services {
rejectVerify(new Error('Device save verification failed'));
}
};
verifyRequest.onerror = () => {
console.error('❌ Verification failed: Could not retrieve saved device', verifyRequest.error);
rejectVerify(verifyRequest.error);
};
});
resolve();
} catch (verifyError) {
reject(verifyError);
}
};
transaction.onerror = () => {
console.error('❌ Transaction failed:', transaction.error);
reject(transaction.error);
@ -2302,7 +2302,7 @@ export default class Services {
try {
// First set the updated device in memory
this.sdkClient.restore_device(device);
// Vérifier que le device a été restauré en mémoire
const restoredDevice = this.dumpDeviceFromMemory();
if (restoredDevice?.sp_wallet?.birthday === device.sp_wallet.birthday) {
@ -2313,7 +2313,7 @@ export default class Services {
// Then save it to database
await this.saveDeviceInDatabase(device);
// Vérifier que le device a été sauvegardé en base de données
const savedDevice = await this.getDeviceFromDatabase();
if (savedDevice?.sp_wallet?.birthday === device.sp_wallet.birthday) {
@ -2325,7 +2325,7 @@ export default class Services {
// For new wallets, perform initial scan to catch any existing transactions
console.log(`🔄 Performing initial scan for new wallet from block ${device.sp_wallet.birthday} to ${this.currentBlockHeight}...`);
await this.sdkClient.scan_blocks(this.currentBlockHeight, BLINDBITURL);
// Vérifier que le scan est terminé en vérifiant last_scan
const deviceAfterScan = this.dumpDeviceFromMemory();
if (deviceAfterScan?.sp_wallet?.last_scan === this.currentBlockHeight) {
@ -2337,7 +2337,7 @@ export default class Services {
// Update last_scan to current block height
device.sp_wallet.last_scan = this.currentBlockHeight;
await this.saveDeviceInDatabase(device);
// Vérifier que le device a été sauvegardé avec last_scan mis à jour
const finalDevice = await this.getDeviceFromDatabase();
if (finalDevice?.sp_wallet?.last_scan === this.currentBlockHeight) {