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:
parent
c9ff430b09
commit
222f92e058
@ -1,5 +1,6 @@
|
||||
import Services from '../../services/service';
|
||||
import { addressToWords } from '../../utils/sp-address.utils';
|
||||
import { secureLogger } from '../../services/secure-logger';
|
||||
|
||||
// Global function declarations
|
||||
declare global {
|
||||
@ -51,7 +52,7 @@ export class DeviceManagementComponent extends HTMLElement {
|
||||
}
|
||||
}
|
||||
} 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();
|
||||
}, 2000);
|
||||
} 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');
|
||||
}
|
||||
}
|
||||
@ -834,9 +835,9 @@ export class DeviceManagementComponent extends HTMLElement {
|
||||
// Add to document body
|
||||
document.body.appendChild(navContainer);
|
||||
|
||||
console.log('✅ Account navigation injected');
|
||||
secureLogger.info('Account navigation injected', { component: 'DeviceManagement' });
|
||||
} catch (error) {
|
||||
console.error('❌ Error injecting account navigation:', error);
|
||||
secureLogger.error('Error injecting account navigation', error as Error, { component: 'DeviceManagement' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import ModalService from '../../services/modal.service';
|
||||
import { secureLogger } from '../../services/secure-logger';
|
||||
|
||||
async function validate() {
|
||||
console.log('==> VALIDATE');
|
||||
secureLogger.debug('Validation modal triggered', { component: 'ValidationModal' });
|
||||
const modalservice = await ModalService.getInstance();
|
||||
modalservice.closeValidationModal();
|
||||
}
|
||||
|
||||
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) {
|
||||
let diffs = '';
|
||||
for (const value of diff) {
|
||||
|
||||
@ -16,8 +16,8 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
isInitializing = true;
|
||||
secureLogger.info('🎂 Birthday setup page loaded', { component: 'BirthdaySetup' });
|
||||
console.log('🔍 Current URL:', window.location.href);
|
||||
console.log('🔍 Referrer:', document.referrer);
|
||||
secureLogger.debug(`Current URL: ${window.location.href}`, { component: 'BirthdaySetup' });
|
||||
secureLogger.debug(`Referrer: ${document.referrer}`, { component: 'BirthdaySetup' });
|
||||
|
||||
const status = document.getElementById('status') as HTMLDivElement;
|
||||
const progressBar = document.getElementById('progressBar') as HTMLDivElement;
|
||||
@ -31,7 +31,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
try {
|
||||
secureLogger.info('🔄 Importing services...', { component: 'BirthdaySetup' });
|
||||
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
|
||||
const Services = serviceModule.default;
|
||||
@ -84,7 +84,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// Vérifier que le wallet contient bien les données attendues
|
||||
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 {
|
||||
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
|
||||
const currentBlockHeight = services.getCurrentBlockHeight();
|
||||
if (currentBlockHeight !== -1 && currentBlockHeight > 0) {
|
||||
console.log('✅ Relays connected successfully, chain_tip:', currentBlockHeight);
|
||||
console.log('✅ Communication handshake completed, chain_tip:', currentBlockHeight);
|
||||
secureLogger.info(`Relays connected successfully, chain_tip: ${currentBlockHeight}`, { component: 'BirthdaySetup' });
|
||||
secureLogger.info(`Communication handshake completed, chain_tip: ${currentBlockHeight}`, { component: 'BirthdaySetup' });
|
||||
} else {
|
||||
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' });
|
||||
const updatedWallet = await services.getDeviceFromDatabase();
|
||||
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 {
|
||||
console.error('❌ Birthday update verification failed:', {
|
||||
birthday: updatedWallet?.sp_wallet?.birthday,
|
||||
hasSpWallet: !!updatedWallet?.sp_wallet
|
||||
secureLogger.error('Birthday update verification failed', new Error('Verification failed'), {
|
||||
component: 'BirthdaySetup',
|
||||
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}`);
|
||||
}
|
||||
@ -170,13 +173,13 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
}, 1000);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Services not available:', error);
|
||||
secureLogger.error('Services not available', error as Error, { component: 'BirthdaySetup' });
|
||||
updateStatus('❌ Erreur: Services non disponibles', 'error');
|
||||
throw 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');
|
||||
} finally {
|
||||
isInitializing = false;
|
||||
|
||||
@ -91,7 +91,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
break;
|
||||
} catch (error) {
|
||||
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) {
|
||||
throw new Error('Failed to initialize services after maximum attempts');
|
||||
}
|
||||
@ -214,14 +214,14 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
} catch (error) {
|
||||
// Restaurer la fonction console.log originale en cas d'erreur
|
||||
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');
|
||||
updateSyncItem('blocksToScan', 'Erreur', 'error');
|
||||
throw 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');
|
||||
|
||||
// Rediriger vers la page appropriée selon l'erreur
|
||||
|
||||
@ -90,7 +90,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// Vérifier que le wallet contient bien les données attendues
|
||||
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 {
|
||||
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' });
|
||||
} 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');
|
||||
|
||||
// Si l'erreur est liée aux prérequis, rediriger vers la page appropriée
|
||||
|
||||
@ -14,7 +14,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// Initialiser la base de données avec la configuration complète
|
||||
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();
|
||||
secureLogger.info('✅ Database initialized successfully', { component: 'SecuritySetup' });
|
||||
} catch (error) {
|
||||
@ -62,7 +62,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('🔐 Processing security mode:', selectedMode);
|
||||
secureLogger.info(`Processing security mode: ${selectedMode}`, { component: 'SecuritySetup' });
|
||||
|
||||
// Sauvegarder le mode de sécurité
|
||||
const { SecurityModeService } = await import('../../services/security-mode.service');
|
||||
@ -71,7 +71,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
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
|
||||
continueBtn.disabled = true;
|
||||
@ -82,7 +82,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
const { SecureCredentialsService } = await import('../../services/secure-credentials.service');
|
||||
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
|
||||
// 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';
|
||||
|
||||
} 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.');
|
||||
|
||||
// Réactiver le bouton
|
||||
@ -103,7 +103,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
}
|
||||
|
||||
} 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é');
|
||||
|
||||
// Réactiver le bouton
|
||||
|
||||
@ -69,7 +69,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
}
|
||||
|
||||
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à
|
||||
updateStatus('🔍 Vérification du wallet existant...', 'loading');
|
||||
@ -135,7 +135,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
await Promise.all(cacheNames.map(name => caches.delete(name)));
|
||||
secureLogger.info('🧹 Caches cleared', { component: 'WalletSetup' });
|
||||
} 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 {
|
||||
secureLogger.info('🔄 Importing services...', { component: 'WalletSetup' });
|
||||
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
|
||||
const Services = serviceModule.default;
|
||||
@ -182,7 +182,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
break;
|
||||
} catch (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
|
||||
if (errorMessage.includes('Out of memory') || errorMessage.includes('insufficient memory')) {
|
||||
@ -208,7 +208,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Services not available:', error);
|
||||
secureLogger.error('Services not available', error as Error, { component: 'WalletSetup' });
|
||||
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
|
||||
// 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
|
||||
const { EncryptionService } = await import('../../services/encryption.service');
|
||||
@ -237,14 +237,14 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
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é
|
||||
// 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;
|
||||
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');
|
||||
throw new Error('CRITICAL: Failed to retrieve PBKDF2 key');
|
||||
}
|
||||
@ -256,21 +256,21 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
pbkdf2Key
|
||||
);
|
||||
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
|
||||
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 request = indexedDB.open(DATABASE_CONFIG.name, DATABASE_CONFIG.version); // Utiliser la version centralisée
|
||||
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);
|
||||
};
|
||||
request.onsuccess = () => {
|
||||
secureLogger.info('✅ IndexedDB opened successfully', { component: 'WalletSetup' });
|
||||
console.log('🔍 Database name:', request.result.name);
|
||||
console.log('🔍 Database version:', request.result.version);
|
||||
console.log('🔍 Available stores:', Array.from(request.result.objectStoreNames));
|
||||
secureLogger.debug(`Database name: ${request.result.name}`, { component: 'WalletSetup' });
|
||||
secureLogger.debug(`Database version: ${request.result.version}`, { component: 'WalletSetup' });
|
||||
secureLogger.debug(`Available stores: ${Array.from(request.result.objectStoreNames)}`, { component: 'WalletSetup' });
|
||||
resolve(request.result);
|
||||
};
|
||||
request.onupgradeneeded = () => {
|
||||
@ -299,26 +299,29 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// We set birthday later when we have the chain tip from relay
|
||||
secureLogger.info('🔧 Creating new device with birthday 0...', { component: 'WalletSetup' });
|
||||
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
|
||||
secureLogger.info('🔧 Forcing wallet generation...', { component: 'WalletSetup' });
|
||||
try {
|
||||
const wallet = await services.sdkClient.dump_wallet();
|
||||
console.log('✅ Wallet generated:', JSON.stringify(wallet));
|
||||
secureLogger.debug('Wallet generated', { component: 'WalletSetup', data: wallet });
|
||||
} 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
|
||||
const device = services.dumpDeviceFromMemory();
|
||||
console.log('🔍 Device structure from SDK:', {
|
||||
hasSpWallet: !!device.sp_wallet,
|
||||
hasSpClient: !!device.sp_client,
|
||||
spClientKeys: device.sp_client ? Object.keys(device.sp_client) : 'none'
|
||||
secureLogger.debug('Device structure from SDK', {
|
||||
component: 'WalletSetup',
|
||||
data: {
|
||||
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
|
||||
// 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) => {
|
||||
const transaction = db.transaction([DATABASE_CONFIG.stores.wallet.name], 'readwrite');
|
||||
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
|
||||
const walletObject = {
|
||||
@ -340,34 +343,40 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
};
|
||||
|
||||
secureLogger.debug('🔍 Attempting to save encrypted wallet object', { component: 'WalletSetup' });
|
||||
console.log('🔐 Object contains only encrypted data:', {
|
||||
hasEncryptedDevice: !!walletObject.encrypted_device,
|
||||
hasEncryptedWallet: !!walletObject.encrypted_wallet,
|
||||
// Ne pas logger le contenu chiffré
|
||||
secureLogger.debug('Object contains only encrypted data', {
|
||||
component: 'WalletSetup',
|
||||
data: {
|
||||
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
|
||||
const request = store.put(walletObject);
|
||||
request.onsuccess = () => {
|
||||
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();
|
||||
};
|
||||
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);
|
||||
};
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
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 = () => {
|
||||
console.error('❌ Transaction failed:', transaction.error);
|
||||
console.error('🔍 Transaction error details:', {
|
||||
error: transaction.error,
|
||||
store: store.name,
|
||||
mode: transaction.mode
|
||||
secureLogger.error('Transaction failed', transaction.error as Error, { component: 'WalletSetup' });
|
||||
secureLogger.error('Transaction error details', new Error('Transaction failed'), {
|
||||
component: 'WalletSetup',
|
||||
data: {
|
||||
error: transaction.error,
|
||||
store: store.name,
|
||||
mode: transaction.mode
|
||||
}
|
||||
});
|
||||
reject(transaction.error);
|
||||
};
|
||||
@ -380,19 +389,22 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
const verificationRequest = store.get('1');
|
||||
verificationRequest.onsuccess = () => {
|
||||
console.log('🔍 Verification result structure:', verificationRequest.result ? {
|
||||
hasPreId: !!verificationRequest.result.pre_id,
|
||||
hasEncryptedDevice: !!verificationRequest.result.encrypted_device,
|
||||
hasEncryptedWallet: !!verificationRequest.result.encrypted_wallet,
|
||||
hasDeviceInClear: !!verificationRequest.result.device // DEVRAIT ÊTRE NULL
|
||||
} : 'null');
|
||||
secureLogger.debug('Verification result structure', {
|
||||
component: 'WalletSetup',
|
||||
data: verificationRequest.result ? {
|
||||
hasPreId: !!verificationRequest.result.pre_id,
|
||||
hasEncryptedDevice: !!verificationRequest.result.encrypted_device,
|
||||
hasEncryptedWallet: !!verificationRequest.result.encrypted_wallet,
|
||||
hasDeviceInClear: !!verificationRequest.result.device // DEVRAIT ÊTRE NULL
|
||||
} : 'null'
|
||||
});
|
||||
|
||||
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
|
||||
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'));
|
||||
return;
|
||||
}
|
||||
@ -407,19 +419,19 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
secureLogger.info('✅ Wallet stored correctly: only encrypted data present', { component: 'WalletSetup' });
|
||||
resolve();
|
||||
} 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'));
|
||||
}
|
||||
};
|
||||
verificationRequest.onerror = () => {
|
||||
console.error('❌ Wallet verification failed:', verificationRequest.error);
|
||||
secureLogger.error('Wallet verification failed', verificationRequest.error as Error, { component: 'WalletSetup' });
|
||||
reject(verificationRequest.error);
|
||||
};
|
||||
});
|
||||
|
||||
// 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
|
||||
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
|
||||
secureLogger.debug('🔍 Final verification: checking wallet in IndexedDB...', { component: 'WalletSetup' });
|
||||
|
||||
@ -1098,7 +1098,7 @@ async function handlePairing4WordsCreate(_event: MessageEvent) {
|
||||
// Pairing creation initiated - no response needed
|
||||
} catch (error) {
|
||||
const errorMsg = `Error creating 4 words pairing: ${error}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
}
|
||||
@ -1121,7 +1121,7 @@ async function handlePairing4WordsJoin(event: MessageEvent) {
|
||||
// Pairing join initiated - no response needed
|
||||
} catch (error) {
|
||||
const errorMsg = `Error joining 4 words pairing: ${error}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
@ -277,28 +277,28 @@ export class SecureCredentialsService {
|
||||
// Essayer d'abord de récupérer une clé existante
|
||||
const existingKey = await this.retrievePBKDF2Key(securityMode);
|
||||
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;
|
||||
}
|
||||
|
||||
// Générer une nouvelle clé PBKDF2 si aucune n'existe
|
||||
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é
|
||||
switch (securityMode) {
|
||||
case 'proton-pass':
|
||||
case 'os':
|
||||
// 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);
|
||||
break;
|
||||
|
||||
case 'otp':
|
||||
// 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();
|
||||
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)
|
||||
await this.storePBKDF2KeyInStore(pbkdf2Key, securityMode);
|
||||
// Afficher le QR code pour l'utilisateur
|
||||
@ -307,7 +307,7 @@ export class SecureCredentialsService {
|
||||
|
||||
case 'password':
|
||||
// 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 encryptedKey = await encryptionService.encrypt(pbkdf2Key, userPassword);
|
||||
await this.storePBKDF2KeyInStore(encryptedKey, securityMode);
|
||||
@ -315,7 +315,7 @@ export class SecureCredentialsService {
|
||||
|
||||
case 'none':
|
||||
// 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 encryptedKeyNone = await encryptionService.encrypt(pbkdf2Key, hardcodedKey);
|
||||
await this.storePBKDF2KeyInStore(encryptedKeyNone, securityMode);
|
||||
@ -482,7 +482,7 @@ export class SecureCredentialsService {
|
||||
|
||||
// Dumper le wallet pour récupérer les vraies clés
|
||||
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
|
||||
const walletObj = typeof wallet === 'string' ? JSON.parse(wallet) : wallet;
|
||||
@ -499,20 +499,23 @@ export class SecureCredentialsService {
|
||||
scanKeyStr = walletObj.scan_sk;
|
||||
}
|
||||
|
||||
console.log('🔑 Extracted keys from wallet:', {
|
||||
has_spend_key: !!spendKeyStr,
|
||||
has_scan_key: !!scanKeyStr,
|
||||
spend_key_length: spendKeyStr.length,
|
||||
scan_key_length: scanKeyStr.length
|
||||
secureLogger.debug('Extracted keys from wallet', {
|
||||
component: 'SecureCredentials',
|
||||
data: {
|
||||
has_spend_key: !!spendKeyStr,
|
||||
has_scan_key: !!scanKeyStr,
|
||||
spend_key_length: spendKeyStr.length,
|
||||
scan_key_length: scanKeyStr.length
|
||||
}
|
||||
});
|
||||
|
||||
if (!spendKeyStr || !scanKeyStr) {
|
||||
throw new Error('Failed to extract keys from wallet SDK');
|
||||
}
|
||||
} 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
|
||||
console.warn('⚠️ Fallback: generating random keys');
|
||||
secureLogger.warn('Fallback: generating random keys', { component: 'SecureCredentials' });
|
||||
const keys = encryptionService.generateRandomKeys();
|
||||
spendKeyStr = keys.spendKey;
|
||||
scanKeyStr = keys.scanKey;
|
||||
@ -845,8 +848,8 @@ export class SecureCredentialsService {
|
||||
const account = '4NK Security';
|
||||
const qrUrl = `otpauth://totp/${encodeURIComponent(account)}?secret=${secret}&issuer=${encodeURIComponent(issuer)}`;
|
||||
|
||||
console.log('🔐 OTP QR Code URL:', qrUrl);
|
||||
console.log('🔐 Manual secret:', secret);
|
||||
secureLogger.info(`OTP QR Code URL: ${qrUrl}`, { component: 'SecureCredentials' });
|
||||
secureLogger.info(`Manual secret: ${secret}`, { component: 'SecureCredentials' });
|
||||
|
||||
// Afficher une alerte avec les instructions
|
||||
alert(`🔐 Configuration OTP terminée !
|
||||
@ -1013,7 +1016,7 @@ QR Code URL: ${qrUrl}`);
|
||||
private async promptForPasswordWithBrowser(): Promise<string> {
|
||||
// Vérifier si l'API Credential Management est disponible
|
||||
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();
|
||||
}
|
||||
|
||||
@ -1028,11 +1031,11 @@ QR Code URL: ${qrUrl}`);
|
||||
if (existingCredential?.type === 'password') {
|
||||
// @ts-ignore - PasswordCredential API may not be in TypeScript definitions
|
||||
const passwordCredential = existingCredential as any;
|
||||
console.log('🔐 Retrieved existing password from browser');
|
||||
secureLogger.info('Retrieved existing password from browser', { component: 'SecureCredentials' });
|
||||
return passwordCredential.password;
|
||||
}
|
||||
} 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
|
||||
@ -1118,10 +1121,10 @@ QR Code URL: ${qrUrl}`);
|
||||
});
|
||||
|
||||
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) {
|
||||
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
|
||||
}
|
||||
|
||||
@ -1162,7 +1165,7 @@ QR Code URL: ${qrUrl}`);
|
||||
// Récupérer le mot de passe depuis le gestionnaire de mots de passe du navigateur
|
||||
const password = await this.getPasswordFromBrowser();
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1185,7 +1188,7 @@ QR Code URL: ${qrUrl}`);
|
||||
private async getPasswordFromBrowser(): Promise<string | null> {
|
||||
// Vérifier si l'API Credential Management est disponible
|
||||
if (!navigator.credentials) {
|
||||
console.warn('⚠️ Credential Management API not available');
|
||||
secureLogger.warn('Credential Management API not available', { component: 'SecureCredentials' });
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1199,11 +1202,11 @@ QR Code URL: ${qrUrl}`);
|
||||
if (credential?.type === 'password') {
|
||||
// @ts-ignore - PasswordCredential API may not be in TypeScript definitions
|
||||
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;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('🔐 No password found in browser password manager');
|
||||
secureLogger.info('No password found in browser password manager', { component: 'SecureCredentials' });
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
* SecureKeyManager - Gestion sécurisée des clés privées
|
||||
* Chiffre les clés privées avant stockage et les déchiffre à la demande
|
||||
*/
|
||||
|
||||
import { secureLogger } from './secure-logger';
|
||||
export class SecureKeyManager {
|
||||
private keyStore: CryptoKey | null = null;
|
||||
private salt: Uint8Array;
|
||||
@ -19,9 +21,9 @@ export class SecureKeyManager {
|
||||
const derivedKey = await this.deriveKey(password);
|
||||
this.keyStore = derivedKey;
|
||||
this.isInitialized = true;
|
||||
console.log('🔐 SecureKeyManager initialized');
|
||||
secureLogger.info('SecureKeyManager initialized', { component: 'SecureKeyManager' });
|
||||
} 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');
|
||||
}
|
||||
}
|
||||
@ -52,9 +54,9 @@ export class SecureKeyManager {
|
||||
// Stocker dans IndexedDB de manière sécurisée
|
||||
await this.storeEncryptedData(encryptedData);
|
||||
|
||||
console.log('🔐 Private key stored securely');
|
||||
secureLogger.info('Private key stored securely', { component: 'SecureKeyManager' });
|
||||
} 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');
|
||||
}
|
||||
}
|
||||
@ -79,7 +81,7 @@ export class SecureKeyManager {
|
||||
|
||||
return new TextDecoder().decode(decrypted);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to retrieve private key:', error);
|
||||
secureLogger.error('Failed to retrieve private key', error as Error, { component: 'SecureKeyManager' });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -92,9 +94,9 @@ export class SecureKeyManager {
|
||||
await this.clearEncryptedData();
|
||||
this.keyStore = null;
|
||||
this.isInitialized = false;
|
||||
console.log('🔐 All keys cleared');
|
||||
secureLogger.info('All keys cleared', { component: 'SecureKeyManager' });
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to clear keys:', error);
|
||||
secureLogger.error('Failed to clear keys', error as Error, { component: 'SecureKeyManager' });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -197,7 +197,7 @@ export default class Services {
|
||||
|
||||
// More aggressive cleanup
|
||||
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
|
||||
if (window.gc) {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { secureLogger } from './secure-logger';
|
||||
|
||||
export async function storeData(
|
||||
servers: string[],
|
||||
@ -28,10 +29,10 @@ export async function storeData(
|
||||
// Test first that data is not already stored
|
||||
const testResponse = await testData(url, key);
|
||||
if (testResponse) {
|
||||
console.log('Data already stored:', key);
|
||||
secureLogger.debug(`Data already stored: ${key}`, { component: 'StorageService' });
|
||||
continue;
|
||||
} 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.
|
||||
@ -40,9 +41,9 @@ export async function storeData(
|
||||
'Content-Type': 'application/octet-stream',
|
||||
},
|
||||
});
|
||||
console.log('Data stored successfully:', key);
|
||||
secureLogger.info(`Data stored successfully: ${key}`, { component: 'StorageService' });
|
||||
if (response.status !== 200) {
|
||||
console.error('Received response status', response.status);
|
||||
secureLogger.error(`Received response status: ${response.status}`, { component: 'StorageService' });
|
||||
continue;
|
||||
}
|
||||
return response;
|
||||
@ -50,7 +51,7 @@ export async function storeData(
|
||||
if (axios.isAxiosError(error) && error.response?.status === 409) {
|
||||
return null;
|
||||
}
|
||||
console.error('Error storing data:', error);
|
||||
secureLogger.error('Error storing data', error as Error, { component: 'StorageService' });
|
||||
}
|
||||
}
|
||||
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
|
||||
: 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:
|
||||
const response = await axios.get(url, {
|
||||
responseType: 'arraybuffer',
|
||||
@ -75,30 +76,30 @@ export async function retrieveData(servers: string[], key: string): Promise<Arra
|
||||
if (response.data instanceof ArrayBuffer) {
|
||||
return response.data;
|
||||
} else {
|
||||
console.error('Server returned non-ArrayBuffer data:', typeof response.data);
|
||||
secureLogger.error(`Server returned non-ArrayBuffer data: ${typeof response.data}`, { component: 'StorageService' });
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
console.error(`Server ${server} returned status ${response.status}`);
|
||||
secureLogger.error(`Server ${server} returned status ${response.status}`, { component: 'StorageService' });
|
||||
continue;
|
||||
}
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
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
|
||||
} else if (error.response?.status) {
|
||||
console.error(
|
||||
`Server ${server} error ${error.response.status}:`,
|
||||
error.response.statusText
|
||||
secureLogger.error(
|
||||
`Server ${server} error ${error.response.status}: ${error.response.statusText}`,
|
||||
{ component: 'StorageService' }
|
||||
);
|
||||
continue;
|
||||
} 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;
|
||||
}
|
||||
} else {
|
||||
console.error(`Unexpected error retrieving data from ${server}:`, error);
|
||||
secureLogger.error(`Unexpected error retrieving data from ${server}`, error as Error, { component: 'StorageService' });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -110,13 +111,13 @@ export async function testData(url: string, _key: string): Promise<boolean | nul
|
||||
try {
|
||||
const response = await axios.get(url);
|
||||
if (response.status !== 200) {
|
||||
console.error(`Test response status: ${response.status}`);
|
||||
secureLogger.error(`Test response status: ${response.status}`, { component: 'StorageService' });
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error testing data:', error);
|
||||
secureLogger.error('Error testing data', error as Error, { component: 'StorageService' });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import * as jose from 'jose';
|
||||
import { secureLogger } from './secure-logger';
|
||||
|
||||
interface TokenPair {
|
||||
accessToken: string;
|
||||
@ -47,11 +48,11 @@ export default class TokenService {
|
||||
return payload.origin === origin;
|
||||
} catch (error: any) {
|
||||
if (error?.code === 'ERR_JWT_EXPIRED') {
|
||||
console.log('Token expiré');
|
||||
secureLogger.info('Token expiré', { component: 'TokenService' });
|
||||
return false;
|
||||
}
|
||||
|
||||
console.error('Erreur de validation du token:', error);
|
||||
secureLogger.error('Erreur de validation du token', error as Error, { component: 'TokenService' });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -80,7 +81,7 @@ export default class TokenService {
|
||||
|
||||
return newAccessToken;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
* WebSocketManager - Gestion robuste des connexions WebSocket
|
||||
* Gère la reconnexion automatique, la queue des messages et la gestion d'erreurs
|
||||
*/
|
||||
|
||||
import { secureLogger } from './secure-logger';
|
||||
export interface WebSocketConfig {
|
||||
url: string;
|
||||
reconnectAttempts?: number;
|
||||
@ -172,7 +174,7 @@ export class WebSocketManager {
|
||||
try {
|
||||
callback(data);
|
||||
} 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' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import { logger } from './logger';
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
|
||||
export enum ErrorCode {
|
||||
// Erreurs de pairing
|
||||
@ -223,7 +224,7 @@ export class ErrorHandler {
|
||||
try {
|
||||
callback(error);
|
||||
} catch (callbackError) {
|
||||
console.error('Error in error callback:', callbackError);
|
||||
secureLogger.error('Error in error callback', callbackError as Error, { component: 'ErrorHandler' });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
* Fournit des logs cohérents avec différents niveaux et contextes
|
||||
*/
|
||||
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
|
||||
export enum LogLevel {
|
||||
DEBUG = 0,
|
||||
INFO = 1,
|
||||
@ -86,18 +88,18 @@ class Logger {
|
||||
|
||||
switch (entry.level) {
|
||||
case LogLevel.DEBUG:
|
||||
console.debug(logMessage);
|
||||
secureLogger.debug(logMessage, { component: 'Logger' });
|
||||
break;
|
||||
case LogLevel.INFO:
|
||||
console.info(logMessage);
|
||||
secureLogger.info(logMessage, { component: 'Logger' });
|
||||
break;
|
||||
case LogLevel.WARN:
|
||||
console.warn(logMessage);
|
||||
secureLogger.warn(logMessage, { component: 'Logger' });
|
||||
break;
|
||||
case LogLevel.ERROR:
|
||||
console.error(logMessage);
|
||||
secureLogger.error(logMessage, { component: 'Logger' });
|
||||
if (entry.stack) {
|
||||
console.error(entry.stack);
|
||||
secureLogger.error(entry.stack, { component: 'Logger' });
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
|
||||
import { SecureCredentialsService } from '../services/secure-credentials.service';
|
||||
import { DeviceReaderService } from '../services/device-reader.service';
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
|
||||
export type SecurityMode = 'none' | 'otp' | 'password' | 'os' | 'proton-pass';
|
||||
|
||||
@ -23,13 +24,13 @@ export async function checkPBKDF2Key(): Promise<{ key: string; mode: SecurityMod
|
||||
if (hasKey) {
|
||||
const key = await secureCredentialsService.retrievePBKDF2Key(mode);
|
||||
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 };
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// 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();
|
||||
if (wallet) {
|
||||
if (attempt > 0) {
|
||||
console.log(`✅ Wallet found after ${attempt + 1} attempts`);
|
||||
secureLogger.info(`Wallet found after ${attempt + 1} attempts`, { component: 'PrerequisitesUtils' });
|
||||
}
|
||||
return wallet;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`⚠️ Wallet still not found after ${maxAttempts} attempts`);
|
||||
secureLogger.warn(`Wallet still not found after ${maxAttempts} attempts`, { component: 'PrerequisitesUtils' });
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -80,4 +81,3 @@ export async function checkAllPrerequisites(): Promise<{
|
||||
|
||||
return { pbkdf2Key, wallet };
|
||||
}
|
||||
|
||||
|
||||
@ -2772,7 +2772,7 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
|
||||
// Register device as paired
|
||||
// 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]);
|
||||
|
||||
// Handle API return
|
||||
@ -2789,15 +2789,15 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
|
||||
// Approve change
|
||||
// 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);
|
||||
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);
|
||||
secureLogger.info('🔐 Pairing 4NK: Changement approuvé avec succès', { component: 'SPAddressUtils' });
|
||||
|
||||
// Wait for pairing commitment
|
||||
// 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);
|
||||
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é
|
||||
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) {
|
||||
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
|
||||
@ -2850,7 +2850,7 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
|
||||
const lastCommitedState = service.getLastCommitedState(process);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2871,19 +2871,19 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
const decryptedAttribute = await service.decryptAttribute(processId, lastCommitedState, attribute);
|
||||
if (decryptedAttribute) {
|
||||
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 {
|
||||
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) {
|
||||
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) {
|
||||
secureLogger.info('✅ Pairing 4NK: ${decryptedCount} attribut(s) déchiffré(s) pour le processus ${processId}', { component: 'SPAddressUtils' });
|
||||
} 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) {
|
||||
secureLogger.warn('⚠️ Pairing 4NK: Erreur lors du traitement du processus ${processId}:', { component: 'SPAddressUtils', data: processError });
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
|
||||
let subscriptions: {
|
||||
element: Element | Document;
|
||||
event: any;
|
||||
@ -5,7 +7,7 @@ let subscriptions: {
|
||||
}[] = [];
|
||||
|
||||
export function cleanSubscriptions(): void {
|
||||
console.log('🚀 ~ cleanSubscriptions ~ sub:', subscriptions);
|
||||
secureLogger.debug('Cleaning subscriptions', { component: 'SubscriptionUtils', data: subscriptions });
|
||||
for (const sub of subscriptions) {
|
||||
const el = sub.element;
|
||||
const eventHandler = sub.eventHandler;
|
||||
|
||||
@ -115,9 +115,11 @@ async function decodeData(data: any): Promise<any> {
|
||||
|
||||
// Gérer les erreurs non capturées
|
||||
self.addEventListener('error', (error) => {
|
||||
// Note: secureLogger not available in worker context
|
||||
console.error('Encoder worker error:', error);
|
||||
});
|
||||
|
||||
self.addEventListener('unhandledrejection', (event) => {
|
||||
// Note: secureLogger not available in worker context
|
||||
console.error('Encoder worker unhandled rejection:', event.reason);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user