Refactor wallet setup and improve error handling

**Motivations:**
• Simplify wallet key extraction logic using restoreDevice API
• Improve error handling and logging throughout the application
• Remove unused scanner.js file
• Enhance secure credential management service
• Standardize logging format for better debugging
• Fix storage service error handling

**Modifications:**
• Updated wallet-setup page to use proper wallet key extraction
• Refactored secure-credentials service with better error handling
• Improved storage service with proper error logging
• Enhanced validation modal and device management components
• Updated error utilities and logger with standardized formats
• Removed deprecated scanner.js file
• Fixed birthday-setup and block-sync page error handling
• Updated security-setup page with improved error messages
• Enhanced websocket manager error handling
• Improved prerequisite utils and subscription utils
• Fixed sp-address utils error handling
• Updated encoder worker with better error logging

**Pages affected:**
• device-management component
• validation-modal component
• birthday-setup page
• block-sync page
• pairing page
• security-setup page
• wallet-setup page
• router
• All service files (secure-credentials, secure-key-manager, service, storage, token, websocket-manager)
• All utility files (errors, logger, prerequisites, sp-address, subscription)
• encoder worker
This commit is contained in:
NicolasCantu 2025-10-30 07:40:59 +01:00
parent c9ff430b09
commit 222f92e058
21 changed files with 189 additions and 173 deletions

View File

@ -1,5 +1,6 @@
import Services from '../../services/service'; import Services from '../../services/service';
import { addressToWords } from '../../utils/sp-address.utils'; import { addressToWords } from '../../utils/sp-address.utils';
import { secureLogger } from '../../services/secure-logger';
// Global function declarations // Global function declarations
declare global { declare global {
@ -51,7 +52,7 @@ export class DeviceManagementComponent extends HTMLElement {
} }
} }
} catch (error) { } catch (error) {
console.error('Error loading device data:', error); secureLogger.error('Error loading device data', error as Error, { component: 'DeviceManagement' });
} }
} }
@ -797,7 +798,7 @@ export class DeviceManagementComponent extends HTMLElement {
window.location.reload(); window.location.reload();
}, 2000); }, 2000);
} catch (error) { } catch (error) {
console.error('❌ Erreur lors de la suppression du compte:', error); secureLogger.error('Erreur lors de la suppression du compte', error as Error, { component: 'DeviceManagement' });
this.showStatus(`❌ Erreur lors de la suppression du compte: ${error}`, 'error'); this.showStatus(`❌ Erreur lors de la suppression du compte: ${error}`, 'error');
} }
} }
@ -834,9 +835,9 @@ export class DeviceManagementComponent extends HTMLElement {
// Add to document body // Add to document body
document.body.appendChild(navContainer); document.body.appendChild(navContainer);
console.log('✅ Account navigation injected'); secureLogger.info('Account navigation injected', { component: 'DeviceManagement' });
} catch (error) { } catch (error) {
console.error('❌ Error injecting account navigation:', error); secureLogger.error('Error injecting account navigation', error as Error, { component: 'DeviceManagement' });
} }
} }
} }

View File

