Standardize logging system and fix error display
**Motivations :** - Inconsistent use of console.* methods across codebase - Missing structured logging with proper levels and context - Inline error display breaking UI layout - Risk of sensitive data exposure in logs **Modifications :** - Replace all console.* calls with secureLogger.* in main files - Add proper log levels: DEBUG, INFO, WARN, ERROR - Add component context for better debugging - Create styled error/warning/success containers - Add comprehensive logging guidelines documentation - Fix import paths for secureLogger in security-setup.ts **Pages affectées :** - src/services/service.ts - Main service logging - src/pages/home/home.ts - Home page logging - src/pages/security-setup/security-setup.ts - Security setup logging - src/utils/sp-address.utils.ts - SP address utilities logging - src/router.ts - Router logging - src/websockets.ts - WebSocket logging - src/4nk.css - Error container styles - docs/LOGGING_GUIDELINES.md - Logging best practices
This commit is contained in:
parent
df835332e5
commit
c9ff430b09
@ -3,7 +3,7 @@ description: Règles pour tous aussi pour l'IA et pour Cursor
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Lecoffre
|
||||
# IHM_CLIENT
|
||||
|
||||
voir les fichiers README.md
|
||||
|
||||
|
||||
6
.cursor/rules/webiste.mdc
Normal file
6
.cursor/rules/webiste.mdc
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
le site tourne sur le port 3004
|
||||
l'url du site est https://dev3.4nkweb.com
|
||||
@ -1,8 +1,8 @@
|
||||
# Documentation de l'Initialisation LeCoffre.io
|
||||
# Documentation de l'Initialisation IHM_CLIENT
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Le système LeCoffre.io suit un processus d'initialisation en plusieurs étapes pour créer et sécuriser un wallet Bitcoin. Ce document détaille chaque étape du processus, depuis le choix du mode de sécurité jusqu'au pairing réussi et à la récupération des processus.
|
||||
Le système IHM_CLIENT suit un processus d'initialisation en plusieurs étapes pour créer et sécuriser un wallet Bitcoin. Ce document détaille chaque étape du processus, depuis le choix du mode de sécurité jusqu'au pairing réussi et à la récupération des processus.
|
||||
|
||||
## Architecture des Stores IndexedDB
|
||||
|
||||
@ -386,7 +386,7 @@ window.location.href = '/src/pages/block-sync/block-sync.html';
|
||||
|
||||
#### But et Objectif du Pairing
|
||||
|
||||
Le processus de pairing dans LeCoffre.io sert à **créer une identité numérique vérifiable** qui permet :
|
||||
Le processus de pairing dans IHM_CLIENT sert à **créer une identité numérique vérifiable** qui permet :
|
||||
|
||||
1. **MFA (Multi-Factor Authentication) entre appareils** : Le quorum du processus permet de valider les actions critiques nécessitant plusieurs appareils appairés
|
||||
2. **Gestion autonome de la liste d'appareils** : L'utilisateur contrôle lui-même sa liste d'appareils autorisés, sans dépendre d'un tiers
|
||||
@ -643,4 +643,4 @@ Tous les logs de succès sont maintenant émis uniquement après vérification r
|
||||
9. **Synchronisation IndexedDB** : Utilisation directe d'IndexedDB pour éviter les problèmes de synchronisation avec le service worker
|
||||
10. **Retry automatique** : Retry automatique jusqu'à 5 tentatives avec délai de 500ms pour les vérifications de wallet en base
|
||||
|
||||
Cette documentation couvre l'ensemble du processus d'initialisation du système LeCoffre.io, depuis la configuration de sécurité jusqu'au pairing réussi et à la récupération des processus.
|
||||
Cette documentation couvre l'ensemble du processus d'initialisation du système IHM_CLIENT, depuis la configuration de sécurité jusqu'au pairing réussi et à la récupération des processus.
|
||||
|
||||
256
docs/LOGGING_GUIDELINES.md
Normal file
256
docs/LOGGING_GUIDELINES.md
Normal file
@ -0,0 +1,256 @@
|
||||
# Guide des bonnes pratiques de logging
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Ce document décrit les bonnes pratiques pour l'utilisation des logs dans l'application 4NK. Nous utilisons un système de logging centralisé avec `secureLogger` pour assurer la cohérence et la sécurité.
|
||||
|
||||
## Système de logging
|
||||
|
||||
### SecureLogger
|
||||
|
||||
Le `secureLogger` est le système de logging principal de l'application. Il fournit :
|
||||
|
||||
- **Sanitisation automatique** des données sensibles
|
||||
- **Niveaux de log structurés** (DEBUG, INFO, WARN, ERROR)
|
||||
- **Contexte enrichi** avec composant et métadonnées
|
||||
- **Formatage cohérent** des messages
|
||||
|
||||
### Import
|
||||
|
||||
```typescript
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
```
|
||||
|
||||
## Niveaux de log
|
||||
|
||||
### DEBUG
|
||||
Utilisé pour les informations de débogage détaillées, généralement utiles uniquement lors du développement.
|
||||
|
||||
```typescript
|
||||
secureLogger.debug('Memory usage after cleanup: 45.2%', { component: 'Service' });
|
||||
secureLogger.debug('Checking credentials availability', { component: 'HomePage' });
|
||||
```
|
||||
|
||||
**Quand utiliser :**
|
||||
- Informations de débogage
|
||||
- État interne des variables
|
||||
- Progression des opérations complexes
|
||||
- Messages avec emoji 🔍
|
||||
|
||||
### INFO
|
||||
Utilisé pour les informations générales sur le fonctionnement de l'application.
|
||||
|
||||
```typescript
|
||||
secureLogger.info('Home/Pairing page loaded', { component: 'HomePage' });
|
||||
secureLogger.info('Services initialized successfully', { component: 'Service' });
|
||||
```
|
||||
|
||||
**Quand utiliser :**
|
||||
- Initialisation de composants
|
||||
- Succès d'opérations
|
||||
- Messages avec emoji ✅, 🔄, 🚀
|
||||
- Événements importants du flux utilisateur
|
||||
|
||||
### WARN
|
||||
Utilisé pour les avertissements qui n'empêchent pas le fonctionnement mais méritent attention.
|
||||
|
||||
```typescript
|
||||
secureLogger.warn('High memory detected, performing cleanup', { component: 'Service' });
|
||||
secureLogger.warn('Home page already initializing, skipping...', { component: 'HomePage' });
|
||||
```
|
||||
|
||||
**Quand utiliser :**
|
||||
- Conditions non critiques mais inhabituelles
|
||||
- Messages avec emoji ⚠️
|
||||
- Opérations de récupération
|
||||
- Dégradations de performance
|
||||
|
||||
### ERROR
|
||||
Utilisé pour les erreurs qui empêchent le fonctionnement normal.
|
||||
|
||||
```typescript
|
||||
secureLogger.error('Failed to initialize services', error, { component: 'Service' });
|
||||
secureLogger.error('Authentication failed', error, { component: 'HomePage' });
|
||||
```
|
||||
|
||||
**Quand utiliser :**
|
||||
- Erreurs critiques
|
||||
- Messages avec emoji ❌
|
||||
- Échecs d'opérations importantes
|
||||
- Exceptions non gérées
|
||||
|
||||
## Contexte et métadonnées
|
||||
|
||||
### Composant
|
||||
|
||||
Toujours spécifier le composant dans le contexte :
|
||||
|
||||
```typescript
|
||||
secureLogger.info('Operation completed', { component: 'HomePage' });
|
||||
secureLogger.error('Database connection failed', error, { component: 'Service' });
|
||||
```
|
||||
|
||||
### Métadonnées supplémentaires
|
||||
|
||||
Ajouter des métadonnées utiles pour le débogage :
|
||||
|
||||
```typescript
|
||||
secureLogger.debug('Wallet details', {
|
||||
component: 'HomePage',
|
||||
hasSpendKey: !!wallet.sp_wallet?.spend_key,
|
||||
hasScanKey: !!wallet.sp_wallet?.scan_key,
|
||||
birthday: wallet.sp_wallet?.birthday
|
||||
});
|
||||
```
|
||||
|
||||
## Bonnes pratiques
|
||||
|
||||
### 1. Utiliser secureLogger au lieu de console.*
|
||||
|
||||
❌ **Mauvais :**
|
||||
```typescript
|
||||
console.log('User authenticated');
|
||||
console.error('Database error:', error);
|
||||
```
|
||||
|
||||
✅ **Bon :**
|
||||
```typescript
|
||||
secureLogger.info('User authenticated', { component: 'AuthService' });
|
||||
secureLogger.error('Database error', error, { component: 'DatabaseService' });
|
||||
```
|
||||
|
||||
### 2. Messages clairs et concis
|
||||
|
||||
❌ **Mauvais :**
|
||||
```typescript
|
||||
secureLogger.info('x', { component: 'Service' });
|
||||
secureLogger.info('Processing user request with id 12345 and data {name: "John", email: "john@example.com"}', { component: 'UserService' });
|
||||
```
|
||||
|
||||
✅ **Bon :**
|
||||
```typescript
|
||||
secureLogger.info('Processing user request', {
|
||||
component: 'UserService',
|
||||
userId: 12345,
|
||||
userName: 'John'
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Niveaux appropriés
|
||||
|
||||
❌ **Mauvais :**
|
||||
```typescript
|
||||
secureLogger.error('User clicked button'); // Pas une erreur
|
||||
secureLogger.info('Critical system failure'); // Pas une info
|
||||
```
|
||||
|
||||
✅ **Bon :**
|
||||
```typescript
|
||||
secureLogger.debug('User clicked button', { component: 'UI' });
|
||||
secureLogger.error('Critical system failure', error, { component: 'System' });
|
||||
```
|
||||
|
||||
### 4. Contexte enrichi
|
||||
|
||||
❌ **Mauvais :**
|
||||
```typescript
|
||||
secureLogger.info('Operation failed');
|
||||
```
|
||||
|
||||
✅ **Bon :**
|
||||
```typescript
|
||||
secureLogger.error('Operation failed', error, {
|
||||
component: 'PaymentService',
|
||||
operation: 'processPayment',
|
||||
userId: user.id,
|
||||
amount: payment.amount
|
||||
});
|
||||
```
|
||||
|
||||
### 5. Gestion des erreurs
|
||||
|
||||
```typescript
|
||||
try {
|
||||
await riskyOperation();
|
||||
secureLogger.info('Operation completed successfully', { component: 'Service' });
|
||||
} catch (error) {
|
||||
secureLogger.error('Operation failed', error, {
|
||||
component: 'Service',
|
||||
operation: 'riskyOperation'
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
```
|
||||
|
||||
## Patterns d'emojis
|
||||
|
||||
### DEBUG (🔍)
|
||||
- `🔍 Checking...`
|
||||
- `🔍 Debug info:`
|
||||
- `🔍 Memory usage:`
|
||||
|
||||
### INFO (✅, 🔄, 🚀)
|
||||
- `✅ Operation completed`
|
||||
- `🔄 Processing...`
|
||||
- `🚀 Starting...`
|
||||
- `🔧 Initializing...`
|
||||
|
||||
### WARN (⚠️)
|
||||
- `⚠️ Warning:`
|
||||
- `⚠️ Skipping...`
|
||||
- `⚠️ High memory detected`
|
||||
|
||||
### ERROR (❌)
|
||||
- `❌ Error:`
|
||||
- `❌ Failed to:`
|
||||
- `❌ Critical error:`
|
||||
|
||||
## Exemples par composant
|
||||
|
||||
### Service
|
||||
```typescript
|
||||
secureLogger.info('Service initialized', { component: 'Service' });
|
||||
secureLogger.debug('Memory usage: 45.2%', { component: 'Service' });
|
||||
secureLogger.warn('High memory detected', { component: 'Service' });
|
||||
secureLogger.error('Service initialization failed', error, { component: 'Service' });
|
||||
```
|
||||
|
||||
### HomePage
|
||||
```typescript
|
||||
secureLogger.info('Home page loaded', { component: 'HomePage' });
|
||||
secureLogger.info('Prerequisites verified', { component: 'HomePage' });
|
||||
secureLogger.warn('Already initializing, skipping', { component: 'HomePage' });
|
||||
secureLogger.error('Page initialization failed', error, { component: 'HomePage' });
|
||||
```
|
||||
|
||||
### PairingPage
|
||||
```typescript
|
||||
secureLogger.info('Pairing page loaded', { component: 'PairingPage' });
|
||||
secureLogger.info('Pairing process started', { component: 'PairingPage' });
|
||||
secureLogger.warn('Pairing already in progress', { component: 'PairingPage' });
|
||||
secureLogger.error('Pairing failed', error, { component: 'PairingPage' });
|
||||
```
|
||||
|
||||
## Outils de correction
|
||||
|
||||
Un script automatique est disponible pour corriger les logs existants :
|
||||
|
||||
```bash
|
||||
node fix-logs.cjs
|
||||
```
|
||||
|
||||
Ce script :
|
||||
- Remplace `console.*` par `secureLogger.*`
|
||||
- Ajoute les imports nécessaires
|
||||
- Détermine automatiquement les niveaux appropriés
|
||||
- Ajoute le contexte de composant
|
||||
|
||||
## Vérification
|
||||
|
||||
Pour vérifier que tous les logs utilisent le système centralisé :
|
||||
|
||||
```bash
|
||||
grep -r "console\.\(log\|info\|warn\|error\|debug\)" src/
|
||||
```
|
||||
|
||||
Cette commande ne devrait retourner aucun résultat si tous les logs sont correctement migrés.
|
||||
@ -6,7 +6,7 @@ Ce document résume l'analyse complète du système de pairing et les correction
|
||||
|
||||
## But et Objectif du Pairing
|
||||
|
||||
Le système de pairing dans LeCoffre.io sert avant tout à **créer une identité numérique vérifiable** qui permet :
|
||||
Le système de pairing dans 4NK sert avant tout à **créer une identité numérique vérifiable** qui permet :
|
||||
|
||||
1. **MFA (Multi-Factor Authentication) entre appareils** : Le quorum du processus de pairing permet de valider les actions critiques nécessitant plusieurs appareils appairés
|
||||
2. **Gestion autonome de la liste d'appareils** : L'utilisateur contrôle lui-même sa liste d'appareils autorisés, sans dépendre d'un tiers
|
||||
|
||||
148
fix-logs.js
Normal file
148
fix-logs.js
Normal file
@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Script pour corriger automatiquement tous les logs console.* en secureLogger
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Fichiers à corriger
|
||||
const filesToFix = [
|
||||
'src/pages/home/home.ts',
|
||||
'src/pages/pairing/pairing.ts',
|
||||
'src/pages/wallet-setup/wallet-setup.ts',
|
||||
'src/pages/security-setup/security-setup.ts',
|
||||
'src/pages/birthday-setup/birthday-setup.ts',
|
||||
'src/pages/block-sync/block-sync.ts',
|
||||
'src/utils/sp-address.utils.ts',
|
||||
'src/router.ts',
|
||||
'src/websockets.ts'
|
||||
];
|
||||
|
||||
// Fonction pour déterminer le niveau de log
|
||||
function determineLogLevel(message) {
|
||||
const lowerMessage = message.toLowerCase();
|
||||
|
||||
if (lowerMessage.includes('error') || lowerMessage.includes('failed') || lowerMessage.includes('❌')) {
|
||||
return 'error';
|
||||
}
|
||||
|
||||
if (lowerMessage.includes('warn') || lowerMessage.includes('⚠️') || lowerMessage.includes('skipping')) {
|
||||
return 'warn';
|
||||
}
|
||||
|
||||
if (lowerMessage.includes('debug') || lowerMessage.includes('🔍') || lowerMessage.includes('checking')) {
|
||||
return 'debug';
|
||||
}
|
||||
|
||||
return 'info';
|
||||
}
|
||||
|
||||
// Fonction pour déterminer le contexte
|
||||
function determineContext(filePath, message) {
|
||||
const fileName = path.basename(filePath, '.ts');
|
||||
|
||||
if (fileName.includes('service')) return 'Service';
|
||||
if (fileName.includes('home')) return 'HomePage';
|
||||
if (fileName.includes('pairing')) return 'PairingPage';
|
||||
if (fileName.includes('wallet')) return 'WalletSetup';
|
||||
if (fileName.includes('security')) return 'SecuritySetup';
|
||||
if (fileName.includes('birthday')) return 'BirthdaySetup';
|
||||
if (fileName.includes('block-sync')) return 'BlockSync';
|
||||
if (fileName.includes('router')) return 'Router';
|
||||
if (fileName.includes('websocket')) return 'WebSocket';
|
||||
if (fileName.includes('sp-address')) return 'SPAddressUtils';
|
||||
|
||||
return 'Application';
|
||||
}
|
||||
|
||||
// Fonction pour corriger un fichier
|
||||
function fixFile(filePath) {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.log(`⚠️ Fichier non trouvé: ${filePath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
let modified = false;
|
||||
|
||||
// Ajouter l'import secureLogger si pas déjà présent
|
||||
if (!content.includes('import { secureLogger }')) {
|
||||
const importMatch = content.match(/import.*from.*['"][^'"]+['"];?\s*\n/);
|
||||
if (importMatch) {
|
||||
const importIndex = content.lastIndexOf(importMatch[0]) + importMatch[0].length;
|
||||
content = content.slice(0, importIndex) +
|
||||
`import { secureLogger } from '../services/secure-logger';\n` +
|
||||
content.slice(importIndex);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Remplacer console.log par secureLogger
|
||||
content = content.replace(
|
||||
/console\.log\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
||||
(match, message) => {
|
||||
const level = determineLogLevel(message);
|
||||
const context = determineContext(filePath, message);
|
||||
modified = true;
|
||||
return `secureLogger.${level}('${message}', { component: '${context}' })`;
|
||||
}
|
||||
);
|
||||
|
||||
// Remplacer console.warn par secureLogger.warn
|
||||
content = content.replace(
|
||||
/console\.warn\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
||||
(match, message) => {
|
||||
const context = determineContext(filePath, message);
|
||||
modified = true;
|
||||
return `secureLogger.warn('${message}', { component: '${context}' })`;
|
||||
}
|
||||
);
|
||||
|
||||
// Remplacer console.error par secureLogger.error
|
||||
content = content.replace(
|
||||
/console\.error\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
||||
(match, message) => {
|
||||
const context = determineContext(filePath, message);
|
||||
modified = true;
|
||||
return `secureLogger.error('${message}', { component: '${context}' })`;
|
||||
}
|
||||
);
|
||||
|
||||
// Remplacer console.info par secureLogger.info
|
||||
content = content.replace(
|
||||
/console\.info\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
||||
(match, message) => {
|
||||
const context = determineContext(filePath, message);
|
||||
modified = true;
|
||||
return `secureLogger.info('${message}', { component: '${context}' })`;
|
||||
}
|
||||
);
|
||||
|
||||
// Remplacer console.debug par secureLogger.debug
|
||||
content = content.replace(
|
||||
/console\.debug\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
||||
(match, message) => {
|
||||
const context = determineContext(filePath, message);
|
||||
modified = true;
|
||||
return `secureLogger.debug('${message}', { component: '${context}' })`;
|
||||
}
|
||||
);
|
||||
|
||||
if (modified) {
|
||||
fs.writeFileSync(filePath, content);
|
||||
console.log(`✅ Corrigé: ${filePath}`);
|
||||
} else {
|
||||
console.log(`⏭️ Aucune modification: ${filePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Exécuter les corrections
|
||||
console.log('🔧 Correction des logs console.* en secureLogger...\n');
|
||||
|
||||
filesToFix.forEach(file => {
|
||||
fixFile(file);
|
||||
});
|
||||
|
||||
console.log('\n✅ Correction terminée !');
|
||||
96
src/4nk.css
96
src/4nk.css
@ -1290,3 +1290,99 @@ select[data-multi-select-plugin] {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Error, Warning, Success and Loading Container Styles */
|
||||
.error-container, .warning-container, .success-container, .loading-container {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
margin: 16px 0;
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.error-container {
|
||||
border-left-color: var(--error-color);
|
||||
background: rgba(244, 67, 54, 0.05);
|
||||
}
|
||||
|
||||
.warning-container {
|
||||
border-left-color: var(--warning-color);
|
||||
background: rgba(255, 152, 0, 0.05);
|
||||
}
|
||||
|
||||
.success-container {
|
||||
border-left-color: var(--success-color);
|
||||
background: rgba(76, 175, 80, 0.05);
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
border-left-color: var(--info-color);
|
||||
background: rgba(33, 150, 243, 0.05);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.error-icon, .warning-icon, .success-icon {
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.error-content, .warning-content, .success-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.error-title, .warning-title, .success-title {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
margin: 0 0 4px 0;
|
||||
color: var(--error-color);
|
||||
}
|
||||
|
||||
.warning-title {
|
||||
color: var(--warning-color);
|
||||
}
|
||||
|
||||
.success-title {
|
||||
color: var(--success-color);
|
||||
}
|
||||
|
||||
.error-message, .warning-message, .success-message {
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
color: #333;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.loading-message {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* Responsive adjustments for status containers */
|
||||
@media (max-width: 768px) {
|
||||
.error-container, .warning-container, .success-container, .loading-container {
|
||||
padding: 12px;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.error-icon, .warning-icon, .success-icon {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.error-title, .warning-title, .success-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.error-message, .warning-message, .success-message, .loading-message {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Configuration de la Date Anniversaire - LeCoffre</title>
|
||||
<title>Configuration de la Date Anniversaire - 4NK</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
|
||||
@ -5,16 +5,17 @@
|
||||
|
||||
import { checkPBKDF2Key, checkWalletWithRetries } from '../../utils/prerequisites.utils';
|
||||
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
let isInitializing = false;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
if (isInitializing) {
|
||||
console.log('⚠️ Birthday setup page already initializing, skipping...');
|
||||
secureLogger.warn('⚠️ Birthday setup page already initializing, skipping...', { component: 'BirthdaySetup' });
|
||||
return;
|
||||
}
|
||||
|
||||
isInitializing = true;
|
||||
console.log('🎂 Birthday setup page loaded');
|
||||
secureLogger.info('🎂 Birthday setup page loaded', { component: 'BirthdaySetup' });
|
||||
console.log('🔍 Current URL:', window.location.href);
|
||||
console.log('🔍 Referrer:', document.referrer);
|
||||
|
||||
@ -28,7 +29,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
updateProgress(20);
|
||||
|
||||
try {
|
||||
console.log('🔄 Importing services...');
|
||||
secureLogger.info('🔄 Importing services...', { component: 'BirthdaySetup' });
|
||||
const serviceModule = await import('../../services/service');
|
||||
console.log('✅ Service module imported:', Object.keys(serviceModule));
|
||||
|
||||
@ -38,17 +39,17 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
if (!Services) {
|
||||
throw new Error('Services class not found in default export');
|
||||
}
|
||||
console.log('🔄 Getting existing services instance...');
|
||||
secureLogger.info('🔄 Getting existing services instance...', { component: 'BirthdaySetup' });
|
||||
|
||||
// Utiliser l'instance existante des services avec gestion des erreurs de mémoire
|
||||
let services;
|
||||
try {
|
||||
services = await Services.getInstance();
|
||||
console.log('✅ Services instance obtained successfully');
|
||||
secureLogger.info('✅ Services instance obtained successfully', { component: 'BirthdaySetup' });
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
if (errorMessage.includes('Out of memory') || errorMessage.includes('insufficient memory')) {
|
||||
console.error('🚫 Memory error detected');
|
||||
secureLogger.error('🚫 Memory error detected', { component: 'BirthdaySetup' });
|
||||
updateStatus('❌ Erreur: Mémoire insuffisante. Veuillez actualiser la page.', 'error');
|
||||
throw new Error('WebAssembly initialization failed due to insufficient memory. Please refresh the page.');
|
||||
}
|
||||
@ -62,7 +63,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Vérifier que le PBKDF2 key existe d'abord (prérequis le plus basique)
|
||||
const pbkdf2KeyResult = await checkPBKDF2Key();
|
||||
if (!pbkdf2KeyResult) {
|
||||
console.log('⚠️ PBKDF2 key not found in pbkdf2keys store, redirecting to security-setup...');
|
||||
secureLogger.warn('⚠️ PBKDF2 key not found in pbkdf2keys store, redirecting to security-setup...', { component: 'BirthdaySetup' });
|
||||
updateStatus('⚠️ Redirection vers la configuration de sécurité...', 'loading');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/security-setup/security-setup.html';
|
||||
@ -73,7 +74,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Vérifier que le wallet existe en base (avec plusieurs tentatives pour gérer les problèmes de synchronisation)
|
||||
const wallet = await checkWalletWithRetries();
|
||||
if (!wallet) {
|
||||
console.log('⚠️ Wallet still not found after retries, redirecting to wallet-setup...');
|
||||
secureLogger.warn('⚠️ Wallet still not found after retries, redirecting to wallet-setup...', { component: 'BirthdaySetup' });
|
||||
updateStatus('⚠️ Redirection vers la configuration du wallet...', 'loading');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/wallet-setup/wallet-setup.html';
|
||||
@ -91,7 +92,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Vérifier que tous les prérequis sont remplis
|
||||
const prerequisitesOk = wallet && pbkdf2KeyResult;
|
||||
if (prerequisitesOk) {
|
||||
console.log('✅ All prerequisites verified');
|
||||
secureLogger.info('✅ All prerequisites verified', { component: 'BirthdaySetup' });
|
||||
} else {
|
||||
throw new Error('Prerequisites verification failed');
|
||||
}
|
||||
@ -112,7 +113,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
const checkBlockHeight = () => {
|
||||
const blockHeight = services.getCurrentBlockHeight();
|
||||
if (blockHeight !== -1 && blockHeight > 0) {
|
||||
console.log(`✅ Block height set from handshake: ${blockHeight}`);
|
||||
secureLogger.info('✅ Block height set from handshake: ${blockHeight}', { component: 'BirthdaySetup' });
|
||||
clearTimeout(timeout);
|
||||
resolve();
|
||||
} else {
|
||||
@ -135,14 +136,14 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Mettre à jour la date anniversaire du wallet
|
||||
updateStatus('🎂 Mise à jour de la date anniversaire...', 'loading');
|
||||
updateProgress(60);
|
||||
console.log('🔄 Calling updateDeviceBlockHeight()...');
|
||||
secureLogger.info('🔄 Calling updateDeviceBlockHeight()...', { component: 'BirthdaySetup' });
|
||||
await services.updateDeviceBlockHeight();
|
||||
console.log('✅ updateDeviceBlockHeight() completed successfully');
|
||||
secureLogger.info('✅ updateDeviceBlockHeight() completed successfully', { component: 'BirthdaySetup' });
|
||||
|
||||
// Vérifier que le birthday a bien été mis à jour en récupérant le wallet depuis la base
|
||||
updateStatus('🔍 Vérification de la mise à jour...', 'loading');
|
||||
updateProgress(70);
|
||||
console.log('🔄 Verifying birthday update...');
|
||||
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);
|
||||
@ -158,13 +159,13 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
updateStatus('🔄 Redirection vers la synchronisation des blocs...', 'loading');
|
||||
updateProgress(100);
|
||||
|
||||
console.log('🎉 Birthday setup completed successfully - redirecting to block sync');
|
||||
console.log('📍 Target URL: /src/pages/block-sync/block-sync.html');
|
||||
console.log('⏰ Redirecting in 1 second...');
|
||||
secureLogger.info('🎉 Birthday setup completed successfully - redirecting to block sync', { component: 'BirthdaySetup' });
|
||||
secureLogger.info('📍 Target URL: /src/pages/block-sync/block-sync.html', { component: 'BirthdaySetup' });
|
||||
secureLogger.info('⏰ Redirecting in 1 second...', { component: 'BirthdaySetup' });
|
||||
|
||||
// Rediriger vers la page de synchronisation des blocs
|
||||
setTimeout(() => {
|
||||
console.log('🔄 Executing redirect now...');
|
||||
secureLogger.info('🔄 Executing redirect now...', { component: 'BirthdaySetup' });
|
||||
window.location.href = '/src/pages/block-sync/block-sync.html';
|
||||
}, 1000);
|
||||
|
||||
@ -183,9 +184,9 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// Gestion du bouton continuer
|
||||
continueBtn.addEventListener('click', async () => {
|
||||
console.log('🏠 Redirecting to main application...');
|
||||
secureLogger.info('🏠 Redirecting to main application...', { component: 'BirthdaySetup' });
|
||||
// Rediriger vers l'application principale
|
||||
console.log('🎂 Birthday setup completed, checking storage state...');
|
||||
secureLogger.debug('🎂 Birthday setup completed, checking storage state...', { component: 'BirthdaySetup' });
|
||||
const { checkStorageStateAndNavigate } = await import('../../router');
|
||||
await checkStorageStateAndNavigate();
|
||||
});
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Synchronisation des Blocs - LeCoffre</title>
|
||||
<title>Synchronisation des Blocs - 4NK</title>
|
||||
<link rel="stylesheet" href="../../4nk.css">
|
||||
<style>
|
||||
body {
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { checkPBKDF2Key, checkWalletWithRetries } from '../../utils/prerequisites.utils';
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
import Services from '../../services/service';
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
console.log("🔄 Block sync page loaded");
|
||||
secureLogger.info('🔄 Block sync page loaded', { component: 'BlockSync' });
|
||||
|
||||
const status = document.getElementById("status") as HTMLElement;
|
||||
const progressBar = document.getElementById("progressBar") as HTMLElement;
|
||||
@ -32,19 +33,19 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
// Gestion du bouton continuer (définie avant le try pour être toujours disponible)
|
||||
if (continueBtn) {
|
||||
continueBtn.addEventListener('click', async () => {
|
||||
console.log('🔗 Redirecting to pairing page...');
|
||||
secureLogger.info('🔗 Redirecting to pairing page...', { component: 'BlockSync' });
|
||||
window.location.href = '/src/pages/pairing/pairing.html';
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// Vérifier les prérequis
|
||||
console.log('🔍 Verifying prerequisites...');
|
||||
secureLogger.debug('🔍 Verifying prerequisites...', { component: 'BlockSync' });
|
||||
updateStatus('🔍 Vérification des prérequis...', 'loading');
|
||||
|
||||
const pbkdf2KeyResult = await checkPBKDF2Key();
|
||||
if (!pbkdf2KeyResult) {
|
||||
console.log('⚠️ PBKDF2 key not found, redirecting to security-setup...');
|
||||
secureLogger.warn('⚠️ PBKDF2 key not found, redirecting to security-setup...', { component: 'BlockSync' });
|
||||
updateStatus('⚠️ Redirection vers la configuration de sécurité...', 'loading');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/security-setup/security-setup.html';
|
||||
@ -54,7 +55,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
|
||||
const wallet = await checkWalletWithRetries();
|
||||
if (!wallet) {
|
||||
console.log('⚠️ Wallet not found, redirecting to wallet-setup...');
|
||||
secureLogger.warn('⚠️ Wallet not found, redirecting to wallet-setup...', { component: 'BlockSync' });
|
||||
updateStatus('⚠️ Redirection vers la configuration du wallet...', 'loading');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/wallet-setup/wallet-setup.html';
|
||||
@ -63,7 +64,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
}
|
||||
|
||||
if (!wallet.sp_wallet?.birthday || wallet.sp_wallet.birthday === 0) {
|
||||
console.log('⚠️ Birthday not configured, redirecting to birthday-setup...');
|
||||
secureLogger.warn('⚠️ Birthday not configured, redirecting to birthday-setup...', { component: 'BlockSync' });
|
||||
updateStatus('⚠️ Redirection vers la configuration de la date anniversaire...', 'loading');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
|
||||
@ -71,11 +72,11 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✅ All prerequisites verified for block sync');
|
||||
secureLogger.info('✅ All prerequisites verified for block sync', { component: 'BlockSync' });
|
||||
updateStatus('✅ Prerequisites verified', 'success');
|
||||
|
||||
// Initialiser les services
|
||||
console.log('🔄 Waiting for services to be ready...');
|
||||
secureLogger.info('🔄 Waiting for services to be ready...', { component: 'BlockSync' });
|
||||
updateStatus('🔄 Initialisation des services...', 'loading');
|
||||
|
||||
let services: Services;
|
||||
@ -84,9 +85,9 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
|
||||
while (attempts < maxAttempts) {
|
||||
try {
|
||||
console.log(`🔄 Attempting to get services (attempt ${attempts + 1}/${maxAttempts})...`);
|
||||
secureLogger.info('🔄 Attempting to get services (attempt ${attempts + 1}/${maxAttempts})...', { component: 'BlockSync' });
|
||||
services = await Services.getInstance();
|
||||
console.log('✅ Services initialized successfully');
|
||||
secureLogger.info('✅ Services initialized successfully', { component: 'BlockSync' });
|
||||
break;
|
||||
} catch (error) {
|
||||
attempts++;
|
||||
@ -105,7 +106,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
// Vérifier si le wallet est déjà synchronisé
|
||||
const currentBlockHeight = services.getCurrentBlockHeight();
|
||||
if (currentBlockHeight === -1) {
|
||||
console.log('⚠️ Block height not available, connecting to relays...');
|
||||
secureLogger.warn('⚠️ Block height not available, connecting to relays...', { component: 'BlockSync' });
|
||||
updateStatus('⚠️ Connexion aux relays...', 'loading');
|
||||
|
||||
// Attendre que les services se connectent aux relays
|
||||
@ -120,7 +121,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
const lastScan = wallet.sp_wallet.last_scan || 0;
|
||||
const toScan = Math.max(0, finalBlockHeight - lastScan);
|
||||
|
||||
console.log(`📊 Sync info: current=${finalBlockHeight}, birthday=${birthday}, lastScan=${lastScan}, toScan=${toScan}`);
|
||||
secureLogger.info('📊 Sync info: current=${finalBlockHeight}, birthday=${birthday}, lastScan=${lastScan}, toScan=${toScan}', { component: 'BlockSync' });
|
||||
|
||||
// Mettre à jour l'interface
|
||||
updateSyncItem('currentBlock', finalBlockHeight.toString(), 'completed');
|
||||
@ -128,7 +129,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
updateSyncItem('lastScan', lastScan.toString(), 'completed');
|
||||
|
||||
if (toScan === 0) {
|
||||
console.log('✅ Wallet already synchronized');
|
||||
secureLogger.info('✅ Wallet already synchronized', { component: 'BlockSync' });
|
||||
updateStatus('✅ Wallet déjà synchronisé', 'success');
|
||||
updateSyncItem('blocksToScan', '0', 'completed');
|
||||
updateSyncItem('blocksScanned', '0', 'completed');
|
||||
@ -142,7 +143,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
|
||||
// Auto-redirection après 3 secondes
|
||||
setTimeout(() => {
|
||||
console.log('🔗 Auto-redirecting to pairing page...');
|
||||
secureLogger.info('🔗 Auto-redirecting to pairing page...', { component: 'BlockSync' });
|
||||
window.location.href = '/src/pages/pairing/pairing.html';
|
||||
}, 3000);
|
||||
return;
|
||||
@ -187,7 +188,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
try {
|
||||
// Effectuer la synchronisation
|
||||
await services.updateDeviceBlockHeight();
|
||||
console.log('✅ Block scan completed successfully');
|
||||
secureLogger.info('✅ Block scan completed successfully', { component: 'BlockSync' });
|
||||
|
||||
// Restaurer la fonction console.log originale
|
||||
console.log = originalConsoleLog;
|
||||
@ -206,7 +207,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
|
||||
// Auto-redirection après 3 secondes
|
||||
setTimeout(() => {
|
||||
console.log('🔗 Auto-redirecting to pairing page...');
|
||||
secureLogger.info('🔗 Auto-redirecting to pairing page...', { component: 'BlockSync' });
|
||||
window.location.href = '/src/pages/pairing/pairing.html';
|
||||
}, 3000);
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { DeviceReaderService } from '../../services/device-reader.service';
|
||||
import { SecureCredentialsService } from '../../services/secure-credentials.service';
|
||||
import { SecurityModeService, SecurityMode } from '../../services/security-mode.service';
|
||||
import { secureLogger } from '../../services/secure-logger';
|
||||
import Services from '../../services/service';
|
||||
import { addSubscription } from '../../utils/subscription.utils';
|
||||
import { displayEmojis, generateCreateBtn, addressToEmoji, prepareAndSendPairingTx } from '../../utils/sp-address.utils';
|
||||
@ -23,24 +24,24 @@ let isInitializing = false;
|
||||
|
||||
export async function initHomePage(): Promise<void> {
|
||||
if (isInitializing) {
|
||||
console.log('⚠️ Home page already initializing, skipping...');
|
||||
secureLogger.warn('Home page already initializing, skipping...', { component: 'HomePage' });
|
||||
return;
|
||||
}
|
||||
|
||||
isInitializing = true;
|
||||
console.log('🏠 Home/Pairing page loaded');
|
||||
secureLogger.info('Home/Pairing page loaded', { component: 'HomePage' });
|
||||
|
||||
// Vérifier les prérequis en base de données
|
||||
console.log('🔍 Verifying prerequisites...');
|
||||
secureLogger.info('Verifying prerequisites...', { component: 'HomePage' });
|
||||
|
||||
try {
|
||||
console.log('🔧 Getting device reader service...');
|
||||
secureLogger.info('🔧 Getting device reader service...', { component: 'HomePage' });
|
||||
const deviceReader = DeviceReaderService.getInstance();
|
||||
|
||||
// Vérifier que le PBKDF2 key existe d'abord (prérequis le plus basique) dans le store pbkdf2keys
|
||||
const pbkdf2KeyResult = await checkPBKDF2Key();
|
||||
if (!pbkdf2KeyResult) {
|
||||
console.log('⚠️ PBKDF2 key not found in pbkdf2keys store, redirecting to security-setup...');
|
||||
secureLogger.warn('⚠️ PBKDF2 key not found in pbkdf2keys store, redirecting to security-setup...', { component: 'HomePage' });
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/security-setup/security-setup.html';
|
||||
}, 1000);
|
||||
@ -50,7 +51,7 @@ 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)
|
||||
const wallet = await checkWalletWithRetries();
|
||||
if (!wallet) {
|
||||
console.log('⚠️ Wallet still not found after retries, redirecting to wallet-setup...');
|
||||
secureLogger.warn('⚠️ Wallet still not found after retries, redirecting to wallet-setup...', { component: 'HomePage' });
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/wallet-setup/wallet-setup.html';
|
||||
}, 1000);
|
||||
@ -59,144 +60,156 @@ export async function initHomePage(): Promise<void> {
|
||||
|
||||
// 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: 'HomePage' });
|
||||
} 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...');
|
||||
secureLogger.warn('⚠️ Birthday not configured (birthday = 0), redirecting to birthday-setup...', { component: 'HomePage' });
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✅ All prerequisites verified for pairing page');
|
||||
secureLogger.info('✅ All prerequisites verified for pairing page', { component: 'HomePage' });
|
||||
|
||||
// Restaurer le mode de sécurité depuis la clé PBKDF2 détectée
|
||||
// Le SecurityModeService stocke le mode uniquement en mémoire, donc on doit le restaurer
|
||||
if (pbkdf2KeyResult.mode) {
|
||||
console.log(`🔐 Restoring security mode from PBKDF2 key: ${pbkdf2KeyResult.mode}`);
|
||||
secureLogger.info('🔐 Restoring security mode from PBKDF2 key: ${pbkdf2KeyResult.mode}', { component: 'HomePage' });
|
||||
const securityModeService = SecurityModeService.getInstance();
|
||||
// Le mode retourné par checkPBKDF2Key() est compatible avec SecurityMode (sauf '2fa' qui n'est pas utilisé)
|
||||
await securityModeService.setSecurityMode(pbkdf2KeyResult.mode as SecurityMode);
|
||||
console.log(`✅ Security mode restored: ${pbkdf2KeyResult.mode}`);
|
||||
secureLogger.info('✅ Security mode restored: ${pbkdf2KeyResult.mode}', { component: 'HomePage' });
|
||||
}
|
||||
|
||||
// No loading spinner - let the interface load naturally
|
||||
// No loading spinner - let the interface load naturally
|
||||
|
||||
// Initialize iframe pairing, content menu, and communication only if in iframe
|
||||
if (window.parent !== window) {
|
||||
initIframePairing();
|
||||
initContentMenu();
|
||||
initIframeCommunication();
|
||||
}
|
||||
// Initialize iframe pairing, content menu, and communication only if in iframe
|
||||
if (window.parent !== window) {
|
||||
initIframePairing();
|
||||
initContentMenu();
|
||||
initIframeCommunication();
|
||||
}
|
||||
|
||||
// Set up iframe pairing button listeners
|
||||
setupIframePairingButtons();
|
||||
// Set up iframe pairing button listeners
|
||||
setupIframePairingButtons();
|
||||
|
||||
// Set up main pairing interface (avec protection contre les appels multiples)
|
||||
if (!isMainPairingSetup) {
|
||||
setupMainPairing();
|
||||
}
|
||||
// Set up main pairing interface (avec protection contre les appels multiples)
|
||||
if (!isMainPairingSetup) {
|
||||
setupMainPairing();
|
||||
}
|
||||
|
||||
// Set up account actions
|
||||
setupAccountActions();
|
||||
// Set up account actions
|
||||
setupAccountActions();
|
||||
|
||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
||||
container.querySelectorAll('.tab').forEach(tab => {
|
||||
addSubscription(tab, 'click', () => {
|
||||
container.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
||||
container.querySelectorAll('.tab').forEach(tab => {
|
||||
addSubscription(tab, 'click', () => {
|
||||
container.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
|
||||
container
|
||||
.querySelectorAll('.tab-content')
|
||||
.forEach(content => content.classList.remove('active'));
|
||||
container
|
||||
.querySelector(`#${tab.getAttribute('data-tab') as string}`)
|
||||
?.classList.add('active');
|
||||
});
|
||||
container
|
||||
.querySelectorAll('.tab-content')
|
||||
.forEach(content => content.classList.remove('active'));
|
||||
container
|
||||
.querySelector(`#${tab.getAttribute('data-tab') as string}`)
|
||||
?.classList.add('active');
|
||||
});
|
||||
});
|
||||
|
||||
// Les prérequis sont vérifiés, le wallet existe et le birthday est configuré
|
||||
// Maintenant vérifier si les credentials de pairing existent
|
||||
console.log('🔐 Checking pairing credentials...');
|
||||
secureLogger.debug('🔐 Checking pairing credentials...', { component: 'HomePage' });
|
||||
const secureCredentialsService = SecureCredentialsService.getInstance();
|
||||
|
||||
const hasCredentials = await secureCredentialsService.hasCredentials();
|
||||
|
||||
if (!hasCredentials) {
|
||||
console.log('🔐 No pairing credentials found, user must authenticate...');
|
||||
secureLogger.info('🔐 No pairing credentials found, user must authenticate...', { component: 'HomePage' });
|
||||
// Afficher le sélecteur de mode de sécurité si nécessaire ou déclencher l'authentification
|
||||
await handleMainPairing();
|
||||
return;
|
||||
}
|
||||
|
||||
// Wallet existe et credentials existent, procéder avec le pairing
|
||||
console.log('✅ Wallet and credentials verified, proceeding with pairing...');
|
||||
console.log('🔍 Wallet details:', {
|
||||
secureLogger.info('✅ Wallet and credentials verified, proceeding with pairing...', { component: 'HomePage' });
|
||||
secureLogger.debug('Wallet details', {
|
||||
component: 'HomePage',
|
||||
hasSpendKey: !!wallet.sp_wallet?.spend_key,
|
||||
hasScanKey: !!wallet.sp_wallet?.scan_key,
|
||||
birthday: wallet.sp_wallet?.birthday
|
||||
});
|
||||
|
||||
// Trigger WebAuthn authentication pour déchiffrer les credentials existants
|
||||
console.log('🔐 Triggering WebAuthn authentication to decrypt credentials...');
|
||||
secureLogger.info('🔐 Triggering WebAuthn authentication to decrypt credentials...', { component: 'HomePage' });
|
||||
await handleMainPairing();
|
||||
|
||||
// Attendre que les credentials soient réellement disponibles avant de continuer
|
||||
console.log('⏳ Waiting for credentials to be fully available...');
|
||||
secureLogger.info('⏳ Waiting for credentials to be fully available...', { component: 'HomePage' });
|
||||
await waitForCredentialsAvailability();
|
||||
console.log('✅ Credentials confirmed as available, proceeding...');
|
||||
secureLogger.info('✅ Credentials confirmed as available, proceeding...', { component: 'HomePage' });
|
||||
|
||||
// After WebAuthn, get device address and setup UI
|
||||
console.log('🔧 Getting device address...');
|
||||
secureLogger.info('🔧 Getting device address...', { component: 'HomePage' });
|
||||
|
||||
try {
|
||||
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);
|
||||
secureLogger.info('🔧 Generating create button...', { component: 'HomePage' });
|
||||
generateCreateBtn();
|
||||
secureLogger.info('🔧 Displaying emojis...', { component: 'HomePage' });
|
||||
displayEmojis(spAddress);
|
||||
} catch (error) {
|
||||
secureLogger.error('Failed to get device address', error as Error, { component: 'HomePage' });
|
||||
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;
|
||||
}
|
||||
secureLogger.error('❌ Wallet keys not available - authentication failed', { component: 'HomePage' });
|
||||
throw new Error('Authentication failed - wallet keys not available');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log('✅ Home page initialization completed');
|
||||
secureLogger.info('✅ Home page initialization completed', { component: 'HomePage' });
|
||||
} catch (error) {
|
||||
console.error('❌ Error initializing home/pairing page:', error);
|
||||
secureLogger.error('Error initializing home/pairing page', error as Error, { component: 'HomePage' });
|
||||
|
||||
// Afficher un message d'erreur à l'utilisateur
|
||||
// Afficher un message d'erreur à l'utilisateur dans un conteneur stylé
|
||||
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>`;
|
||||
mainStatus.innerHTML = `
|
||||
<div class="error-container">
|
||||
<div class="error-icon">❌</div>
|
||||
<div class="error-content">
|
||||
<div class="error-title">Error</div>
|
||||
<div class="error-message">${(error as Error).message}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// 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')) {
|
||||
console.log('⚠️ Security error detected, redirecting to security-setup...');
|
||||
secureLogger.error('⚠️ Security error detected, redirecting to security-setup...', { component: 'HomePage' });
|
||||
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...');
|
||||
} else if (errorMessage.includes('wallet') && !errorMessage.includes('keys not available')) {
|
||||
secureLogger.error('⚠️ Wallet error detected, redirecting to wallet-setup...', { component: 'HomePage' });
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/wallet-setup/wallet-setup.html';
|
||||
}, 2000);
|
||||
} else if (errorMessage.includes('keys not available') || errorMessage.includes('SDK device creation failed')) {
|
||||
secureLogger.error('⚠️ SDK/Keys error detected, staying on pairing page...', { component: 'HomePage' });
|
||||
// Ne pas rediriger, rester sur la page de pairing pour afficher l'erreur
|
||||
} else if (errorMessage.includes('birthday')) {
|
||||
console.log('⚠️ Birthday error detected, redirecting to birthday-setup...');
|
||||
secureLogger.error('⚠️ Birthday error detected, redirecting to birthday-setup...', { component: 'HomePage' });
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
|
||||
}, 2000);
|
||||
@ -220,7 +233,10 @@ export function initIframePairing() {
|
||||
// Listen for pairing events
|
||||
window.addEventListener('pairing-words-generated', (event: Event) => {
|
||||
const customEvent = event as CustomEvent;
|
||||
console.log('✅ 4 words generated via iframe:', customEvent.detail.words);
|
||||
secureLogger.info('4 words generated via iframe', {
|
||||
component: 'HomePage',
|
||||
words: customEvent.detail.words
|
||||
});
|
||||
// Update the UI with the generated words
|
||||
const creatorWordsElement = document.querySelector('#creator-words');
|
||||
if (creatorWordsElement) {
|
||||
@ -242,7 +258,7 @@ export function initIframePairing() {
|
||||
|
||||
window.addEventListener('pairing-status-update', (event: Event) => {
|
||||
const customEvent = event as CustomEvent;
|
||||
console.log('📊 Pairing status update:', customEvent.detail.status);
|
||||
secureLogger.info('📊 Pairing status update:', { component: 'HomePage', data: customEvent.detail.status });
|
||||
// Update status indicators
|
||||
const statusElement = document.querySelector(`#${customEvent.detail.type}-status span`);
|
||||
if (statusElement) {
|
||||
@ -263,7 +279,7 @@ export function initIframePairing() {
|
||||
|
||||
window.addEventListener('pairing-success', (event: Event) => {
|
||||
const customEvent = event as CustomEvent;
|
||||
console.log('✅ Pairing successful:', customEvent.detail.message);
|
||||
secureLogger.info('✅ Pairing successful:', { component: 'HomePage', data: customEvent.detail.message });
|
||||
|
||||
// Send message to parent
|
||||
if (window.parent !== window) {
|
||||
@ -284,7 +300,7 @@ export function initIframePairing() {
|
||||
|
||||
window.addEventListener('pairing-error', (event: Event) => {
|
||||
const customEvent = event as CustomEvent;
|
||||
console.error('❌ Pairing error:', customEvent.detail.error);
|
||||
secureLogger.error('❌ Pairing error:', customEvent.detail.error, { component: 'HomePage' });
|
||||
|
||||
// Send message to parent
|
||||
if (window.parent !== window) {
|
||||
@ -334,7 +350,7 @@ export function initContentMenu() {
|
||||
button.classList.add('active');
|
||||
|
||||
const page = button.getAttribute('data-page');
|
||||
console.log(`Menu clicked: ${page}`);
|
||||
secureLogger.info('Menu clicked: ${page}', { component: 'HomePage' });
|
||||
|
||||
// Send message to parent window
|
||||
window.parent.postMessage(
|
||||
@ -365,13 +381,13 @@ export function initIframeCommunication() {
|
||||
}
|
||||
|
||||
// Security check - in production, verify event.origin
|
||||
console.log('📨 Received message from parent:', event.data);
|
||||
secureLogger.info('📨 Received message from parent:', { component: 'HomePage', data: event.data });
|
||||
|
||||
const { type, data } = event.data;
|
||||
|
||||
switch (type) {
|
||||
case 'TEST_MESSAGE':
|
||||
console.log('🧪 Test message received:', data.message);
|
||||
secureLogger.info('🧪 Test message received:', { component: 'HomePage', data: data.message });
|
||||
// Send response back to parent
|
||||
if (window.parent !== window) {
|
||||
window.parent.postMessage(
|
||||
@ -385,25 +401,25 @@ export function initIframeCommunication() {
|
||||
break;
|
||||
|
||||
case 'PAIRING_4WORDS_CREATE':
|
||||
console.log('🔐 Parent requested pairing creation');
|
||||
secureLogger.info('🔐 Parent requested pairing creation', { component: 'HomePage' });
|
||||
createPairingViaIframe();
|
||||
break;
|
||||
|
||||
case 'PAIRING_4WORDS_JOIN':
|
||||
console.log('🔗 Parent requested pairing join with words:', data.words);
|
||||
secureLogger.info('🔗 Parent requested pairing join with words:', { component: 'HomePage', data: data.words });
|
||||
joinPairingViaIframe(data.words);
|
||||
break;
|
||||
|
||||
case 'LISTENING':
|
||||
console.log('👂 Parent is listening for messages');
|
||||
secureLogger.info('👂 Parent is listening for messages', { component: 'HomePage' });
|
||||
break;
|
||||
|
||||
case 'IFRAME_READY':
|
||||
console.log('✅ Iframe is ready and initialized');
|
||||
secureLogger.info('✅ Iframe is ready and initialized', { component: 'HomePage' });
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('❓ Unknown message type from parent:', type);
|
||||
secureLogger.info('❓ Unknown message type from parent:', { component: 'HomePage', data: type });
|
||||
}
|
||||
});
|
||||
|
||||
@ -416,7 +432,7 @@ export function initIframeCommunication() {
|
||||
},
|
||||
'*'
|
||||
);
|
||||
console.log('📡 Notified parent that iframe is ready');
|
||||
secureLogger.info('📡 Notified parent that iframe is ready', { component: 'HomePage' });
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,7 +445,7 @@ export async function createPairingViaIframe() {
|
||||
try {
|
||||
await iframePairing!.createPairing();
|
||||
} catch (error) {
|
||||
console.error('Error creating pairing via iframe:', error);
|
||||
secureLogger.error('Error creating pairing via iframe:', error, { component: 'HomePage' });
|
||||
alert(`Error creating pairing: ${(error as Error).message}`);
|
||||
}
|
||||
}
|
||||
@ -442,7 +458,7 @@ export async function joinPairingViaIframe(words: string) {
|
||||
try {
|
||||
await iframePairing!.joinPairing(words);
|
||||
} catch (error) {
|
||||
console.error('Error joining pairing via iframe:', error);
|
||||
secureLogger.error('Error joining pairing via iframe:', error, { component: 'HomePage' });
|
||||
alert(`Error joining pairing: ${(error as Error).message}`);
|
||||
}
|
||||
}
|
||||
@ -453,7 +469,7 @@ export function setupIframePairingButtons() {
|
||||
const createButton = document.getElementById('createButton');
|
||||
if (createButton) {
|
||||
createButton.addEventListener('click', async () => {
|
||||
console.log('🔐 Create button clicked - using iframe pairing');
|
||||
secureLogger.info('🔐 Create button clicked - using iframe pairing', { component: 'HomePage' });
|
||||
await createPairingViaIframe();
|
||||
});
|
||||
}
|
||||
@ -472,7 +488,7 @@ export function setupIframePairingButtons() {
|
||||
joinButton.addEventListener('click', async () => {
|
||||
const words = wordsInput.value.trim();
|
||||
if (words) {
|
||||
console.log('🔗 Join button clicked - using iframe pairing with words:', words);
|
||||
secureLogger.info('🔗 Join button clicked - using iframe pairing with words:', { component: 'HomePage', data: words });
|
||||
await joinPairingViaIframe(words);
|
||||
}
|
||||
});
|
||||
@ -487,7 +503,7 @@ export function setupIframePairingButtons() {
|
||||
navigator.clipboard
|
||||
.writeText(creatorWordsElement.textContent)
|
||||
.then(() => {
|
||||
console.log('✅ Words copied to clipboard');
|
||||
secureLogger.info('✅ Words copied to clipboard', { component: 'HomePage' });
|
||||
// Show feedback
|
||||
const originalText = copyWordsBtn.textContent;
|
||||
copyWordsBtn.textContent = '✅ Copied!';
|
||||
@ -496,7 +512,7 @@ export function setupIframePairingButtons() {
|
||||
}, 2000);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Failed to copy words:', err);
|
||||
secureLogger.error('Failed to copy words:', err, { component: 'HomePage' });
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -510,7 +526,7 @@ let isMainPairingSetup = false;
|
||||
export function setupMainPairing(): void {
|
||||
// Protection contre les appels multiples
|
||||
if (isMainPairingSetup) {
|
||||
console.log('🔐 Main pairing already setup, skipping...');
|
||||
secureLogger.warn('🔐 Main pairing already setup, skipping...', { component: 'HomePage' });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -523,7 +539,7 @@ export function setupMainPairing(): void {
|
||||
mainStatus.innerHTML = '<span style="color: var(--info-color)">⏳ Waiting for user to validate secure key access...</span>';
|
||||
}
|
||||
|
||||
console.log('🔐 Main pairing setup - waiting for user interaction');
|
||||
secureLogger.info('🔐 Main pairing setup - waiting for user interaction', { component: 'HomePage' });
|
||||
}
|
||||
|
||||
function setupUserInteractionListener(): void {
|
||||
@ -533,7 +549,7 @@ function setupUserInteractionListener(): void {
|
||||
if (hasTriggered) {return;}
|
||||
hasTriggered = true;
|
||||
|
||||
console.log('🔐 User interaction detected:', event.type, 'triggering WebAuthn...');
|
||||
secureLogger.info('🔐 User interaction detected:', { component: 'HomePage', data: event.type, 'triggering WebAuthn...' });
|
||||
await handleMainPairing();
|
||||
};
|
||||
|
||||
@ -543,7 +559,7 @@ function setupUserInteractionListener(): void {
|
||||
document.addEventListener('touchstart', triggerWebAuthn, { once: true, passive: true });
|
||||
document.addEventListener('mousedown', triggerWebAuthn, { once: true, passive: true });
|
||||
|
||||
console.log('🔐 User interaction listeners set up');
|
||||
secureLogger.info('🔐 User interaction listeners set up', { component: 'HomePage' });
|
||||
}
|
||||
|
||||
|
||||
@ -556,7 +572,7 @@ let isWaitingForCredentials = false;
|
||||
async function waitForCredentialsAvailability(): Promise<void> {
|
||||
// Protection contre les appels multiples
|
||||
if (isWaitingForCredentials) {
|
||||
console.log('🔍 Already waiting for credentials, skipping...');
|
||||
secureLogger.warn('🔍 Already waiting for credentials, skipping...', { component: 'HomePage' });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -571,23 +587,23 @@ async function waitForCredentialsAvailability(): Promise<void> {
|
||||
|
||||
while (attempts < maxAttempts) {
|
||||
attempts++;
|
||||
console.log(`🔍 Vérification de la disponibilité des credentials (tentative ${attempts}/${maxAttempts})...`);
|
||||
secureLogger.debug('🔍 Vérification de la disponibilité des credentials (tentative ${attempts}/${maxAttempts})...', { component: 'HomePage' });
|
||||
|
||||
try {
|
||||
// Vérifier que les credentials sont réellement disponibles et accessibles
|
||||
const credentials = await secureCredentialsService.retrieveCredentials('');
|
||||
|
||||
if (credentials?.spendKey && credentials.scanKey) {
|
||||
console.log('✅ Credentials confirmés comme disponibles');
|
||||
secureLogger.info('✅ Credentials confirmés comme disponibles', { component: 'HomePage' });
|
||||
return;
|
||||
} else {
|
||||
throw new Error('Credentials incomplets');
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ Credentials pas encore disponibles (tentative ${attempts}):`, error);
|
||||
secureLogger.warn('⚠️ Credentials pas encore disponibles (tentative ${attempts}):', { component: 'HomePage', data: error });
|
||||
|
||||
if (attempts < maxAttempts) {
|
||||
console.log(`⏳ Attente de ${delayMs}ms avant la prochaine tentative...`);
|
||||
secureLogger.info('⏳ Attente de ${delayMs}ms avant la prochaine tentative...', { component: 'HomePage' });
|
||||
await new Promise(resolve => setTimeout(resolve, delayMs));
|
||||
}
|
||||
}
|
||||
@ -607,12 +623,12 @@ const MAX_PAIRING_ATTEMPTS = 1;
|
||||
async function handleMainPairing(): Promise<void> {
|
||||
// Protection renforcée contre les appels multiples
|
||||
if (isPairingInProgress) {
|
||||
console.log('🔐 Pairing already in progress, skipping...');
|
||||
secureLogger.warn('🔐 Pairing already in progress, skipping...', { component: 'HomePage' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (pairingAttempts >= MAX_PAIRING_ATTEMPTS) {
|
||||
console.log('🔐 Maximum pairing attempts reached, skipping...');
|
||||
secureLogger.warn('🔐 Maximum pairing attempts reached, skipping...', { component: 'HomePage' });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -632,9 +648,17 @@ async function handleMainPairing(): Promise<void> {
|
||||
currentMode = await securityModeService.getCurrentMode();
|
||||
} catch (error) {
|
||||
// Si aucun mode n'est configuré, rediriger vers security-setup (le mode devrait déjà être configuré avant d'arriver ici)
|
||||
console.log('⚠️ No security mode configured, redirecting to security-setup...');
|
||||
secureLogger.warn('⚠️ No security mode configured, redirecting to security-setup...', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--warning-color)">⚠️ Security mode not configured, redirecting...</span>';
|
||||
mainStatus.innerHTML = `
|
||||
<div class="warning-container">
|
||||
<div class="warning-icon">⚠️</div>
|
||||
<div class="warning-content">
|
||||
<div class="warning-title">Configuration Required</div>
|
||||
<div class="warning-message">Security mode not configured, redirecting...</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/security-setup/security-setup.html';
|
||||
@ -644,9 +668,17 @@ async function handleMainPairing(): Promise<void> {
|
||||
|
||||
if (!currentMode) {
|
||||
// Aucun mode sélectionné, rediriger vers security-setup
|
||||
console.log('⚠️ No security mode selected, redirecting to security-setup...');
|
||||
secureLogger.warn('⚠️ No security mode selected, redirecting to security-setup...', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--warning-color)">⚠️ Redirecting to security setup...</span>';
|
||||
mainStatus.innerHTML = `
|
||||
<div class="warning-container">
|
||||
<div class="warning-icon">⚠️</div>
|
||||
<div class="warning-content">
|
||||
<div class="warning-title">Configuration Required</div>
|
||||
<div class="warning-message">Redirecting to security setup...</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/security-setup/security-setup.html';
|
||||
@ -655,7 +687,7 @@ async function handleMainPairing(): Promise<void> {
|
||||
}
|
||||
|
||||
// Mode sélectionné, continuer avec l'authentification
|
||||
console.log(`🔐 Using security mode: ${currentMode}`);
|
||||
secureLogger.info('🔐 Using security mode: ${currentMode}', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Authenticating with selected security mode...</span>';
|
||||
}
|
||||
@ -664,44 +696,52 @@ async function handleMainPairing(): Promise<void> {
|
||||
const secureCredentialsService = SecureCredentialsService.getInstance();
|
||||
|
||||
// Check if we have existing credentials (regardless of wallet existence)
|
||||
console.log('🔍 Checking for existing credentials...');
|
||||
secureLogger.debug('🔍 Checking for existing credentials...', { component: 'HomePage' });
|
||||
const hasCredentials = await secureCredentialsService.hasCredentials();
|
||||
|
||||
if (hasCredentials) {
|
||||
console.log('🔓 Existing credentials found, decrypting...');
|
||||
secureLogger.info('🔓 Existing credentials found, decrypting...', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Decrypting existing credentials...</span>';
|
||||
}
|
||||
|
||||
try {
|
||||
// This will trigger authentication for decryption of existing credentials
|
||||
console.log('🔐 Starting credentials decryption process...');
|
||||
secureLogger.info('🔐 Starting credentials decryption process...', { component: 'HomePage' });
|
||||
const decryptedCredentials = await secureCredentialsService.retrieveCredentials('');
|
||||
|
||||
if (!decryptedCredentials) {
|
||||
throw new Error('Failed to decrypt existing credentials - no data returned');
|
||||
}
|
||||
|
||||
console.log('✅ Credentials decryption completed successfully');
|
||||
secureLogger.info('✅ Credentials decryption completed successfully', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ Credentials decrypted successfully</span>';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Credentials decryption failed:', error);
|
||||
secureLogger.error('❌ Credentials decryption failed:', error, { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--error-color)">❌ Failed to decrypt credentials. Please try again.</span>';
|
||||
mainStatus.innerHTML = `
|
||||
<div class="error-container">
|
||||
<div class="error-icon">❌</div>
|
||||
<div class="error-content">
|
||||
<div class="error-title">Authentication Failed</div>
|
||||
<div class="error-message">Failed to decrypt credentials. Please try again.</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
throw error; // Arrêter le processus si le déchiffrement échoue
|
||||
}
|
||||
} else {
|
||||
console.log('🔐 No existing credentials, creating new ones...');
|
||||
secureLogger.info('🔐 No existing credentials, creating new ones...', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>🔐 Setting up secure authentication...</span>';
|
||||
}
|
||||
|
||||
try {
|
||||
// This will trigger authentication for creation of new credentials
|
||||
console.log('🔐 Starting credentials creation process...');
|
||||
secureLogger.info('🔐 Starting credentials creation process...', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>🔐 Creating secure credentials with your device...</span>';
|
||||
}
|
||||
@ -712,22 +752,22 @@ async function handleMainPairing(): Promise<void> {
|
||||
throw new Error('Failed to generate valid credentials - missing spendKey or scanKey');
|
||||
}
|
||||
|
||||
console.log('✅ Credentials creation completed successfully');
|
||||
secureLogger.info('✅ Credentials creation completed successfully', { component: 'HomePage' });
|
||||
|
||||
// Store the credentials in IndexedDB
|
||||
console.log('💾 Storing credentials in IndexedDB...');
|
||||
secureLogger.info('💾 Storing credentials in IndexedDB...', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>💾 Securing credentials...</span>';
|
||||
}
|
||||
|
||||
await secureCredentialsService.storeCredentials(credentialData, '');
|
||||
console.log('✅ Credentials stored successfully');
|
||||
secureLogger.info('✅ Credentials stored successfully', { component: 'HomePage' });
|
||||
|
||||
// Note: Faucet temporarily disabled due to relay configuration issue
|
||||
console.log('🪙 Faucet temporarily disabled - relay needs Bitcoin Core wallet configuration');
|
||||
secureLogger.info('🪙 Faucet temporarily disabled - relay needs Bitcoin Core wallet configuration', { component: 'HomePage' });
|
||||
|
||||
// Decrypt and make keys available to SDK
|
||||
console.log('🔓 Decrypting credentials for SDK access...');
|
||||
secureLogger.info('🔓 Decrypting credentials for SDK access...', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>🔓 Making keys available...</span>';
|
||||
}
|
||||
@ -738,25 +778,33 @@ async function handleMainPairing(): Promise<void> {
|
||||
throw new Error('Failed to retrieve stored credentials - decryption failed');
|
||||
}
|
||||
|
||||
console.log('✅ Credentials decrypted and available');
|
||||
secureLogger.info('✅ Credentials decrypted and available', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ Secure authentication ready</span>';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Credentials creation/encryption/decryption failed:', error);
|
||||
secureLogger.error('❌ Credentials creation/encryption/decryption failed:', error, { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--error-color)">❌ Failed to create/encrypt/decrypt credentials. Please try again.</span>';
|
||||
mainStatus.innerHTML = `
|
||||
<div class="error-container">
|
||||
<div class="error-icon">❌</div>
|
||||
<div class="error-content">
|
||||
<div class="error-title">Credentials Error</div>
|
||||
<div class="error-message">Failed to create/encrypt/decrypt credentials. Please try again.</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
throw error; // Arrêter le processus si la génération/chiffrement/déchiffrement échoue
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure WebAuthn process is completely finished
|
||||
console.log('🔐 WebAuthn process completed, waiting for final confirmation...');
|
||||
secureLogger.info('🔐 WebAuthn process completed, waiting for final confirmation...', { component: 'HomePage' });
|
||||
await new Promise(resolve => setTimeout(resolve, 1000)); // Additional wait to ensure completion
|
||||
|
||||
// Wait longer to ensure credentials are fully processed and stored
|
||||
console.log('⏳ Waiting for credentials to be fully processed...');
|
||||
secureLogger.info('⏳ Waiting for credentials to be fully processed...', { component: 'HomePage' });
|
||||
await new Promise(resolve => setTimeout(resolve, 5000)); // Increased wait time to 5 seconds
|
||||
|
||||
// Verify credentials are available before proceeding with retry mechanism
|
||||
@ -767,7 +815,7 @@ async function handleMainPairing(): Promise<void> {
|
||||
|
||||
while (!credentialsReady && attempts < maxAttempts) {
|
||||
attempts++;
|
||||
console.log(`🔍 Checking credentials availability (attempt ${attempts}/${maxAttempts})...`);
|
||||
secureLogger.debug('🔍 Checking credentials availability (attempt ${attempts}/${maxAttempts})...', { component: 'HomePage' });
|
||||
|
||||
try {
|
||||
// Vérifier que les credentials sont réellement disponibles
|
||||
@ -776,11 +824,11 @@ async function handleMainPairing(): Promise<void> {
|
||||
throw new Error('Credentials not properly available');
|
||||
}
|
||||
credentialsReady = true;
|
||||
console.log('✅ Credentials verified as available');
|
||||
secureLogger.info('✅ Credentials verified as available', { component: 'HomePage' });
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ Credentials not ready on attempt ${attempts}:`, error);
|
||||
secureLogger.warn('⚠️ Credentials not ready on attempt ${attempts}:', { component: 'HomePage', data: error });
|
||||
if (attempts < maxAttempts) {
|
||||
console.log(`⏳ Waiting ${delayMs}ms before next attempt...`);
|
||||
secureLogger.info('⏳ Waiting ${delayMs}ms before next attempt...', { component: 'HomePage' });
|
||||
await new Promise(resolve => setTimeout(resolve, delayMs));
|
||||
}
|
||||
}
|
||||
@ -788,17 +836,25 @@ async function handleMainPairing(): Promise<void> {
|
||||
|
||||
// Si les credentials ne sont toujours pas disponibles après tous les essais, arrêter le processus
|
||||
if (!credentialsReady) {
|
||||
console.error('❌ Credentials not available after all attempts - stopping process');
|
||||
secureLogger.error('❌ Credentials not available after all attempts - stopping process', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--error-color)">❌ Authentication failed - credentials not available</span>';
|
||||
mainStatus.innerHTML = `
|
||||
<div class="error-container">
|
||||
<div class="error-icon">❌</div>
|
||||
<div class="error-content">
|
||||
<div class="error-title">Authentication Failed</div>
|
||||
<div class="error-message">Authentication failed - credentials not available</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
throw new Error('Credentials not available after maximum retry attempts');
|
||||
}
|
||||
|
||||
console.log('✅ Credentials verified, proceeding with pairing...');
|
||||
secureLogger.info('✅ Credentials verified, proceeding with pairing...', { component: 'HomePage' });
|
||||
|
||||
// Now proceed with pairing process
|
||||
console.log('🚀 Starting pairing process...');
|
||||
secureLogger.info('🚀 Starting pairing process...', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>🚀 Starting secure pairing process...</span>';
|
||||
}
|
||||
@ -810,7 +866,7 @@ async function handleMainPairing(): Promise<void> {
|
||||
await prepareAndSendPairingTx();
|
||||
|
||||
// Après le succès du pairing, mettre à jour l'UI
|
||||
console.log('✅ Pairing process completed successfully');
|
||||
secureLogger.info('✅ Pairing process completed successfully', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ Pairing complété avec succès ! Les 4 mots sont affichés ci-dessus. Récupération des processus en cours...</span>';
|
||||
}
|
||||
@ -819,7 +875,7 @@ async function handleMainPairing(): Promise<void> {
|
||||
const service = await Services.getInstance();
|
||||
const isPaired = service.isPaired();
|
||||
if (isPaired) {
|
||||
console.log('✅ Device is now paired');
|
||||
secureLogger.info('✅ Device is now paired', { component: 'HomePage' });
|
||||
|
||||
// La récupération et déchiffrement des processus est déjà gérée dans prepareAndSendPairingTx()
|
||||
// Ici on peut juste confirmer que tout est OK
|
||||
@ -827,7 +883,7 @@ async function handleMainPairing(): Promise<void> {
|
||||
mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ Pairing complété ! Les 4 mots sont affichés ci-dessus. Les processus ont été récupérés et déchiffrés lorsqu\'ils sont accessibles.</span>';
|
||||
}
|
||||
} else {
|
||||
console.warn('⚠️ Device not detected as paired after pairing process');
|
||||
secureLogger.warn('⚠️ Device not detected as paired after pairing process', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--warning-color)">⚠️ Pairing effectué mais appareil non détecté comme appairé. Attente de synchronisation...</span>';
|
||||
}
|
||||
@ -836,7 +892,7 @@ async function handleMainPairing(): Promise<void> {
|
||||
} catch (error) {
|
||||
// If WebAuthn fails due to no user gesture, wait for real interaction
|
||||
if (error instanceof Error && error.message && error.message.includes('WebAuthn authentication was cancelled or timed out')) {
|
||||
console.log('🔐 WebAuthn requires user interaction, waiting...');
|
||||
secureLogger.info('🔐 WebAuthn requires user interaction, waiting...', { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--info-color)">⏳ Waiting for user to validate secure key access...</span>';
|
||||
}
|
||||
@ -844,9 +900,17 @@ async function handleMainPairing(): Promise<void> {
|
||||
// Set up listener for real user interaction
|
||||
setupUserInteractionListener();
|
||||
} else {
|
||||
console.error('Pairing failed:', error);
|
||||
secureLogger.error('Pairing failed:', error, { component: 'HomePage' });
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--error-color)">❌ Pairing failed: ' + (error as Error).message + '</span>';
|
||||
mainStatus.innerHTML = `
|
||||
<div class="error-container">
|
||||
<div class="error-icon">❌</div>
|
||||
<div class="error-content">
|
||||
<div class="error-title">Pairing Failed</div>
|
||||
<div class="error-message">${(error as Error).message}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
@ -948,7 +1012,7 @@ async function handleDeleteAccount(): Promise<void> {
|
||||
}, 2000);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Account deletion failed:', error);
|
||||
secureLogger.error('Account deletion failed:', error, { component: 'HomePage' });
|
||||
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--error-color)">❌ Failed to delete account</span>';
|
||||
|
||||
@ -1,12 +1,6 @@
|
||||
import { DeviceReaderService } from '../../services/device-reader.service';
|
||||
import { SecureCredentialsService } from '../../services/secure-credentials.service';
|
||||
import { SecurityModeService } from '../../services/security-mode.service';
|
||||
import { addSubscription } from '../../utils/subscription.utils';
|
||||
import { displayEmojis, generateCreateBtn, addressToEmoji, prepareAndSendPairingTx } from '../../utils/sp-address.utils';
|
||||
import { getCorrectDOM } from '../../utils/html.utils';
|
||||
import { IframePairingComponent } from '../../components/iframe-pairing/iframe-pairing';
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
import { checkPBKDF2Key, checkWalletWithRetries } from '../../utils/prerequisites.utils';
|
||||
import loginHtml from '../home/home.html?raw';
|
||||
|
||||
// Extend WindowEventMap to include custom events
|
||||
declare global {
|
||||
@ -21,35 +15,61 @@ let isInitializing = false;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
if (isInitializing) {
|
||||
console.log('⚠️ Pairing page already initializing, skipping...');
|
||||
secureLogger.warn('⚠️ Pairing page already initializing, skipping...', { component: 'PairingPage' });
|
||||
return;
|
||||
}
|
||||
|
||||
isInitializing = true;
|
||||
console.log('🔐 Pairing page loaded');
|
||||
secureLogger.info('🔐 Pairing page loaded', { component: 'PairingPage' });
|
||||
|
||||
const status = document.getElementById('status') as HTMLElement;
|
||||
const contentArea = document.getElementById('contentArea') as HTMLElement;
|
||||
|
||||
function updateStatus(message: string, type: 'loading' | 'success' | 'error') {
|
||||
if (status) {
|
||||
status.textContent = message;
|
||||
if (type === 'error') {
|
||||
status.innerHTML = `
|
||||
<div class="error-container">
|
||||
<div class="error-icon">❌</div>
|
||||
<div class="error-content">
|
||||
<div class="error-title">Error</div>
|
||||
<div class="error-message">${message}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
} else if (type === 'success') {
|
||||
status.innerHTML = `
|
||||
<div class="success-container">
|
||||
<div class="success-icon">✅</div>
|
||||
<div class="success-content">
|
||||
<div class="success-title">Success</div>
|
||||
<div class="success-message">${message}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
status.innerHTML = `
|
||||
<div class="loading-container">
|
||||
<div class="spinner"></div>
|
||||
<div class="loading-message">${message}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
status.className = `status ${type}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Vérifier les prérequis en base de données
|
||||
console.log('🔍 Verifying prerequisites...');
|
||||
secureLogger.debug('🔍 Verifying prerequisites...', { component: 'PairingPage' });
|
||||
updateStatus('🔍 Vérification des prérequis...', 'loading');
|
||||
|
||||
try {
|
||||
console.log('🔧 Getting device reader service...');
|
||||
secureLogger.info('🔧 Getting device reader service...', { component: 'PairingPage' });
|
||||
const deviceReader = DeviceReaderService.getInstance();
|
||||
|
||||
// Vérifier que le PBKDF2 key existe d'abord
|
||||
const pbkdf2KeyResult = await checkPBKDF2Key();
|
||||
if (!pbkdf2KeyResult) {
|
||||
console.log('⚠️ PBKDF2 key not found, redirecting to security-setup...');
|
||||
secureLogger.warn('⚠️ PBKDF2 key not found, redirecting to security-setup...', { component: 'PairingPage' });
|
||||
updateStatus('⚠️ Redirection vers la configuration de sécurité...', 'loading');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/security-setup/security-setup.html';
|
||||
@ -60,7 +80,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Vérifier que le wallet existe en base
|
||||
const wallet = await checkWalletWithRetries();
|
||||
if (!wallet) {
|
||||
console.log('⚠️ Wallet still not found after retries, redirecting to wallet-setup...');
|
||||
secureLogger.warn('⚠️ Wallet still not found after retries, redirecting to wallet-setup...', { component: 'PairingPage' });
|
||||
updateStatus('⚠️ Redirection vers la configuration du wallet...', 'loading');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/wallet-setup/wallet-setup.html';
|
||||
@ -77,7 +97,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// Vérifier que le birthday est configuré (> 0)
|
||||
if (!wallet.sp_wallet.birthday || wallet.sp_wallet.birthday === 0) {
|
||||
console.log('⚠️ Birthday not configured, redirecting to birthday-setup...');
|
||||
secureLogger.warn('⚠️ Birthday not configured, redirecting to birthday-setup...', { component: 'PairingPage' });
|
||||
updateStatus('⚠️ Redirection vers la configuration de la date anniversaire...', 'loading');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
|
||||
@ -85,7 +105,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✅ All prerequisites verified for pairing page');
|
||||
secureLogger.info('✅ All prerequisites verified for pairing page', { component: 'PairingPage' });
|
||||
|
||||
// Charger le contenu de pairing depuis home.html
|
||||
updateStatus('🔄 Initialisation du pairing...', 'loading');
|
||||
@ -93,7 +113,31 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Injecter le contenu de pairing dans la zone de contenu
|
||||
const pairingContainer = document.getElementById('pairingContainer');
|
||||
if (pairingContainer) {
|
||||
pairingContainer.innerHTML = loginHtml;
|
||||
// Créer un contenu HTML complet pour la page de pairing
|
||||
const pairingContent = `
|
||||
<div class="pairing-container">
|
||||
<!-- Main Pairing Interface -->
|
||||
<div id="main-pairing" class="card pairing-card">
|
||||
<div class="card-header">
|
||||
<h2>🔐 4NK Pairing</h2>
|
||||
<p class="card-description">Secure device pairing with WebAuthn authentication</p>
|
||||
</div>
|
||||
|
||||
<div class="pairing-request"></div>
|
||||
|
||||
<div class="status-container">
|
||||
<div class="status-indicator" id="main-status">
|
||||
<!-- Content will be set by JavaScript -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="account-actions">
|
||||
<button id="deleteAccountButton" class="danger-btn">🗑️ Delete Account</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
pairingContainer.innerHTML = pairingContent;
|
||||
}
|
||||
|
||||
// Importer et initialiser la logique de pairing depuis home.ts
|
||||
@ -107,7 +151,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
console.log('✅ Pairing page initialization completed');
|
||||
secureLogger.info('✅ Pairing page initialization completed', { component: 'PairingPage' });
|
||||
} catch (error) {
|
||||
console.error('❌ Error initializing pairing page:', error);
|
||||
updateStatus(`❌ Erreur: ${(error as Error).message}`, 'error');
|
||||
@ -115,17 +159,17 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// 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')) {
|
||||
console.log('⚠️ Security error detected, redirecting to security-setup...');
|
||||
secureLogger.error('⚠️ Security error detected, redirecting to security-setup...', { component: 'PairingPage' });
|
||||
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...');
|
||||
secureLogger.error('⚠️ Wallet error detected, redirecting to wallet-setup...', { component: 'PairingPage' });
|
||||
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...');
|
||||
secureLogger.error('⚠️ Birthday error detected, redirecting to birthday-setup...', { component: 'PairingPage' });
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
|
||||
}, 2000);
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Configuration de la Sécurité - LeCoffre</title>
|
||||
<title>Configuration de la Sécurité - 4NK</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
|
||||
@ -4,20 +4,21 @@
|
||||
*/
|
||||
|
||||
import { SecurityMode } from '../../services/security-mode.service';
|
||||
import { secureLogger } from '../../services/secure-logger';
|
||||
import { DATABASE_CONFIG, openDatabase } from '../../services/database-config';
|
||||
|
||||
let selectedMode: SecurityMode | null = null;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
console.log('🔐 Security setup page loaded');
|
||||
secureLogger.info('🔐 Security setup page loaded', { component: 'SecuritySetup' });
|
||||
|
||||
// Initialiser la base de données avec la configuration complète
|
||||
try {
|
||||
console.log(`🔍 Initializing database ${DATABASE_CONFIG.name} version ${DATABASE_CONFIG.version}...`);
|
||||
secureLogger.debug('🔍 Initializing database ${DATABASE_CONFIG.name} version ${DATABASE_CONFIG.version}...', { component: 'SecuritySetup' });
|
||||
await openDatabase();
|
||||
console.log('✅ Database initialized successfully');
|
||||
secureLogger.info('✅ Database initialized successfully', { component: 'SecuritySetup' });
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to initialize database:', error);
|
||||
secureLogger.error('Failed to initialize database', error as Error, { component: 'SecuritySetup' });
|
||||
alert('Erreur lors de l\'initialisation de la base de données. Veuillez réessayer.');
|
||||
return;
|
||||
}
|
||||
@ -49,14 +50,14 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Activer le bouton continuer
|
||||
continueBtn.disabled = false;
|
||||
|
||||
console.log('🔐 Security mode selected:', mode);
|
||||
secureLogger.info(`Security mode selected: ${mode}`, { component: 'SecuritySetup' });
|
||||
});
|
||||
});
|
||||
|
||||
// Gestion du bouton continuer
|
||||
continueBtn.addEventListener('click', async () => {
|
||||
if (!selectedMode) {
|
||||
console.error('❌ No security mode selected');
|
||||
secureLogger.error('❌ No security mode selected', { component: 'SecuritySetup' });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -68,7 +69,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
const securityModeService = SecurityModeService.getInstance();
|
||||
await securityModeService.setSecurityMode(selectedMode);
|
||||
|
||||
console.log('✅ Security mode saved successfully');
|
||||
secureLogger.info('✅ Security mode saved successfully', { component: 'SecuritySetup' });
|
||||
|
||||
console.log('🔐 Generating PBKDF2 key for security mode:', selectedMode);
|
||||
|
||||
@ -86,10 +87,10 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// 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
|
||||
const pbkdf2Key = await secureCredentialsService.generatePBKDF2Key(selectedMode);
|
||||
console.log('✅ PBKDF2 key generated and stored securely');
|
||||
secureLogger.info('✅ PBKDF2 key generated and stored securely', { component: 'SecuritySetup' });
|
||||
|
||||
// Rediriger directement vers la page de génération du wallet
|
||||
console.log('🔐 Security setup completed, redirecting to wallet-setup...');
|
||||
secureLogger.info('🔐 Security setup completed, redirecting to wallet-setup...', { component: 'SecuritySetup' });
|
||||
window.location.href = '/src/pages/wallet-setup/wallet-setup.html';
|
||||
|
||||
} catch (error) {
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Génération du Wallet - LeCoffre</title>
|
||||
<title>Génération du Wallet - 4NK</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
|
||||
@ -4,10 +4,11 @@
|
||||
*/
|
||||
|
||||
import { DATABASE_CONFIG } from '../../services/database-config';
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
import { checkPBKDF2Key } from '../../utils/prerequisites.utils';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
console.log('💰 Wallet setup page loaded');
|
||||
secureLogger.info('💰 Wallet setup page loaded', { component: 'WalletSetup' });
|
||||
|
||||
const status = document.getElementById('status') as HTMLDivElement;
|
||||
const progressBar = document.getElementById('progressBar') as HTMLDivElement;
|
||||
@ -55,11 +56,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// CRITICAL: wallet-setup ne doit PAS générer de credentials
|
||||
// Les credentials et clé PBKDF2 doivent être créés dans security-setup
|
||||
// On vérifie que la clé PBKDF2 existe dans le store pbkdf2keys
|
||||
console.log('🔐 Checking for existing PBKDF2 key in pbkdf2keys store...');
|
||||
secureLogger.debug('🔐 Checking for existing PBKDF2 key in pbkdf2keys store...', { component: 'WalletSetup' });
|
||||
|
||||
const pbkdf2KeyResult = await checkPBKDF2Key();
|
||||
if (!pbkdf2KeyResult) {
|
||||
console.log('⚠️ No PBKDF2 key found in pbkdf2keys store, redirecting to security-setup...');
|
||||
secureLogger.warn('⚠️ No PBKDF2 key found in pbkdf2keys store, redirecting to security-setup...', { component: 'WalletSetup' });
|
||||
updateStatus('⚠️ Redirection vers la configuration de sécurité...', 'loading');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/src/pages/security-setup/security-setup.html';
|
||||
@ -79,7 +80,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
const existingDevice = await deviceReader.getDeviceFromDatabase();
|
||||
|
||||
if (existingDevice && existingDevice.sp_wallet) {
|
||||
console.log('✅ Wallet already exists, skipping creation');
|
||||
secureLogger.warn('✅ Wallet already exists, skipping creation', { component: 'WalletSetup' });
|
||||
updateStatus('✅ Wallet existant trouvé', 'success');
|
||||
updateProgress(100);
|
||||
|
||||
@ -97,7 +98,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('🔧 No existing wallet found, creating new one...');
|
||||
secureLogger.info('🔧 No existing wallet found, creating new one...', { component: 'WalletSetup' });
|
||||
updateStatus('🔧 Création du nouveau wallet...', 'loading');
|
||||
updateProgress(30);
|
||||
|
||||
@ -112,11 +113,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
const usedMB = memory.usedJSHeapSize / 1024 / 1024;
|
||||
const limitMB = memory.jsHeapSizeLimit / 1024 / 1024;
|
||||
|
||||
console.log(`📊 Current memory usage: ${usedPercent.toFixed(1)}% (${usedMB.toFixed(1)}MB / ${limitMB.toFixed(1)}MB)`);
|
||||
secureLogger.info('📊 Current memory usage: ${usedPercent.toFixed(1)}% (${usedMB.toFixed(1)}MB / ${limitMB.toFixed(1)}MB)', { component: 'WalletSetup' });
|
||||
|
||||
// Si la mémoire est très élevée (>75%), tenter un nettoyage agressif
|
||||
if (usedPercent > 75) {
|
||||
console.warn('⚠️ High memory usage detected, attempting aggressive cleanup...');
|
||||
secureLogger.warn('⚠️ High memory usage detected, attempting aggressive cleanup...', { component: 'WalletSetup' });
|
||||
updateStatus('🧹 Nettoyage de la mémoire en cours...', 'loading');
|
||||
|
||||
// Nettoyage agressif
|
||||
@ -132,7 +133,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
try {
|
||||
const cacheNames = await caches.keys();
|
||||
await Promise.all(cacheNames.map(name => caches.delete(name)));
|
||||
console.log('🧹 Caches cleared');
|
||||
secureLogger.info('🧹 Caches cleared', { component: 'WalletSetup' });
|
||||
} catch (e) {
|
||||
console.warn('⚠️ Cache cleanup error:', e);
|
||||
}
|
||||
@ -141,11 +142,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Vérifier la mémoire après nettoyage
|
||||
const memoryAfter = (performance as any).memory;
|
||||
const usedPercentAfter = (memoryAfter.usedJSHeapSize / memoryAfter.jsHeapSizeLimit) * 100;
|
||||
console.log(`📊 Memory after cleanup: ${usedPercentAfter.toFixed(1)}% (${(memoryAfter.usedJSHeapSize / 1024 / 1024).toFixed(1)}MB)`);
|
||||
secureLogger.info('📊 Memory after cleanup: ${usedPercentAfter.toFixed(1)}% (${(memoryAfter.usedJSHeapSize / 1024 / 1024).toFixed(1)}MB)', { component: 'WalletSetup' });
|
||||
|
||||
// Si toujours >90% après nettoyage, avertir l'utilisateur
|
||||
if (usedPercentAfter > 90) {
|
||||
console.error('❌ Memory still too high after cleanup');
|
||||
secureLogger.error('❌ Memory still too high after cleanup', { component: 'WalletSetup' });
|
||||
updateStatus('⚠️ Mémoire trop élevée. Fermez les autres onglets et actualisez la page.', 'error');
|
||||
alert('⚠️ Mémoire insuffisante détectée.\n\nVeuillez :\n- Fermer les autres onglets du navigateur\n- Actualiser cette page\n\nSi le problème persiste, redémarrez le navigateur.');
|
||||
return;
|
||||
@ -156,7 +157,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
let services: any; // Déclarer services au niveau supérieur
|
||||
|
||||
try {
|
||||
console.log('🔄 Importing services...');
|
||||
secureLogger.info('🔄 Importing services...', { component: 'WalletSetup' });
|
||||
const serviceModule = await import('../../services/service');
|
||||
console.log('✅ Service module imported:', Object.keys(serviceModule));
|
||||
|
||||
@ -166,7 +167,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
if (!Services) {
|
||||
throw new Error('Services class not found in default export');
|
||||
}
|
||||
console.log('🔄 Waiting for services to be ready...');
|
||||
secureLogger.info('🔄 Waiting for services to be ready...', { component: 'WalletSetup' });
|
||||
|
||||
// Attendre que les services soient initialisés avec plus de patience
|
||||
let attempts = 0;
|
||||
@ -175,9 +176,9 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
while (attempts < maxAttempts) {
|
||||
try {
|
||||
console.log(`🔄 Attempting to get services (attempt ${attempts + 1}/${maxAttempts})...`);
|
||||
secureLogger.info('🔄 Attempting to get services (attempt ${attempts + 1}/${maxAttempts})...', { component: 'WalletSetup' });
|
||||
services = await Services.getInstance();
|
||||
console.log('✅ Services initialized successfully');
|
||||
secureLogger.info('✅ Services initialized successfully', { component: 'WalletSetup' });
|
||||
break;
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
@ -185,17 +186,17 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// Si c'est une erreur de mémoire, arrêter immédiatement
|
||||
if (errorMessage.includes('Out of memory') || errorMessage.includes('insufficient memory')) {
|
||||
console.error('🚫 Memory error detected - stopping retry attempts');
|
||||
secureLogger.error('🚫 Memory error detected - stopping retry attempts', { component: 'WalletSetup' });
|
||||
updateStatus('❌ Erreur: Mémoire insuffisante. Veuillez actualiser la page.', 'error');
|
||||
throw new Error('WebAssembly initialization failed due to insufficient memory. Please refresh the page.');
|
||||
}
|
||||
|
||||
// Diagnostic plus détaillé
|
||||
if (attempts === 5) {
|
||||
console.log('🔍 Diagnostic: Checking memory usage...');
|
||||
secureLogger.debug('🔍 Diagnostic: Checking memory usage...', { component: 'WalletSetup' });
|
||||
if ((performance as any).memory) {
|
||||
const memory = (performance as any).memory;
|
||||
console.log(`📊 Memory usage: ${Math.round(memory.usedJSHeapSize / 1024 / 1024)}MB / ${Math.round(memory.totalJSHeapSize / 1024 / 1024)}MB`);
|
||||
secureLogger.info('📊 Memory usage: ${Math.round(memory.usedJSHeapSize / 1024 / 1024)}MB / ${Math.round(memory.totalJSHeapSize / 1024 / 1024)}MB', { component: 'WalletSetup' });
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,7 +217,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
updateProgress(60);
|
||||
|
||||
try {
|
||||
console.log('🔐 Sauvegarde du wallet avec état birthday_waiting...');
|
||||
secureLogger.info('🔐 Sauvegarde du wallet avec état birthday_waiting...', { component: 'WalletSetup' });
|
||||
|
||||
// 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é
|
||||
@ -247,14 +248,14 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
updateStatus('❌ Erreur: Impossible de récupérer la clé de chiffrement.', 'error');
|
||||
throw new Error('CRITICAL: Failed to retrieve PBKDF2 key');
|
||||
}
|
||||
console.log('🔐 PBKDF2 key retrieved for wallet encryption');
|
||||
secureLogger.info('🔐 PBKDF2 key retrieved for wallet encryption', { component: 'WalletSetup' });
|
||||
|
||||
// Chiffrer le wallet avec la clé PBKDF2
|
||||
const encryptedWallet = await encryptionService.encrypt(
|
||||
JSON.stringify(walletData),
|
||||
pbkdf2Key
|
||||
);
|
||||
console.log('🔐 Wallet encrypted with PBKDF2 key');
|
||||
secureLogger.info('🔐 Wallet encrypted with PBKDF2 key', { component: 'WalletSetup' });
|
||||
console.log('🔐 Encrypted wallet data:', encryptedWallet);
|
||||
|
||||
// Ouvrir la base de données 4nk existante sans la modifier
|
||||
@ -266,7 +267,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
reject(request.error);
|
||||
};
|
||||
request.onsuccess = () => {
|
||||
console.log('✅ IndexedDB opened successfully');
|
||||
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));
|
||||
@ -274,21 +275,21 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
};
|
||||
request.onupgradeneeded = () => {
|
||||
const db = request.result;
|
||||
console.log('🔄 IndexedDB upgrade needed, checking wallet store...');
|
||||
secureLogger.debug('🔄 IndexedDB upgrade needed, checking wallet store...', { component: 'WalletSetup' });
|
||||
|
||||
// Créer le store wallet seulement s'il n'existe pas
|
||||
if (!db.objectStoreNames.contains(DATABASE_CONFIG.stores.wallet.name)) {
|
||||
const store = db.createObjectStore(DATABASE_CONFIG.stores.wallet.name, { keyPath: DATABASE_CONFIG.stores.wallet.keyPath as string });
|
||||
console.log(`✅ Wallet store created with keyPath: ${DATABASE_CONFIG.stores.wallet.keyPath}`);
|
||||
secureLogger.info('✅ Wallet store created with keyPath: ${DATABASE_CONFIG.stores.wallet.keyPath}', { component: 'WalletSetup' });
|
||||
} else {
|
||||
console.log('✅ Wallet store already exists');
|
||||
secureLogger.info('✅ Wallet store already exists', { component: 'WalletSetup' });
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Étape 1: Sauvegarder le wallet dans le format attendu par getDeviceFromDatabase
|
||||
// Utiliser le SDK directement pour éviter le service worker qui bloque
|
||||
console.log('🔧 Creating device using SDK...');
|
||||
secureLogger.info('🔧 Creating device using SDK...', { component: 'WalletSetup' });
|
||||
|
||||
// Créer le device directement avec le SDK sans passer par saveDeviceInDatabase
|
||||
if (!services.sdkClient) {
|
||||
@ -296,12 +297,12 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
}
|
||||
|
||||
// We set birthday later when we have the chain tip from relay
|
||||
console.log('🔧 Creating new device with birthday 0...');
|
||||
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);
|
||||
|
||||
// Force wallet generation to ensure keys are created
|
||||
console.log('🔧 Forcing wallet generation...');
|
||||
secureLogger.info('🔧 Forcing wallet generation...', { component: 'WalletSetup' });
|
||||
try {
|
||||
const wallet = await services.sdkClient.dump_wallet();
|
||||
console.log('✅ Wallet generated:', JSON.stringify(wallet));
|
||||
@ -317,14 +318,14 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
spClientKeys: device.sp_client ? Object.keys(device.sp_client) : 'none'
|
||||
});
|
||||
|
||||
console.log(`🔍 Opening transaction for ${DATABASE_CONFIG.stores.wallet.name} store...`);
|
||||
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
|
||||
console.log('🔐 Encrypting device data before storage...');
|
||||
secureLogger.info('🔐 Encrypting device data before storage...', { component: 'WalletSetup' });
|
||||
const deviceString = JSON.stringify(device);
|
||||
const encryptedDevice = await encryptionService.encrypt(deviceString, pbkdf2Key);
|
||||
console.log('🔐 Device encrypted successfully');
|
||||
secureLogger.info('🔐 Device encrypted successfully', { component: 'WalletSetup' });
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const transaction = db.transaction([DATABASE_CONFIG.stores.wallet.name], 'readwrite');
|
||||
@ -338,7 +339,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
encrypted_wallet: encryptedWallet // Wallet chiffré
|
||||
};
|
||||
|
||||
console.log('🔍 Attempting to save encrypted wallet object');
|
||||
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,
|
||||
@ -348,7 +349,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Le store utilise des clés in-line (keyPath: 'pre_id'), ne pas fournir de clé explicite
|
||||
const request = store.put(walletObject);
|
||||
request.onsuccess = () => {
|
||||
console.log('✅ Wallet saved in IndexedDB with correct format');
|
||||
secureLogger.info('✅ Wallet saved in IndexedDB with correct format', { component: 'WalletSetup' });
|
||||
console.log('🔍 Saved wallet object:', walletObject);
|
||||
resolve();
|
||||
};
|
||||
@ -358,7 +359,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
};
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
console.log('✅ Transaction completed successfully');
|
||||
secureLogger.info('✅ Transaction completed successfully', { component: 'WalletSetup' });
|
||||
console.log('🔍 Transaction completed for store:', store.name);
|
||||
};
|
||||
transaction.onerror = () => {
|
||||
@ -391,19 +392,19 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// Vérifier qu'il n'y a AUCUN wallet en clair
|
||||
if (verificationRequest.result.device) {
|
||||
console.error('❌ CRITICAL: Device in clear found in database! This should be encrypted.');
|
||||
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;
|
||||
}
|
||||
|
||||
// Vérifier que les données chiffrées sont présentes
|
||||
if (!verificationRequest.result.encrypted_device || !verificationRequest.result.encrypted_wallet) {
|
||||
console.error('❌ Wallet verification failed: encrypted data missing');
|
||||
secureLogger.error('❌ Wallet verification failed: encrypted data missing', { component: 'WalletSetup' });
|
||||
reject(new Error('Encrypted data missing'));
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✅ Wallet stored correctly: only encrypted data present');
|
||||
secureLogger.info('✅ Wallet stored correctly: only encrypted data present', { component: 'WalletSetup' });
|
||||
resolve();
|
||||
} else {
|
||||
console.error('❌ Wallet verification: Not found in IndexedDB with key "1"');
|
||||
@ -421,7 +422,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
console.log('🔐 Security mode is implicitly stored via PBKDF2 key:', currentMode);
|
||||
|
||||
// Vérification finale : s'assurer que le wallet est bien dans IndexedDB
|
||||
console.log('🔍 Final verification: checking wallet in IndexedDB...');
|
||||
secureLogger.debug('🔍 Final verification: checking wallet in IndexedDB...', { component: 'WalletSetup' });
|
||||
const finalVerification = await new Promise<any>((resolve, reject) => {
|
||||
const transaction = db.transaction([DATABASE_CONFIG.stores.wallet.name], 'readonly');
|
||||
const store = transaction.objectStore(DATABASE_CONFIG.stores.wallet.name);
|
||||
@ -433,11 +434,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
if (finalVerification) {
|
||||
// Vérifier qu'il n'y a PAS de device en clair
|
||||
if (finalVerification.device) {
|
||||
console.error('❌ CRITICAL: Final verification - Device in clear found!');
|
||||
secureLogger.error('❌ CRITICAL: Final verification - Device in clear found!', { component: 'WalletSetup' });
|
||||
throw new Error('Security violation: wallet stored in clear');
|
||||
}
|
||||
|
||||
console.log('✅ Wallet saved exclusively in IndexedDB and verified');
|
||||
secureLogger.info('✅ Wallet saved exclusively in IndexedDB and verified', { component: 'WalletSetup' });
|
||||
console.log('🔍 Wallet contains only encrypted data:', {
|
||||
hasEncryptedDevice: !!finalVerification.encrypted_device,
|
||||
hasEncryptedWallet: !!finalVerification.encrypted_wallet,
|
||||
@ -445,13 +446,13 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
});
|
||||
|
||||
// TEST: Déchiffrer le wallet pour valider que ça fonctionne
|
||||
console.log('🔐 TEST: Attempting to decrypt wallet to validate encryption...');
|
||||
secureLogger.info('🔐 TEST: Attempting to decrypt wallet to validate encryption...', { component: 'WalletSetup' });
|
||||
try {
|
||||
const pbkdf2KeyTest = pbkdf2KeyResult.key;
|
||||
if (!pbkdf2KeyTest) {
|
||||
console.error('❌ TEST: Failed to retrieve PBKDF2 key for decryption test');
|
||||
secureLogger.error('❌ TEST: Failed to retrieve PBKDF2 key for decryption test', { component: 'WalletSetup' });
|
||||
} else {
|
||||
console.log('✅ TEST: PBKDF2 key retrieved for decryption test');
|
||||
secureLogger.info('✅ TEST: PBKDF2 key retrieved for decryption test', { component: 'WalletSetup' });
|
||||
|
||||
// Déchiffrer le wallet chiffré
|
||||
const decryptedWallet = await encryptionService.decrypt(
|
||||
@ -478,14 +479,14 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
network: parsedDevice.network
|
||||
});
|
||||
|
||||
console.log('✅ TEST: Full decryption test passed - wallet and device decrypt correctly');
|
||||
secureLogger.info('✅ TEST: Full decryption test passed - wallet and device decrypt correctly', { component: 'WalletSetup' });
|
||||
}
|
||||
} catch (decryptError) {
|
||||
console.error('❌ TEST: Decryption test failed:', decryptError);
|
||||
console.error('❌ This indicates an issue with encryption/decryption logic');
|
||||
secureLogger.error('❌ This indicates an issue with encryption/decryption logic', { component: 'WalletSetup' });
|
||||
}
|
||||
} else {
|
||||
console.error('❌ Final wallet verification failed - wallet not found in IndexedDB');
|
||||
secureLogger.error('❌ Final wallet verification failed - wallet not found in IndexedDB', { component: 'WalletSetup' });
|
||||
throw new Error('Wallet verification failed - wallet not found');
|
||||
}
|
||||
|
||||
@ -499,16 +500,16 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
updateStatus('✅ Wallet sauvegardé avec succès! Redirection automatique dans 3 secondes...', 'success');
|
||||
updateProgress(100);
|
||||
|
||||
console.log('🎉 Wallet setup completed successfully - wallet saved with birthday_waiting state');
|
||||
console.log('🔗 Ready to proceed to network connection and birthday setup');
|
||||
secureLogger.info('🎉 Wallet setup completed successfully - wallet saved with birthday_waiting state', { component: 'WalletSetup' });
|
||||
secureLogger.info('🔗 Ready to proceed to network connection and birthday setup', { component: 'WalletSetup' });
|
||||
|
||||
// Activer le bouton continuer
|
||||
continueBtn.disabled = false;
|
||||
console.log('✅ Continue button enabled');
|
||||
secureLogger.info('✅ Continue button enabled', { component: 'WalletSetup' });
|
||||
|
||||
// Redirection automatique après 3 secondes si l'utilisateur ne clique pas
|
||||
setTimeout(() => {
|
||||
console.log('🔄 Auto-redirecting to birthday setup after timeout...');
|
||||
secureLogger.info('🔄 Auto-redirecting to birthday setup after timeout...', { component: 'WalletSetup' });
|
||||
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
|
||||
}, 3000);
|
||||
|
||||
@ -519,8 +520,8 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// Gestion du bouton continuer
|
||||
continueBtn.addEventListener('click', async () => {
|
||||
console.log('🔗 Redirecting to birthday setup...');
|
||||
console.log('💰 Wallet setup completed, redirecting to birthday configuration...');
|
||||
secureLogger.info('🔗 Redirecting to birthday setup...', { component: 'WalletSetup' });
|
||||
secureLogger.info('💰 Wallet setup completed, redirecting to birthday configuration...', { component: 'WalletSetup' });
|
||||
// Rediriger directement vers la page de configuration de la date anniversaire
|
||||
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
|
||||
});
|
||||
|
||||
245
src/router.ts
245
src/router.ts
@ -1,5 +1,6 @@
|
||||
// CSS is loaded via HTML link tag
|
||||
import Database from './services/database.service';
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
import Services from './services/service';
|
||||
import TokenService from './services/token';
|
||||
import { cleanSubscriptions } from './utils/subscription.utils';
|
||||
@ -36,7 +37,7 @@ export let currentRoute = '';
|
||||
* - Sinon → security-setup
|
||||
*/
|
||||
export async function checkStorageStateAndNavigate(): Promise<void> {
|
||||
console.log('🔍 Checking storage state to determine next step...');
|
||||
secureLogger.debug('🔍 Checking storage state to determine next step...', { component: 'Router' });
|
||||
|
||||
try {
|
||||
// Utiliser DeviceReaderService pour éviter d'initialiser WebAssembly
|
||||
@ -48,7 +49,7 @@ export async function checkStorageStateAndNavigate(): Promise<void> {
|
||||
|
||||
if (!pbkdf2KeyResult) {
|
||||
// Aucune clé PBKDF2 trouvée, commencer par la configuration de sécurité
|
||||
console.log('🔐 No PBKDF2 key found, navigating to security-setup');
|
||||
secureLogger.info('🔐 No PBKDF2 key found, navigating to security-setup', { component: 'Router' });
|
||||
await navigate('security-setup');
|
||||
return;
|
||||
}
|
||||
@ -56,34 +57,34 @@ export async function checkStorageStateAndNavigate(): Promise<void> {
|
||||
// Vérifier si le wallet existe (même avec birthday = 0)
|
||||
const device = await deviceReader.getDeviceFromDatabase();
|
||||
if (!device?.sp_wallet) {
|
||||
console.log('💰 Wallet does not exist, navigating to wallet-setup');
|
||||
secureLogger.info('💰 Wallet does not exist, navigating to wallet-setup', { component: 'Router' });
|
||||
await navigate('wallet-setup');
|
||||
return;
|
||||
}
|
||||
|
||||
// Vérifier si la date anniversaire est configurée (wallet avec birthday > 0)
|
||||
if (device.sp_wallet.birthday && device.sp_wallet.birthday > 0) {
|
||||
console.log('🎂 Birthday is configured, navigating to pairing');
|
||||
secureLogger.info('🎂 Birthday is configured, navigating to pairing', { component: 'Router' });
|
||||
// Rediriger vers la page de pairing standalone
|
||||
await navigate('pairing');
|
||||
return;
|
||||
}
|
||||
|
||||
// Wallet existe mais birthday pas configuré
|
||||
console.log('💰 Wallet exists but birthday not set, navigating to birthday-setup');
|
||||
secureLogger.info('💰 Wallet exists but birthday not set, navigating to birthday-setup', { component: 'Router' });
|
||||
await navigate('birthday-setup');
|
||||
return;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error checking storage state:', error);
|
||||
secureLogger.error('❌ Error checking storage state:', error, { component: 'Router' });
|
||||
// En cas d'erreur, commencer par la configuration de sécurité
|
||||
console.log('🔐 Error occurred, defaulting to security-setup');
|
||||
secureLogger.error('🔐 Error occurred, defaulting to security-setup', { component: 'Router' });
|
||||
await navigate('security-setup');
|
||||
}
|
||||
}
|
||||
|
||||
export async function navigate(path: string) {
|
||||
console.log('🧭 Navigate called with path:', path);
|
||||
secureLogger.info('🧭 Navigate called with path:', { component: 'Router', data: path });
|
||||
cleanSubscriptions();
|
||||
cleanPage();
|
||||
path = path.replace(/^\//, '');
|
||||
@ -93,39 +94,39 @@ export async function navigate(path: string) {
|
||||
path = 'home';
|
||||
}
|
||||
}
|
||||
console.log('🧭 Final path after processing:', path);
|
||||
secureLogger.info('🧭 Final path after processing:', { component: 'Router', data: path });
|
||||
|
||||
await handleLocation(path);
|
||||
console.log('🧭 handleLocation completed for path:', path);
|
||||
secureLogger.info('🧭 handleLocation completed for path:', { component: 'Router', data: path });
|
||||
}
|
||||
|
||||
async function handleLocation(path: string) {
|
||||
console.log('📍 handleLocation called with path:', path);
|
||||
secureLogger.info('📍 handleLocation called with path:', { component: 'Router', data: path });
|
||||
const parsedPath = path.split('/');
|
||||
if (path.includes('/')) {
|
||||
path = parsedPath[0];
|
||||
}
|
||||
currentRoute = path;
|
||||
const routeHtml = routes[path] || routes['home'];
|
||||
console.log('📍 Current route set to:', currentRoute);
|
||||
console.log('📍 Route HTML:', routeHtml);
|
||||
secureLogger.info('📍 Current route set to:', { component: 'Router', data: currentRoute });
|
||||
secureLogger.info('📍 Route HTML:', { component: 'Router', data: routeHtml });
|
||||
|
||||
// Pour les pages de setup, rediriger directement vers la page HTML
|
||||
if (path === 'security-setup' || path === 'wallet-setup' || path === 'birthday-setup' || path === 'block-sync' || path === 'pairing') {
|
||||
console.log('📍 Processing setup route:', path);
|
||||
secureLogger.info('📍 Processing setup route:', { component: 'Router', data: path });
|
||||
window.location.href = routeHtml;
|
||||
return;
|
||||
}
|
||||
|
||||
const content = document.getElementById('containerId');
|
||||
console.log('📍 Container element found:', !!content);
|
||||
secureLogger.info('📍 Container element found:', { component: 'Router', data: !!content });
|
||||
if (content) {
|
||||
if (path === 'home') {
|
||||
console.log('🏠 Processing home route...');
|
||||
secureLogger.info('🏠 Processing home route...', { component: 'Router' });
|
||||
// Use LoginComponent
|
||||
const loginComponent = LoginComponent;
|
||||
const container = document.querySelector('#containerId');
|
||||
console.log('🏠 Container for home:', !!container);
|
||||
secureLogger.info('🏠 Container for home:', { component: 'Router', data: !!container });
|
||||
const accountComponent = document.createElement('login-4nk-component');
|
||||
accountComponent.setAttribute(
|
||||
'style',
|
||||
@ -133,20 +134,20 @@ async function handleLocation(path: string) {
|
||||
);
|
||||
if (container) {
|
||||
container.appendChild(accountComponent);
|
||||
console.log('🏠 Component appended to container');
|
||||
secureLogger.info('🏠 Component appended to container', { component: 'Router' });
|
||||
}
|
||||
|
||||
// Initialize the home page after component is added to DOM
|
||||
console.log('🏠 Initializing home page...');
|
||||
secureLogger.info('🏠 Initializing home page...', { component: 'Router' });
|
||||
try {
|
||||
const { initHomePage } = await import('./pages/home/home');
|
||||
await initHomePage();
|
||||
console.log('✅ Home page initialized successfully');
|
||||
secureLogger.info('✅ Home page initialized successfully', { component: 'Router' });
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to initialize home page:', error);
|
||||
secureLogger.error('❌ Failed to initialize home page:', error, { component: 'Router' });
|
||||
}
|
||||
} else {
|
||||
console.log('📍 Processing other route:', path);
|
||||
secureLogger.info('📍 Processing other route:', { component: 'Router', data: path });
|
||||
const html = await fetch(routeHtml).then(data => data.text());
|
||||
content.innerHTML = html;
|
||||
}
|
||||
@ -160,13 +161,13 @@ async function handleLocation(path: string) {
|
||||
switch (path) {
|
||||
case 'process':
|
||||
// Process functionality removed - redirect to account
|
||||
console.warn('Process functionality has been removed, redirecting to account');
|
||||
secureLogger.warn('Process functionality has been removed, redirecting to account', { component: 'Router' });
|
||||
await navigate('account');
|
||||
break;
|
||||
|
||||
case 'process-element':
|
||||
// Process element functionality removed
|
||||
console.warn('Process element functionality has been removed');
|
||||
secureLogger.warn('Process element functionality has been removed', { component: 'Router' });
|
||||
break;
|
||||
|
||||
case 'account':
|
||||
@ -187,7 +188,7 @@ async function handleLocation(path: string) {
|
||||
|
||||
case 'signature':
|
||||
// Signature functionality removed
|
||||
console.warn('Signature functionality has been removed');
|
||||
secureLogger.warn('Signature functionality has been removed', { component: 'Router' });
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -204,35 +205,35 @@ window.onpopstate = async () => {
|
||||
|
||||
export async function init(): Promise<void> {
|
||||
try {
|
||||
console.log('🚀 Starting application initialization...');
|
||||
secureLogger.info('🚀 Starting application initialization...', { component: 'Router' });
|
||||
|
||||
// Initialiser uniquement la base de données (sans WebAssembly)
|
||||
console.log('🔧 Initializing database...');
|
||||
secureLogger.info('🔧 Initializing database...', { component: 'Router' });
|
||||
const db = await Database.getInstance();
|
||||
|
||||
// Register service worker
|
||||
console.log('📱 Registering service worker...');
|
||||
secureLogger.info('📱 Registering service worker...', { component: 'Router' });
|
||||
await db.registerServiceWorker('/src/service-workers/database.worker.js');
|
||||
|
||||
// Vérifier l'état du storage et naviguer vers la page appropriée
|
||||
// Cette fonction est maintenant légère et ne nécessite pas WebAssembly
|
||||
console.log('🔍 Checking storage state and navigating to appropriate page...');
|
||||
secureLogger.debug('🔍 Checking storage state and navigating to appropriate page...', { component: 'Router' });
|
||||
await checkStorageStateAndNavigate();
|
||||
|
||||
console.log('✅ Application initialization completed successfully');
|
||||
secureLogger.info('✅ Application initialization completed successfully', { component: 'Router' });
|
||||
} catch (error) {
|
||||
console.error('❌ Application initialization failed:', error);
|
||||
secureLogger.error('❌ Application initialization failed:', error, { component: 'Router' });
|
||||
|
||||
// Handle WebAssembly memory errors specifically
|
||||
if (error instanceof RangeError && error.message.includes('WebAssembly.instantiate')) {
|
||||
console.error('🚨 WebAssembly memory error detected');
|
||||
console.log('💡 Try refreshing the page or closing other tabs to free memory');
|
||||
secureLogger.error('🚨 WebAssembly memory error detected', { component: 'Router' });
|
||||
secureLogger.info('💡 Try refreshing the page or closing other tabs to free memory', { component: 'Router' });
|
||||
|
||||
// Show user-friendly error message
|
||||
alert('⚠️ Insufficient memory for WebAssembly. Please refresh the page or close other tabs.');
|
||||
}
|
||||
|
||||
console.log('🔄 Falling back to security-setup...');
|
||||
secureLogger.info('🔄 Falling back to security-setup...', { component: 'Router' });
|
||||
await navigate('security-setup');
|
||||
}
|
||||
}
|
||||
@ -254,7 +255,7 @@ export async function registerAllListeners() {
|
||||
|
||||
const successResponse = (data: any, origin: string, messageId?: string) => {
|
||||
// Use successResponse function
|
||||
console.log('Success response:', data);
|
||||
secureLogger.info('Success response:', { component: 'Router', data: data });
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: MessageType.SUCCESS,
|
||||
@ -290,7 +291,7 @@ export async function registerAllListeners() {
|
||||
|
||||
if (!result) {
|
||||
const errorMsg = 'Failed to pair device: User refused to link';
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
|
||||
@ -305,7 +306,7 @@ export async function registerAllListeners() {
|
||||
window.parent.postMessage(acceptedMsg, event.origin);
|
||||
} catch (error) {
|
||||
const errorMsg = `Failed to generate tokens: ${error}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -315,11 +316,11 @@ export async function registerAllListeners() {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('📨 [Router] Received CREATE_PAIRING request');
|
||||
secureLogger.info('📨 [Router] Received CREATE_PAIRING request', { component: 'Router' });
|
||||
|
||||
if (services.isPaired()) {
|
||||
const errorMsg = '⚠️ Device already paired — ignoring CREATE_PAIRING request';
|
||||
console.warn(errorMsg);
|
||||
secureLogger.warn(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
return;
|
||||
}
|
||||
@ -327,7 +328,7 @@ export async function registerAllListeners() {
|
||||
try {
|
||||
const { accessToken } = event.data;
|
||||
|
||||
console.log('🔐 Checking access token validity...');
|
||||
secureLogger.debug('🔐 Checking access token validity...', { component: 'Router' });
|
||||
const validToken =
|
||||
accessToken && (await tokenService.validateToken(accessToken, event.origin));
|
||||
|
||||
@ -335,54 +336,54 @@ export async function registerAllListeners() {
|
||||
throw new Error('❌ Invalid or expired session token');
|
||||
}
|
||||
|
||||
console.log('✅ Token validated successfully');
|
||||
console.log('🚀 Starting pairing process');
|
||||
secureLogger.info('✅ Token validated successfully', { component: 'Router' });
|
||||
secureLogger.info('🚀 Starting pairing process', { component: 'Router' });
|
||||
|
||||
const myAddress = await services.getDeviceAddress();
|
||||
console.log('📍 Device address:', myAddress);
|
||||
secureLogger.info('📍 Device address:', { component: 'Router', data: myAddress });
|
||||
|
||||
console.log('🧱 Creating pairing process...');
|
||||
secureLogger.info('🧱 Creating pairing process...', { component: 'Router' });
|
||||
const createPairingProcessReturn = await services.createPairingProcess('', [myAddress]);
|
||||
console.log('🧾 Pairing process created:', createPairingProcessReturn);
|
||||
secureLogger.info('🧾 Pairing process created:', { component: 'Router', data: createPairingProcessReturn });
|
||||
|
||||
const pairingId = createPairingProcessReturn.updated_process?.process_id;
|
||||
const stateId = createPairingProcessReturn.updated_process?.current_process?.states[0]
|
||||
?.state_id as string;
|
||||
|
||||
console.log('🔗 Pairing ID:', pairingId);
|
||||
console.log('🧩 State ID:', stateId);
|
||||
secureLogger.info('🔗 Pairing ID:', { component: 'Router', data: pairingId });
|
||||
secureLogger.info('🧩 State ID:', { component: 'Router', data: stateId });
|
||||
|
||||
console.log('🔒 Registering device as paired...');
|
||||
secureLogger.info('🔒 Registering device as paired...', { component: 'Router' });
|
||||
services.pairDevice(pairingId, [myAddress]);
|
||||
|
||||
console.log('🧠 Handling API return for createPairingProcess...');
|
||||
secureLogger.info('🧠 Handling API return for createPairingProcess...', { component: 'Router' });
|
||||
await services.handleApiReturn(createPairingProcessReturn);
|
||||
|
||||
console.log('🔍 DEBUG: About to create PRD update...');
|
||||
console.log('🧰 Creating PRD update...');
|
||||
secureLogger.debug('🔍 DEBUG: About to create PRD update...', { component: 'Router' });
|
||||
secureLogger.info('🧰 Creating PRD update...', { component: 'Router' });
|
||||
const createPrdUpdateReturn = await services.createPrdUpdate(pairingId, stateId);
|
||||
console.log('🧾 PRD update result:', createPrdUpdateReturn);
|
||||
secureLogger.info('🧾 PRD update result:', { component: 'Router', data: createPrdUpdateReturn });
|
||||
await services.handleApiReturn(createPrdUpdateReturn);
|
||||
console.log('✅ DEBUG: PRD update completed successfully!');
|
||||
secureLogger.debug('✅ DEBUG: PRD update completed successfully!', { component: 'Router' });
|
||||
|
||||
console.log('🔍 DEBUG: About to approve change...');
|
||||
console.log('✅ Approving change...');
|
||||
secureLogger.debug('🔍 DEBUG: About to approve change...', { component: 'Router' });
|
||||
secureLogger.info('✅ Approving change...', { component: 'Router' });
|
||||
const approveChangeReturn = await services.approveChange(pairingId, stateId);
|
||||
console.log('📜 Approve change result:', approveChangeReturn);
|
||||
secureLogger.info('📜 Approve change result:', { component: 'Router', data: approveChangeReturn });
|
||||
await services.handleApiReturn(approveChangeReturn);
|
||||
console.log('✅ DEBUG: approveChange completed successfully!');
|
||||
secureLogger.debug('✅ DEBUG: approveChange completed successfully!', { component: 'Router' });
|
||||
|
||||
console.log('🔍 DEBUG: approveChange completed, about to call waitForPairingCommitment...');
|
||||
console.log('⏳ Waiting for pairing process to be committed...');
|
||||
secureLogger.debug('🔍 DEBUG: approveChange completed, about to call waitForPairingCommitment...', { component: 'Router' });
|
||||
secureLogger.info('⏳ Waiting for pairing process to be committed...', { component: 'Router' });
|
||||
await services.waitForPairingCommitment(pairingId);
|
||||
console.log('✅ DEBUG: waitForPairingCommitment completed successfully!');
|
||||
secureLogger.debug('✅ DEBUG: waitForPairingCommitment completed successfully!', { component: 'Router' });
|
||||
|
||||
console.log('🔍 DEBUG: About to call confirmPairing...');
|
||||
console.log('🔁 Confirming pairing...');
|
||||
secureLogger.debug('🔍 DEBUG: About to call confirmPairing...', { component: 'Router' });
|
||||
secureLogger.info('🔁 Confirming pairing...', { component: 'Router' });
|
||||
await services.confirmPairing(pairingId);
|
||||
console.log('✅ DEBUG: confirmPairing completed successfully!');
|
||||
secureLogger.debug('✅ DEBUG: confirmPairing completed successfully!', { component: 'Router' });
|
||||
|
||||
console.log('🎉 Pairing successfully completed!');
|
||||
secureLogger.info('🎉 Pairing successfully completed!', { component: 'Router' });
|
||||
|
||||
// ✅ Send success response to frontend
|
||||
const successMsg = {
|
||||
@ -390,11 +391,11 @@ export async function registerAllListeners() {
|
||||
pairingId,
|
||||
messageId: event.data.messageId,
|
||||
};
|
||||
console.log('📤 Sending PAIRING_CREATED message to UI:', successMsg);
|
||||
secureLogger.info('📤 Sending PAIRING_CREATED message to UI:', { component: 'Router', data: successMsg });
|
||||
window.parent.postMessage(successMsg, event.origin);
|
||||
} catch (e) {
|
||||
const errorMsg = `❌ Failed to create pairing process: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -406,7 +407,7 @@ export async function registerAllListeners() {
|
||||
|
||||
if (!services.isPaired()) {
|
||||
const errorMsg = 'Device not paired';
|
||||
console.warn(errorMsg);
|
||||
secureLogger.warn(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
return;
|
||||
}
|
||||
@ -430,7 +431,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to get processes: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -444,7 +445,7 @@ export async function registerAllListeners() {
|
||||
|
||||
if (!services.isPaired()) {
|
||||
const errorMsg = 'Device not paired';
|
||||
console.warn(errorMsg);
|
||||
secureLogger.warn(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
return;
|
||||
}
|
||||
@ -469,7 +470,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to get processes: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -483,7 +484,7 @@ export async function registerAllListeners() {
|
||||
|
||||
if (!services.isPaired()) {
|
||||
const errorMsg = 'Device not paired';
|
||||
console.warn(errorMsg);
|
||||
secureLogger.warn(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
return;
|
||||
}
|
||||
@ -530,7 +531,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to retrieve data: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -593,7 +594,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (error) {
|
||||
const errorMsg = `Failed to renew token: ${error}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -603,7 +604,7 @@ export async function registerAllListeners() {
|
||||
|
||||
if (!services.isPaired()) {
|
||||
const errorMsg = 'Device not paired';
|
||||
console.warn(errorMsg);
|
||||
secureLogger.warn(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
return;
|
||||
}
|
||||
@ -627,7 +628,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to get pairing id: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -637,7 +638,7 @@ export async function registerAllListeners() {
|
||||
|
||||
if (!services.isPaired()) {
|
||||
const errorMsg = 'Device not paired';
|
||||
console.warn(errorMsg);
|
||||
secureLogger.warn(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
return;
|
||||
}
|
||||
@ -676,7 +677,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to create process: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -686,7 +687,7 @@ export async function registerAllListeners() {
|
||||
|
||||
if (!services.isPaired()) {
|
||||
const errorMsg = 'Device not paired';
|
||||
console.warn(errorMsg);
|
||||
secureLogger.warn(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
return;
|
||||
}
|
||||
@ -714,7 +715,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to notify update for process: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -724,7 +725,7 @@ export async function registerAllListeners() {
|
||||
|
||||
if (!services.isPaired()) {
|
||||
const errorMsg = 'Device not paired';
|
||||
console.warn(errorMsg);
|
||||
secureLogger.warn(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
return;
|
||||
}
|
||||
@ -749,7 +750,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to validate process: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -759,7 +760,7 @@ export async function registerAllListeners() {
|
||||
|
||||
if (!services.isPaired()) {
|
||||
const errorMsg = 'Device not paired';
|
||||
console.warn(errorMsg);
|
||||
secureLogger.warn(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
|
||||
@ -860,7 +861,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to update process: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -870,7 +871,7 @@ export async function registerAllListeners() {
|
||||
|
||||
if (!services.isPaired()) {
|
||||
const errorMsg = 'Device not paired';
|
||||
console.warn(errorMsg);
|
||||
secureLogger.warn(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
return;
|
||||
}
|
||||
@ -894,7 +895,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to decode data: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -902,7 +903,7 @@ export async function registerAllListeners() {
|
||||
const handleHashValue = async (event: MessageEvent) => {
|
||||
if (event.data.type !== MessageType.HASH_VALUE) {return;}
|
||||
|
||||
console.log('handleHashValue', event.data);
|
||||
secureLogger.info('handleHashValue', { component: 'Router', data: event.data });
|
||||
|
||||
try {
|
||||
const { accessToken, commitedIn, label, fileBlob } = event.data;
|
||||
@ -923,7 +924,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to hash value: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -950,7 +951,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to get merkle proof: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -986,7 +987,7 @@ export async function registerAllListeners() {
|
||||
);
|
||||
} catch (e) {
|
||||
const errorMsg = `Failed to get merkle proof: ${e}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
};
|
||||
@ -1025,7 +1026,7 @@ export async function registerAllListeners() {
|
||||
await handleCreateProcess(event);
|
||||
break;
|
||||
case MessageType.CREATE_CONVERSATION:
|
||||
console.warn('CREATE_CONVERSATION functionality has been removed');
|
||||
secureLogger.warn('CREATE_CONVERSATION functionality has been removed', { component: 'Router' });
|
||||
break;
|
||||
case MessageType.NOTIFY_UPDATE:
|
||||
await handleNotifyUpdate(event);
|
||||
@ -1056,18 +1057,18 @@ export async function registerAllListeners() {
|
||||
break;
|
||||
case 'LISTENING':
|
||||
// Parent is listening for messages - no action needed
|
||||
console.log('👂 Parent is listening for messages');
|
||||
secureLogger.info('👂 Parent is listening for messages', { component: 'Router' });
|
||||
break;
|
||||
case 'IFRAME_READY':
|
||||
// Iframe is ready - no action needed
|
||||
console.log('🔗 Iframe is ready');
|
||||
secureLogger.info('🔗 Iframe is ready', { component: 'Router' });
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unhandled message type: ${event.data.type}`);
|
||||
secureLogger.warn('Unhandled message type: ${event.data.type}', { component: 'Router' });
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMsg = `Error handling message: ${error}`;
|
||||
console.error(errorMsg);
|
||||
secureLogger.error(errorMsg, { component: 'Router' });
|
||||
// Error handling - no response needed
|
||||
}
|
||||
}
|
||||
@ -1083,11 +1084,11 @@ export async function registerAllListeners() {
|
||||
// 4 Words Pairing Handlers
|
||||
async function handlePairing4WordsCreate(_event: MessageEvent) {
|
||||
try {
|
||||
console.log('🔐 Handling 4 words pairing create request');
|
||||
secureLogger.info('🔐 Handling 4 words pairing create request', { component: 'Router' });
|
||||
|
||||
const service = await Services.getInstance();
|
||||
// Use service variable
|
||||
console.log('Service instance:', service);
|
||||
secureLogger.info('Service instance:', { component: 'Router', data: service });
|
||||
const iframePairingService = await import('./services/iframe-pairing.service');
|
||||
const IframePairingService = iframePairingService.default;
|
||||
const pairingService = IframePairingService.getInstance();
|
||||
@ -1104,7 +1105,7 @@ async function handlePairing4WordsCreate(_event: MessageEvent) {
|
||||
|
||||
async function handlePairing4WordsJoin(event: MessageEvent) {
|
||||
try {
|
||||
console.log('🔗 Handling 4 words pairing join request');
|
||||
secureLogger.info('🔗 Handling 4 words pairing join request', { component: 'Router' });
|
||||
|
||||
const { words } = event.data;
|
||||
if (!words) {
|
||||
@ -1156,7 +1157,7 @@ async function cleanPage() {
|
||||
// Reload the page to restart the application
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur lors de la suppression du compte:', error);
|
||||
secureLogger.error('❌ Erreur lors de la suppression du compte:', error, { component: 'Router' });
|
||||
alert('❌ Erreur lors de la suppression du compte. Veuillez réessayer.');
|
||||
}
|
||||
} else {
|
||||
@ -1185,7 +1186,7 @@ document.addEventListener('navigate', (e: Event) => {
|
||||
* Cette étape doit être la première et rien d'autre ne doit s'exécuter en parallèle
|
||||
*/
|
||||
async function handleSecurityKeyManagement(): Promise<boolean> {
|
||||
console.log('🔐 Starting security key management...');
|
||||
secureLogger.info('🔐 Starting security key management...', { component: 'Router' });
|
||||
|
||||
try {
|
||||
// Vérifier d'abord si un mode de sécurité est configuré
|
||||
@ -1195,12 +1196,12 @@ async function handleSecurityKeyManagement(): Promise<boolean> {
|
||||
const currentMode = await securityModeService.getCurrentMode();
|
||||
|
||||
if (!currentMode) {
|
||||
console.log('🔐 No security mode configured, redirecting to security setup...');
|
||||
secureLogger.info('🔐 No security mode configured, redirecting to security setup...', { component: 'Router' });
|
||||
window.location.href = '/src/pages/security-setup/security-setup.html';
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('🔐 Security mode configured:', currentMode);
|
||||
secureLogger.info('🔐 Security mode configured:', { component: 'Router', data: currentMode });
|
||||
|
||||
// Vérifier si des credentials existent
|
||||
const { SecureCredentialsService } = await import('./services/secure-credentials.service');
|
||||
@ -1209,24 +1210,24 @@ async function handleSecurityKeyManagement(): Promise<boolean> {
|
||||
const hasCredentials = await secureCredentialsService.hasCredentials();
|
||||
|
||||
if (!hasCredentials) {
|
||||
console.log('🔐 No security credentials found, redirecting to wallet setup...');
|
||||
secureLogger.info('🔐 No security credentials found, redirecting to wallet setup...', { component: 'Router' });
|
||||
window.location.href = '/src/pages/wallet-setup/wallet-setup.html';
|
||||
return false;
|
||||
} else {
|
||||
console.log('🔐 Security credentials found, verifying access...');
|
||||
secureLogger.info('🔐 Security credentials found, verifying access...', { component: 'Router' });
|
||||
// Vérifier l'accès aux credentials
|
||||
const credentials = await secureCredentialsService.retrieveCredentials('');
|
||||
if (!credentials) {
|
||||
console.log('❌ Failed to access security credentials');
|
||||
secureLogger.error('❌ Failed to access security credentials', { component: 'Router' });
|
||||
window.location.href = '/src/pages/wallet-setup/wallet-setup.html';
|
||||
return false;
|
||||
}
|
||||
console.log('✅ Security credentials verified');
|
||||
secureLogger.info('✅ Security credentials verified', { component: 'Router' });
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Security key management failed:', error);
|
||||
console.log('🔐 Redirecting to security setup...');
|
||||
secureLogger.error('❌ Security key management failed:', error, { component: 'Router' });
|
||||
secureLogger.info('🔐 Redirecting to security setup...', { component: 'Router' });
|
||||
window.location.href = '/src/pages/security-setup/security-setup.html';
|
||||
return false;
|
||||
}
|
||||
@ -1236,14 +1237,14 @@ async function handleSecurityKeyManagement(): Promise<boolean> {
|
||||
* ÉTAPE 5: Handshake
|
||||
*/
|
||||
async function performHandshake(_services: any): Promise<void> {
|
||||
console.log('🤝 Performing handshake...');
|
||||
secureLogger.info('🤝 Performing handshake...', { component: 'Router' });
|
||||
|
||||
try {
|
||||
// Le handshake est déjà fait lors de la connexion aux relais
|
||||
// Cette fonction peut être étendue pour des handshakes supplémentaires
|
||||
console.log('✅ Handshake completed');
|
||||
secureLogger.info('✅ Handshake completed', { component: 'Router' });
|
||||
} catch (error) {
|
||||
console.error('❌ Handshake failed:', error);
|
||||
secureLogger.error('❌ Handshake failed:', error, { component: 'Router' });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@ -1252,22 +1253,22 @@ async function performHandshake(_services: any): Promise<void> {
|
||||
* ÉTAPE 6: Pairing
|
||||
*/
|
||||
async function handlePairing(services: any): Promise<void> {
|
||||
console.log('🔗 Handling device pairing...');
|
||||
secureLogger.info('🔗 Handling device pairing...', { component: 'Router' });
|
||||
|
||||
try {
|
||||
// Vérifier le statut de pairing
|
||||
const isPaired = services.isPaired();
|
||||
console.log('🔍 Device pairing status:', isPaired ? 'Paired' : 'Not paired');
|
||||
secureLogger.debug('🔍 Device pairing status:', { component: 'Router', data: isPaired ? 'Paired' : 'Not paired' });
|
||||
|
||||
if (!isPaired) {
|
||||
console.log('⚠️ Device not paired, user must complete pairing...');
|
||||
secureLogger.warn('⚠️ Device not paired, user must complete pairing...', { component: 'Router' });
|
||||
// Le pairing sera géré par la page home
|
||||
return;
|
||||
} else {
|
||||
console.log('✅ Device is already paired');
|
||||
secureLogger.info('✅ Device is already paired', { component: 'Router' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Pairing handling failed:', error);
|
||||
secureLogger.error('❌ Pairing handling failed:', error, { component: 'Router' });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@ -1276,27 +1277,27 @@ async function handlePairing(services: any): Promise<void> {
|
||||
* ÉTAPE 7: Écoute des processus
|
||||
*/
|
||||
async function startProcessListening(services: any): Promise<void> {
|
||||
console.log('👂 Starting process listening...');
|
||||
secureLogger.info('👂 Starting process listening...', { component: 'Router' });
|
||||
|
||||
try {
|
||||
// Restore data from database (these operations can fail, so we handle them separately)
|
||||
try {
|
||||
console.log('📊 Restoring processes from database...');
|
||||
secureLogger.info('📊 Restoring processes from database...', { component: 'Router' });
|
||||
await services.restoreProcessesFromDB();
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Failed to restore processes from database:', error);
|
||||
secureLogger.warn('⚠️ Failed to restore processes from database:', { component: 'Router', data: error });
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('🔐 Restoring secrets from database...');
|
||||
secureLogger.info('🔐 Restoring secrets from database...', { component: 'Router' });
|
||||
await services.restoreSecretsFromDB();
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Failed to restore secrets from database:', error);
|
||||
secureLogger.warn('⚠️ Failed to restore secrets from database:', { component: 'Router', data: error });
|
||||
}
|
||||
|
||||
console.log('✅ Process listening started');
|
||||
secureLogger.info('✅ Process listening started', { component: 'Router' });
|
||||
} catch (error) {
|
||||
console.error('❌ Process listening failed:', error);
|
||||
secureLogger.error('❌ Process listening failed:', error, { component: 'Router' });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -841,8 +841,8 @@ export class SecureCredentialsService {
|
||||
private displayOTPQRCode(secret: string): void {
|
||||
try {
|
||||
// Créer l'URL pour le QR code (format standard TOTP)
|
||||
const issuer = 'LeCoffre';
|
||||
const account = 'LeCoffre Security';
|
||||
const issuer = '4NK';
|
||||
const account = '4NK Security';
|
||||
const qrUrl = `otpauth://totp/${encodeURIComponent(account)}?secret=${secret}&issuer=${encodeURIComponent(issuer)}`;
|
||||
|
||||
console.log('🔐 OTP QR Code URL:', qrUrl);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
200
src/utils/log-analyzer.ts
Normal file
200
src/utils/log-analyzer.ts
Normal file
@ -0,0 +1,200 @@
|
||||
/**
|
||||
* Analyseur de logs pour identifier les problèmes d'utilisation de console
|
||||
* et proposer des corrections pour utiliser le système de logging centralisé
|
||||
*/
|
||||
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
|
||||
export interface LogIssue {
|
||||
file: string;
|
||||
line: number;
|
||||
type: 'console.log' | 'console.info' | 'console.warn' | 'console.error' | 'console.debug';
|
||||
message: string;
|
||||
suggestedLevel: 'debug' | 'info' | 'warn' | 'error';
|
||||
suggestedContext?: string;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
export class LogAnalyzer {
|
||||
private issues: LogIssue[] = [];
|
||||
|
||||
/**
|
||||
* Analyse un message de log pour déterminer le niveau approprié
|
||||
*/
|
||||
private analyzeLogMessage(message: string, currentType: string): {
|
||||
suggestedLevel: 'debug' | 'info' | 'warn' | 'error';
|
||||
reason: string;
|
||||
} {
|
||||
const lowerMessage = message.toLowerCase();
|
||||
|
||||
// Patterns pour identifier les niveaux
|
||||
if (lowerMessage.includes('error') || lowerMessage.includes('failed') || lowerMessage.includes('❌')) {
|
||||
return { suggestedLevel: 'error', reason: 'Contains error indicators' };
|
||||
}
|
||||
|
||||
if (lowerMessage.includes('warn') || lowerMessage.includes('⚠️') || lowerMessage.includes('skipping')) {
|
||||
return { suggestedLevel: 'warn', reason: 'Contains warning indicators' };
|
||||
}
|
||||
|
||||
if (lowerMessage.includes('debug') || lowerMessage.includes('🔍') || lowerMessage.includes('checking')) {
|
||||
return { suggestedLevel: 'debug', reason: 'Contains debug indicators' };
|
||||
}
|
||||
|
||||
if (lowerMessage.includes('success') || lowerMessage.includes('✅') || lowerMessage.includes('completed')) {
|
||||
return { suggestedLevel: 'info', reason: 'Contains success indicators' };
|
||||
}
|
||||
|
||||
if (lowerMessage.includes('initializing') || lowerMessage.includes('starting') || lowerMessage.includes('🔄')) {
|
||||
return { suggestedLevel: 'info', reason: 'Contains initialization indicators' };
|
||||
}
|
||||
|
||||
// Par défaut, utiliser le niveau actuel ou info
|
||||
if (currentType === 'console.error') {
|
||||
return { suggestedLevel: 'error', reason: 'Already using error level' };
|
||||
}
|
||||
if (currentType === 'console.warn') {
|
||||
return { suggestedLevel: 'warn', reason: 'Already using warn level' };
|
||||
}
|
||||
|
||||
return { suggestedLevel: 'info', reason: 'Default to info level' };
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggère un contexte basé sur le nom du fichier et le message
|
||||
*/
|
||||
private suggestContext(file: string, message: string): string {
|
||||
const fileName = file.split('/').pop()?.replace('.ts', '') || '';
|
||||
|
||||
// Patterns pour identifier le composant
|
||||
if (fileName.includes('service')) {
|
||||
return 'Service';
|
||||
}
|
||||
if (fileName.includes('home')) {
|
||||
return 'HomePage';
|
||||
}
|
||||
if (fileName.includes('pairing')) {
|
||||
return 'PairingPage';
|
||||
}
|
||||
if (fileName.includes('wallet')) {
|
||||
return 'WalletSetup';
|
||||
}
|
||||
if (fileName.includes('security')) {
|
||||
return 'SecuritySetup';
|
||||
}
|
||||
if (fileName.includes('birthday')) {
|
||||
return 'BirthdaySetup';
|
||||
}
|
||||
|
||||
return 'Application';
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyse un fichier pour identifier les problèmes de logging
|
||||
*/
|
||||
analyzeFile(filePath: string, content: string): LogIssue[] {
|
||||
const lines = content.split('\n');
|
||||
const issues: LogIssue[] = [];
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
const consoleMatch = line.match(/console\.(log|info|warn|error|debug)\s*\(\s*['"`]([^'"`]+)['"`]/);
|
||||
|
||||
if (consoleMatch) {
|
||||
const [, type, message] = consoleMatch;
|
||||
const analysis = this.analyzeLogMessage(message, `console.${type}`);
|
||||
|
||||
issues.push({
|
||||
file: filePath,
|
||||
line: index + 1,
|
||||
type: `console.${type}` as any,
|
||||
message,
|
||||
suggestedLevel: analysis.suggestedLevel,
|
||||
suggestedContext: this.suggestContext(filePath, message),
|
||||
reason: analysis.reason
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return issues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Génère un rapport d'analyse
|
||||
*/
|
||||
generateReport(issues: LogIssue[]): string {
|
||||
const report = [];
|
||||
|
||||
report.push('# Rapport d\'analyse des logs\n');
|
||||
report.push(`Total d'issues trouvées: ${issues.length}\n`);
|
||||
|
||||
// Grouper par fichier
|
||||
const byFile = issues.reduce((acc, issue) => {
|
||||
if (!acc[issue.file]) acc[issue.file] = [];
|
||||
acc[issue.file].push(issue);
|
||||
return acc;
|
||||
}, {} as Record<string, LogIssue[]>);
|
||||
|
||||
Object.entries(byFile).forEach(([file, fileIssues]) => {
|
||||
report.push(`## ${file}\n`);
|
||||
report.push(`Issues: ${fileIssues.length}\n`);
|
||||
|
||||
fileIssues.forEach(issue => {
|
||||
report.push(`- **Ligne ${issue.line}**: ${issue.type}`);
|
||||
report.push(` - Message: "${issue.message}"`);
|
||||
report.push(` - Niveau suggéré: ${issue.suggestedLevel}`);
|
||||
report.push(` - Contexte suggéré: ${issue.suggestedContext}`);
|
||||
report.push(` - Raison: ${issue.reason}\n`);
|
||||
});
|
||||
});
|
||||
|
||||
return report.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Génère le code de correction pour un fichier
|
||||
*/
|
||||
generateCorrection(filePath: string, issues: LogIssue[]): string {
|
||||
const corrections = [];
|
||||
|
||||
corrections.push(`// Corrections pour ${filePath}\n`);
|
||||
corrections.push(`import { secureLogger } from '../services/secure-logger';\n`);
|
||||
|
||||
issues.forEach(issue => {
|
||||
const context = issue.suggestedContext ? `, { component: '${issue.suggestedContext}' }` : '';
|
||||
corrections.push(`// Ligne ${issue.line}: Remplacer`);
|
||||
corrections.push(`// ${issue.type}('${issue.message}');`);
|
||||
corrections.push(`// Par:`);
|
||||
corrections.push(`secureLogger.${issue.suggestedLevel}('${issue.message}'${context});\n`);
|
||||
});
|
||||
|
||||
return corrections.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Exemple d'utilisation
|
||||
export function analyzeLoggingIssues(): void {
|
||||
const analyzer = new LogAnalyzer();
|
||||
|
||||
// Exemples d'issues typiques
|
||||
const exampleIssues: LogIssue[] = [
|
||||
{
|
||||
file: 'src/services/service.ts',
|
||||
line: 90,
|
||||
type: 'console.log',
|
||||
message: 'initializing services',
|
||||
suggestedLevel: 'info',
|
||||
suggestedContext: 'Service',
|
||||
reason: 'Initialization message'
|
||||
},
|
||||
{
|
||||
file: 'src/pages/home/home.ts',
|
||||
line: 26,
|
||||
type: 'console.log',
|
||||
message: '⚠️ Home page already initializing, skipping...',
|
||||
suggestedLevel: 'warn',
|
||||
suggestedContext: 'HomePage',
|
||||
reason: 'Contains warning indicators'
|
||||
}
|
||||
];
|
||||
|
||||
console.log(analyzer.generateReport(exampleIssues));
|
||||
}
|
||||
121
src/utils/log-fixer.ts
Normal file
121
src/utils/log-fixer.ts
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Correcteur automatique de logs pour remplacer console.* par secureLogger
|
||||
*/
|
||||
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
|
||||
export class LogFixer {
|
||||
/**
|
||||
* Corrige les logs dans un contenu de fichier
|
||||
*/
|
||||
static fixLogs(content: string, filePath: string): string {
|
||||
let fixedContent = content;
|
||||
|
||||
// Ajouter l'import secureLogger si pas déjà présent
|
||||
if (!fixedContent.includes('import { secureLogger }')) {
|
||||
const importMatch = fixedContent.match(/import.*from.*['"][^'"]+['"];?\s*\n/);
|
||||
if (importMatch) {
|
||||
const importIndex = fixedContent.lastIndexOf(importMatch[0]) + importMatch[0].length;
|
||||
fixedContent = fixedContent.slice(0, importIndex) +
|
||||
`import { secureLogger } from '../services/secure-logger';\n` +
|
||||
fixedContent.slice(importIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Remplacer console.log par secureLogger.info
|
||||
fixedContent = fixedContent.replace(
|
||||
/console\.log\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
||||
(match, message) => {
|
||||
const level = this.determineLogLevel(message);
|
||||
const context = this.determineContext(filePath, message);
|
||||
return `secureLogger.${level}('${message}'${context})`;
|
||||
}
|
||||
);
|
||||
|
||||
// Remplacer console.warn par secureLogger.warn
|
||||
fixedContent = fixedContent.replace(
|
||||
/console\.warn\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
||||
(match, message) => {
|
||||
const context = this.determineContext(filePath, message);
|
||||
return `secureLogger.warn('${message}'${context})`;
|
||||
}
|
||||
);
|
||||
|
||||
// Remplacer console.error par secureLogger.error
|
||||
fixedContent = fixedContent.replace(
|
||||
/console\.error\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
||||
(match, message) => {
|
||||
const context = this.determineContext(filePath, message);
|
||||
return `secureLogger.error('${message}'${context})`;
|
||||
}
|
||||
);
|
||||
|
||||
// Remplacer console.info par secureLogger.info
|
||||
fixedContent = fixedContent.replace(
|
||||
/console\.info\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
||||
(match, message) => {
|
||||
const context = this.determineContext(filePath, message);
|
||||
return `secureLogger.info('${message}'${context})`;
|
||||
}
|
||||
);
|
||||
|
||||
// Remplacer console.debug par secureLogger.debug
|
||||
fixedContent = fixedContent.replace(
|
||||
/console\.debug\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
||||
(match, message) => {
|
||||
const context = this.determineContext(filePath, message);
|
||||
return `secureLogger.debug('${message}'${context})`;
|
||||
}
|
||||
);
|
||||
|
||||
return fixedContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Détermine le niveau de log approprié basé sur le message
|
||||
*/
|
||||
private static determineLogLevel(message: string): 'debug' | 'info' | 'warn' | 'error' {
|
||||
const lowerMessage = message.toLowerCase();
|
||||
|
||||
if (lowerMessage.includes('error') || lowerMessage.includes('failed') || lowerMessage.includes('❌')) {
|
||||
return 'error';
|
||||
}
|
||||
|
||||
if (lowerMessage.includes('warn') || lowerMessage.includes('⚠️') || lowerMessage.includes('skipping')) {
|
||||
return 'warn';
|
||||
}
|
||||
|
||||
if (lowerMessage.includes('debug') || lowerMessage.includes('🔍') || lowerMessage.includes('checking')) {
|
||||
return 'debug';
|
||||
}
|
||||
|
||||
return 'info';
|
||||
}
|
||||
|
||||
/**
|
||||
* Détermine le contexte basé sur le fichier et le message
|
||||
*/
|
||||
private static determineContext(filePath: string, message: string): string {
|
||||
const fileName = filePath.split('/').pop()?.replace('.ts', '') || '';
|
||||
|
||||
let component = 'Application';
|
||||
|
||||
if (fileName.includes('service')) {
|
||||
component = 'Service';
|
||||
} else if (fileName.includes('home')) {
|
||||
component = 'HomePage';
|
||||
} else if (fileName.includes('pairing')) {
|
||||
component = 'PairingPage';
|
||||
} else if (fileName.includes('wallet')) {
|
||||
component = 'WalletSetup';
|
||||
} else if (fileName.includes('security')) {
|
||||
component = 'SecuritySetup';
|
||||
} else if (fileName.includes('birthday')) {
|
||||
component = 'BirthdaySetup';
|
||||
} else if (fileName.includes('block-sync')) {
|
||||
component = 'BlockSync';
|
||||
}
|
||||
|
||||
return `, { component: '${component}' }`;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
import Services from '../services/service';
|
||||
import { secureLogger } from '../services/secure-logger';
|
||||
import { getCorrectDOM } from './html.utils';
|
||||
import { addSubscription } from './subscription.utils';
|
||||
|
||||
@ -8,7 +9,7 @@ export async function copyToClipboard(fullAddress: string) {
|
||||
await navigator.clipboard.writeText(fullAddress);
|
||||
alert('Adresse copiée dans le presse-papiers !');
|
||||
} catch (err) {
|
||||
console.error('Failed to copy the address: ', err);
|
||||
secureLogger.error('Failed to copy the address: ', err, { component: 'SPAddressUtils' });
|
||||
}
|
||||
}
|
||||
|
||||
@ -2292,13 +2293,13 @@ async function emojisPairingRequest() {
|
||||
emojiDisplay.textContent = '(Request from: ' + emojis + ')';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
secureLogger.error('Error in operation', err as Error, { component: 'SPAddressUtils' });
|
||||
}
|
||||
}
|
||||
|
||||
// Display address emojis and other device emojis
|
||||
export async function displayEmojis(text: string) {
|
||||
console.log('🚀 ~ Services ~ adressToEmoji');
|
||||
secureLogger.info('🚀 ~ Services ~ adressToEmoji', { component: 'SPAddressUtils' });
|
||||
try {
|
||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
||||
const emojis = await addressToEmoji(text);
|
||||
@ -2312,7 +2313,7 @@ export async function displayEmojis(text: string) {
|
||||
|
||||
initAddressInput();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
secureLogger.error('Error in operation', err as Error, { component: 'SPAddressUtils' });
|
||||
}
|
||||
}
|
||||
|
||||
@ -2501,7 +2502,7 @@ async function onCreateButtonClick() {
|
||||
|
||||
if (words) {
|
||||
// Joiner flow: Use 4 words to discover and join existing pairing process
|
||||
console.log(`🔍 Joiner flow detected with words: ${words}`);
|
||||
secureLogger.debug('🔍 Joiner flow detected with words: ${words}', { component: 'SPAddressUtils' });
|
||||
updateJoinerStatus('Discovering pairing process...');
|
||||
|
||||
await discoverAndJoinPairingProcessWithWords(words);
|
||||
@ -2512,52 +2513,52 @@ async function onCreateButtonClick() {
|
||||
|
||||
// Wait for pairing commitment with synchronization
|
||||
updateJoinerStatus('Synchronizing with network...');
|
||||
console.log('🔍 DEBUG: Joiner - About to call waitForPairingCommitment...');
|
||||
secureLogger.debug('🔍 DEBUG: Joiner - About to call waitForPairingCommitment...', { component: 'SPAddressUtils' });
|
||||
await service.waitForPairingCommitment(pairingId!);
|
||||
console.log('✅ DEBUG: Joiner - waitForPairingCommitment completed!');
|
||||
secureLogger.debug('✅ DEBUG: Joiner - waitForPairingCommitment completed!', { component: 'SPAddressUtils' });
|
||||
|
||||
// Then confirm pairing
|
||||
updateJoinerStatus('Confirming pairing...');
|
||||
console.log('🔍 DEBUG: Joiner - About to call confirmPairing...');
|
||||
secureLogger.debug('🔍 DEBUG: Joiner - About to call confirmPairing...', { component: 'SPAddressUtils' });
|
||||
await service.confirmPairing();
|
||||
console.log('✅ DEBUG: Joiner - confirmPairing completed!');
|
||||
secureLogger.debug('✅ DEBUG: Joiner - confirmPairing completed!', { component: 'SPAddressUtils' });
|
||||
|
||||
// Redirect to account page after successful pairing
|
||||
updateJoinerStatus('✅ Pairing successful! Redirecting...');
|
||||
console.log('🔍 DEBUG: Redirecting to account page...');
|
||||
secureLogger.debug('🔍 DEBUG: Redirecting to account page...', { component: 'SPAddressUtils' });
|
||||
setTimeout(() => {
|
||||
window.location.href = '/account';
|
||||
}, 2000);
|
||||
} else {
|
||||
// Creator flow: Create new pairing process
|
||||
console.log(`🔍 Creator flow detected`);
|
||||
secureLogger.debug('🔍 Creator flow detected', { component: 'SPAddressUtils' });
|
||||
updateCreatorStatus('Creating pairing process...');
|
||||
|
||||
// Initialize WebAuthn credentials immediately on user click
|
||||
try {
|
||||
console.log('🔍 DEBUG: Testing WebAuthn availability...');
|
||||
console.log('🔍 DEBUG: isSecureContext:', window.isSecureContext);
|
||||
console.log('🔍 DEBUG: hasCredentials:', !!navigator.credentials);
|
||||
console.log('🔍 DEBUG: hasCreate:', !!navigator.credentials?.create);
|
||||
console.log('🔍 DEBUG: protocol:', window.location.protocol);
|
||||
secureLogger.debug('🔍 DEBUG: Testing WebAuthn availability...', { component: 'SPAddressUtils' });
|
||||
secureLogger.debug('🔍 DEBUG: isSecureContext:', { component: 'SPAddressUtils', data: window.isSecureContext });
|
||||
secureLogger.debug('🔍 DEBUG: hasCredentials:', { component: 'SPAddressUtils', data: !!navigator.credentials });
|
||||
secureLogger.debug('🔍 DEBUG: hasCreate:', { component: 'SPAddressUtils', data: !!navigator.credentials?.create });
|
||||
secureLogger.debug('🔍 DEBUG: protocol:', { component: 'SPAddressUtils', data: window.location.protocol });
|
||||
|
||||
const { secureCredentialsService } = await import('../services/secure-credentials.service');
|
||||
updateCreatorStatus('🔐 Authenticating with browser...');
|
||||
|
||||
// Auto-trigger WebAuthn authentication
|
||||
console.log('🔍 DEBUG: Auto-triggering WebAuthn authentication...');
|
||||
secureLogger.debug('🔍 DEBUG: Auto-triggering WebAuthn authentication...', { component: 'SPAddressUtils' });
|
||||
|
||||
try {
|
||||
// This should trigger the browser popup automatically
|
||||
await secureCredentialsService.generateSecureCredentials('4nk-pairing-password');
|
||||
console.log('✅ WebAuthn credentials obtained');
|
||||
secureLogger.info('✅ WebAuthn credentials obtained', { component: 'SPAddressUtils' });
|
||||
updateCreatorStatus('✅ Browser authentication successful');
|
||||
} catch (error) {
|
||||
console.error('❌ WebAuthn failed:', error);
|
||||
secureLogger.error('❌ WebAuthn failed:', error, { component: 'SPAddressUtils' });
|
||||
updateCreatorStatus('❌ Browser authentication failed');
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('⚠️ WebAuthn failed, continuing with fallback:', error);
|
||||
secureLogger.warn('⚠️ WebAuthn failed, continuing with fallback:', { component: 'SPAddressUtils', data: error });
|
||||
updateCreatorStatus('⚠️ Using fallback authentication');
|
||||
}
|
||||
|
||||
@ -2569,25 +2570,25 @@ async function onCreateButtonClick() {
|
||||
|
||||
// Wait for pairing commitment with synchronization
|
||||
updateCreatorStatus('Synchronizing with network...');
|
||||
console.log('🔍 DEBUG: Creator - About to call waitForPairingCommitment...');
|
||||
secureLogger.debug('🔍 DEBUG: Creator - About to call waitForPairingCommitment...', { component: 'SPAddressUtils' });
|
||||
await service.waitForPairingCommitment(pairingId!);
|
||||
console.log('✅ DEBUG: Creator - waitForPairingCommitment completed!');
|
||||
secureLogger.debug('✅ DEBUG: Creator - waitForPairingCommitment completed!', { component: 'SPAddressUtils' });
|
||||
|
||||
// Then confirm pairing
|
||||
updateCreatorStatus('Confirming pairing...');
|
||||
console.log('🔍 DEBUG: Creator - About to call confirmPairing...');
|
||||
secureLogger.debug('🔍 DEBUG: Creator - About to call confirmPairing...', { component: 'SPAddressUtils' });
|
||||
await service.confirmPairing();
|
||||
console.log('✅ DEBUG: Creator - confirmPairing completed!');
|
||||
secureLogger.debug('✅ DEBUG: Creator - confirmPairing completed!', { component: 'SPAddressUtils' });
|
||||
|
||||
// Redirect to account page after successful pairing
|
||||
updateCreatorStatus('✅ Pairing successful! Redirecting...');
|
||||
console.log('🔍 DEBUG: Redirecting to account page...');
|
||||
secureLogger.debug('🔍 DEBUG: Redirecting to account page...', { component: 'SPAddressUtils' });
|
||||
setTimeout(() => {
|
||||
window.location.href = '/account';
|
||||
}, 2000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`onCreateButtonClick error: ${(e as Error).message}`);
|
||||
secureLogger.error('onCreateButtonClick error: ${(e as Error).message}', { component: 'SPAddressUtils' });
|
||||
}
|
||||
}
|
||||
|
||||
@ -2596,7 +2597,7 @@ export async function discoverAndJoinPairingProcessWithWords(words: string): Pro
|
||||
const service = await Services.getInstance();
|
||||
|
||||
try {
|
||||
console.log(`🔍 DEBUG: Joiner discovering pairing process with words: ${words}`);
|
||||
secureLogger.debug('🔍 DEBUG: Joiner discovering pairing process with words: ${words}', { component: 'SPAddressUtils' });
|
||||
|
||||
// Wait for the pairing process to be available in the network
|
||||
const maxRetries = 20;
|
||||
@ -2604,12 +2605,12 @@ export async function discoverAndJoinPairingProcessWithWords(words: string): Pro
|
||||
|
||||
for (let i = 0; i < maxRetries; i++) {
|
||||
try {
|
||||
console.log(`🔍 Attempt ${i + 1}/${maxRetries}: Looking for pairing process...`);
|
||||
secureLogger.debug('🔍 Attempt ${i + 1}/${maxRetries}: Looking for pairing process...', { component: 'SPAddressUtils' });
|
||||
|
||||
// Try to get the pairing process ID from SDK
|
||||
const pairingProcessId = service.getPairingProcessId();
|
||||
if (pairingProcessId) {
|
||||
console.log(`✅ Found pairing process: ${pairingProcessId}`);
|
||||
secureLogger.info('✅ Found pairing process: ${pairingProcessId}', { component: 'SPAddressUtils' });
|
||||
|
||||
// Get the process and extract paired addresses
|
||||
const process = await service.getProcess(pairingProcessId);
|
||||
@ -2619,7 +2620,7 @@ export async function discoverAndJoinPairingProcessWithWords(words: string): Pro
|
||||
|
||||
if (publicData && publicData['pairedAddresses']) {
|
||||
const pairedAddresses = service.decodeValue(publicData['pairedAddresses']);
|
||||
console.log(`✅ Found paired addresses: ${JSON.stringify(pairedAddresses)}`);
|
||||
secureLogger.info('✅ Found paired addresses: ${JSON.stringify(pairedAddresses)}', { component: 'SPAddressUtils' });
|
||||
|
||||
// Set the process ID for the joiner
|
||||
service.setProcessId(pairingProcessId);
|
||||
@ -2627,26 +2628,26 @@ export async function discoverAndJoinPairingProcessWithWords(words: string): Pro
|
||||
|
||||
// Check connections with the discovered addresses
|
||||
await service.checkConnections(process);
|
||||
console.log(`✅ Joiner successfully joined pairing process`);
|
||||
secureLogger.info('✅ Joiner successfully joined pairing process', { component: 'SPAddressUtils' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`⏳ Still waiting for pairing process... (${i + 1}/${maxRetries})`);
|
||||
secureLogger.info('⏳ Still waiting for pairing process... (${i + 1}/${maxRetries})', { component: 'SPAddressUtils' });
|
||||
} catch (e) {
|
||||
console.log(`⚠️ Attempt ${i + 1}/${maxRetries}: ${(e as Error).message}`);
|
||||
secureLogger.error('⚠️ Attempt ${i + 1}/${maxRetries}: ${(e as Error).message}', { component: 'SPAddressUtils' });
|
||||
}
|
||||
|
||||
if (i < maxRetries - 1) {
|
||||
console.log(`⏳ Waiting ${retryDelay}ms before next attempt...`);
|
||||
secureLogger.info('⏳ Waiting ${retryDelay}ms before next attempt...', { component: 'SPAddressUtils' });
|
||||
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`❌ Failed to discover pairing process after ${maxRetries} attempts`);
|
||||
} catch (err) {
|
||||
console.error(`❌ Joiner discovery failed:`, (err as Error).message);
|
||||
secureLogger.error('❌ Joiner discovery failed:', (err as Error, { component: 'SPAddressUtils' }).message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@ -2656,7 +2657,7 @@ export async function discoverAndJoinPairingProcess(creatorAddress: string): Pro
|
||||
const service = await Services.getInstance();
|
||||
|
||||
try {
|
||||
console.log(`🔍 DEBUG: Joiner discovering pairing process for creator: ${creatorAddress}`);
|
||||
secureLogger.debug('🔍 DEBUG: Joiner discovering pairing process for creator: ${creatorAddress}', { component: 'SPAddressUtils' });
|
||||
|
||||
// Wait for the pairing process to be available in the network
|
||||
const maxRetries = 20;
|
||||
@ -2664,12 +2665,12 @@ export async function discoverAndJoinPairingProcess(creatorAddress: string): Pro
|
||||
|
||||
for (let i = 0; i < maxRetries; i++) {
|
||||
try {
|
||||
console.log(`🔍 Attempt ${i + 1}/${maxRetries}: Looking for pairing process...`);
|
||||
secureLogger.debug('🔍 Attempt ${i + 1}/${maxRetries}: Looking for pairing process...', { component: 'SPAddressUtils' });
|
||||
|
||||
// Try to get the pairing process ID from SDK
|
||||
const pairingProcessId = service.getPairingProcessId();
|
||||
if (pairingProcessId) {
|
||||
console.log(`✅ Found pairing process: ${pairingProcessId}`);
|
||||
secureLogger.info('✅ Found pairing process: ${pairingProcessId}', { component: 'SPAddressUtils' });
|
||||
|
||||
// Get the process and extract paired addresses
|
||||
const process = await service.getProcess(pairingProcessId);
|
||||
@ -2679,7 +2680,7 @@ export async function discoverAndJoinPairingProcess(creatorAddress: string): Pro
|
||||
|
||||
if (publicData && publicData['pairedAddresses']) {
|
||||
const pairedAddresses = service.decodeValue(publicData['pairedAddresses']);
|
||||
console.log(`✅ Found paired addresses: ${JSON.stringify(pairedAddresses)}`);
|
||||
secureLogger.info('✅ Found paired addresses: ${JSON.stringify(pairedAddresses)}', { component: 'SPAddressUtils' });
|
||||
|
||||
// Set the process ID for the joiner
|
||||
service.setProcessId(pairingProcessId);
|
||||
@ -2687,26 +2688,26 @@ export async function discoverAndJoinPairingProcess(creatorAddress: string): Pro
|
||||
|
||||
// Check connections with the discovered addresses
|
||||
await service.checkConnections(process);
|
||||
console.log(`✅ Joiner successfully joined pairing process`);
|
||||
secureLogger.info('✅ Joiner successfully joined pairing process', { component: 'SPAddressUtils' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`⏳ Still waiting for pairing process... (${i + 1}/${maxRetries})`);
|
||||
secureLogger.info('⏳ Still waiting for pairing process... (${i + 1}/${maxRetries})', { component: 'SPAddressUtils' });
|
||||
} catch (e) {
|
||||
console.log(`⚠️ Attempt ${i + 1}/${maxRetries}: ${(e as Error).message}`);
|
||||
secureLogger.error('⚠️ Attempt ${i + 1}/${maxRetries}: ${(e as Error).message}', { component: 'SPAddressUtils' });
|
||||
}
|
||||
|
||||
if (i < maxRetries - 1) {
|
||||
console.log(`⏳ Waiting ${retryDelay}ms before next attempt...`);
|
||||
secureLogger.info('⏳ Waiting ${retryDelay}ms before next attempt...', { component: 'SPAddressUtils' });
|
||||
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`❌ Failed to discover pairing process after ${maxRetries} attempts`);
|
||||
} catch (err) {
|
||||
console.error(`❌ Joiner discovery failed:`, (err as Error).message);
|
||||
secureLogger.error('❌ Joiner discovery failed:', (err as Error, { component: 'SPAddressUtils' }).message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@ -2729,12 +2730,12 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
const service = await Services.getInstance();
|
||||
|
||||
try {
|
||||
console.log(`🔐 Pairing 4NK: Démarrage du processus de pairing (création d'identité numérique vérifiable)...`);
|
||||
secureLogger.info('Pairing 4NK: Démarrage du processus de pairing (création d\'identité numérique vérifiable)...', { component: 'SPAddressUtils' });
|
||||
|
||||
// Connecter aux relays et effectuer le handshake avant de procéder
|
||||
console.log(`🔐 Pairing 4NK: Connexion aux relays et handshake...`);
|
||||
secureLogger.info('🔐 Pairing 4NK: Connexion aux relays et handshake...', { component: 'SPAddressUtils' });
|
||||
await service.connectAllRelays();
|
||||
console.log(`✅ Pairing 4NK: Relays connectés et handshake effectué`);
|
||||
secureLogger.info('✅ Pairing 4NK: Relays connectés et handshake effectué', { component: 'SPAddressUtils' });
|
||||
|
||||
// Get the creator's own address
|
||||
const creatorAddress = await service.getDeviceAddress();
|
||||
@ -2742,7 +2743,7 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
throw new Error('Creator address not available');
|
||||
}
|
||||
|
||||
console.log(`🔐 Pairing 4NK: Adresse du créateur (premier appareil): ${creatorAddress}`);
|
||||
secureLogger.info('🔐 Pairing 4NK: Adresse du créateur (premier appareil): ${creatorAddress}', { component: 'SPAddressUtils' });
|
||||
|
||||
// Update UI with creator address
|
||||
updateCreatorStatus(`Creator address: ${creatorAddress}`);
|
||||
@ -2751,7 +2752,7 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
|
||||
// Create pairing process with creator's address
|
||||
// Ce processus servira d'identité numérique vérifiable et permettra l'ajout d'autres appareils
|
||||
console.log(`🔐 Pairing 4NK: Création du processus de pairing (identité numérique décentralisée)...`);
|
||||
secureLogger.info('🔐 Pairing 4NK: Création du processus de pairing (identité numérique décentralisée)...', { component: 'SPAddressUtils' });
|
||||
const createPairingProcessReturn = await service.createPairingProcess(
|
||||
creatorAddress, // Use creator's address as memberPublicName
|
||||
[creatorAddress] // Include creator's address in pairedAddresses (liste des appareils appairés)
|
||||
@ -2764,7 +2765,7 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
const pairingId = createPairingProcessReturn.updated_process.process_id;
|
||||
const stateId = createPairingProcessReturn.updated_process.current_process.states[0].state_id;
|
||||
|
||||
console.log(`🔐 Pairing 4NK: Processus de pairing créé - ID: ${pairingId}, State ID: ${stateId}`);
|
||||
secureLogger.info('🔐 Pairing 4NK: Processus de pairing créé - ID: ${pairingId}, State ID: ${stateId}', { component: 'SPAddressUtils' });
|
||||
|
||||
service.setProcessId(pairingId);
|
||||
service.setStateId(stateId);
|
||||
@ -2775,16 +2776,16 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
service.pairDevice(pairingId, [creatorAddress]);
|
||||
|
||||
// Handle API return
|
||||
console.log(`🔐 Pairing 4NK: Traitement de la réponse API pour createPairingProcess...`);
|
||||
secureLogger.info('🔐 Pairing 4NK: Traitement de la réponse API pour createPairingProcess...', { component: 'SPAddressUtils' });
|
||||
await service.handleApiReturn(createPairingProcessReturn);
|
||||
|
||||
// Create PRD update (Private Data Relay update)
|
||||
// Met à jour les données privées via les relais pour synchroniser les secrets partagés
|
||||
console.log(`🔐 Pairing 4NK: Création de la mise à jour PRD (Private Data Relay) pour synchroniser les secrets partagés...`);
|
||||
secureLogger.info('🔐 Pairing 4NK: Création de la mise à jour PRD (Private Data Relay) pour synchroniser les secrets partagés...', { component: 'SPAddressUtils' });
|
||||
const createPrdUpdateReturn = await service.createPrdUpdate(pairingId, stateId);
|
||||
console.log(`🔐 Pairing 4NK: Résultat de la mise à jour PRD:`, createPrdUpdateReturn);
|
||||
secureLogger.info('🔐 Pairing 4NK: Résultat de la mise à jour PRD:', { component: 'SPAddressUtils', data: createPrdUpdateReturn });
|
||||
await service.handleApiReturn(createPrdUpdateReturn);
|
||||
console.log(`🔐 Pairing 4NK: Mise à jour PRD complétée avec succès (secrets partagés synchronisés)`);
|
||||
secureLogger.info('🔐 Pairing 4NK: Mise à jour PRD complétée avec succès (secrets partagés synchronisés)', { component: 'SPAddressUtils' });
|
||||
|
||||
// Approve change
|
||||
// Approbation du changement d'état du processus (nécessaire pour le quorum)
|
||||
@ -2792,30 +2793,30 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
const approveChangeReturn = await service.approveChange(pairingId, stateId);
|
||||
console.log(`🔐 Pairing 4NK: Résultat de l'approbation:`, approveChangeReturn);
|
||||
await service.handleApiReturn(approveChangeReturn);
|
||||
console.log(`🔐 Pairing 4NK: Changement approuvé avec succès`);
|
||||
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)...`);
|
||||
await service.waitForPairingCommitment(pairingId);
|
||||
console.log(`🔐 Pairing 4NK: Commit du processus de pairing reçu (identité numérique vérifiable créée)`);
|
||||
secureLogger.info('🔐 Pairing 4NK: Commit du processus de pairing reçu (identité numérique vérifiable créée)', { component: 'SPAddressUtils' });
|
||||
|
||||
// Confirm pairing
|
||||
// Confirmation finale du pairing (appareil maintenant appairé et partie du quorum)
|
||||
console.log(`🔐 Pairing 4NK: Confirmation finale du pairing (appareil maintenant partie du quorum MFA)...`);
|
||||
secureLogger.info('🔐 Pairing 4NK: Confirmation finale du pairing (appareil maintenant partie du quorum MFA)...', { component: 'SPAddressUtils' });
|
||||
await service.confirmPairing(pairingId);
|
||||
console.log(`🔐 Pairing 4NK: Pairing confirmé avec succès (MFA activé entre appareils)`);
|
||||
secureLogger.info('🔐 Pairing 4NK: Pairing confirmé avec succès (MFA activé entre appareils)', { component: 'SPAddressUtils' });
|
||||
|
||||
console.log(`✅ Pairing 4NK: Processus de pairing complété avec succès (identité numérique vérifiable créée, MFA activé)!`);
|
||||
secureLogger.info('✅ Pairing 4NK: Processus de pairing complété avec succès (identité numérique vérifiable créée, MFA activé)!', { component: 'SPAddressUtils' });
|
||||
|
||||
// Générer et afficher les 4 mots pour le partage avec d'autres appareils
|
||||
console.log(`🔐 Pairing 4NK: Génération des 4 mots de pairing...`);
|
||||
secureLogger.info('🔐 Pairing 4NK: Génération des 4 mots de pairing...', { component: 'SPAddressUtils' });
|
||||
try {
|
||||
await generateWordsDisplay(creatorAddress);
|
||||
console.log(`✅ Pairing 4NK: 4 mots générés et affichés`);
|
||||
secureLogger.info('✅ Pairing 4NK: 4 mots générés et affichés', { component: 'SPAddressUtils' });
|
||||
updateCreatorStatus('✅ Pairing complété ! Partagez les 4 mots avec les autres appareils.');
|
||||
} catch (wordsError) {
|
||||
console.warn(`⚠️ Pairing 4NK: Erreur lors de la génération des mots (non bloquant):`, wordsError);
|
||||
secureLogger.warn('⚠️ Pairing 4NK: Erreur lors de la génération des mots (non bloquant):', { component: 'SPAddressUtils', data: wordsError });
|
||||
updateCreatorStatus('✅ Pairing complété !');
|
||||
}
|
||||
|
||||
@ -2828,22 +2829,22 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
}
|
||||
|
||||
// Étape suivante : Récupération et déchiffrement des processus
|
||||
console.log(`🔍 Pairing 4NK: Récupération des processus...`);
|
||||
secureLogger.debug('🔍 Pairing 4NK: Récupération des processus...', { component: 'SPAddressUtils' });
|
||||
try {
|
||||
const myProcesses = await service.getMyProcesses();
|
||||
if (myProcesses && myProcesses.length > 0) {
|
||||
console.log(`✅ Pairing 4NK: ${myProcesses.length} processus trouvés pour cet appareil`);
|
||||
secureLogger.info('✅ Pairing 4NK: ${myProcesses.length} processus trouvés pour cet appareil', { component: 'SPAddressUtils' });
|
||||
|
||||
// Récupérer tous les processus
|
||||
const allProcesses = await service.getProcesses();
|
||||
console.log(`✅ Pairing 4NK: ${Object.keys(allProcesses).length} processus récupérés au total`);
|
||||
secureLogger.info('✅ Pairing 4NK: ${Object.keys(allProcesses).length} processus récupérés au total', { component: 'SPAddressUtils' });
|
||||
|
||||
// Pour chaque processus, tenter de déchiffrer les attributs possibles
|
||||
for (const processId of myProcesses) {
|
||||
try {
|
||||
const process = await service.getProcess(processId);
|
||||
if (!process) {
|
||||
console.warn(`⚠️ Pairing 4NK: Processus ${processId} introuvable`);
|
||||
secureLogger.warn('⚠️ Pairing 4NK: Processus ${processId} introuvable', { component: 'SPAddressUtils' });
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2853,7 +2854,7 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`🔍 Pairing 4NK: Tentative de déchiffrement des attributs pour le processus ${processId}...`);
|
||||
secureLogger.debug('🔍 Pairing 4NK: Tentative de déchiffrement des attributs pour le processus ${processId}...', { component: 'SPAddressUtils' });
|
||||
|
||||
// Vérifier les connexions avec les membres du processus
|
||||
await service.checkConnections(process);
|
||||
@ -2880,27 +2881,27 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
}
|
||||
|
||||
if (decryptedCount > 0) {
|
||||
console.log(`✅ Pairing 4NK: ${decryptedCount} attribut(s) déchiffré(s) pour le processus ${processId}`);
|
||||
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)`);
|
||||
}
|
||||
} catch (processError) {
|
||||
console.warn(`⚠️ Pairing 4NK: Erreur lors du traitement du processus ${processId}:`, processError);
|
||||
secureLogger.warn('⚠️ Pairing 4NK: Erreur lors du traitement du processus ${processId}:', { component: 'SPAddressUtils', data: processError });
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ Pairing 4NK: Récupération et déchiffrement des processus terminés`);
|
||||
secureLogger.info('✅ Pairing 4NK: Récupération et déchiffrement des processus terminés', { component: 'SPAddressUtils' });
|
||||
} else {
|
||||
console.log(`ℹ️ Pairing 4NK: Aucun processus trouvé pour cet appareil (normal pour un nouveau pairing)`);
|
||||
secureLogger.info('ℹ️ Pairing 4NK: Aucun processus trouvé pour cet appareil (normal pour un nouveau pairing)', { component: 'SPAddressUtils' });
|
||||
}
|
||||
} catch (processRetrievalError) {
|
||||
console.warn(`⚠️ Pairing 4NK: Erreur lors de la récupération des processus (non bloquant):`, processRetrievalError);
|
||||
secureLogger.warn('⚠️ Pairing 4NK: Erreur lors de la récupération des processus (non bloquant):', { component: 'SPAddressUtils', data: processRetrievalError });
|
||||
}
|
||||
|
||||
console.log(`✅ DEBUG: Creator pairing process created and 4 words generated`);
|
||||
console.log(`⏳ DEBUG: Creator waiting for joiner to enter 4 words...`);
|
||||
secureLogger.debug('✅ DEBUG: Creator pairing process created and 4 words generated', { component: 'SPAddressUtils' });
|
||||
secureLogger.debug('⏳ DEBUG: Creator waiting for joiner to enter 4 words...', { component: 'SPAddressUtils' });
|
||||
} catch (err) {
|
||||
console.error(`❌ Pairing 4NK: Erreur lors du processus de pairing:`, err);
|
||||
secureLogger.error('❌ Pairing 4NK: Erreur lors du processus de pairing:', err, { component: 'SPAddressUtils' });
|
||||
updateCreatorStatus(`❌ Erreur lors du pairing: ${(err as Error).message}`, true);
|
||||
throw err;
|
||||
}
|
||||
@ -2911,19 +2912,19 @@ export async function waitForJoinerAndUpdateProcess(): Promise<void> {
|
||||
const service = await Services.getInstance();
|
||||
|
||||
try {
|
||||
console.log(`🔍 DEBUG: Creator waiting for joiner to join...`);
|
||||
secureLogger.debug('🔍 DEBUG: Creator waiting for joiner to join...', { component: 'SPAddressUtils' });
|
||||
|
||||
const maxRetries = 30; // 30 attempts
|
||||
const retryDelay = 2000; // 2 seconds
|
||||
|
||||
for (let i = 0; i < maxRetries; i++) {
|
||||
try {
|
||||
console.log(`🔍 Attempt ${i + 1}/${maxRetries}: Checking for joiner...`);
|
||||
secureLogger.debug('🔍 Attempt ${i + 1}/${maxRetries}: Checking for joiner...', { component: 'SPAddressUtils' });
|
||||
|
||||
// Get current process
|
||||
const processId = service.getProcessId();
|
||||
if (!processId) {
|
||||
console.log(`⚠️ No process ID available yet, waiting...`);
|
||||
secureLogger.warn('⚠️ No process ID available yet, waiting...', { component: 'SPAddressUtils' });
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2935,31 +2936,31 @@ export async function waitForJoinerAndUpdateProcess(): Promise<void> {
|
||||
|
||||
if (publicData && publicData['pairedAddresses']) {
|
||||
const pairedAddresses = service.decodeValue(publicData['pairedAddresses']);
|
||||
console.log(`🔍 Current paired addresses: ${JSON.stringify(pairedAddresses)}`);
|
||||
secureLogger.debug('🔍 Current paired addresses: ${JSON.stringify(pairedAddresses)}', { component: 'SPAddressUtils' });
|
||||
|
||||
// Check if we have more than just the creator's address
|
||||
if (pairedAddresses && pairedAddresses.length > 1) {
|
||||
console.log(`✅ Joiner detected! Found ${pairedAddresses.length} addresses`);
|
||||
console.log(`✅ Creator process updated with joiner address`);
|
||||
secureLogger.info('✅ Joiner detected! Found ${pairedAddresses.length} addresses', { component: 'SPAddressUtils' });
|
||||
secureLogger.info('✅ Creator process updated with joiner address', { component: 'SPAddressUtils' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`⏳ Still waiting for joiner... (${i + 1}/${maxRetries})`);
|
||||
secureLogger.info('⏳ Still waiting for joiner... (${i + 1}/${maxRetries})', { component: 'SPAddressUtils' });
|
||||
} catch (e) {
|
||||
console.log(`⚠️ Attempt ${i + 1}/${maxRetries}: ${(e as Error).message}`);
|
||||
secureLogger.error('⚠️ Attempt ${i + 1}/${maxRetries}: ${(e as Error).message}', { component: 'SPAddressUtils' });
|
||||
}
|
||||
|
||||
if (i < maxRetries - 1) {
|
||||
console.log(`⏳ Waiting ${retryDelay}ms before next attempt...`);
|
||||
secureLogger.info('⏳ Waiting ${retryDelay}ms before next attempt...', { component: 'SPAddressUtils' });
|
||||
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`❌ No joiner detected after ${maxRetries} attempts`);
|
||||
} catch (err) {
|
||||
console.error(`❌ Creator waiting for joiner failed:`, err);
|
||||
secureLogger.error('❌ Creator waiting for joiner failed:', err, { component: 'SPAddressUtils' });
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@ -2979,9 +2980,9 @@ export async function generateWordsDisplay(spAddress: string) {
|
||||
// Update status
|
||||
updateCreatorStatus('4 words generated! Share them with the other device.');
|
||||
|
||||
console.log(`✅ Generated 4 words: ${words}`);
|
||||
secureLogger.info('✅ Generated 4 words: ${words}', { component: 'SPAddressUtils' });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
secureLogger.error('Error in operation', err as Error, { component: 'SPAddressUtils' });
|
||||
updateCreatorStatus('Failed to generate words', true);
|
||||
}
|
||||
}
|
||||
@ -2995,6 +2996,6 @@ export async function generateCreateBtn() {
|
||||
createBtn.textContent = 'CREATE';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
secureLogger.error('Error in operation', err as Error, { component: 'SPAddressUtils' });
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ export async function initWebsocket(url: string) {
|
||||
|
||||
if (ws !== null) {
|
||||
ws.onopen = async (_event) => {
|
||||
console.log('WebSocket connection established');
|
||||
secureLogger.info('WebSocket connection established', { component: 'WebSocket' });
|
||||
|
||||
while (messageQueue.length > 0) {
|
||||
const message = messageQueue.shift();
|
||||
@ -28,16 +28,16 @@ export async function initWebsocket(url: string) {
|
||||
if (typeof msgData === 'string') {
|
||||
try {
|
||||
// Valider le message avant traitement
|
||||
console.log('🔍 DEBUG: Raw WebSocket message:', msgData);
|
||||
secureLogger.debug('🔍 DEBUG: Raw WebSocket message:', { component: 'WebSocket', data: msgData });
|
||||
const validation = messageValidator.validateWebSocketMessage(msgData);
|
||||
console.log('🔍 DEBUG: Validation result:', validation);
|
||||
secureLogger.debug('🔍 DEBUG: Validation result:', { component: 'WebSocket', data: validation });
|
||||
|
||||
if (!validation.isValid) {
|
||||
console.warn('⚠️ Invalid WebSocket message received:', {
|
||||
secureLogger.warn('⚠️ Invalid WebSocket message received:', { component: 'WebSocket', data: {
|
||||
errors: validation.errors,
|
||||
messagePreview: msgData.substring(0, 100)
|
||||
messagePreview: msgData.substring(0, 100 })
|
||||
});
|
||||
console.log('🔍 DEBUG: Full validation errors:', validation.errors);
|
||||
secureLogger.error('🔍 DEBUG: Full validation errors:', { component: 'WebSocket', data: validation.errors });
|
||||
secureLogger.warn('Invalid WebSocket message received', {
|
||||
component: 'WebSocket',
|
||||
operation: 'message_validation',
|
||||
@ -120,10 +120,10 @@ export function sendMessage(flag: AnkFlag, message: string): void {
|
||||
flag: flag,
|
||||
content: message,
|
||||
};
|
||||
console.log('Sending message of type:', flag);
|
||||
secureLogger.info('Sending message of type:', { component: 'WebSocket', data: flag });
|
||||
ws.send(JSON.stringify(networkMessage));
|
||||
} else {
|
||||
console.error('WebSocket is not open. ReadyState:', ws.readyState);
|
||||
secureLogger.error('WebSocket is not open. ReadyState:', ws.readyState, { component: 'WebSocket' });
|
||||
messageQueue.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user