ihm_client/src/pages/block-sync/block-sync.ts
NicolasCantu b3af85d3a0 fix: add prerequisite checks and real block sync to block-sync page
**Motivations :**
- La page block-sync ne vérifie pas les prérequis comme les autres pages
- La synchronisation est simulée au lieu d'être réelle
- Il manque les vérifications de PBKDF2, wallet et birthday

**Modifications :**
- Ajout des vérifications de prérequis (PBKDF2 key, wallet, birthday) dans block-sync.ts
- Remplacement de la synchronisation simulée par une synchronisation réelle via updateDeviceBlockHeight()
- Ajout de la connexion aux relais si chain_tip n'est pas disponible
- Ajout de vérifications de wallet avec retry pour gérer les problèmes de synchronisation
- Ajout de la gestion d'erreur avec redirection vers les pages appropriées selon le type d'erreur
- Amélioration de la gestion d'erreur avec messages clairs et redirections automatiques
- Déplacement de l'écouteur du bouton continuer avant le try pour être toujours disponible
- Ajout de vérifications de nullité pour les éléments DOM

**Pages affectées :**
- src/pages/block-sync/block-sync.ts (ajout des vérifications de prérequis et synchronisation réelle)
- src/pages/home/home.ts (ajout des vérifications de prérequis pour la page de pairing)
2025-10-29 15:21:19 +01:00

281 lines
13 KiB
TypeScript

