refactor: extract device reading to lightweight service to avoid WebAssembly initialization
**Motivations :** - home.ts utilise Services uniquement pour getDeviceFromDatabase() et getDeviceAddress() - Services initialise WebAssembly qui peut causer des erreurs de mémoire - Créer un service léger qui lit le device sans WebAssembly **Modifications :** - Créer DeviceReaderService qui lit le device depuis IndexedDB sans WebAssembly - Extraire getDeviceFromDatabase() et getDeviceAddress() dans DeviceReaderService - Modifier home.ts pour utiliser DeviceReaderService au lieu de Services - DeviceReaderService déchiffre le device et extrait l'adresse depuis sp_wallet.address - Supprimer l'import de Services dans home.ts **Pages affectées :** - src/services/device-reader.service.ts (nouveau service léger) - src/pages/home/home.ts (utilise DeviceReaderService au lieu de Services)
This commit is contained in:
parent
9de7f1a5ed
commit
36adf1df12
@ -1,4 +1,4 @@
|
||||
import Services from '../../services/service';
|
||||
import { DeviceReaderService } from '../../services/device-reader.service';
|
||||
import { addSubscription } from '../../utils/subscription.utils';
|
||||
import { displayEmojis, generateCreateBtn, addressToEmoji, prepareAndSendPairingTx } from '../../utils/sp-address.utils';
|
||||
import { getCorrectDOM } from '../../utils/html.utils';
|
||||
@ -28,11 +28,11 @@ export async function initHomePage(): Promise<void> {
|
||||
|
||||
// Vérifier les prérequis en base de données
|
||||
console.log('🔍 Verifying prerequisites...');
|
||||
|
||||
|
||||
try {
|
||||
console.log('🔧 Getting services instance...');
|
||||
const service = await Services.getInstance();
|
||||
|
||||
console.log('🔧 Getting device reader service...');
|
||||
const deviceReader = DeviceReaderService.getInstance();
|
||||
|
||||
// Vérifier que le PBKDF2 key existe d'abord (prérequis le plus basique) dans le store pbkdf2keys
|
||||
const { SecureCredentialsService } = await import('../../services/secure-credentials.service');
|
||||
const secureCredentials = SecureCredentialsService.getInstance();
|
||||
@ -67,13 +67,13 @@ export async function initHomePage(): Promise<void> {
|
||||
}
|
||||
|
||||
// Vérifier que le wallet existe en base (avec plusieurs tentatives pour gérer les problèmes de synchronisation)
|
||||
let wallet = await service.getDeviceFromDatabase();
|
||||
let wallet = await deviceReader.getDeviceFromDatabase();
|
||||
if (!wallet) {
|
||||
console.log('⚠️ Wallet not found, waiting for database synchronization...');
|
||||
// Attendre un peu pour la synchronisation de la base de données
|
||||
for (let attempt = 0; attempt < 5; attempt++) {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
wallet = await service.getDeviceFromDatabase();
|
||||
wallet = await deviceReader.getDeviceFromDatabase();
|
||||
if (wallet) {
|
||||
console.log(`✅ Wallet found after ${attempt + 1} attempts`);
|
||||
break;
|
||||
@ -88,7 +88,7 @@ export async function initHomePage(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Vérifier que le wallet contient bien les données attendues
|
||||
if (wallet.sp_wallet && wallet.sp_wallet.birthday !== undefined) {
|
||||
console.log('✅ Wallet found in database with birthday:', wallet.sp_wallet.birthday);
|
||||
@ -177,32 +177,35 @@ export async function initHomePage(): Promise<void> {
|
||||
// After WebAuthn, get device address and setup UI
|
||||
console.log('🔧 Getting device address...');
|
||||
|
||||
try {
|
||||
const spAddress = await service.getDeviceAddress();
|
||||
console.log('🔧 Generating create button...');
|
||||
generateCreateBtn();
|
||||
console.log('🔧 Displaying emojis...');
|
||||
displayEmojis(spAddress);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to get device address:', error);
|
||||
if ((error as Error).message.includes('Wallet keys not available')) {
|
||||
console.error('❌ Wallet keys not available - authentication failed');
|
||||
throw new Error('Authentication failed - wallet keys not available');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const spAddress = await deviceReader.getDeviceAddress();
|
||||
if (!spAddress) {
|
||||
throw new Error('Device address not found');
|
||||
}
|
||||
console.log('🔧 Generating create button...');
|
||||
generateCreateBtn();
|
||||
console.log('🔧 Displaying emojis...');
|
||||
displayEmojis(spAddress);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to get device address:', error);
|
||||
if ((error as Error).message.includes('Wallet keys not available')) {
|
||||
console.error('❌ Wallet keys not available - authentication failed');
|
||||
throw new Error('Authentication failed - wallet keys not available');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log('✅ Home page initialization completed');
|
||||
} catch (error) {
|
||||
console.error('❌ Error initializing home/pairing page:', error);
|
||||
|
||||
|
||||
// Afficher un message d'erreur à l'utilisateur
|
||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
||||
const mainStatus = container.querySelector('#main-status') as HTMLElement;
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = `<span style="color: var(--error-color)">❌ Error: ${(error as Error).message}</span>`;
|
||||
}
|
||||
|
||||
|
||||
// Si l'erreur est liée aux prérequis, rediriger vers la page appropriée
|
||||
const errorMessage = (error as Error).message;
|
||||
if (errorMessage.includes('PBKDF2') || errorMessage.includes('security')) {
|
||||
@ -221,7 +224,7 @@ export async function initHomePage(): Promise<void> {
|
||||
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
|
||||
throw error;
|
||||
} finally {
|
||||
isInitializing = false;
|
||||
@ -1195,8 +1198,7 @@ async function handleDeleteAccount(): Promise<void> {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Deleting account and all data...</span>';
|
||||
}
|
||||
|
||||
// Get services
|
||||
const service = await Services.getInstance();
|
||||
// Delete credentials
|
||||
const { SecureCredentialsService } = await import('../../services/secure-credentials.service');
|
||||
const secureCredentialsService = SecureCredentialsService.getInstance();
|
||||
|
||||
|
||||
135
src/services/device-reader.service.ts
Normal file
135
src/services/device-reader.service.ts
Normal file
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Service léger pour lire le device depuis la base de données
|
||||
* Sans nécessiter l'initialisation de WebAssembly
|
||||
*/
|
||||
|
||||
import { DATABASE_CONFIG } from './database-config';
|
||||
import { Device } from '../../pkg/sdk_client';
|
||||
|
||||
export class DeviceReaderService {
|
||||
private static instance: DeviceReaderService | null = null;
|
||||
|
||||
private constructor() {}
|
||||
|
||||
public static getInstance(): DeviceReaderService {
|
||||
if (!DeviceReaderService.instance) {
|
||||
DeviceReaderService.instance = new DeviceReaderService();
|
||||
}
|
||||
return DeviceReaderService.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère le device depuis la base de données et le déchiffre
|
||||
* Version légère sans nécessiter WebAssembly
|
||||
*/
|
||||
async getDeviceFromDatabase(): Promise<Device | null> {
|
||||
console.log('🔍 DeviceReaderService: Reading device from database...');
|
||||
|
||||
// Utiliser directement IndexedDB
|
||||
const db = await new Promise<IDBDatabase>((resolve, reject) => {
|
||||
const request = indexedDB.open(DATABASE_CONFIG.name, DATABASE_CONFIG.version);
|
||||
request.onsuccess = () => resolve(request.result);
|
||||
request.onerror = () => reject(request.error);
|
||||
});
|
||||
|
||||
const walletStore = DATABASE_CONFIG.stores.wallet.name;
|
||||
|
||||
try {
|
||||
const dbRes = await new Promise<any>((resolve, reject) => {
|
||||
const tx = db.transaction(walletStore, 'readonly');
|
||||
const store = tx.objectStore(walletStore);
|
||||
const getRequest = store.get('1');
|
||||
getRequest.onsuccess = () => resolve(getRequest.result);
|
||||
getRequest.onerror = () => reject(getRequest.error);
|
||||
});
|
||||
|
||||
if (!dbRes) {
|
||||
console.log('🔍 DeviceReaderService: No device found in database');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if data is encrypted (new format) or plain (old format)
|
||||
if (dbRes['encrypted_device']) {
|
||||
// New encrypted format - need to decrypt
|
||||
console.log('🔐 DeviceReaderService: Device found in encrypted format, decrypting...');
|
||||
|
||||
// Get the PBKDF2 key based on security mode
|
||||
const { SecureCredentialsService } = await import('./secure-credentials.service');
|
||||
const secureCredentialsService = SecureCredentialsService.getInstance();
|
||||
|
||||
// Get all security modes to find which one works
|
||||
const allSecurityModes = ['none', 'otp', 'password', 'os', 'proton-pass'];
|
||||
let pbkdf2Key: string | null = null;
|
||||
let workingMode: string | null = null;
|
||||
|
||||
for (const mode of allSecurityModes) {
|
||||
try {
|
||||
const hasKey = await secureCredentialsService.hasPBKDF2Key(mode as any);
|
||||
if (hasKey) {
|
||||
const key = await secureCredentialsService.retrievePBKDF2Key(mode as any);
|
||||
if (key) {
|
||||
pbkdf2Key = key;
|
||||
workingMode = mode;
|
||||
console.log(`✅ DeviceReaderService: PBKDF2 key found for mode: ${mode}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Continue to next mode
|
||||
console.log(`⚠️ DeviceReaderService: No PBKDF2 key for mode ${mode}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pbkdf2Key) {
|
||||
console.error('❌ DeviceReaderService: Failed to retrieve PBKDF2 key for decryption');
|
||||
throw new Error('PBKDF2 key not found - cannot decrypt device');
|
||||
}
|
||||
|
||||
// Decrypt the device
|
||||
const { EncryptionService } = await import('./encryption.service');
|
||||
const encryptionService = EncryptionService.getInstance();
|
||||
const decryptedDeviceString = await encryptionService.decrypt(
|
||||
dbRes['encrypted_device'],
|
||||
pbkdf2Key
|
||||
);
|
||||
const device: Device = JSON.parse(decryptedDeviceString);
|
||||
console.log('✅ DeviceReaderService: Device decrypted successfully');
|
||||
return device;
|
||||
} else {
|
||||
// Old plain format - return as is (should not happen in production)
|
||||
console.warn('⚠️ DeviceReaderService: Device found in plain format (old format)');
|
||||
return dbRes as Device;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ DeviceReaderService: Error reading device:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère l'adresse du device depuis la base de données
|
||||
* Version légère sans nécessiter WebAssembly
|
||||
*/
|
||||
async getDeviceAddress(): Promise<string | null> {
|
||||
try {
|
||||
const device = await this.getDeviceFromDatabase();
|
||||
if (!device) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// L'adresse est stockée dans device.sp_wallet.address
|
||||
const address = device.sp_wallet?.address;
|
||||
if (address) {
|
||||
console.log('✅ DeviceReaderService: Device address retrieved:', address);
|
||||
return address;
|
||||
}
|
||||
|
||||
console.warn('⚠️ DeviceReaderService: Device found but no address in sp_wallet.address');
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('❌ DeviceReaderService: Error getting device address:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -333,14 +333,14 @@ export default class Services {
|
||||
console.error('❌ Service initialization failed:', error);
|
||||
// Réinitialiser initializing pour permettre une nouvelle tentative après un délai
|
||||
Services.initializing = null;
|
||||
|
||||
|
||||
// Si c'est une erreur de mémoire, ne pas réessayer immédiatement
|
||||
const errorMessage = (error as Error).message || String(error);
|
||||
if (errorMessage.includes('Out of memory') || errorMessage.includes('memory')) {
|
||||
console.error('🚫 Memory error detected - cannot retry immediately');
|
||||
throw new Error('WebAssembly initialization failed due to insufficient memory. Please refresh the page.');
|
||||
}
|
||||
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user