@ -1,13 +1,14 @@
import ModalService from '../../services/modal.service'; import ModalService from '../../services/modal.service';
import { secureLogger } from '../../services/secure-logger';
async function validate() { async function validate() {
console.log('==> VALIDATE'); secureLogger.debug('Validation modal triggered', { component: 'ValidationModal' });
const modalservice = await ModalService.getInstance(); const modalservice = await ModalService.getInstance();
modalservice.closeValidationModal(); modalservice.closeValidationModal();
} }
export async function initValidationModal(processDiffs: any) { export async function initValidationModal(processDiffs: any) {
console.log('🚀 ~ initValidationModal ~ processDiffs:', processDiffs); secureLogger.debug('Initializing validation modal', { component: 'ValidationModal', data: processDiffs });
for (const diff of processDiffs.diffs) { for (const diff of processDiffs.diffs) {
let diffs = ''; let diffs = '';
for (const value of diff) { for (const value of diff) {

View File

@ -16,8 +16,8 @@ document.addEventListener('DOMContentLoaded', async () => {
isInitializing = true; isInitializing = true;
secureLogger.info('🎂 Birthday setup page loaded', { component: 'BirthdaySetup' }); secureLogger.info('🎂 Birthday setup page loaded', { component: 'BirthdaySetup' });
console.log('🔍 Current URL:', window.location.href); secureLogger.debug(`Current URL: ${window.location.href}`, { component: 'BirthdaySetup' });
console.log('🔍 Referrer:', document.referrer); secureLogger.debug(`Referrer: ${document.referrer}`, { component: 'BirthdaySetup' });
const status = document.getElementById('status') as HTMLDivElement; const status = document.getElementById('status') as HTMLDivElement;
const progressBar = document.getElementById('progressBar') as HTMLDivElement; const progressBar = document.getElementById('progressBar') as HTMLDivElement;
@ -31,7 +31,7 @@ document.addEventListener('DOMContentLoaded', async () => {
try { try {
secureLogger.info('🔄 Importing services...', { component: 'BirthdaySetup' }); secureLogger.info('🔄 Importing services...', { component: 'BirthdaySetup' });
const serviceModule = await import('../../services/service'); const serviceModule = await import('../../services/service');
console.log('✅ Service module imported:', Object.keys(serviceModule)); secureLogger.debug(`Service module imported: ${Object.keys(serviceModule)}`, { component: 'BirthdaySetup' });
// La classe Services est exportée par défaut // La classe Services est exportée par défaut
const Services = serviceModule.default; const Services = serviceModule.default;
@ -84,7 +84,7 @@ document.addEventListener('DOMContentLoaded', async () => {
// Vérifier que le wallet contient bien les données attendues // Vérifier que le wallet contient bien les données attendues
if (wallet.sp_wallet?.birthday !== undefined) { if (wallet.sp_wallet?.birthday !== undefined) {
console.log('✅ Wallet found in database with birthday:', wallet.sp_wallet.birthday); secureLogger.info(`Wallet found in database with birthday: ${wallet.sp_wallet.birthday}`, { component: 'BirthdaySetup' });
} else { } else {
throw new Error('Wallet found but missing required data (sp_wallet or birthday)'); throw new Error('Wallet found but missing required data (sp_wallet or birthday)');
} }
@ -127,8 +127,8 @@ document.addEventListener('DOMContentLoaded', async () => {
// Vérifier que les relais sont connectés et que le handshake a été reçu // Vérifier que les relais sont connectés et que le handshake a été reçu
const currentBlockHeight = services.getCurrentBlockHeight(); const currentBlockHeight = services.getCurrentBlockHeight();
if (currentBlockHeight !== -1 && currentBlockHeight > 0) { if (currentBlockHeight !== -1 && currentBlockHeight > 0) {
console.log('✅ Relays connected successfully, chain_tip:', currentBlockHeight); secureLogger.info(`Relays connected successfully, chain_tip: ${currentBlockHeight}`, { component: 'BirthdaySetup' });
console.log('✅ Communication handshake completed, chain_tip:', currentBlockHeight); secureLogger.info(`Communication handshake completed, chain_tip: ${currentBlockHeight}`, { component: 'BirthdaySetup' });
} else { } else {
throw new Error('Handshake not received or chain_tip not set'); throw new Error('Handshake not received or chain_tip not set');
} }
@ -146,11 +146,14 @@ document.addEventListener('DOMContentLoaded', async () => {
secureLogger.info('🔄 Verifying birthday update...', { component: 'BirthdaySetup' }); secureLogger.info('🔄 Verifying birthday update...', { component: 'BirthdaySetup' });
const updatedWallet = await services.getDeviceFromDatabase(); const updatedWallet = await services.getDeviceFromDatabase();
if (updatedWallet?.sp_wallet?.birthday && updatedWallet.sp_wallet.birthday > 0) { if (updatedWallet?.sp_wallet?.birthday && updatedWallet.sp_wallet.birthday > 0) {
console.log('✅ Birthday updated successfully:', updatedWallet.sp_wallet.birthday); secureLogger.info(`Birthday updated successfully: ${updatedWallet.sp_wallet.birthday}`, { component: 'BirthdaySetup' });
} else { } else {
console.error('❌ Birthday update verification failed:', { secureLogger.error('Birthday update verification failed', new Error('Verification failed'), {
birthday: updatedWallet?.sp_wallet?.birthday, component: 'BirthdaySetup',
hasSpWallet: !!updatedWallet?.sp_wallet data: {
birthday: updatedWallet?.sp_wallet?.birthday,
hasSpWallet: !!updatedWallet?.sp_wallet
}
}); });
throw new Error(`Birthday update verification failed: expected birthday > 0, got ${updatedWallet?.sp_wallet?.birthday}`); throw new Error(`Birthday update verification failed: expected birthday > 0, got ${updatedWallet?.sp_wallet?.birthday}`);
} }
@ -170,13 +173,13 @@ document.addEventListener('DOMContentLoaded', async () => {
}, 1000); }, 1000);
} catch (error) { } catch (error) {
console.error('❌ Services not available:', error); secureLogger.error('Services not available', error as Error, { component: 'BirthdaySetup' });
updateStatus('❌ Erreur: Services non disponibles', 'error'); updateStatus('❌ Erreur: Services non disponibles', 'error');
throw error; throw error;
} }
} catch (error) { } catch (error) {
console.error('❌ Error during birthday setup:', error); secureLogger.error('Error during birthday setup', error as Error, { component: 'BirthdaySetup' });
updateStatus('❌ Erreur lors de la configuration de la date anniversaire', 'error'); updateStatus('❌ Erreur lors de la configuration de la date anniversaire', 'error');
} finally { } finally {
isInitializing = false; isInitializing = false;

View File

@ -91,7 +91,7 @@ document.addEventListener("DOMContentLoaded", async () => {
break; break;
} catch (error) { } catch (error) {
attempts++; attempts++;
console.log(`⚠️ Services initialization failed (attempt ${attempts}/${maxAttempts}):`, error); secureLogger.warn(`Services initialization failed (attempt ${attempts}/${maxAttempts})`, error as Error, { component: 'BlockSync' });
if (attempts >= maxAttempts) { if (attempts >= maxAttempts) {
throw new Error('Failed to initialize services after maximum attempts'); throw new Error('Failed to initialize services after maximum attempts');
} }
@ -214,14 +214,14 @@ document.addEventListener("DOMContentLoaded", async () => {
} catch (error) { } catch (error) {
// Restaurer la fonction console.log originale en cas d'erreur // Restaurer la fonction console.log originale en cas d'erreur
console.log = originalConsoleLog; console.log = originalConsoleLog;
console.error('❌ Error during block scan:', error); secureLogger.error('Error during block scan', error as Error, { component: 'BlockSync' });
updateStatus(`❌ Erreur lors de la synchronisation: ${(error as Error).message}`, 'error'); updateStatus(`❌ Erreur lors de la synchronisation: ${(error as Error).message}`, 'error');
updateSyncItem('blocksToScan', 'Erreur', 'error'); updateSyncItem('blocksToScan', 'Erreur', 'error');
throw error; throw error;
} }
} catch (error) { } catch (error) {
console.error('❌ Error in block sync page:', error); secureLogger.error('Error in block sync page', error as Error, { component: 'BlockSync' });
updateStatus(`❌ Erreur: ${(error as Error).message}`, 'error'); updateStatus(`❌ Erreur: ${(error as Error).message}`, 'error');
// Rediriger vers la page appropriée selon l'erreur // Rediriger vers la page appropriée selon l'erreur

View File

@ -90,7 +90,7 @@ document.addEventListener('DOMContentLoaded', async () => {
// Vérifier que le wallet contient bien les données attendues // Vérifier que le wallet contient bien les données attendues
if (wallet.sp_wallet?.birthday !== undefined) { if (wallet.sp_wallet?.birthday !== undefined) {
console.log('✅ Wallet found in database with birthday:', wallet.sp_wallet.birthday); secureLogger.info(`Wallet found in database with birthday: ${wallet.sp_wallet.birthday}`, { component: 'Pairing' });
} else { } else {
throw new Error('Wallet found but missing required data (sp_wallet or birthday)'); throw new Error('Wallet found but missing required data (sp_wallet or birthday)');
} }
@ -153,7 +153,7 @@ document.addEventListener('DOMContentLoaded', async () => {
secureLogger.info('✅ Pairing page initialization completed', { component: 'PairingPage' }); secureLogger.info('✅ Pairing page initialization completed', { component: 'PairingPage' });
} catch (error) { } catch (error) {
console.error('❌ Error initializing pairing page:', error); secureLogger.error('Error initializing pairing page', error as Error, { component: 'Pairing' });
updateStatus(`❌ Erreur: ${(error as Error).message}`, 'error'); updateStatus(`❌ Erreur: ${(error as Error).message}`, 'error');
// Si l'erreur est liée aux prérequis, rediriger vers la page appropriée // Si l'erreur est liée aux prérequis, rediriger vers la page appropriée

View File

@ -14,7 +14,7 @@ document.addEventListener('DOMContentLoaded', async () => {
// Initialiser la base de données avec la configuration complète // Initialiser la base de données avec la configuration complète
try { try {
secureLogger.debug('🔍 Initializing database ${DATABASE_CONFIG.name} version ${DATABASE_CONFIG.version}...', { component: 'SecuritySetup' }); secureLogger.debug(`🔍 Initializing database ${DATABASE_CONFIG.name} version ${DATABASE_CONFIG.version}...`, { component: 'SecuritySetup' });
await openDatabase(); await openDatabase();
secureLogger.info('✅ Database initialized successfully', { component: 'SecuritySetup' }); secureLogger.info('✅ Database initialized successfully', { component: 'SecuritySetup' });
} catch (error) { } catch (error) {
@ -62,7 +62,7 @@ document.addEventListener('DOMContentLoaded', async () => {
} }
try { try {
console.log('🔐 Processing security mode:', selectedMode); secureLogger.info(`Processing security mode: ${selectedMode}`, { component: 'SecuritySetup' });
// Sauvegarder le mode de sécurité // Sauvegarder le mode de sécurité
const { SecurityModeService } = await import('../../services/security-mode.service'); const { SecurityModeService } = await import('../../services/security-mode.service');
@ -71,7 +71,7 @@ document.addEventListener('DOMContentLoaded', async () => {
secureLogger.info('✅ Security mode saved successfully', { component: 'SecuritySetup' }); secureLogger.info('✅ Security mode saved successfully', { component: 'SecuritySetup' });
console.log('🔐 Generating PBKDF2 key for security mode:', selectedMode); secureLogger.info(`Generating PBKDF2 key for security mode: ${selectedMode}`, { component: 'SecuritySetup' });
// Désactiver le bouton pendant la génération // Désactiver le bouton pendant la génération
continueBtn.disabled = true; continueBtn.disabled = true;
@ -82,7 +82,7 @@ document.addEventListener('DOMContentLoaded', async () => {
const { SecureCredentialsService } = await import('../../services/secure-credentials.service'); const { SecureCredentialsService } = await import('../../services/secure-credentials.service');
const secureCredentialsService = SecureCredentialsService.getInstance(); const secureCredentialsService = SecureCredentialsService.getInstance();
console.log('🔐 Generating PBKDF2 key with security mode:', selectedMode); secureLogger.info(`Generating PBKDF2 key with security mode: ${selectedMode}`, { component: 'SecuritySetup' });
// Générer la clé PBKDF2 et la stocker selon le mode // Générer la clé PBKDF2 et la stocker selon le mode
// IMPORTANT: Cette opération doit être directe (pas de délai) pour que WebAuthn fonctionne // IMPORTANT: Cette opération doit être directe (pas de délai) pour que WebAuthn fonctionne
@ -94,7 +94,7 @@ document.addEventListener('DOMContentLoaded', async () => {
window.location.href = '/src/pages/wallet-setup/wallet-setup.html'; window.location.href = '/src/pages/wallet-setup/wallet-setup.html';
} catch (error) { } catch (error) {
console.error('❌ PBKDF2 key generation failed:', error); secureLogger.error('PBKDF2 key generation failed', error as Error, { component: 'SecuritySetup' });
alert('Erreur lors de la génération de la clé de sécurité. Veuillez réessayer.'); alert('Erreur lors de la génération de la clé de sécurité. Veuillez réessayer.');
// Réactiver le bouton // Réactiver le bouton
@ -103,7 +103,7 @@ document.addEventListener('DOMContentLoaded', async () => {
} }
} catch (error) { } catch (error) {
console.error('❌ Error processing security mode:', error); secureLogger.error('Error processing security mode', error as Error, { component: 'SecuritySetup' });
alert('Erreur lors du traitement du mode de sécurité'); alert('Erreur lors du traitement du mode de sécurité');
// Réactiver le bouton // Réactiver le bouton

View File

@ -69,7 +69,7 @@ document.addEventListener('DOMContentLoaded', async () => {
} }
const currentMode = pbkdf2KeyResult.mode; const currentMode = pbkdf2KeyResult.mode;
console.log('✅ Prerequisites verified: PBKDF2 key found in pbkdf2keys store for mode:', currentMode); secureLogger.info(`Prerequisites verified: PBKDF2 key found in pbkdf2keys store for mode: ${currentMode}`, { component: 'WalletSetup' });
// Étape 1.5: Vérifier si un wallet existe déjà // Étape 1.5: Vérifier si un wallet existe déjà
updateStatus('🔍 Vérification du wallet existant...', 'loading'); updateStatus('🔍 Vérification du wallet existant...', 'loading');
@ -135,7 +135,7 @@ document.addEventListener('DOMContentLoaded', async () => {
await Promise.all(cacheNames.map(name => caches.delete(name))); await Promise.all(cacheNames.map(name => caches.delete(name)));
secureLogger.info('🧹 Caches cleared', { component: 'WalletSetup' }); secureLogger.info('🧹 Caches cleared', { component: 'WalletSetup' });
} catch (e) { } catch (e) {
console.warn('⚠️ Cache cleanup error:', e); secureLogger.warn('Cache cleanup error', e as Error, { component: 'WalletSetup' });
} }
} }
@ -159,7 +159,7 @@ document.addEventListener('DOMContentLoaded', async () => {
try { try {
secureLogger.info('🔄 Importing services...', { component: 'WalletSetup' }); secureLogger.info('🔄 Importing services...', { component: 'WalletSetup' });
const serviceModule = await import('../../services/service'); const serviceModule = await import('../../services/service');
console.log('✅ Service module imported:', Object.keys(serviceModule)); secureLogger.debug(`Service module imported: ${Object.keys(serviceModule)}`, { component: 'WalletSetup' });
// La classe Services est exportée par défaut // La classe Services est exportée par défaut
const Services = serviceModule.default; const Services = serviceModule.default;
@ -182,7 +182,7 @@ document.addEventListener('DOMContentLoaded', async () => {
break; break;
} catch (error) { } catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error); const errorMessage = error instanceof Error ? error.message : String(error);
console.log(`Services not ready yet (attempt ${attempts + 1}/${maxAttempts}):`, errorMessage); secureLogger.debug(`Services not ready yet (attempt ${attempts + 1}/${maxAttempts}): ${errorMessage}`, { component: 'WalletSetup' });
// Si c'est une erreur de mémoire, arrêter immédiatement // Si c'est une erreur de mémoire, arrêter immédiatement
if (errorMessage.includes('Out of memory') || errorMessage.includes('insufficient memory')) { if (errorMessage.includes('Out of memory') || errorMessage.includes('insufficient memory')) {
@ -208,7 +208,7 @@ document.addEventListener('DOMContentLoaded', async () => {
} }
} }
} catch (error) { } catch (error) {
console.error('❌ Services not available:', error); secureLogger.error('Services not available', error as Error, { component: 'WalletSetup' });
throw error; throw error;
} }
@ -221,7 +221,7 @@ document.addEventListener('DOMContentLoaded', async () => {
// Le mode de sécurité a déjà été trouvé dans la vérification des prérequis // Le mode de sécurité a déjà été trouvé dans la vérification des prérequis
// currentMode est déjà défini et vérifié // currentMode est déjà défini et vérifié
console.log('🔐 Using security mode for wallet encryption:', currentMode); secureLogger.info(`Using security mode for wallet encryption: ${currentMode}`, { component: 'WalletSetup' });
// Générer un wallet temporaire avec état birthday_waiting // Générer un wallet temporaire avec état birthday_waiting
const { EncryptionService } = await import('../../services/encryption.service'); const { EncryptionService } = await import('../../services/encryption.service');
@ -237,14 +237,14 @@ document.addEventListener('DOMContentLoaded', async () => {
created_at: new Date().toISOString() created_at: new Date().toISOString()
}; };
console.log('🔐 Wallet data generated:', walletData); secureLogger.debug('Wallet data generated', { component: 'WalletSetup', data: walletData });
// Récupérer la clé PBKDF2 existante pour le mode détecté // Récupérer la clé PBKDF2 existante pour le mode détecté
// IMPORTANT: Ne PAS générer de nouvelle clé, utiliser celle qui existe // IMPORTANT: Ne PAS générer de nouvelle clé, utiliser celle qui existe
console.log('🔐 Retrieving existing PBKDF2 key for security mode:', currentMode); secureLogger.info(`Retrieving existing PBKDF2 key for security mode: ${currentMode}`, { component: 'WalletSetup' });
const pbkdf2Key = pbkdf2KeyResult.key; const pbkdf2Key = pbkdf2KeyResult.key;
if (!pbkdf2Key) { if (!pbkdf2Key) {
console.error('❌ CRITICAL: Failed to retrieve PBKDF2 key for mode:', currentMode); secureLogger.error(`CRITICAL: Failed to retrieve PBKDF2 key for mode: ${currentMode}`, { component: 'WalletSetup' });
updateStatus('❌ Erreur: Impossible de récupérer la clé de chiffrement.', 'error'); updateStatus('❌ Erreur: Impossible de récupérer la clé de chiffrement.', 'error');
throw new Error('CRITICAL: Failed to retrieve PBKDF2 key'); throw new Error('CRITICAL: Failed to retrieve PBKDF2 key');
} }
@ -256,21 +256,21 @@ document.addEventListener('DOMContentLoaded', async () => {
pbkdf2Key pbkdf2Key
); );
secureLogger.info('🔐 Wallet encrypted with PBKDF2 key', { component: 'WalletSetup' }); secureLogger.info('🔐 Wallet encrypted with PBKDF2 key', { component: 'WalletSetup' });
console.log('🔐 Encrypted wallet data:', encryptedWallet); secureLogger.debug('Encrypted wallet data', { component: 'WalletSetup', data: encryptedWallet });
// Ouvrir la base de données 4nk existante sans la modifier // Ouvrir la base de données 4nk existante sans la modifier
console.log(`🔍 Opening IndexedDB database "${DATABASE_CONFIG.name}" version ${DATABASE_CONFIG.version}...`); secureLogger.info(`Opening IndexedDB database "${DATABASE_CONFIG.name}" version ${DATABASE_CONFIG.version}...`, { component: 'WalletSetup' });
const db = await new Promise<IDBDatabase>((resolve, reject) => { const db = await new Promise<IDBDatabase>((resolve, reject) => {
const request = indexedDB.open(DATABASE_CONFIG.name, DATABASE_CONFIG.version); // Utiliser la version centralisée const request = indexedDB.open(DATABASE_CONFIG.name, DATABASE_CONFIG.version); // Utiliser la version centralisée
request.onerror = () => { request.onerror = () => {
console.error('❌ Failed to open IndexedDB:', request.error); secureLogger.error('Failed to open IndexedDB', request.error as Error, { component: 'WalletSetup' });
reject(request.error); reject(request.error);
}; };
request.onsuccess = () => { request.onsuccess = () => {
secureLogger.info('✅ IndexedDB opened successfully', { component: 'WalletSetup' }); secureLogger.info('✅ IndexedDB opened successfully', { component: 'WalletSetup' });
console.log('🔍 Database name:', request.result.name); secureLogger.debug(`Database name: ${request.result.name}`, { component: 'WalletSetup' });
console.log('🔍 Database version:', request.result.version); secureLogger.debug(`Database version: ${request.result.version}`, { component: 'WalletSetup' });
console.log('🔍 Available stores:', Array.from(request.result.objectStoreNames)); secureLogger.debug(`Available stores: ${Array.from(request.result.objectStoreNames)}`, { component: 'WalletSetup' });
resolve(request.result); resolve(request.result);
}; };
request.onupgradeneeded = () => { request.onupgradeneeded = () => {
@ -299,26 +299,29 @@ document.addEventListener('DOMContentLoaded', async () => {
// We set birthday later when we have the chain tip from relay // We set birthday later when we have the chain tip from relay
secureLogger.info('🔧 Creating new device with birthday 0...', { component: 'WalletSetup' }); secureLogger.info('🔧 Creating new device with birthday 0...', { component: 'WalletSetup' });
const spAddress = await services.sdkClient.create_new_device(0, 'signet'); const spAddress = await services.sdkClient.create_new_device(0, 'signet');
console.log('✅ Device created with address:', spAddress); secureLogger.info(`Device created with address: ${spAddress}`, { component: 'WalletSetup' });
// Force wallet generation to ensure keys are created // Force wallet generation to ensure keys are created
secureLogger.info('🔧 Forcing wallet generation...', { component: 'WalletSetup' }); secureLogger.info('🔧 Forcing wallet generation...', { component: 'WalletSetup' });
try { try {
const wallet = await services.sdkClient.dump_wallet(); const wallet = await services.sdkClient.dump_wallet();
console.log('✅ Wallet generated:', JSON.stringify(wallet)); secureLogger.debug('Wallet generated', { component: 'WalletSetup', data: wallet });
} catch (walletError) { } catch (walletError) {
console.warn('⚠️ Wallet generation failed:', walletError); secureLogger.warn('Wallet generation failed', walletError as Error, { component: 'WalletSetup' });
} }
// Récupérer le device créé par le SDK // Récupérer le device créé par le SDK
const device = services.dumpDeviceFromMemory(); const device = services.dumpDeviceFromMemory();
console.log('🔍 Device structure from SDK:', { secureLogger.debug('Device structure from SDK', {
hasSpWallet: !!device.sp_wallet, component: 'WalletSetup',
hasSpClient: !!device.sp_client, data: {
spClientKeys: device.sp_client ? Object.keys(device.sp_client) : 'none' hasSpWallet: !!device.sp_wallet,
hasSpClient: !!device.sp_client,
spClientKeys: device.sp_client ? Object.keys(device.sp_client) : 'none'
}
}); });
secureLogger.debug('🔍 Opening transaction for ${DATABASE_CONFIG.stores.wallet.name} store...', { component: 'WalletSetup' }); secureLogger.debug(`Opening transaction for ${DATABASE_CONFIG.stores.wallet.name} store...`, { component: 'WalletSetup' });
// CRITICAL: Chiffrer TOUS les données du wallet avant stockage // 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 // Le device contient des données sensibles (sp_wallet) qui ne doivent JAMAIS être en clair
@ -330,7 +333,7 @@ document.addEventListener('DOMContentLoaded', async () => {
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); secureLogger.debug(`Store opened: ${store.name}`, { component: 'WalletSetup' });
// Stocker UNIQUEMENT des données chiffrées - aucun wallet en clair // Stocker UNIQUEMENT des données chiffrées - aucun wallet en clair
const walletObject = { const walletObject = {
@ -340,34 +343,40 @@ document.addEventListener('DOMContentLoaded', async () => {
}; };
secureLogger.debug('🔍 Attempting to save encrypted wallet object', { component: 'WalletSetup' }); secureLogger.debug('🔍 Attempting to save encrypted wallet object', { component: 'WalletSetup' });
console.log('🔐 Object contains only encrypted data:', { secureLogger.debug('Object contains only encrypted data', {
hasEncryptedDevice: !!walletObject.encrypted_device, component: 'WalletSetup',
hasEncryptedWallet: !!walletObject.encrypted_wallet, data: {
// Ne pas logger le contenu chiffré hasEncryptedDevice: !!walletObject.encrypted_device,
hasEncryptedWallet: !!walletObject.encrypted_wallet
// Ne pas logger le contenu chiffré
}
}); });
// Le store utilise des clés in-line (keyPath: 'pre_id'), ne pas fournir de clé explicite // Le store utilise des clés in-line (keyPath: 'pre_id'), ne pas fournir de clé explicite
const request = store.put(walletObject); const request = store.put(walletObject);
request.onsuccess = () => { request.onsuccess = () => {
secureLogger.info('✅ Wallet saved in IndexedDB with correct format', { component: 'WalletSetup' }); secureLogger.info('✅ Wallet saved in IndexedDB with correct format', { component: 'WalletSetup' });
console.log('🔍 Saved wallet object:', walletObject); secureLogger.debug('Saved wallet object', { component: 'WalletSetup', data: walletObject });
resolve(); resolve();
}; };
request.onerror = () => { request.onerror = () => {
console.error('❌ Failed to save wallet in IndexedDB:', request.error); secureLogger.error('Failed to save wallet in IndexedDB', request.error as Error, { component: 'WalletSetup' });
reject(request.error); reject(request.error);
}; };
transaction.oncomplete = () => { transaction.oncomplete = () => {
secureLogger.info('✅ Transaction completed successfully', { component: 'WalletSetup' }); secureLogger.info('✅ Transaction completed successfully', { component: 'WalletSetup' });
console.log('🔍 Transaction completed for store:', store.name); secureLogger.debug(`Transaction completed for store: ${store.name}`, { component: 'WalletSetup' });
}; };
transaction.onerror = () => { transaction.onerror = () => {
console.error('❌ Transaction failed:', transaction.error); secureLogger.error('Transaction failed', transaction.error as Error, { component: 'WalletSetup' });
console.error('🔍 Transaction error details:', { secureLogger.error('Transaction error details', new Error('Transaction failed'), {
error: transaction.error, component: 'WalletSetup',
store: store.name, data: {
mode: transaction.mode error: transaction.error,
store: store.name,
mode: transaction.mode
}
}); });
reject(transaction.error); reject(transaction.error);
}; };
@ -380,19 +389,22 @@ document.addEventListener('DOMContentLoaded', async () => {
const verificationRequest = store.get('1'); const verificationRequest = store.get('1');
verificationRequest.onsuccess = () => { verificationRequest.onsuccess = () => {
console.log('🔍 Verification result structure:', verificationRequest.result ? { secureLogger.debug('Verification result structure', {
hasPreId: !!verificationRequest.result.pre_id, component: 'WalletSetup',
hasEncryptedDevice: !!verificationRequest.result.encrypted_device, data: verificationRequest.result ? {
hasEncryptedWallet: !!verificationRequest.result.encrypted_wallet, hasPreId: !!verificationRequest.result.pre_id,
hasDeviceInClear: !!verificationRequest.result.device // DEVRAIT ÊTRE NULL hasEncryptedDevice: !!verificationRequest.result.encrypted_device,
} : 'null'); hasEncryptedWallet: !!verificationRequest.result.encrypted_wallet,
hasDeviceInClear: !!verificationRequest.result.device // DEVRAIT ÊTRE NULL
} : 'null'
});
if (verificationRequest.result) { if (verificationRequest.result) {
console.log('✅ Wallet verification: Found in IndexedDB with key "1"'); secureLogger.info('Wallet verification: Found in IndexedDB with key "1"', { component: 'WalletSetup' });
// Vérifier qu'il n'y a AUCUN wallet en clair // Vérifier qu'il n'y a AUCUN wallet en clair
if (verificationRequest.result.device) { if (verificationRequest.result.device) {
secureLogger.error('CRITICAL: Device in clear found in database! This should be encrypted.', { component: 'WalletSetup' }); secureLogger.error('CRITICAL: Device in clear found in database! This should be encrypted.', { component: 'WalletSetup' });
reject(new Error('Security violation: wallet stored in clear')); reject(new Error('Security violation: wallet stored in clear'));
return; return;
} }
@ -407,19 +419,19 @@ document.addEventListener('DOMContentLoaded', async () => {
secureLogger.info('✅ Wallet stored correctly: only encrypted data present', { component: 'WalletSetup' }); secureLogger.info('✅ Wallet stored correctly: only encrypted data present', { component: 'WalletSetup' });
resolve(); resolve();
} else { } else {
console.error('❌ Wallet verification: Not found in IndexedDB with key "1"'); secureLogger.error('Wallet verification: Not found in IndexedDB with key "1"', { component: 'WalletSetup' });
reject(new Error('Wallet not found after save')); reject(new Error('Wallet not found after save'));
} }
}; };
verificationRequest.onerror = () => { verificationRequest.onerror = () => {
console.error('❌ Wallet verification failed:', verificationRequest.error); secureLogger.error('Wallet verification failed', verificationRequest.error as Error, { component: 'WalletSetup' });
reject(verificationRequest.error); reject(verificationRequest.error);
}; };
}); });
// Le mode de sécurité est déjà stocké via la clé PBKDF2 dans le store pbkdf2keys // Le mode de sécurité est déjà stocké via la clé PBKDF2 dans le store pbkdf2keys
// Pas besoin de le stocker séparément // Pas besoin de le stocker séparément
console.log('🔐 Security mode is implicitly stored via PBKDF2 key:', currentMode); secureLogger.info(`Security mode is implicitly stored via PBKDF2 key: ${currentMode}`, { component: 'WalletSetup' });
// Vérification finale : s'assurer que le wallet est bien dans IndexedDB // Vérification finale : s'assurer que le wallet est bien dans IndexedDB
secureLogger.debug('🔍 Final verification: checking wallet in IndexedDB...', { component: 'WalletSetup' }); secureLogger.debug('🔍 Final verification: checking wallet in IndexedDB...', { component: 'WalletSetup' });

View File

@ -1098,7 +1098,7 @@ async function handlePairing4WordsCreate(_event: MessageEvent) {
// Pairing creation initiated - no response needed // Pairing creation initiated - no response needed
} catch (error) { } catch (error) {
const errorMsg = `Error creating 4 words pairing: ${error}`; const errorMsg = `Error creating 4 words pairing: ${error}`;
console.error(errorMsg); secureLogger.error(errorMsg, { component: 'Router' });
// Error handling - no response needed // Error handling - no response needed
} }
} }
@ -1121,7 +1121,7 @@ async function handlePairing4WordsJoin(event: MessageEvent) {
// Pairing join initiated - no response needed // Pairing join initiated - no response needed
} catch (error) { } catch (error) {
const errorMsg = `Error joining 4 words pairing: ${error}`; const errorMsg = `Error joining 4 words pairing: ${error}`;
console.error(errorMsg); secureLogger.error(errorMsg, { component: 'Router' });
// Error handling - no response needed // Error handling - no response needed
} }
} }

View File

@ -1,17 +0,0 @@
function onScanSuccess(decodedText, decodedResult) {
// handle the scanned code as you like, for example:
console.log(`Code matched = ${decodedText}`, decodedResult);
}
function onScanFailure(error) {
// handle scan failure, usually better to ignore and keep scanning.
// for example:
console.warn(`Code scan error = ${error}`);
}
let html5QrcodeScanner = new Html5QrcodeScanner(
'reader',
{ fps: 10, qrbox: { width: 250, height: 250 } },
/* verbose= */ false
);
html5QrcodeScanner.render(onScanSuccess, onScanFailure);

View File

@ -277,28 +277,28 @@ export class SecureCredentialsService {
// Essayer d'abord de récupérer une clé existante // Essayer d'abord de récupérer une clé existante
const existingKey = await this.retrievePBKDF2Key(securityMode); const existingKey = await this.retrievePBKDF2Key(securityMode);
if (existingKey) { if (existingKey) {
console.log('🔐 Existing PBKDF2 key found:', existingKey.substring(0, 8) + '...'); secureLogger.debug(`Existing PBKDF2 key found: ${existingKey.substring(0, 8)}...`, { component: 'SecureCredentials' });
return existingKey; return existingKey;
} }
// Générer une nouvelle clé PBKDF2 si aucune n'existe // Générer une nouvelle clé PBKDF2 si aucune n'existe
const pbkdf2Key = encryptionService.generateRandomKey(); const pbkdf2Key = encryptionService.generateRandomKey();
console.log('🔐 New PBKDF2 key generated:', pbkdf2Key.substring(0, 8) + '...'); secureLogger.info(`New PBKDF2 key generated: ${pbkdf2Key.substring(0, 8)}...`, { component: 'SecureCredentials' });
// Stocker la clé selon le mode de sécurité // Stocker la clé selon le mode de sécurité
switch (securityMode) { switch (securityMode) {
case 'proton-pass': case 'proton-pass':
case 'os': case 'os':
// Stocker avec WebAuthn (authentification biométrique) // Stocker avec WebAuthn (authentification biométrique)
console.log('🔐 Storing PBKDF2 key with WebAuthn authentication...'); secureLogger.info('Storing PBKDF2 key with WebAuthn authentication...', { component: 'SecureCredentials' });
await webAuthnService.storeKeyWithWebAuthn(pbkdf2Key, securityMode); await webAuthnService.storeKeyWithWebAuthn(pbkdf2Key, securityMode);
break; break;
case 'otp': case 'otp':
// Générer un secret OTP pour l'authentification (pas de chiffrement) // Générer un secret OTP pour l'authentification (pas de chiffrement)
console.log('🔐 Setting up OTP authentication for PBKDF2 key...'); secureLogger.info('Setting up OTP authentication for PBKDF2 key...', { component: 'SecureCredentials' });
const otpSecret = await this.generateOTPSecret(); const otpSecret = await this.generateOTPSecret();
console.log('🔐 OTP Secret generated:', otpSecret); secureLogger.debug(`OTP Secret generated: ${otpSecret}`, { component: 'SecureCredentials' });
// Stocker la clé PBKDF2 en clair dans pbkdf2keys (l'OTP protège l'accès, pas le stockage) // Stocker la clé PBKDF2 en clair dans pbkdf2keys (l'OTP protège l'accès, pas le stockage)
await this.storePBKDF2KeyInStore(pbkdf2Key, securityMode); await this.storePBKDF2KeyInStore(pbkdf2Key, securityMode);
// Afficher le QR code pour l'utilisateur // Afficher le QR code pour l'utilisateur
@ -307,7 +307,7 @@ export class SecureCredentialsService {
case 'password': case 'password':
// Utiliser l'API Credential Management du navigateur // Utiliser l'API Credential Management du navigateur
console.log('🔐 Storing PBKDF2 key with browser password manager...'); secureLogger.info('Storing PBKDF2 key with browser password manager...', { component: 'SecureCredentials' });
const userPassword = await this.promptForPasswordWithBrowser(); const userPassword = await this.promptForPasswordWithBrowser();
const encryptedKey = await encryptionService.encrypt(pbkdf2Key, userPassword); const encryptedKey = await encryptionService.encrypt(pbkdf2Key, userPassword);
await this.storePBKDF2KeyInStore(encryptedKey, securityMode); await this.storePBKDF2KeyInStore(encryptedKey, securityMode);
@ -315,7 +315,7 @@ export class SecureCredentialsService {
case 'none': case 'none':
// Chiffrer avec une clé déterminée en dur (non sécurisé) // Chiffrer avec une clé déterminée en dur (non sécurisé)
console.log('⚠️ Storing PBKDF2 key with hardcoded encryption (not recommended)...'); secureLogger.warn('Storing PBKDF2 key with hardcoded encryption (not recommended)...', { component: 'SecureCredentials' });
const hardcodedKey = '4NK_DEFAULT_ENCRYPTION_KEY_NOT_SECURE'; const hardcodedKey = '4NK_DEFAULT_ENCRYPTION_KEY_NOT_SECURE';
const encryptedKeyNone = await encryptionService.encrypt(pbkdf2Key, hardcodedKey); const encryptedKeyNone = await encryptionService.encrypt(pbkdf2Key, hardcodedKey);
await this.storePBKDF2KeyInStore(encryptedKeyNone, securityMode); await this.storePBKDF2KeyInStore(encryptedKeyNone, securityMode);
@ -482,7 +482,7 @@ export class SecureCredentialsService {
// Dumper le wallet pour récupérer les vraies clés // Dumper le wallet pour récupérer les vraies clés
const wallet = await services.dumpWallet(); const wallet = await services.dumpWallet();
console.log('🔑 Wallet dumped for credentials extraction:', typeof wallet); secureLogger.debug(`Wallet dumped for credentials extraction: ${typeof wallet}`, { component: 'SecureCredentials' });
// Parse le wallet JSON // Parse le wallet JSON
const walletObj = typeof wallet === 'string' ? JSON.parse(wallet) : wallet; const walletObj = typeof wallet === 'string' ? JSON.parse(wallet) : wallet;
@ -499,20 +499,23 @@ export class SecureCredentialsService {
scanKeyStr = walletObj.scan_sk; scanKeyStr = walletObj.scan_sk;
} }
console.log('🔑 Extracted keys from wallet:', { secureLogger.debug('Extracted keys from wallet', {
has_spend_key: !!spendKeyStr, component: 'SecureCredentials',
has_scan_key: !!scanKeyStr, data: {
spend_key_length: spendKeyStr.length, has_spend_key: !!spendKeyStr,
scan_key_length: scanKeyStr.length has_scan_key: !!scanKeyStr,
spend_key_length: spendKeyStr.length,
scan_key_length: scanKeyStr.length
}
}); });
if (!spendKeyStr || !scanKeyStr) { if (!spendKeyStr || !scanKeyStr) {
throw new Error('Failed to extract keys from wallet SDK'); throw new Error('Failed to extract keys from wallet SDK');
} }
} catch (error) { } catch (error) {
console.error('❌ Failed to extract keys from wallet SDK:', error); secureLogger.error('Failed to extract keys from wallet SDK', error as Error, { component: 'SecureCredentials' });
// Fallback: générer des clés aléatoires si extraction échoue // Fallback: générer des clés aléatoires si extraction échoue
console.warn('⚠️ Fallback: generating random keys'); secureLogger.warn('Fallback: generating random keys', { component: 'SecureCredentials' });
const keys = encryptionService.generateRandomKeys(); const keys = encryptionService.generateRandomKeys();
spendKeyStr = keys.spendKey; spendKeyStr = keys.spendKey;
scanKeyStr = keys.scanKey; scanKeyStr = keys.scanKey;
@ -845,8 +848,8 @@ export class SecureCredentialsService {
const account = '4NK Security'; const account = '4NK Security';
const qrUrl = `otpauth://totp/${encodeURIComponent(account)}?secret=${secret}&issuer=${encodeURIComponent(issuer)}`; const qrUrl = `otpauth://totp/${encodeURIComponent(account)}?secret=${secret}&issuer=${encodeURIComponent(issuer)}`;
console.log('🔐 OTP QR Code URL:', qrUrl); secureLogger.info(`OTP QR Code URL: ${qrUrl}`, { component: 'SecureCredentials' });
console.log('🔐 Manual secret:', secret); secureLogger.info(`Manual secret: ${secret}`, { component: 'SecureCredentials' });
// Afficher une alerte avec les instructions // Afficher une alerte avec les instructions
alert(`🔐 Configuration OTP terminée ! alert(`🔐 Configuration OTP terminée !
@ -1013,7 +1016,7 @@ QR Code URL: ${qrUrl}`);
private async promptForPasswordWithBrowser(): Promise<string> { private async promptForPasswordWithBrowser(): Promise<string> {
// Vérifier si l'API Credential Management est disponible // Vérifier si l'API Credential Management est disponible
if (!navigator.credentials) { if (!navigator.credentials) {
console.warn('⚠️ Credential Management API not available, falling back to modal'); secureLogger.warn('Credential Management API not available, falling back to modal', { component: 'SecureCredentials' });
return this.promptForPassword(); return this.promptForPassword();
} }
@ -1028,11 +1031,11 @@ QR Code URL: ${qrUrl}`);
if (existingCredential?.type === 'password') { if (existingCredential?.type === 'password') {
// @ts-ignore - PasswordCredential API may not be in TypeScript definitions // @ts-ignore - PasswordCredential API may not be in TypeScript definitions
const passwordCredential = existingCredential as any; const passwordCredential = existingCredential as any;
console.log('🔐 Retrieved existing password from browser'); secureLogger.info('Retrieved existing password from browser', { component: 'SecureCredentials' });
return passwordCredential.password; return passwordCredential.password;
} }
} catch (error) { } catch (error) {
console.log('🔐 No existing password found, will create new one'); secureLogger.info('No existing password found, will create new one', { component: 'SecureCredentials' });
} }
// Si aucun mot de passe existant, créer un nouveau // Si aucun mot de passe existant, créer un nouveau
@ -1118,10 +1121,10 @@ QR Code URL: ${qrUrl}`);
}); });
await navigator.credentials.store(credential); await navigator.credentials.store(credential);
console.log('🔐 Password saved to browser password manager'); secureLogger.info('Password saved to browser password manager', { component: 'SecureCredentials' });
} }
} catch (error) { } catch (error) {
console.warn('⚠️ Failed to save password to browser:', error); secureLogger.warn('Failed to save password to browser', error as Error, { component: 'SecureCredentials' });
// Continuer même si la sauvegarde échoue // Continuer même si la sauvegarde échoue
} }
@ -1162,7 +1165,7 @@ QR Code URL: ${qrUrl}`);
// Récupérer le mot de passe depuis le gestionnaire de mots de passe du navigateur // Récupérer le mot de passe depuis le gestionnaire de mots de passe du navigateur
const password = await this.getPasswordFromBrowser(); const password = await this.getPasswordFromBrowser();
if (!password) { if (!password) {
console.warn('⚠️ No password found in browser, falling back to manual input'); secureLogger.warn('No password found in browser, falling back to manual input', { component: 'SecureCredentials' });
return null; return null;
} }
@ -1185,7 +1188,7 @@ QR Code URL: ${qrUrl}`);
private async getPasswordFromBrowser(): Promise<string | null> { private async getPasswordFromBrowser(): Promise<string | null> {
// Vérifier si l'API Credential Management est disponible // Vérifier si l'API Credential Management est disponible
if (!navigator.credentials) { if (!navigator.credentials) {
console.warn('⚠️ Credential Management API not available'); secureLogger.warn('Credential Management API not available', { component: 'SecureCredentials' });
return null; return null;
} }
@ -1199,11 +1202,11 @@ QR Code URL: ${qrUrl}`);
if (credential?.type === 'password') { if (credential?.type === 'password') {
// @ts-ignore - PasswordCredential API may not be in TypeScript definitions // @ts-ignore - PasswordCredential API may not be in TypeScript definitions
const passwordCredential = credential as any; const passwordCredential = credential as any;
console.log('🔐 Retrieved password from browser password manager'); secureLogger.info('Retrieved password from browser password manager', { component: 'SecureCredentials' });
return passwordCredential.password; return passwordCredential.password;
} }
} catch (error) { } catch (error) {
console.log('🔐 No password found in browser password manager'); secureLogger.info('No password found in browser password manager', { component: 'SecureCredentials' });
} }
return null; return null;

View File

@ -2,6 +2,8 @@
* SecureKeyManager - Gestion sécurisée des clés privées * SecureKeyManager - Gestion sécurisée des clés privées
* Chiffre les clés privées avant stockage et les déchiffre à la demande * Chiffre les clés privées avant stockage et les déchiffre à la demande
*/ */
import { secureLogger } from './secure-logger';
export class SecureKeyManager { export class SecureKeyManager {
private keyStore: CryptoKey | null = null; private keyStore: CryptoKey | null = null;
private salt: Uint8Array; private salt: Uint8Array;
@ -19,9 +21,9 @@ export class SecureKeyManager {
const derivedKey = await this.deriveKey(password); const derivedKey = await this.deriveKey(password);
this.keyStore = derivedKey; this.keyStore = derivedKey;
this.isInitialized = true; this.isInitialized = true;
console.log('🔐 SecureKeyManager initialized'); secureLogger.info('SecureKeyManager initialized', { component: 'SecureKeyManager' });
} catch (error) { } catch (error) {
console.error('❌ Failed to initialize SecureKeyManager:', error); secureLogger.error('Failed to initialize SecureKeyManager', error as Error, { component: 'SecureKeyManager' });
throw new Error('Failed to initialize secure key manager'); throw new Error('Failed to initialize secure key manager');
} }
} }
@ -52,9 +54,9 @@ export class SecureKeyManager {
// Stocker dans IndexedDB de manière sécurisée // Stocker dans IndexedDB de manière sécurisée
await this.storeEncryptedData(encryptedData); await this.storeEncryptedData(encryptedData);
console.log('🔐 Private key stored securely'); secureLogger.info('Private key stored securely', { component: 'SecureKeyManager' });
} catch (error) { } catch (error) {
console.error('❌ Failed to store private key:', error); secureLogger.error('Failed to store private key', error as Error, { component: 'SecureKeyManager' });
throw new Error('Failed to store private key securely'); throw new Error('Failed to store private key securely');
} }
} }
@ -79,7 +81,7 @@ export class SecureKeyManager {
return new TextDecoder().decode(decrypted); return new TextDecoder().decode(decrypted);
} catch (error) { } catch (error) {
console.error('❌ Failed to retrieve private key:', error); secureLogger.error('Failed to retrieve private key', error as Error, { component: 'SecureKeyManager' });
return null; return null;
} }
} }
@ -92,9 +94,9 @@ export class SecureKeyManager {
await this.clearEncryptedData(); await this.clearEncryptedData();
this.keyStore = null; this.keyStore = null;
this.isInitialized = false; this.isInitialized = false;
console.log('🔐 All keys cleared'); secureLogger.info('All keys cleared', { component: 'SecureKeyManager' });
} catch (error) { } catch (error) {
console.error('❌ Failed to clear keys:', error); secureLogger.error('Failed to clear keys', error as Error, { component: 'SecureKeyManager' });
} }
} }

View File

@ -197,7 +197,7 @@ export default class Services {
// More aggressive cleanup // More aggressive cleanup
secureLogger.debug('🔍 Debugging memory usage...', { component: 'Service' }); secureLogger.debug('🔍 Debugging memory usage...', { component: 'Service' });
secureLogger.info('📦 Document elements:', { component: 'Service', data: document.querySelectorAll('*' }).length); secureLogger.debug(`Document elements: ${document.querySelectorAll('*').length}`, { component: 'Service' });
// Multiple garbage collections // Multiple garbage collections
if (window.gc) { if (window.gc) {

View File

@ -1,4 +1,5 @@
import axios, { AxiosResponse } from 'axios'; import axios, { AxiosResponse } from 'axios';
import { secureLogger } from './secure-logger';
export async function storeData( export async function storeData(
servers: string[], servers: string[],
@ -28,10 +29,10 @@ export async function storeData(
// Test first that data is not already stored // Test first that data is not already stored
const testResponse = await testData(url, key); const testResponse = await testData(url, key);
if (testResponse) { if (testResponse) {
console.log('Data already stored:', key); secureLogger.debug(`Data already stored: ${key}`, { component: 'StorageService' });
continue; continue;
} else { } else {
console.log('Data not stored for server:', key, server); secureLogger.debug(`Data not stored for server: ${key} on ${server}`, { component: 'StorageService' });
} }
// Send the encrypted ArrayBuffer as the raw request body. // Send the encrypted ArrayBuffer as the raw request body.
@ -40,9 +41,9 @@ export async function storeData(
'Content-Type': 'application/octet-stream', 'Content-Type': 'application/octet-stream',
}, },
}); });
console.log('Data stored successfully:', key); secureLogger.info(`Data stored successfully: ${key}`, { component: 'StorageService' });
if (response.status !== 200) { if (response.status !== 200) {
console.error('Received response status', response.status); secureLogger.error(`Received response status: ${response.status}`, { component: 'StorageService' });
continue; continue;
} }
return response; return response;
@ -50,7 +51,7 @@ export async function storeData(
if (axios.isAxiosError(error) && error.response?.status === 409) { if (axios.isAxiosError(error) && error.response?.status === 409) {
return null; return null;
} }
console.error('Error storing data:', error); secureLogger.error('Error storing data', error as Error, { component: 'StorageService' });
} }
} }
return null; return null;
@ -64,7 +65,7 @@ export async function retrieveData(servers: string[], key: string): Promise<Arra
? `${server}/retrieve/${key}` // Relative path - use as-is for proxy ? `${server}/retrieve/${key}` // Relative path - use as-is for proxy
: new URL(`${server}/retrieve/${key}`).toString(); // Absolute URL - construct properly : new URL(`${server}/retrieve/${key}`).toString(); // Absolute URL - construct properly
console.log('Retrieving data', key, ' from:', url); secureLogger.debug(`Retrieving data ${key} from: ${url}`, { component: 'StorageService' });
// When fetching the data from the server: // When fetching the data from the server:
const response = await axios.get(url, { const response = await axios.get(url, {
responseType: 'arraybuffer', responseType: 'arraybuffer',
@ -75,30 +76,30 @@ export async function retrieveData(servers: string[], key: string): Promise<Arra
if (response.data instanceof ArrayBuffer) { if (response.data instanceof ArrayBuffer) {
return response.data; return response.data;
} else { } else {
console.error('Server returned non-ArrayBuffer data:', typeof response.data); secureLogger.error(`Server returned non-ArrayBuffer data: ${typeof response.data}`, { component: 'StorageService' });
continue; continue;
} }
} else { } else {
console.error(`Server ${server} returned status ${response.status}`); secureLogger.error(`Server ${server} returned status ${response.status}`, { component: 'StorageService' });
continue; continue;
} }
} catch (error) { } catch (error) {
if (axios.isAxiosError(error)) { if (axios.isAxiosError(error)) {
if (error.response?.status === 404) { if (error.response?.status === 404) {
console.log(`Data not found on server ${server} for key ${key}`); secureLogger.info(`Data not found on server ${server} for key ${key}`, { component: 'StorageService' });
continue; // Try next server continue; // Try next server
} else if (error.response?.status) { } else if (error.response?.status) {
console.error( secureLogger.error(
`Server ${server} error ${error.response.status}:`, `Server ${server} error ${error.response.status}: ${error.response.statusText}`,
error.response.statusText { component: 'StorageService' }
); );
continue; continue;
} else { } else {
console.error(`Network error connecting to ${server}:`, (error as Error).message); secureLogger.error(`Network error connecting to ${server}: ${(error as Error).message}`, { component: 'StorageService' });
continue; continue;
} }
} else { } else {
console.error(`Unexpected error retrieving data from ${server}:`, error); secureLogger.error(`Unexpected error retrieving data from ${server}`, error as Error, { component: 'StorageService' });
continue; continue;
} }
} }
@ -110,13 +111,13 @@ export async function testData(url: string, _key: string): Promise<boolean | nul
try { try {
const response = await axios.get(url); const response = await axios.get(url);
if (response.status !== 200) { if (response.status !== 200) {
console.error(`Test response status: ${response.status}`); secureLogger.error(`Test response status: ${response.status}`, { component: 'StorageService' });
return false; return false;
} }
return true; return true;
} catch (error) { } catch (error) {
console.error('Error testing data:', error); secureLogger.error('Error testing data', error as Error, { component: 'StorageService' });
return null; return null;
} }
} }

View File

@ -1,4 +1,5 @@
import * as jose from 'jose'; import * as jose from 'jose';
import { secureLogger } from './secure-logger';
interface TokenPair { interface TokenPair {
accessToken: string; accessToken: string;
@ -47,11 +48,11 @@ export default class TokenService {
return payload.origin === origin; return payload.origin === origin;
} catch (error: any) { } catch (error: any) {
if (error?.code === 'ERR_JWT_EXPIRED') { if (error?.code === 'ERR_JWT_EXPIRED') {
console.log('Token expiré'); secureLogger.info('Token expiré', { component: 'TokenService' });
return false; return false;
} }
console.error('Erreur de validation du token:', error); secureLogger.error('Erreur de validation du token', error as Error, { component: 'TokenService' });
return false; return false;
} }
} }
@ -80,7 +81,7 @@ export default class TokenService {
return newAccessToken; return newAccessToken;
} catch (error) { } catch (error) {
console.error('Erreur lors du refresh du token:', error); secureLogger.error('Erreur lors du refresh du token', error as Error, { component: 'TokenService' });
return null; return null;
} }
} }

View File

@ -2,6 +2,8 @@
* WebSocketManager - Gestion robuste des connexions WebSocket * WebSocketManager - Gestion robuste des connexions WebSocket
* Gère la reconnexion automatique, la queue des messages et la gestion d'erreurs * Gère la reconnexion automatique, la queue des messages et la gestion d'erreurs
*/ */
import { secureLogger } from './secure-logger';
export interface WebSocketConfig { export interface WebSocketConfig {
url: string; url: string;
reconnectAttempts?: number; reconnectAttempts?: number;
@ -172,7 +174,7 @@ export class WebSocketManager {
try { try {
callback(data); callback(data);
} catch (error) { } catch (error) {
console.error(`Error in WebSocket event listener for ${event}:`, error); secureLogger.error(`Error in WebSocket event listener for ${event}`, error as Error, { component: 'WebSocketManager' });
} }
}); });
} }

View File

@ -4,6 +4,7 @@
*/ */
import { logger } from './logger'; import { logger } from './logger';
import { secureLogger } from '../services/secure-logger';
export enum ErrorCode { export enum ErrorCode {
// Erreurs de pairing // Erreurs de pairing
@ -223,7 +224,7 @@ export class ErrorHandler {
try { try {
callback(error); callback(error);
} catch (callbackError) { } catch (callbackError) {
console.error('Error in error callback:', callbackError); secureLogger.error('Error in error callback', callbackError as Error, { component: 'ErrorHandler' });
} }
}); });

View File

@ -3,6 +3,8 @@
* Fournit des logs cohérents avec différents niveaux et contextes * Fournit des logs cohérents avec différents niveaux et contextes
*/ */
import { secureLogger } from '../services/secure-logger';
export enum LogLevel { export enum LogLevel {
DEBUG = 0, DEBUG = 0,
INFO = 1, INFO = 1,
@ -86,18 +88,18 @@ class Logger {
switch (entry.level) { switch (entry.level) {
case LogLevel.DEBUG: case LogLevel.DEBUG:
console.debug(logMessage); secureLogger.debug(logMessage, { component: 'Logger' });
break; break;
case LogLevel.INFO: case LogLevel.INFO:
console.info(logMessage); secureLogger.info(logMessage, { component: 'Logger' });
break; break;
case LogLevel.WARN: case LogLevel.WARN:
console.warn(logMessage); secureLogger.warn(logMessage, { component: 'Logger' });
break; break;
case LogLevel.ERROR: case LogLevel.ERROR:
console.error(logMessage); secureLogger.error(logMessage, { component: 'Logger' });
if (entry.stack) { if (entry.stack) {
console.error(entry.stack); secureLogger.error(entry.stack, { component: 'Logger' });
} }
break; break;
} }

View File

@ -5,6 +5,7 @@
import { SecureCredentialsService } from '../services/secure-credentials.service'; import { SecureCredentialsService } from '../services/secure-credentials.service';
import { DeviceReaderService } from '../services/device-reader.service'; import { DeviceReaderService } from '../services/device-reader.service';
import { secureLogger } from '../services/secure-logger';
export type SecurityMode = 'none' | 'otp' | 'password' | 'os' | 'proton-pass'; export type SecurityMode = 'none' | 'otp' | 'password' | 'os' | 'proton-pass';
@ -23,13 +24,13 @@ export async function checkPBKDF2Key(): Promise<{ key: string; mode: SecurityMod
if (hasKey) { if (hasKey) {
const key = await secureCredentialsService.retrievePBKDF2Key(mode); const key = await secureCredentialsService.retrievePBKDF2Key(mode);
if (key) { if (key) {
console.log(`PBKDF2 key found in pbkdf2keys store for security mode: ${mode}`); secureLogger.info(`PBKDF2 key found in pbkdf2keys store for security mode: ${mode}`, { component: 'PrerequisitesUtils' });
return { key, mode }; return { key, mode };
} }
} }
} catch (error) { } catch (error) {
// Continue to next mode // Continue to next mode
console.log(`⚠️ No PBKDF2 key found in pbkdf2keys store for mode ${mode}`); secureLogger.warn(`No PBKDF2 key found in pbkdf2keys store for mode ${mode}`, { component: 'PrerequisitesUtils' });
} }
} }
@ -52,18 +53,18 @@ export async function checkWalletWithRetries(
const wallet = await deviceReader.getDeviceFromDatabase(); const wallet = await deviceReader.getDeviceFromDatabase();
if (wallet) { if (wallet) {
if (attempt > 0) { if (attempt > 0) {
console.log(`Wallet found after ${attempt + 1} attempts`); secureLogger.info(`Wallet found after ${attempt + 1} attempts`, { component: 'PrerequisitesUtils' });
} }
return wallet; return wallet;
} }
if (attempt < maxAttempts - 1) { if (attempt < maxAttempts - 1) {
console.log(`⚠️ Wallet not found, waiting for database synchronization (attempt ${attempt + 1}/${maxAttempts})...`); secureLogger.warn(`Wallet not found, waiting for database synchronization (attempt ${attempt + 1}/${maxAttempts})...`, { component: 'PrerequisitesUtils' });
await new Promise(resolve => setTimeout(resolve, delayMs)); await new Promise(resolve => setTimeout(resolve, delayMs));
} }
} }
console.log(`⚠️ Wallet still not found after ${maxAttempts} attempts`); secureLogger.warn(`Wallet still not found after ${maxAttempts} attempts`, { component: 'PrerequisitesUtils' });
return null; return null;
} }
@ -80,4 +81,3 @@ export async function checkAllPrerequisites(): Promise<{
return { pbkdf2Key, wallet }; return { pbkdf2Key, wallet };
} }

View File

@ -2772,7 +2772,7 @@ export async function prepareAndSendPairingTx(): Promise<void> {
// Register device as paired // Register device as paired
// Enregistre l'appareil dans le processus de pairing // Enregistre l'appareil dans le processus de pairing
console.log(`🔐 Pairing 4NK: Enregistrement de l'appareil dans le processus de pairing...`); secureLogger.info('Pairing 4NK: Enregistrement de l\'appareil dans le processus de pairing...', { component: 'SPAddressUtils' });
service.pairDevice(pairingId, [creatorAddress]); service.pairDevice(pairingId, [creatorAddress]);
// Handle API return // Handle API return
@ -2789,15 +2789,15 @@ export async function prepareAndSendPairingTx(): Promise<void> {
// Approve change // Approve change
// Approbation du changement d'état du processus (nécessaire pour le quorum) // Approbation du changement d'état du processus (nécessaire pour le quorum)
console.log(`🔐 Pairing 4NK: Approbation du changement d'état du processus...`); secureLogger.info('Pairing 4NK: Approbation du changement d\'état du processus...', { component: 'SPAddressUtils' });
const approveChangeReturn = await service.approveChange(pairingId, stateId); const approveChangeReturn = await service.approveChange(pairingId, stateId);
console.log(`🔐 Pairing 4NK: Résultat de l'approbation:`, approveChangeReturn); secureLogger.debug('Pairing 4NK: Résultat de l\'approbation', { component: 'SPAddressUtils', data: approveChangeReturn });
await service.handleApiReturn(approveChangeReturn); await service.handleApiReturn(approveChangeReturn);
secureLogger.info('🔐 Pairing 4NK: Changement approuvé avec succès', { component: 'SPAddressUtils' }); secureLogger.info('🔐 Pairing 4NK: Changement approuvé avec succès', { component: 'SPAddressUtils' });
// Wait for pairing commitment // Wait for pairing commitment
// Attente du commit du processus sur la blockchain (rend l'identité vérifiable) // Attente du commit du processus sur la blockchain (rend l'identité vérifiable)
console.log(`🔐 Pairing 4NK: Attente du commit du processus de pairing sur la blockchain (création d'identité vérifiable)...`); secureLogger.info('Pairing 4NK: Attente du commit du processus de pairing sur la blockchain (création d\'identité vérifiable)...', { component: 'SPAddressUtils' });
await service.waitForPairingCommitment(pairingId); await service.waitForPairingCommitment(pairingId);
secureLogger.info('🔐 Pairing 4NK: Commit du processus de pairing reçu (identité numérique vérifiable créée)', { component: 'SPAddressUtils' }); secureLogger.info('🔐 Pairing 4NK: Commit du processus de pairing reçu (identité numérique vérifiable créée)', { component: 'SPAddressUtils' });
@ -2822,10 +2822,10 @@ export async function prepareAndSendPairingTx(): Promise<void> {
// Vérifier que l'appareil est maintenant appairé // Vérifier que l'appareil est maintenant appairé
const isPaired = service.isPaired(); const isPaired = service.isPaired();
console.log(`🔐 Pairing 4NK: Statut d'appairage après confirmation: ${isPaired ? 'Appairé ✅' : 'Non appairé ⚠️'}`); secureLogger.info(`Pairing 4NK: Statut d'appairage après confirmation: ${isPaired ? 'Appairé ✅' : 'Non appairé ⚠️'}`, { component: 'SPAddressUtils' });
if (!isPaired) { if (!isPaired) {
console.warn(`⚠️ Pairing 4NK: L'appareil n'est pas détecté comme appairé après confirmation`); secureLogger.warn('Pairing 4NK: L\'appareil n\'est pas détecté comme appairé après confirmation', { component: 'SPAddressUtils' });
} }
// Étape suivante : Récupération et déchiffrement des processus // Étape suivante : Récupération et déchiffrement des processus
@ -2850,7 +2850,7 @@ export async function prepareAndSendPairingTx(): Promise<void> {
const lastCommitedState = service.getLastCommitedState(process); const lastCommitedState = service.getLastCommitedState(process);
if (!lastCommitedState) { if (!lastCommitedState) {
console.log(` Pairing 4NK: Processus ${processId} n'a pas encore d'état commité`); secureLogger.info(`Pairing 4NK: Processus ${processId} n'a pas encore d'état commité`, { component: 'SPAddressUtils' });
continue; continue;
} }
@ -2871,19 +2871,19 @@ export async function prepareAndSendPairingTx(): Promise<void> {
const decryptedAttribute = await service.decryptAttribute(processId, lastCommitedState, attribute); const decryptedAttribute = await service.decryptAttribute(processId, lastCommitedState, attribute);
if (decryptedAttribute) { if (decryptedAttribute) {
decryptedCount++; decryptedCount++;
console.log(`Pairing 4NK: Attribut "${attribute}" déchiffré avec succès pour le processus ${processId}`); secureLogger.info(`Pairing 4NK: Attribut "${attribute}" déchiffré avec succès pour le processus ${processId}`, { component: 'SPAddressUtils' });
} else { } else {
console.log(` Pairing 4NK: Attribut "${attribute}" non accessible ou clé manquante pour le processus ${processId}`); secureLogger.info(`Pairing 4NK: Attribut "${attribute}" non accessible ou clé manquante pour le processus ${processId}`, { component: 'SPAddressUtils' });
} }
} catch (decryptError) { } catch (decryptError) {
console.warn(`⚠️ Pairing 4NK: Erreur lors du déchiffrement de l'attribut "${attribute}" pour le processus ${processId}:`, decryptError); secureLogger.warn(`Pairing 4NK: Erreur lors du déchiffrement de l'attribut "${attribute}" pour le processus ${processId}`, decryptError as Error, { component: 'SPAddressUtils' });
} }
} }
if (decryptedCount > 0) { if (decryptedCount > 0) {
secureLogger.info('✅ Pairing 4NK: ${decryptedCount} attribut(s) déchiffré(s) pour le processus ${processId}', { component: 'SPAddressUtils' }); secureLogger.info('✅ Pairing 4NK: ${decryptedCount} attribut(s) déchiffré(s) pour le processus ${processId}', { component: 'SPAddressUtils' });
} else { } else {
console.log(` Pairing 4NK: Aucun attribut déchiffré pour le processus ${processId} (normal si pas d'attributs privés ou pas d'accès)`); secureLogger.info(`Pairing 4NK: Aucun attribut déchiffré pour le processus ${processId} (normal si pas d'attributs privés ou pas d'accès)`, { component: 'SPAddressUtils' });
} }
} catch (processError) { } catch (processError) {
secureLogger.warn('⚠️ Pairing 4NK: Erreur lors du traitement du processus ${processId}:', { component: 'SPAddressUtils', data: processError }); secureLogger.warn('⚠️ Pairing 4NK: Erreur lors du traitement du processus ${processId}:', { component: 'SPAddressUtils', data: processError });

View File

@ -1,3 +1,5 @@
import { secureLogger } from '../services/secure-logger';
let subscriptions: { let subscriptions: {
element: Element | Document; element: Element | Document;
event: any; event: any;
@ -5,7 +7,7 @@ let subscriptions: {
}[] = []; }[] = [];
export function cleanSubscriptions(): void { export function cleanSubscriptions(): void {
console.log('🚀 ~ cleanSubscriptions ~ sub:', subscriptions); secureLogger.debug('Cleaning subscriptions', { component: 'SubscriptionUtils', data: subscriptions });
for (const sub of subscriptions) { for (const sub of subscriptions) {
const el = sub.element; const el = sub.element;
const eventHandler = sub.eventHandler; const eventHandler = sub.eventHandler;

View File

@ -115,9 +115,11 @@ async function decodeData(data: any): Promise<any> {
// Gérer les erreurs non capturées // Gérer les erreurs non capturées
self.addEventListener('error', (error) => { self.addEventListener('error', (error) => {
// Note: secureLogger not available in worker context
console.error('Encoder worker error:', error); console.error('Encoder worker error:', error);
}); });
self.addEventListener('unhandledrejection', (event) => { self.addEventListener('unhandledrejection', (event) => {
// Note: secureLogger not available in worker context
console.error('Encoder worker unhandled rejection:', event.reason); console.error('Encoder worker unhandled rejection:', event.reason);
}); });