document.addEventListener("DOMContentLoaded", async () => {
console.log("🔄 Block sync page loaded");
const status = document.getElementById("status") as HTMLElement;
const progressBar = document.getElementById("progressBar") as HTMLElement;
const continueBtn = document.getElementById("continueBtn") as HTMLButtonElement;
function updateStatus(message: string, type: 'loading' | 'success' | 'error') {
if (status) {
status.textContent = message;
status.className = `status ${type}`;
}
}
function updateProgress(percentage: number) {
if (progressBar) {
progressBar.style.width = `${percentage}%`;
}
}
function updateSyncItem(elementId: string, value: string, status: 'pending' | 'completed' | 'error' = 'pending') {
const element = document.getElementById(elementId);
if (element) {
element.textContent = value;
element.className = `sync-status ${status}`;
}
}
// Gestion du bouton continuer (définie avant le try pour être toujours disponible)
if (continueBtn) {
continueBtn.addEventListener('click', async () => {
console.log('🏠 Redirecting to main application...');
// Rediriger vers l'application principale
console.log('🔄 Block sync completed, checking storage state...');
const { checkStorageStateAndNavigate } = await import('../../router');
await checkStorageStateAndNavigate();
});
}
try {
// Étape 1: Vérification des prérequis
updateStatus('🔍 Vérification des prérequis...', 'loading');
updateProgress(10);
// 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();
let pbkdf2KeyFound = false;
const securityModes = ['none', 'otp', 'password', 'os', 'proton-pass'];
for (const mode of securityModes) {
try {
const hasKey = await secureCredentials.hasPBKDF2Key(mode as any);
if (hasKey) {
const key = await secureCredentials.retrievePBKDF2Key(mode as any);
if (key) {
pbkdf2KeyFound = true;
console.log(`✅ PBKDF2 key found in pbkdf2keys store for security mode: ${mode}`);
break;
}
}
} catch (error) {
console.log(`⚠️ No PBKDF2 key found in pbkdf2keys store for mode ${mode}`);
}
}
if (!pbkdf2KeyFound) {
console.log('⚠️ PBKDF2 key not found in pbkdf2keys store, redirecting to security-setup...');
updateStatus('⚠️ Redirection vers la configuration de sécurité...', 'loading');
setTimeout(() => {
window.location.href = '/src/pages/security-setup/security-setup.html';
}, 1000);
return;
}
// Étape 2: Initialisation des services
updateStatus('🔄 Initialisation des services...', 'loading');
updateProgress(20);
const { default: Services } = await import('../../services/service');
if (!Services) {
throw new Error('Services class not found in default export');
}
console.log('🔄 Waiting for services to be ready...');
let attempts = 0;
const maxAttempts = 30;
const delayMs = 2000;
let services;
while (attempts < maxAttempts) {
try {
console.log(`🔄 Attempting to get services (attempt ${attempts + 1}/${maxAttempts})...`);
services = await Services.getInstance();
console.log('✅ Services initialized successfully');
break;
} catch (error) {
console.log(`⏳ Services not ready yet (attempt ${attempts + 1}/${maxAttempts}):`, (error as Error).message);
attempts++;
if (attempts >= maxAttempts) {
throw new Error(`Services failed to initialize after ${maxAttempts} attempts.`);
}
await new Promise(resolve => setTimeout(resolve, delayMs));
}
}
if (!services) {
throw new Error('Services not initialized');
}
// Vérifier que le wallet existe en base (avec plusieurs tentatives pour gérer les problèmes de synchronisation)
let wallet = await services.getDeviceFromDatabase();
if (!wallet) {
console.log('⚠️ Wallet not found, waiting for database synchronization...');
for (let attempt = 0; attempt < 5; attempt++) {
await new Promise(resolve => setTimeout(resolve, 500));
wallet = await services.getDeviceFromDatabase();
if (wallet) {
console.log(`✅ Wallet found after ${attempt + 1} attempts`);
break;
}
}
if (!wallet) {
console.log('⚠️ Wallet still not found after retries, redirecting to wallet-setup...');
updateStatus('⚠️ Redirection vers la configuration du wallet...', 'loading');
setTimeout(() => {
window.location.href = '/src/pages/wallet-setup/wallet-setup.html';
}, 1000);
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);
} else {
throw new Error('Wallet found but missing required data (sp_wallet or birthday)');
}
// Vérifier que le birthday est configuré (> 0)
if (!wallet.sp_wallet.birthday || wallet.sp_wallet.birthday === 0) {
console.log('⚠️ Birthday not configured (birthday = 0), redirecting to birthday-setup...');
updateStatus('⚠️ Redirection vers la configuration de la date anniversaire...', 'loading');
setTimeout(() => {
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
}, 1000);
return;
}
console.log('✅ All prerequisites verified for block sync');
// Étape 3: Connexion aux relais si nécessaire
updateStatus('🔗 Connexion aux relais...', 'loading');
updateProgress(40);
let currentBlockHeight = services.getCurrentBlockHeight();
if (currentBlockHeight === -1 || currentBlockHeight === 0) {
console.log('⚠️ Block height not available, connecting to relays...');
await services.connectAllRelays();
// Attendre que le handshake arrive et que chain_tip soit défini
await new Promise<void>((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('Timeout waiting for block height from handshake'));
}, 15000); // 15 secondes de timeout
const checkBlockHeight = () => {
const blockHeight = services.getCurrentBlockHeight();
if (blockHeight !== -1 && blockHeight > 0) {
console.log(`✅ Block height set from handshake: ${blockHeight}`);
currentBlockHeight = blockHeight;
clearTimeout(timeout);
resolve();
} else {
setTimeout(checkBlockHeight, 100);
}
};
checkBlockHeight();
});
}
// Étape 4: Récupération des informations de synchronisation
updateStatus('📊 Récupération des informations de synchronisation...', 'loading');
updateProgress(50);
const birthday = wallet.sp_wallet.birthday;
const lastScan = wallet.sp_wallet.last_scan || birthday;
const blocksToScan = currentBlockHeight - lastScan;
// Mettre à jour l'interface avec les informations
updateSyncItem('currentBlock', currentBlockHeight.toString(), 'completed');
updateSyncItem('birthday', birthday.toString(), 'completed');
updateSyncItem('blocksToScan', blocksToScan.toString(), 'pending');
console.log(`📊 Sync info: current=${currentBlockHeight}, birthday=${birthday}, lastScan=${lastScan}, toScan=${blocksToScan}`);
// Vérifier si une synchronisation est nécessaire
if (blocksToScan <= 0) {
console.log('✅ Wallet already synchronized');
updateStatus('✅ Wallet déjà synchronisé!', 'success');
updateProgress(100);
updateSyncItem('blocksScanned', lastScan.toString(), 'completed');
updateSyncItem('blocksToScan', '0', 'completed');
continueBtn.disabled = false;
return;
}
// Étape 5: Synchronisation réelle des blocs
updateStatus('🔍 Synchronisation des blocs en cours...', 'loading');
updateProgress(60);
console.log(`🔄 Starting real block scan from ${lastScan} to ${currentBlockHeight}...`);
// Utiliser updateDeviceBlockHeight qui gère la synchronisation si nécessaire
// Cette méthode vérifie si last_scan < currentBlockHeight et synchronise si nécessaire
try {
await services.updateDeviceBlockHeight();
console.log('✅ Block scan completed successfully');
// Vérifier que la mise à jour a été sauvegardée
const finalWallet = await services.getDeviceFromDatabase();
if (finalWallet?.sp_wallet?.last_scan) {
const finalLastScan = finalWallet.sp_wallet.last_scan;
console.log('✅ Wallet updated with last_scan:', finalLastScan);
// Finalisation
updateStatus('✅ Synchronisation terminée avec succès!', 'success');
updateProgress(100);
updateSyncItem('blocksScanned', finalLastScan.toString(), 'completed');
updateSyncItem('blocksToScan', blocksToScan.toString(), 'completed');
// Activer le bouton continuer
if (continueBtn) {
continueBtn.disabled = false;
}
console.log('🎉 Block sync completed successfully');
} else {
throw new Error('Failed to verify wallet update - last_scan not found');
}
} catch (error) {
console.error('❌ Error during block scan:', error);
throw error;
}
} catch (error) {
console.error('❌ Error during block sync:', error);
const errorMessage = (error as Error).message;
updateStatus(`❌ Erreur: ${errorMessage}`, 'error');
// Si l'erreur est liée aux prérequis, rediriger vers la page appropriée
if (errorMessage.includes('PBKDF2') || errorMessage.includes('security')) {
console.log('⚠️ Security error detected, redirecting to security-setup...');
updateStatus('⚠️ Redirection vers la configuration de sécurité...', 'loading');
setTimeout(() => {
window.location.href = '/src/pages/security-setup/security-setup.html';
}, 2000);
} else if (errorMessage.includes('wallet') || errorMessage.includes('device')) {
console.log('⚠️ Wallet error detected, redirecting to wallet-setup...');
updateStatus('⚠️ Redirection vers la configuration du wallet...', 'loading');
setTimeout(() => {
window.location.href = '/src/pages/wallet-setup/wallet-setup.html';
}, 2000);
} else if (errorMessage.includes('birthday')) {
console.log('⚠️ Birthday error detected, redirecting to birthday-setup...');
updateStatus('⚠️ Redirection vers la configuration de la date anniversaire...', 'loading');
setTimeout(() => {
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
}, 2000);
} else {
// Erreur générale, afficher et permettre de réessayer
updateSyncItem('currentBlock', 'Erreur', 'error');
updateSyncItem('birthday', 'Erreur', 'error');
updateSyncItem('blocksToScan', 'Erreur', 'error');
}
}
});