**Motivations :** - Inconsistent use of console.* methods across codebase - Missing structured logging with proper levels and context - Inline error display breaking UI layout - Risk of sensitive data exposure in logs **Modifications :** - Replace all console.* calls with secureLogger.* in main files - Add proper log levels: DEBUG, INFO, WARN, ERROR - Add component context for better debugging - Create styled error/warning/success containers - Add comprehensive logging guidelines documentation - Fix import paths for secureLogger in security-setup.ts **Pages affectées :** - src/services/service.ts - Main service logging - src/pages/home/home.ts - Home page logging - src/pages/security-setup/security-setup.ts - Security setup logging - src/utils/sp-address.utils.ts - SP address utilities logging - src/router.ts - Router logging - src/websockets.ts - WebSocket logging - src/4nk.css - Error container styles - docs/LOGGING_GUIDELINES.md - Logging best practices
647 lines
24 KiB
Markdown
647 lines
24 KiB
Markdown
# Documentation de l'Initialisation IHM_CLIENT
|
|
|
|
## Vue d'ensemble
|
|
|
|
Le système IHM_CLIENT suit un processus d'initialisation en plusieurs étapes pour créer et sécuriser un wallet Bitcoin. Ce document détaille chaque étape du processus, depuis le choix du mode de sécurité jusqu'au pairing réussi et à la récupération des processus.
|
|
|
|
## Architecture des Stores IndexedDB
|
|
|
|
### Stores utilisés :
|
|
- **`pbkdf2keys`** : Stockage des clés PBKDF2 chiffrées par mode de sécurité
|
|
- **`wallet`** : Stockage du wallet chiffré (device + wallet data)
|
|
- **`credentials`** : Stockage des credentials de pairing (utilisé uniquement après pairing)
|
|
- **`env`** : Stockage des variables d'environnement internes (mots de passe, constantes)
|
|
- **`processes`** : Stockage des processus de communication
|
|
- **`labels`** : Stockage des labels de transactions
|
|
- **`shared_secrets`** : Stockage des secrets partagés
|
|
- **`unconfirmed_secrets`** : Stockage des secrets non confirmés
|
|
- **`diffs`** : Stockage des différences de synchronisation
|
|
- **`data`** : Stockage des données générales
|
|
|
|
## Flux d'Initialisation Complet
|
|
|
|
### 1. Démarrage de l'Application
|
|
|
|
**Fichier :** `src/router.ts` → `checkStorageStateAndNavigate()`
|
|
|
|
L'application vérifie l'état du storage pour déterminer l'étape suivante :
|
|
|
|
```typescript
|
|
// Logique de progression :
|
|
// - Si pairing → account
|
|
// - Si date anniversaire → pairing
|
|
// - Si wallet → birthday-setup
|
|
// - Si pbkdf2 → wallet-setup
|
|
// - Sinon → security-setup
|
|
```
|
|
|
|
**États possibles :**
|
|
1. **Appareil appairé** → Redirection vers `account`
|
|
2. **Date anniversaire configurée** → Redirection vers `home` (pairing)
|
|
3. **Wallet existe sans date anniversaire** → Redirection vers `birthday-setup`
|
|
4. **Clé PBKDF2 existe** → Redirection vers `wallet-setup`
|
|
5. **Aucune configuration** → Redirection vers `security-setup`
|
|
|
|
### 2. Configuration du Mode de Sécurité
|
|
|
|
**Fichier :** `src/pages/security-setup/security-setup.ts`
|
|
|
|
#### 2.1 Sélection du Mode
|
|
|
|
L'utilisateur choisit parmi les modes disponibles :
|
|
|
|
| Mode | Nom | Description | Niveau de Sécurité | Clé de Chiffrement PBKDF2 | Stockage de la Clé de Chiffrement |
|
|
|------|-----|-------------|-------------------|---------------------------|-----------------------------------|
|
|
| `proton-pass` | Proton Pass | Authentification biométrique via Proton Pass | High | Clé WebAuthn générée par le navigateur | Stockée dans le navigateur (WebAuthn credential) |
|
|
| `os` | Authentificateur OS | Authentification biométrique du système | High | Clé WebAuthn générée par le système | Stockée dans le système d'exploitation |
|
|
| `otp` | OTP | Code à usage unique (Google Authenticator, etc.) | High | Aucune (clé PBKDF2 stockée en clair) | Secret OTP stocké dans l'application OTP |
|
|
| `password` | Mot de passe | Chiffrement par mot de passe (non sauvegardé) | Low | Mot de passe utilisateur | Stocké dans le gestionnaire de mots de passe du navigateur |
|
|
| `none` | Aucune sécurité | Chiffrement avec clé en dur (non recommandé) | Critical | Clé en dur `4NK_DEFAULT_ENCRYPTION_KEY_NOT_SECURE` | Intégrée dans le code (non sécurisé) |
|
|
|
|
#### 2.2 Génération de la Clé PBKDF2
|
|
|
|
**Fichier :** `src/services/secure-credentials.service.ts` → `generatePBKDF2Key()`
|
|
|
|
Pour chaque mode, une clé PBKDF2 est générée et stockée différemment :
|
|
|
|
##### Mode `proton-pass` et `os` (WebAuthn)
|
|
```typescript
|
|
// Stockage avec WebAuthn (authentification biométrique)
|
|
await webAuthnService.storeKeyWithWebAuthn(pbkdf2Key, securityMode);
|
|
```
|
|
- **Store :** `pbkdf2keys`
|
|
- **Clé :** `security_mode` (ex: "proton-pass")
|
|
- **Valeur :** Clé PBKDF2 chiffrée avec WebAuthn
|
|
- **Authentification :** Biométrique (empreinte, visage, etc.)
|
|
|
|
##### Mode `otp`
|
|
```typescript
|
|
// Génération du secret OTP
|
|
const otpSecret = await this.generateOTPSecret();
|
|
// Stockage de la clé PBKDF2 en clair
|
|
await this.storePBKDF2KeyInStore(pbkdf2Key, securityMode);
|
|
// Affichage du QR code
|
|
this.displayOTPQRCode(otpSecret);
|
|
```
|
|
- **Store :** `pbkdf2keys`
|
|
- **Clé :** `security_mode` ("otp")
|
|
- **Valeur :** Clé PBKDF2 en clair
|
|
- **Authentification :** Code OTP généré par l'application
|
|
|
|
##### Mode `password`
|
|
```typescript
|
|
// Demande du mot de passe utilisateur
|
|
const userPassword = await this.promptForPasswordWithBrowser();
|
|
// Chiffrement de la clé PBKDF2
|
|
const encryptedKey = await encryptionService.encrypt(pbkdf2Key, userPassword);
|
|
// Stockage chiffré
|
|
await this.storePBKDF2KeyInStore(encryptedKey, securityMode);
|
|
```
|
|
- **Store :** `pbkdf2keys`
|
|
- **Clé :** `security_mode` ("password")
|
|
- **Valeur :** Clé PBKDF2 chiffrée avec le mot de passe utilisateur
|
|
- **Authentification :** Mot de passe utilisateur (non sauvegardé)
|
|
|
|
##### Mode `none`
|
|
```typescript
|
|
// Clé de chiffrement en dur
|
|
const hardcodedKey = '4NK_DEFAULT_ENCRYPTION_KEY_NOT_SECURE';
|
|
// Chiffrement avec la clé en dur
|
|
const encryptedKeyNone = await encryptionService.encrypt(pbkdf2Key, hardcodedKey);
|
|
// Stockage chiffré
|
|
await this.storePBKDF2KeyInStore(encryptedKeyNone, securityMode);
|
|
```
|
|
- **Store :** `pbkdf2keys`
|
|
- **Clé :** `security_mode` ("none")
|
|
- **Valeur :** Clé PBKDF2 chiffrée avec clé en dur
|
|
- **Authentification :** Aucune (non sécurisé)
|
|
|
|
### 3. Création du Wallet
|
|
|
|
**Fichier :** `src/pages/wallet-setup/wallet-setup.ts`
|
|
|
|
#### 3.1 Récupération de la Clé PBKDF2
|
|
|
|
Le système teste tous les modes de sécurité pour trouver la clé PBKDF2 valide :
|
|
|
|
```typescript
|
|
const allSecurityModes = ['none', 'otp', 'password', 'os', 'proton-pass'];
|
|
for (const mode of allSecurityModes) {
|
|
const hasKey = await secureCredentialsService.hasPBKDF2Key(mode);
|
|
if (hasKey) {
|
|
const key = await secureCredentialsService.retrievePBKDF2Key(mode);
|
|
if (key) {
|
|
currentMode = mode;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 3.2 Génération des Clés du Wallet
|
|
|
|
```typescript
|
|
// Génération des clés temporaires
|
|
const walletData = {
|
|
scan_sk: encryptionService.generateRandomKey(),
|
|
spend_key: encryptionService.generateRandomKey(),
|
|
network: 'signet',
|
|
state: 'birthday_waiting',
|
|
created_at: new Date().toISOString()
|
|
};
|
|
```
|
|
|
|
#### 3.3 Création du Device via SDK
|
|
|
|
```typescript
|
|
// Création du device avec birthday = 0
|
|
const spAddress = await services.sdkClient.create_new_device(0, 'signet');
|
|
// Génération forcée du wallet
|
|
const wallet = await services.sdkClient.dump_wallet();
|
|
```
|
|
|
|
#### 3.4 Stockage Chiffré du Wallet
|
|
|
|
```typescript
|
|
// Chiffrement du device
|
|
const encryptedDevice = await encryptionService.encrypt(deviceString, pbkdf2Key);
|
|
// Chiffrement du wallet
|
|
const encryptedWallet = await encryptionService.encrypt(walletString, pbkdf2Key);
|
|
|
|
// Stockage dans le store wallet
|
|
const walletObject = {
|
|
pre_id: '1',
|
|
encrypted_device: encryptedDevice,
|
|
encrypted_wallet: encryptedWallet
|
|
};
|
|
```
|
|
|
|
**Store :** `wallet`
|
|
**Clé :** `pre_id` ("1")
|
|
**Valeur :** Objet contenant uniquement des données chiffrées
|
|
|
|
### 4. Configuration de la Date Anniversaire
|
|
|
|
**Fichier :** `src/pages/birthday-setup/birthday-setup.ts`
|
|
|
|
#### 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.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');
|
|
}
|
|
```
|
|
|
|
**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
|
|
// Mise à jour du birthday du device
|
|
await services.updateDeviceBlockHeight();
|
|
```
|
|
|
|
**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
|
|
// 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()` et `src/utils/sp-address.utils.ts` → `prepareAndSendPairingTx()`
|
|
|
|
#### But et Objectif du Pairing
|
|
|
|
Le processus de pairing dans IHM_CLIENT sert à **créer une identité numérique vérifiable** qui permet :
|
|
|
|
1. **MFA (Multi-Factor Authentication) entre appareils** : Le quorum du processus permet de valider les actions critiques nécessitant plusieurs appareils appairés
|
|
2. **Gestion autonome de la liste d'appareils** : L'utilisateur contrôle lui-même sa liste d'appareils autorisés, sans dépendre d'un tiers
|
|
3. **Identité numérique décentralisée** : Le processus de pairing sert d'identité numérique vérifiable sur la blockchain
|
|
4. **Système d'identité et de chiffrement** : Partage des secrets Silent Payment pour le chiffrement entre appareils appairés
|
|
|
|
#### Caractéristiques
|
|
|
|
- **Un wallet peut être appairé à plusieurs appareils** : Un même processus peut inclure N appareils
|
|
- **Le pairing est un processus blockchain** : Création d'un processus avec états commités et vérifiables
|
|
- **Synchronisation via relais** : Les relais synchronisent les transactions et les processus entre tous les appareils appairés
|
|
- **Contrôle via 4 mots** : Les 4 mots permettent de contrôler le processus (rejoindre, mettre à jour, backup, support)
|
|
|
|
#### 5.1 Vérification du Mode de Sécurité
|
|
|
|
```typescript
|
|
const currentMode = await securityModeService.getCurrentMode();
|
|
if (!currentMode) {
|
|
// Redirection vers security-setup si aucun mode n'est configuré
|
|
window.location.href = '/src/pages/security-setup/security-setup.html';
|
|
return;
|
|
}
|
|
```
|
|
|
|
#### 5.2 Authentification selon le Mode
|
|
|
|
##### Mode `proton-pass` et `os`
|
|
```typescript
|
|
// Authentification WebAuthn
|
|
const credential = await navigator.credentials.get({
|
|
publicKey: {
|
|
challenge: new Uint8Array(32),
|
|
allowCredentials: [{
|
|
id: credentialId,
|
|
type: 'public-key'
|
|
}]
|
|
}
|
|
});
|
|
```
|
|
|
|
##### Mode `otp`
|
|
```typescript
|
|
// Demande du code OTP
|
|
const otpCode = await this.promptForOTPCode();
|
|
// Vérification du code OTP
|
|
const isValid = await this.verifyOTPCode(otpCode, otpSecret);
|
|
```
|
|
|
|
##### Mode `password`
|
|
```typescript
|
|
// Demande du mot de passe
|
|
const password = await this.promptForPassword();
|
|
// Déchiffrement de la clé PBKDF2
|
|
const pbkdf2Key = await encryptionService.decrypt(encryptedKey, password);
|
|
```
|
|
|
|
##### Mode `none`
|
|
```typescript
|
|
// Déchiffrement avec la clé en dur
|
|
const pbkdf2Key = await encryptionService.decrypt(encryptedKey, hardcodedKey);
|
|
```
|
|
|
|
#### 5.3 Génération des Credentials de Pairing
|
|
|
|
```typescript
|
|
// Génération des credentials sécurisés (mot de passe récupéré depuis le store env)
|
|
const credentialData = await secureCredentialsService.generateSecureCredentials('');
|
|
|
|
// Stockage des credentials dans le store credentials
|
|
await secureCredentialsService.storeCredentials(credentialData, '');
|
|
|
|
// Récupération et déchiffrement des credentials (mot de passe récupéré depuis le store env)
|
|
const retrievedCredentials = await secureCredentialsService.retrieveCredentials('');
|
|
```
|
|
|
|
**Store `env` :**
|
|
- **Clé :** `CREDENTIALS_PASSWORD`
|
|
- **Valeur :** `4nk-secure-password` (mot de passe interne pour les credentials)
|
|
- **Description :** Mot de passe interne pour la génération des credentials de pairing
|
|
|
|
#### 5.4 Création du Processus de Pairing
|
|
|
|
```typescript
|
|
// Création du processus via le SDK
|
|
const pairingResult = await services.createPairingProcess({
|
|
spendKey: retrievedCredentials.spendKey,
|
|
scanKey: retrievedCredentials.scanKey
|
|
});
|
|
```
|
|
|
|
### 6. Récupération des Processus
|
|
|
|
**Fichier :** `src/services/service.ts` → `restoreProcessesFromDB()`
|
|
|
|
#### 6.1 Synchronisation des Processus
|
|
|
|
```typescript
|
|
// Récupération des processus depuis la base de données
|
|
const processes = await processRepo.getAllProcesses();
|
|
|
|
// Synchronisation avec le réseau
|
|
for (const process of processes) {
|
|
await services.syncProcess(process);
|
|
}
|
|
```
|
|
|
|
#### 6.2 Mise à Jour de l'État de Pairing
|
|
|
|
```typescript
|
|
// Vérification de l'état de pairing
|
|
const isPaired = services.isPaired();
|
|
if (isPaired) {
|
|
// Redirection vers la page account
|
|
await navigate('account');
|
|
}
|
|
```
|
|
|
|
## Diagramme de Flux
|
|
|
|
```mermaid
|
|
graph TD
|
|
A[Démarrage Application] --> B{Vérification État Storage}
|
|
B -->|Aucune config| C[Security Setup]
|
|
B -->|PBKDF2 existe| D[Wallet Setup]
|
|
B -->|Wallet existe| E[Birthday Setup]
|
|
B -->|Birthday configuré| F[Block Sync]
|
|
B -->|Appareil appairé| G[Account]
|
|
|
|
C --> C1[Sélection Mode Sécurité]
|
|
C1 --> C2[Génération Clé PBKDF2]
|
|
C2 --> C3[Stockage selon Mode]
|
|
C3 --> D
|
|
|
|
D --> D1[Récupération Clé PBKDF2]
|
|
D1 --> D2[Création Device SDK]
|
|
D2 --> D3[Génération Wallet]
|
|
D3 --> D4[Stockage Chiffré avec Vérification]
|
|
D4 --> E
|
|
|
|
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[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
|
|
|
|
### Mode `proton-pass` et `os`
|
|
- **Stockage :** Clé PBKDF2 chiffrée avec WebAuthn
|
|
- **Authentification :** Biométrique (empreinte, visage)
|
|
- **Sécurité :** Élevée (clé matérielle)
|
|
|
|
### Mode `otp`
|
|
- **Stockage :** Clé PBKDF2 en clair
|
|
- **Authentification :** Code OTP temporaire
|
|
- **Sécurité :** Élevée (authentification à deux facteurs)
|
|
|
|
### Mode `password`
|
|
- **Stockage :** Clé PBKDF2 chiffrée avec mot de passe utilisateur
|
|
- **Authentification :** Mot de passe utilisateur
|
|
- **Sécurité :** Faible (dépend de la force du mot de passe)
|
|
|
|
### Mode `none`
|
|
- **Stockage :** Clé PBKDF2 chiffrée avec clé en dur
|
|
- **Authentification :** Aucune
|
|
- **Sécurité :** Critique (non recommandé)
|
|
|
|
## Gestion des Erreurs
|
|
|
|
### Erreurs de Chiffrement
|
|
- **Clé PBKDF2 introuvable** → Redirection vers `security-setup`
|
|
- **Échec de déchiffrement** → Demande de réauthentification
|
|
- **Wallet corrompu** → Recréation du wallet
|
|
|
|
### Erreurs de Réseau
|
|
- **Connexion relais échouée** → Retry automatique
|
|
- **Synchronisation échouée** → Mode hors ligne
|
|
- **Pairing échoué** → Nouvelle tentative
|
|
|
|
### Erreurs d'Authentification
|
|
- **WebAuthn échoué** → Fallback vers autre mode
|
|
- **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']`
|
|
2. **Store `credentials`** : Utilisé uniquement après pairing
|
|
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 IHM_CLIENT, depuis la configuration de sécurité jusqu'au pairing réussi et à la récupération des processus.
|