🔐 Implémentation PBKDF2 avec credentials navigateur ✅ Fonctionnalités ajoutées: - SecureCredentialsService avec PBKDF2 (100k itérations) - Chiffrement AES-GCM des clés spend/scan - Interface utilisateur complète pour gestion credentials - Tests unitaires complets - Architecture modulaire avec EventBus - Gestion mémoire optimisée - Performance monitoring - Web Workers pour encodage asynchrone 🛡️ Sécurité: - Dérivation PBKDF2 avec salt unique - Chiffrement AES-GCM des clés sensibles - Validation force mot de passe - Stockage sécurisé IndexedDB + WebAuthn - Logging sécurisé sans exposition données 🔧 Corrections: - Erreur 500 résolue (clé dupliquée package.json) - Configuration Vite simplifiée - Dépendances manquantes corrigées 📊 Améliorations: - Architecture découplée avec repositories - Services spécialisés (PairingService, etc.) - Monitoring performance et mémoire - Tests avec couverture complète - Documentation technique détaillée
124 lines
2.7 KiB
TypeScript
124 lines
2.7 KiB
TypeScript
/**
|
|
* Encoder Worker - Web Worker pour l'encodage asynchrone
|
|
* Traite les données lourdes sans bloquer le thread principal
|
|
*/
|
|
|
|
export interface EncoderMessage {
|
|
type: 'encode' | 'decode';
|
|
data: any;
|
|
id: string;
|
|
}
|
|
|
|
export interface EncoderResponse {
|
|
type: 'success' | 'error';
|
|
result?: any;
|
|
error?: string;
|
|
id: string;
|
|
}
|
|
|
|
// Écouter les messages du thread principal
|
|
self.addEventListener('message', async (event: MessageEvent<EncoderMessage>) => {
|
|
const { type, data, id } = event.data;
|
|
|
|
try {
|
|
let result: any;
|
|
|
|
switch (type) {
|
|
case 'encode':
|
|
result = await encodeData(data);
|
|
break;
|
|
case 'decode':
|
|
result = await decodeData(data);
|
|
break;
|
|
default:
|
|
throw new Error(`Unknown message type: ${type}`);
|
|
}
|
|
|
|
// Envoyer la réponse
|
|
const response: EncoderResponse = {
|
|
type: 'success',
|
|
result,
|
|
id
|
|
};
|
|
|
|
self.postMessage(response);
|
|
} catch (error) {
|
|
// Envoyer l'erreur
|
|
const response: EncoderResponse = {
|
|
type: 'error',
|
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
id
|
|
};
|
|
|
|
self.postMessage(response);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Encode les données de manière asynchrone
|
|
*/
|
|
async function encodeData(data: any): Promise<any> {
|
|
// Simuler un encodage lourd
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
|
|
if (typeof data === 'string') {
|
|
return btoa(data);
|
|
}
|
|
|
|
if (data instanceof ArrayBuffer) {
|
|
const uint8Array = new Uint8Array(data);
|
|
return Array.from(uint8Array).map(byte => byte.toString(16).padStart(2, '0')).join('');
|
|
}
|
|
|
|
if (data instanceof Uint8Array) {
|
|
return Array.from(data).map(byte => byte.toString(16).padStart(2, '0')).join('');
|
|
}
|
|
|
|
if (typeof data === 'object') {
|
|
return JSON.stringify(data);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Décode les données de manière asynchrone
|
|
*/
|
|
async function decodeData(data: any): Promise<any> {
|
|
// Simuler un décodage lourd
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
|
|
if (typeof data === 'string') {
|
|
try {
|
|
// Essayer de décoder en base64
|
|
return atob(data);
|
|
} catch {
|
|
// Essayer de décoder en hex
|
|
const bytes = [];
|
|
for (let i = 0; i < data.length; i += 2) {
|
|
bytes.push(parseInt(data.substr(i, 2), 16));
|
|
}
|
|
return new Uint8Array(bytes);
|
|
}
|
|
}
|
|
|
|
if (typeof data === 'object') {
|
|
try {
|
|
return JSON.parse(data);
|
|
} catch {
|
|
return data;
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
// Gérer les erreurs non capturées
|
|
self.addEventListener('error', (error) => {
|
|
console.error('Encoder worker error:', error);
|
|
});
|
|
|
|
self.addEventListener('unhandledrejection', (event) => {
|
|
console.error('Encoder worker unhandled rejection:', event.reason);
|
|
});
|