NicolasCantu aa95537254 fix: correct TypeScript and ESLint errors
**Motivations :**
- Corriger les erreurs TypeScript qui bloquaient la compilation
- Corriger les erreurs ESLint pour améliorer la qualité du code
- Utiliser les bons formats pour secureLogger.error

**Modifications :**
- Corriger les appels secureLogger.error pour passer error comme 2e paramètre
- Ajouter les imports manquants (Database dans security-mode.service.ts)
- Préfixer les variables non utilisées avec _ pour respecter ESLint
- Corriger les comparaisons BigInt (utiliser BigInt(0) au lieu de 0n)
- Ajouter @ts-expect-error pour PasswordCredential API expérimentale
- Corriger le paramètre services non utilisé dans router.ts

**Pages affectées :**
- src/services/service.ts (comparaisons BigInt, imports)
- src/services/security-mode.service.ts (import Database)
- src/services/secure-credentials.service.ts (secureLogger.error, PasswordCredential)
- src/services/credentials/encryption.service.ts (secureLogger.error, salt type)
- src/router.ts (paramètre _services)
- src/components/device-management/device-management.ts (variable _data)
- src/components/secure-credentials/secure-credentials.ts (variable _error)
- src/components/security-mode-selector/security-mode-selector.ts (paramètre _mode)
- src/components/login-modal/login-modal.js (window globals)
2025-10-29 16:37:28 +01:00

389 lines
12 KiB
TypeScript

