ihm_client/src/services/security-mode.service.ts
NicolasCantu 653c7f32ca ci: docker_tag=dev-test
**Motivations :**
- Implémentation du système de sélection de mode de sécurité
- Séparation claire entre les données de sécurité et les données du wallet
- Suppression des duplications entre 'encrypted-pbkdf2-key' et 'pbkdf2-key'
- Architecture modulaire pour la gestion des credentials

**Modifications :**
- Ajout du composant security-mode-selector pour la sélection du mode de sécurité
- Création des pages séquentielles : security-setup, wallet-setup, birthday-setup
- Implémentation des services de credentials (encryption, storage, webauthn)
- Ajout du service security-mode pour la gestion des modes de sécurité
- Correction du stockage des clés PBKDF2 avec le securityMode dynamique
- Suppression des méthodes redondantes dans StorageService
- Nettoyage des appels redondants dans secure-credentials.service.ts

**Pages affectées :**
- src/components/security-mode-selector/ (nouveau composant)
- src/pages/security-setup/ (nouvelle page)
- src/pages/wallet-setup/ (nouvelle page)
- src/pages/birthday-setup/ (nouvelle page)
- src/services/credentials/ (nouveaux services)
- src/services/security-mode.service.ts (nouveau service)
- src/services/secure-credentials.service.ts (modifié)
- src/services/database.service.ts (modifié)
- src/router.ts (modifié)
- src/pages/home/home.ts (modifié)
2025-10-24 18:29:31 +02:00

412 lines
12 KiB
TypeScript

