feat: encrypt wallet completely and detect security mode from PBKDF2 key
**Motivations :** - Encrypt all wallet data with PBKDF2 key, never store in clear - Detect security mode from available PBKDF2 key instead of using fallback - Stop page without fallback if no PBKDF2 key is available - Use existing PBKDF2 keys only, no generation **Modifications :** - wallet-setup.ts: Encrypt device data before storing, store only encrypted_device and encrypted_wallet - wallet-setup.ts: Detect security mode by testing all modes to find a working PBKDF2 key - wallet-setup.ts: Stop without fallback if no PBKDF2 key is found - wallet-setup.ts: Retrieve existing PBKDF2 key (no generation) - wallet-setup.ts: Remove separate security mode storage (already stored via PBKDF2 key in pbkdf2keys store) - wallet-setup.ts: Add verification to reject any wallet stored in clear - wallet-setup.ts: Fix IndexedDB inline key usage (remove explicit key parameter) **Pages affected :** - wallet-setup.html: Encrypts and stores only encrypted wallet data, detects security mode from PBKDF2 key
This commit is contained in:
parent
aa913ef930
commit
3eae4f0210
@ -152,15 +152,39 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
try {
|
try {
|
||||||
console.log('🔐 Sauvegarde du wallet avec état birthday_waiting...');
|
console.log('🔐 Sauvegarde du wallet avec état birthday_waiting...');
|
||||||
|
|
||||||
// Récupérer le mode de sécurité pour le chiffrement
|
// DÉTECTER le mode de sécurité via la clé PBKDF2 disponible
|
||||||
const { SecurityModeService } = await import('../../services/security-mode.service');
|
// Le mode de sécurité est identifié par la clé PBKDF2 qui fonctionne
|
||||||
const securityModeService = SecurityModeService.getInstance();
|
const { SecureCredentialsService } = await import('../../services/secure-credentials.service');
|
||||||
let currentMode = await securityModeService.getCurrentMode();
|
const secureCredentialsService = SecureCredentialsService.getInstance();
|
||||||
|
|
||||||
// Si aucun mode n'est trouvé, utiliser le mode par défaut
|
console.log('🔍 Testing all security modes to find a PBKDF2 key...');
|
||||||
|
|
||||||
|
// Tester tous les modes de sécurité pour trouver une clé PBKDF2 valide
|
||||||
|
const allSecurityModes: Array<'browser' | 'otp' | 'password' | 'none' | 'os' | 'proton-pass'> =
|
||||||
|
['browser', 'otp', 'password', 'none', 'os', 'proton-pass'];
|
||||||
|
|
||||||
|
let currentMode: string | null = null;
|
||||||
|
|
||||||
|
for (const mode of allSecurityModes) {
|
||||||
|
console.log(`🔍 Testing security mode: ${mode}`);
|
||||||
|
try {
|
||||||
|
const key = await secureCredentialsService.retrievePBKDF2Key(mode);
|
||||||
|
if (key) {
|
||||||
|
currentMode = mode;
|
||||||
|
console.log(`✅ PBKDF2 key found for security mode: ${mode}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`⚠️ No PBKDF2 key found for mode ${mode}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRITICAL: Si aucune clé PBKDF2 n'est disponible, arrêter immédiatement
|
||||||
if (!currentMode) {
|
if (!currentMode) {
|
||||||
console.log('⚠️ No security mode found, using browser mode as fallback');
|
console.error('❌ CRITICAL: No PBKDF2 key found for any security mode.');
|
||||||
currentMode = 'browser';
|
console.error('❌ Cannot proceed with wallet creation without encryption key.');
|
||||||
|
updateStatus('❌ Erreur: Aucune clé de chiffrement trouvée. Veuillez configurer la sécurité.', 'error');
|
||||||
|
throw new Error('CRITICAL: No PBKDF2 key found. Cannot create wallet without encryption key.');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('🔐 Using security mode for wallet encryption:', currentMode);
|
console.log('🔐 Using security mode for wallet encryption:', currentMode);
|
||||||
@ -183,12 +207,15 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
|
|
||||||
console.log('🔐 Wallet data generated:', walletData);
|
console.log('🔐 Wallet data generated:', walletData);
|
||||||
|
|
||||||
// Récupérer la clé PBKDF2 générée par le service de sécurité
|
// Récupérer la clé PBKDF2 existante pour le mode détecté
|
||||||
const { SecureCredentialsService } = await import('../../services/secure-credentials.service');
|
// IMPORTANT: Ne PAS générer de nouvelle clé, utiliser celle qui existe
|
||||||
const secureCredentialsService = SecureCredentialsService.getInstance();
|
console.log('🔐 Retrieving existing PBKDF2 key for security mode:', currentMode);
|
||||||
|
const pbkdf2Key = await secureCredentialsService.retrievePBKDF2Key(currentMode as any);
|
||||||
// Générer la clé PBKDF2 avec le mode de sécurité choisi
|
if (!pbkdf2Key) {
|
||||||
const pbkdf2Key = await secureCredentialsService.generatePBKDF2Key(currentMode);
|
console.error('❌ CRITICAL: Failed to retrieve PBKDF2 key for mode:', currentMode);
|
||||||
|
updateStatus('❌ Erreur: Impossible de récupérer la clé de chiffrement.', 'error');
|
||||||
|
throw new Error('CRITICAL: Failed to retrieve PBKDF2 key');
|
||||||
|
}
|
||||||
console.log('🔐 PBKDF2 key retrieved for wallet encryption');
|
console.log('🔐 PBKDF2 key retrieved for wallet encryption');
|
||||||
|
|
||||||
// Chiffrer le wallet avec la clé PBKDF2
|
// Chiffrer le wallet avec la clé PBKDF2
|
||||||
@ -260,22 +287,37 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
console.log(`🔍 Opening transaction for ${DATABASE_CONFIG.stores.wallet.name} store...`);
|
console.log(`🔍 Opening transaction for ${DATABASE_CONFIG.stores.wallet.name} store...`);
|
||||||
|
|
||||||
|
// CRITICAL: Chiffrer TOUS les données du wallet avant stockage
|
||||||
|
// Le device contient des données sensibles (sp_wallet) qui ne doivent JAMAIS être en clair
|
||||||
|
console.log('🔐 Encrypting device data before storage...');
|
||||||
|
const deviceString = JSON.stringify(device);
|
||||||
|
const encryptedDevice = await encryptionService.encryptWithPassword(deviceString, pbkdf2Key);
|
||||||
|
console.log('🔐 Device encrypted successfully');
|
||||||
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
const transaction = db.transaction([DATABASE_CONFIG.stores.wallet.name], 'readwrite');
|
const transaction = db.transaction([DATABASE_CONFIG.stores.wallet.name], 'readwrite');
|
||||||
const store = transaction.objectStore(DATABASE_CONFIG.stores.wallet.name);
|
const store = transaction.objectStore(DATABASE_CONFIG.stores.wallet.name);
|
||||||
console.log('🔍 Store opened:', store.name);
|
console.log('🔍 Store opened:', store.name);
|
||||||
|
|
||||||
// Stocker le wallet chiffré séparément et laisser le SDK gérer sp_wallet
|
// Stocker UNIQUEMENT des données chiffrées - aucun wallet en clair
|
||||||
const walletObject = {
|
const walletObject = {
|
||||||
pre_id: '1',
|
pre_id: '1',
|
||||||
device: device,
|
encrypted_device: encryptedDevice, // Device complètement chiffré
|
||||||
encrypted_wallet: encryptedWallet, // Stocker le wallet chiffré séparément
|
encrypted_wallet: encryptedWallet, // Wallet chiffré
|
||||||
security_mode: currentMode // Stocker le mode de sécurité
|
security_mode: currentMode // Mode de sécurité utilisé
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('🔍 Attempting to save wallet object:', walletObject);
|
console.log('🔍 Attempting to save encrypted wallet object');
|
||||||
// Le store utilise des clés out-of-line, fournir une clé explicite
|
console.log('🔐 Object contains only encrypted data:', {
|
||||||
const request = store.put(walletObject, '1');
|
hasEncryptedDevice: !!walletObject.encrypted_device,
|
||||||
|
hasEncryptedWallet: !!walletObject.encrypted_wallet,
|
||||||
|
securityMode: walletObject.security_mode,
|
||||||
|
// Ne pas logger le contenu chiffré
|
||||||
|
});
|
||||||
|
|
||||||
|
// Le store utilise des clés in-line (keyPath: 'pre_id'), ne pas fournir de clé explicite
|
||||||
|
const request = store.put(walletObject);
|
||||||
request.onsuccess = () => {
|
request.onsuccess = () => {
|
||||||
console.log('✅ Wallet saved in IndexedDB with correct format');
|
console.log('✅ Wallet saved in IndexedDB with correct format');
|
||||||
console.log('🔍 Saved wallet object:', walletObject);
|
console.log('🔍 Saved wallet object:', walletObject);
|
||||||
@ -308,11 +350,32 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
|
|
||||||
const verificationRequest = store.get('1');
|
const verificationRequest = store.get('1');
|
||||||
verificationRequest.onsuccess = () => {
|
verificationRequest.onsuccess = () => {
|
||||||
console.log('🔍 Verification result:', verificationRequest.result);
|
console.log('🔍 Verification result structure:', verificationRequest.result ? {
|
||||||
|
hasPreId: !!verificationRequest.result.pre_id,
|
||||||
|
hasEncryptedDevice: !!verificationRequest.result.encrypted_device,
|
||||||
|
hasEncryptedWallet: !!verificationRequest.result.encrypted_wallet,
|
||||||
|
hasSecurityMode: !!verificationRequest.result.security_mode,
|
||||||
|
hasDeviceInClear: !!verificationRequest.result.device // DEVRAIT ÊTRE NULL
|
||||||
|
} : 'null');
|
||||||
|
|
||||||
if (verificationRequest.result) {
|
if (verificationRequest.result) {
|
||||||
console.log('✅ Wallet verification: Found in IndexedDB with key "1"');
|
console.log('✅ Wallet verification: Found in IndexedDB with key "1"');
|
||||||
console.log('🔍 Device state:', verificationRequest.result.device.sp_wallet.state);
|
|
||||||
console.log('🔍 Encrypted data present:', !!verificationRequest.result.device.sp_wallet.encrypted_data);
|
// Vérifier qu'il n'y a AUCUN wallet en clair
|
||||||
|
if (verificationRequest.result.device) {
|
||||||
|
console.error('❌ CRITICAL: Device in clear found in database! This should be encrypted.');
|
||||||
|
reject(new Error('Security violation: wallet stored in clear'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier que les données chiffrées sont présentes
|
||||||
|
if (!verificationRequest.result.encrypted_device || !verificationRequest.result.encrypted_wallet) {
|
||||||
|
console.error('❌ Wallet verification failed: encrypted data missing');
|
||||||
|
reject(new Error('Encrypted data missing'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ Wallet stored correctly: only encrypted data present');
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
console.error('❌ Wallet verification: Not found in IndexedDB with key "1"');
|
console.error('❌ Wallet verification: Not found in IndexedDB with key "1"');
|
||||||
@ -325,18 +388,9 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sauvegarder le mode de sécurité choisi
|
// Le mode de sécurité est déjà stocké via la clé PBKDF2 dans le store pbkdf2keys
|
||||||
console.log('🔐 Saving security mode:', currentMode);
|
// Pas besoin de le stocker séparément
|
||||||
await securityModeService.setSecurityMode(currentMode);
|
console.log('🔐 Security mode is implicitly stored via PBKDF2 key:', currentMode);
|
||||||
|
|
||||||
// Vérifier que le mode de sécurité est bien sauvegardé
|
|
||||||
const savedMode = await securityModeService.getCurrentMode();
|
|
||||||
if (savedMode === currentMode) {
|
|
||||||
console.log('✅ Security mode saved and verified:', savedMode);
|
|
||||||
} else {
|
|
||||||
console.error('❌ Security mode verification failed. Expected:', currentMode, 'Got:', savedMode);
|
|
||||||
throw new Error('Security mode verification failed');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérification finale : s'assurer que le wallet est bien dans IndexedDB
|
// Vérification finale : s'assurer que le wallet est bien dans IndexedDB
|
||||||
console.log('🔍 Final verification: checking wallet in IndexedDB...');
|
console.log('🔍 Final verification: checking wallet in IndexedDB...');
|
||||||
@ -348,14 +402,19 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
request.onerror = () => reject(request.error);
|
request.onerror = () => reject(request.error);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (finalVerification && finalVerification.device) {
|
if (finalVerification) {
|
||||||
|
// Vérifier qu'il n'y a PAS de device en clair
|
||||||
|
if (finalVerification.device) {
|
||||||
|
console.error('❌ CRITICAL: Final verification - Device in clear found!');
|
||||||
|
throw new Error('Security violation: wallet stored in clear');
|
||||||
|
}
|
||||||
|
|
||||||
console.log('✅ Wallet saved exclusively in IndexedDB and verified');
|
console.log('✅ Wallet saved exclusively in IndexedDB and verified');
|
||||||
console.log('🔍 Wallet contains:', {
|
console.log('🔍 Wallet contains only encrypted data:', {
|
||||||
hasSpWallet: !!finalVerification.device.sp_wallet,
|
hasEncryptedDevice: !!finalVerification.encrypted_device,
|
||||||
hasSpClient: !!finalVerification.device.sp_client,
|
|
||||||
hasEncryptedWallet: !!finalVerification.encrypted_wallet,
|
hasEncryptedWallet: !!finalVerification.encrypted_wallet,
|
||||||
securityMode: finalVerification.security_mode,
|
securityMode: finalVerification.security_mode,
|
||||||
spClientKeys: finalVerification.device.sp_client ? Object.keys(finalVerification.device.sp_client) : 'none'
|
hasDeviceInClear: !!finalVerification.device // DEVRAIT ÊTRE FALSE
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.error('❌ Final wallet verification failed - wallet not found in IndexedDB');
|
console.error('❌ Final wallet verification failed - wallet not found in IndexedDB');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user