/**
* SecureCredentialsComponent - Composant pour la gestion des credentials sécurisés
* Interface utilisateur pour la gestion des clés de spend et de scan avec PBKDF2
*/
import { SecureCredentialsService } from '../../services/secure-credentials.service';
import { secureLogger } from '../../services/secure-logger';
import { eventBus } from '../../services/event-bus';
export class SecureCredentialsComponent {
private container: HTMLElement | null = null;
private isInitialized = false;
constructor() {
this.init();
}
/**
* Initialise le composant
*/
private async init(): Promise<void> {
try {
this.container = document.getElementById('secure-credentials-container');
if (!this.container) {
throw new Error('Secure credentials container not found');
}
await this.loadHTML();
await this.loadCSS();
this.attachEventListeners();
await this.updateUI();
this.isInitialized = true;
secureLogger.info('SecureCredentialsComponent initialized', {
component: 'SecureCredentialsComponent',
operation: 'init'
});
} catch (error) {
secureLogger.error('Failed to initialize SecureCredentialsComponent', error as Error, {
component: 'SecureCredentialsComponent',
operation: 'init'
});
}
}
/**
* Charge le HTML du composant
*/
private async loadHTML(): Promise<void> {
try {
const response = await fetch('/src/components/secure-credentials/secure-credentials.html');
const html = await response.text();
this.container!.innerHTML = html;
} catch (error) {
secureLogger.error('Failed to load secure credentials HTML', error as Error, {
component: 'SecureCredentialsComponent',
operation: 'loadHTML'
});
}
}
/**
* Charge le CSS du composant
*/
private async loadCSS(): Promise<void> {
try {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = '/src/components/secure-credentials/secure-credentials.css';
document.head.appendChild(link);
} catch (error) {
secureLogger.error('Failed to load secure credentials CSS', error as Error, {
component: 'SecureCredentialsComponent',
operation: 'loadCSS'
});
}
}
/**
* Attache les écouteurs d'événements
*/
private attachEventListeners(): void {
// Formulaire de création de credentials
const createForm = document.getElementById('create-credentials-form') as HTMLFormElement;
if (createForm) {
createForm.addEventListener('submit', this.handleCreateCredentials.bind(this));
}
// Formulaire d'accès aux credentials
const accessForm = document.getElementById('access-credentials-form') as HTMLFormElement;
if (accessForm) {
accessForm.addEventListener('submit', this.handleAccessCredentials.bind(this));
}
// Validation du mot de passe en temps réel
const passwordInput = document.getElementById('password') as HTMLInputElement;
if (passwordInput) {
passwordInput.addEventListener('input', this.handlePasswordInput.bind(this));
}
// Boutons d'action
const refreshBtn = document.getElementById('refresh-credentials-btn');
if (refreshBtn) {
refreshBtn.addEventListener('click', this.handleRefreshCredentials.bind(this));
}
const deleteBtn = document.getElementById('delete-credentials-btn');
if (deleteBtn) {
deleteBtn.addEventListener('click', this.handleDeleteCredentials.bind(this));
}
// Écouter les événements du service
eventBus.on('credentials:created', this.handleCredentialsCreated.bind(this));
eventBus.on('credentials:deleted', this.handleCredentialsDeleted.bind(this));
}
/**
* Gère la création de credentials
*/
private async handleCreateCredentials(event: Event): Promise<void> {
event.preventDefault();
const form = event.target as HTMLFormElement;
const formData = new FormData(form);
const password = formData.get('password') as string;
const confirmPassword = formData.get('confirm-password') as string;
if (password !== confirmPassword) {
this.showMessage('Les mots de passe ne correspondent pas', 'error');
return;
}
try {
this.showMessage('Création des credentials en cours...', 'info');
// Générer les credentials
const secureCredentialsService = SecureCredentialsService.getInstance();
const credentials = await secureCredentialsService.generateSecureCredentials(password);
// Stocker les credentials
await secureCredentialsService.storeCredentials(credentials, password);
this.showMessage('Credentials créés et stockés avec succès !', 'success');
await this.updateUI();
// Émettre l'événement
eventBus.emit('credentials:created', { credentials });
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Erreur inconnue';
this.showMessage(`Erreur lors de la création des credentials: ${errorMessage}`, 'error');
secureLogger.error('Failed to create credentials', error as Error, {
component: 'SecureCredentialsComponent',
operation: 'handleCreateCredentials'
});
}
}
/**
* Gère l'accès aux credentials
*/
private async handleAccessCredentials(event: Event): Promise<void> {
event.preventDefault();
const form = event.target as HTMLFormElement;
const formData = new FormData(form);
const password = formData.get('access-password') as string;
try {
this.showMessage('Récupération des credentials...', 'info');
const secureCredentialsService = SecureCredentialsService.getInstance();
const credentials = await secureCredentialsService.retrieveCredentials(password);
if (credentials) {
this.showMessage('Credentials récupérés avec succès !', 'success');
await this.updateCredentialsInfo(credentials);
await this.updateUI();
} else {
this.showMessage('Aucun credential trouvé ou mot de passe incorrect', 'error');
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Erreur inconnue';
this.showMessage(`Erreur lors de la récupération des credentials: ${errorMessage}`, 'error');
secureLogger.error('Failed to access credentials', error as Error, {
component: 'SecureCredentialsComponent',
operation: 'handleAccessCredentials'
});
}
}
/**
* Gère la validation du mot de passe en temps réel
*/
private handlePasswordInput(event: Event): void {
const input = event.target as HTMLInputElement;
const password = input.value;
const strengthDiv = document.getElementById('password-strength');
if (strengthDiv) {
strengthDiv.className = 'password-strength';
if (password.length === 0) {
strengthDiv.textContent = '';
return;
}
// Simple password strength check
const score = password.length >= 12 ? (password.length >= 16 ? 5 : 4) : (password.length >= 8 ? 3 : 2);
if (score < 3) {
strengthDiv.className += ' weak';
strengthDiv.textContent = 'Mot de passe faible';
} else if (score < 5) {
strengthDiv.className += ' medium';
strengthDiv.textContent = 'Mot de passe moyen';
} else {
strengthDiv.className += ' strong';
strengthDiv.textContent = 'Mot de passe fort';
}
}
}
/**
* Gère l'actualisation des credentials
*/
private async handleRefreshCredentials(): Promise<void> {
try {
await this.updateUI();
this.showMessage('Credentials actualisés', 'success');
} catch (_error) {
this.showMessage('Erreur lors de l\'actualisation', 'error');
}
}
/**
* Gère la suppression des credentials
*/
private async handleDeleteCredentials(): Promise<void> {
if (!confirm('Êtes-vous sûr de vouloir supprimer tous les credentials ? Cette action est irréversible.')) {
return;
}
try {
// TODO: Implement credentials deletion
console.log('Credentials deletion requested but not implemented');
this.showMessage('Suppression des credentials non implémentée', 'warning');
await this.updateUI();
// Émettre l'événement
eventBus.emit('credentials:deleted');
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Erreur inconnue';
this.showMessage(`Erreur lors de la suppression: ${errorMessage}`, 'error');
secureLogger.error('Failed to delete credentials', error as Error, {
component: 'SecureCredentialsComponent',
operation: 'handleDeleteCredentials'
});
}
}
/**
* Met à jour l'interface utilisateur
*/
private async updateUI(): Promise<void> {
try {
const secureCredentialsService = SecureCredentialsService.getInstance();
const hasCredentials = await secureCredentialsService.hasCredentials();
const createSection = document.getElementById('create-credentials-section');
const accessSection = document.getElementById('access-credentials-section');
const manageSection = document.getElementById('manage-credentials-section');
if (hasCredentials) {
createSection!.style.display = 'none';
accessSection!.style.display = 'block';
manageSection!.style.display = 'block';
} else {
createSection!.style.display = 'block';
accessSection!.style.display = 'none';
manageSection!.style.display = 'none';
}
// Mettre à jour le statut
const statusElement = document.getElementById('credentials-status');
if (statusElement) {
statusElement.textContent = hasCredentials ? 'Disponibles' : 'Non disponibles';
statusElement.className = hasCredentials ? 'value success' : 'value error';
}
} catch (error) {
secureLogger.error('Failed to update UI', error as Error, {
component: 'SecureCredentialsComponent',
operation: 'updateUI'
});
}
}
/**
* Met à jour les informations des credentials
*/
private async updateCredentialsInfo(credentials: any): Promise<void> {
const spendKeyStatus = document.getElementById('spend-key-status');
const scanKeyStatus = document.getElementById('scan-key-status');
const timestampElement = document.getElementById('credentials-timestamp');
if (spendKeyStatus) {
spendKeyStatus.textContent = credentials.spendKey ? 'Disponible' : 'Non disponible';
spendKeyStatus.className = credentials.spendKey ? 'value success' : 'value error';
}
if (scanKeyStatus) {
scanKeyStatus.textContent = credentials.scanKey ? 'Disponible' : 'Non disponible';
scanKeyStatus.className = credentials.scanKey ? 'value success' : 'value error';
}
if (timestampElement && credentials.timestamp) {
const date = new Date(credentials.timestamp);
timestampElement.textContent = date.toLocaleString();
}
}
/**
* Affiche un message à l'utilisateur
*/
private showMessage(message: string, type: 'success' | 'error' | 'warning' | 'info'): void {
const messagesContainer = document.getElementById('credentials-messages');
if (!messagesContainer) {return;}
const messageDiv = document.createElement('div');
messageDiv.className = `message ${type}`;
messageDiv.textContent = message;
messagesContainer.appendChild(messageDiv);
// Supprimer le message après 5 secondes
setTimeout(() => {
if (messageDiv.parentNode) {
messageDiv.parentNode.removeChild(messageDiv);
}
}, 5000);
}
/**
* Gère l'événement de création de credentials
*/
private handleCredentialsCreated(data: any): void {
// Use data variable
console.log('Credentials created:', data);
this.showMessage('Credentials créés avec succès !', 'success');
this.updateUI();
}
/**
* Gère l'événement de suppression de credentials
*/
private handleCredentialsDeleted(): void {
this.showMessage('Credentials supprimés', 'info');
this.updateUI();
}
/**
* Détruit le composant
*/
destroy(): void {
if (this.isInitialized) {
// Nettoyer les écouteurs d'événements
eventBus.off('credentials:created', this.handleCredentialsCreated.bind(this));
eventBus.off('credentials:deleted', this.handleCredentialsDeleted.bind(this));
this.isInitialized = false;
secureLogger.info('SecureCredentialsComponent destroyed', {
component: 'SecureCredentialsComponent',
operation: 'destroy'
});
}
}
}
// Export du composant
export default SecureCredentialsComponent;