/**
* SecurityModeService - Gestion des modes de sécurisation
* Gère le stockage et la récupération du mode de sécurisation choisi par l'utilisateur
*/
import { secureLogger } from './secure-logger';
import Database from './database.service';
export type SecurityMode = 'proton-pass' | 'os' | 'browser' | 'otp' | '2fa' | 'password' | 'none';
export interface SecurityModeConfig {
mode: SecurityMode;
name: string;
description: string;
securityLevel: 'high' | 'medium' | 'low' | 'critical';
requiresConfirmation: boolean;
warnings: string[];
implementation: {
useWebAuthn: boolean;
useEncryption: boolean;
usePlatformAuth: boolean;
storageType: 'encrypted' | 'plain' | 'hybrid';
};
}
export class SecurityModeService {
private static instance: SecurityModeService;
private database: Database;
private currentMode: SecurityMode | null = null;
private constructor() {
this.database = new Database();
}
public static getInstance(): SecurityModeService {
if (!SecurityModeService.instance) {
SecurityModeService.instance = new SecurityModeService();
}
return SecurityModeService.instance;
}
/**
* Récupère le mode de sécurisation actuel
*/
public async getCurrentMode(): Promise<SecurityMode | null> {
if (this.currentMode) {
return this.currentMode;
}
try {
// Vérifier que la base de données est disponible
if (!this.database || typeof this.database.getObject !== 'function') {
secureLogger.warn('Database not available, returning null mode', {
component: 'SecurityModeService',
operation: 'getCurrentMode'
});
return null;
}
const storedMode = await this.database.getObject('security_settings', 'current_mode');
this.currentMode = storedMode?.mode || null;
secureLogger.info('Current security mode retrieved', {
component: 'SecurityModeService',
operation: 'getCurrentMode',
mode: this.currentMode
});
return this.currentMode;
} catch (error) {
// Si l'erreur est "object store not found", c'est normal pour un premier lancement
if (error instanceof Error && (error.name === 'NotFoundError' || error.message.includes('object stores was not found'))) {
secureLogger.info('No security mode set yet (first launch)', {
component: 'SecurityModeService',
operation: 'getCurrentMode'
});
return null;
}
secureLogger.error('Failed to retrieve current security mode', error as Error, {
component: 'SecurityModeService',
operation: 'getCurrentMode'
});
return null;
}
}
/**
* Définit le mode de sécurisation
*/
public async setSecurityMode(mode: SecurityMode): Promise<void> {
try {
const modeConfig = this.getSecurityModeConfig(mode);
// Vérifier que la base de données est disponible
if (!this.database || typeof this.database.setObject !== 'function') {
secureLogger.warn('Database not available, setting mode in memory only', {
component: 'SecurityModeService',
operation: 'setSecurityMode',
mode
});
this.currentMode = mode;
return;
}
// Stocker le mode en base
await this.database.setObject('security_settings', 'current_mode', {
mode,
name: modeConfig.name,
description: modeConfig.description,
securityLevel: modeConfig.securityLevel,
timestamp: Date.now(),
implementation: modeConfig.implementation
});
this.currentMode = mode;
secureLogger.info('Security mode set successfully', {
component: 'SecurityModeService',
operation: 'setSecurityMode',
mode,
securityLevel: modeConfig.securityLevel
});
// Émettre un événement pour notifier les autres services
window.dispatchEvent(new CustomEvent('securityModeChanged', {
detail: { mode, config: modeConfig }
}));
} catch (error) {
secureLogger.error('Failed to set security mode', error as Error, {
component: 'SecurityModeService',
operation: 'setSecurityMode',
mode
});
// En cas d'erreur, définir le mode en mémoire seulement
this.currentMode = mode;
secureLogger.warn('Security mode set in memory only due to database error', {
component: 'SecurityModeService',
operation: 'setSecurityMode',
mode
});
}
}
/**
* Récupère la configuration d'un mode de sécurisation
*/
public getSecurityModeConfig(mode: SecurityMode): SecurityModeConfig {
const configs: Record<SecurityMode, SecurityModeConfig> = {
'proton-pass': {
mode: 'proton-pass',
name: 'Proton Pass',
description: 'Utilise Proton Pass pour l\'authentification biométrique et la gestion des clés',
securityLevel: 'high',
requiresConfirmation: false,
warnings: [],
implementation: {
useWebAuthn: true,
useEncryption: true,
usePlatformAuth: true,
storageType: 'encrypted'
}
},
'os': {
mode: 'os',
name: 'Authentificateur OS',
description: 'Utilise l\'authentificateur intégré de votre système d\'exploitation',
securityLevel: 'high',
requiresConfirmation: false,
warnings: [],
implementation: {
useWebAuthn: true,
useEncryption: true,
usePlatformAuth: true,
storageType: 'encrypted'
}
},
'browser': {
mode: 'browser',
name: 'Navigateur',
description: 'Utilise les fonctionnalités de sécurité du navigateur',
securityLevel: 'medium',
requiresConfirmation: false,
warnings: [],
implementation: {
useWebAuthn: true,
useEncryption: true,
usePlatformAuth: false,
storageType: 'encrypted'
}
},
'otp': {
mode: 'otp',
name: 'OTP (Proton Pass Compatible)',
description: 'Utilise un code OTP généré par une application compatible (Proton Pass, Google Authenticator, etc.)',
securityLevel: 'high',
requiresConfirmation: false,
warnings: [],
implementation: {
useWebAuthn: false,
useEncryption: true,
usePlatformAuth: false,
storageType: 'encrypted',
requiresOTP: true
}
},
'2fa': {
mode: '2fa',
name: 'Application 2FA',
description: 'Stockage en clair avec authentification par application 2FA',
securityLevel: 'low',
requiresConfirmation: true,
warnings: [
'⚠️ Clés stockées en clair',
'⚠️ Risque de compromission',
'⚠️ Non recommandé pour des données sensibles'
],
implementation: {
useWebAuthn: false,
useEncryption: false,
usePlatformAuth: false,
storageType: 'plain'
}
},
'password': {
mode: 'password',
name: 'Mot de Passe (Non Sauvegardé)',
description: 'Vos clés sont chiffrées avec un mot de passe que vous devez saisir à chaque utilisation',
securityLevel: 'low',
requiresConfirmation: true,
warnings: [
'⚠️ Le mot de passe n\'est PAS sauvegardé',
'⚠️ NON récupérable en cas d\'oubli',
'⚠️ À saisir à chaque utilisation'
],
implementation: {
useWebAuthn: false,
useEncryption: true,
usePlatformAuth: false,
storageType: 'encrypted',
requiresPassword: true
}
},
'none': {
mode: 'none',
name: 'Aucune Sécurité',
description: 'Stockage en clair sans aucune protection',
securityLevel: 'critical',
requiresConfirmation: true,
warnings: [
'🚨 Clés stockées en clair',
'🚨 Accès non protégé',
'🚨 RISQUE ÉLEVÉ'
],
implementation: {
useWebAuthn: false,
useEncryption: false,
usePlatformAuth: false,
storageType: 'plain'
}
}
};
return configs[mode];
}
/**
* Vérifie si un mode nécessite une confirmation
*/
public requiresConfirmation(mode: SecurityMode): boolean {
const config = this.getSecurityModeConfig(mode);
return config.requiresConfirmation;
}
/**
* Récupère les avertissements pour un mode
*/
public getWarnings(mode: SecurityMode): string[] {
const config = this.getSecurityModeConfig(mode);
return config.warnings;
}
/**
* Vérifie si le mode actuel est sécurisé
*/
public async isCurrentModeSecure(): Promise<boolean> {
const currentMode = await this.getCurrentMode();
if (!currentMode) return false;
const config = this.getSecurityModeConfig(currentMode);
return config.securityLevel === 'high' || config.securityLevel === 'medium';
}
/**
* Récupère tous les modes disponibles
*/
public getAvailableModes(): SecurityMode[] {
return ['proton-pass', 'os', 'browser', '2fa', 'none'];
}
/**
* Récupère les modes recommandés (sécurisés)
*/
public getRecommendedModes(): SecurityMode[] {
return ['proton-pass', 'os', 'browser'];
}
/**
* Récupère les modes non recommandés (non sécurisés)
*/
public getNonRecommendedModes(): SecurityMode[] {
return ['2fa', 'none'];
}
/**
* Vérifie si un mode utilise WebAuthn
*/
public usesWebAuthn(mode: SecurityMode): boolean {
const config = this.getSecurityModeConfig(mode);
return config.implementation.useWebAuthn;
}
/**
* Vérifie si un mode utilise le chiffrement
*/
public usesEncryption(mode: SecurityMode): boolean {
const config = this.getSecurityModeConfig(mode);
return config.implementation.useEncryption;
}
/**
* Vérifie si un mode utilise l'authentificateur de plateforme
*/
public usesPlatformAuth(mode: SecurityMode): boolean {
const config = this.getSecurityModeConfig(mode);
return config.implementation.usePlatformAuth;
}
/**
* Récupère le type de stockage pour un mode
*/
public getStorageType(mode: SecurityMode): 'encrypted' | 'plain' | 'hybrid' {
const config = this.getSecurityModeConfig(mode);
return config.implementation.storageType;
}
/**
* Réinitialise le mode de sécurisation
*/
public async resetSecurityMode(): Promise<void> {
try {
await this.database.deleteObject('security_settings', 'current_mode');
this.currentMode = null;
secureLogger.info('Security mode reset', {
component: 'SecurityModeService',
operation: 'resetSecurityMode'
});
} catch (error) {
secureLogger.error('Failed to reset security mode', error as Error, {
component: 'SecurityModeService',
operation: 'resetSecurityMode'
});
throw error;
}
}
/**
* Récupère l'historique des modes de sécurisation
*/
public async getSecurityModeHistory(): Promise<any[]> {
try {
const history = await this.database.getObject('security_settings', 'mode_history') || [];
return history;
} catch (error) {
secureLogger.error('Failed to retrieve security mode history', error as Error, {
component: 'SecurityModeService',
operation: 'getSecurityModeHistory'
});
return [];
}
}
/**
* Ajoute une entrée à l'historique des modes
*/
private async addToHistory(mode: SecurityMode): Promise<void> {
try {
const history = await this.getSecurityModeHistory();
history.unshift({
mode,
timestamp: Date.now(),
config: this.getSecurityModeConfig(mode)
});
// Garder seulement les 10 dernières entrées
if (history.length > 10) {
history.splice(10);
}
await this.database.setObject('security_settings', 'mode_history', history);
} catch (error) {
secureLogger.error('Failed to add to security mode history', error as Error, {
component: 'SecurityModeService',
operation: 'addToHistory',
mode
});
}
}
}