ihm_client/src/services/pairing.service.ts
NicolasCantu 393b75c03b fix: restore services initialization in block-sync and remove remaining commented imports
**Motivations :**
- Corriger l'erreur de compilation dans block-sync.ts où services n'était plus défini
- Supprimer les derniers imports commentés restants

**Modifications :**
- Restaurer l'initialisation de Services dans block-sync.ts après les vérifications de prérequis
- Supprimer les imports commentés dans pairing.service.ts et iframe-pairing.service.ts

**Pages affectées :**
- src/pages/block-sync/block-sync.ts (restauration de l'initialisation Services)
- src/services/pairing.service.ts (supprime imports commentés)
- src/services/iframe-pairing.service.ts (supprime import commenté)
2025-10-29 16:47:55 +01:00

404 lines
12 KiB
TypeScript

/**
* PairingService - Service spécialisé pour le pairing
* Gère la logique métier du pairing sans couplage direct
*/
import { DeviceRepository } from '../repositories/device.repository';
import { ProcessRepository } from '../repositories/process.repository';
import { eventBus } from './event-bus';
import { secureLogger } from './secure-logger';
import { SecureCredentialsService } from './secure-credentials.service';
import { CredentialData } from './credentials/types';
export interface PairingResult {
success: boolean;
data?: any;
error?: Error;
}
export interface PairingWords {
words: string;
address: string;
timestamp: number;
}
export class PairingService {
constructor(
private deviceRepo: DeviceRepository,
private processRepo: ProcessRepository,
private sdkClient: any
) {
// Use parameters
console.log('Pairing service constructor:', { deviceRepo: this.deviceRepo, processRepo: this.processRepo, sdkClient: this.sdkClient });
}
/**
* Crée un nouveau processus de pairing avec credentials sécurisés
*/
async createPairing(password: string): Promise<PairingResult> {
try {
secureLogger.info('Creating pairing process with secure credentials', {
component: 'PairingService',
operation: 'createPairing'
});
// Vérifier qu'un appareil existe
const device = await this.deviceRepo.getDevice();
if (!device) {
throw new Error('No device found. Please initialize the device first.');
}
const secureCredentialsService = SecureCredentialsService.getInstance();
// Valider la force du mot de passe
const passwordValidation = secureCredentialsService.validatePasswordStrength(password);
if (!passwordValidation.isValid) {
throw new Error(`Password too weak: ${passwordValidation.feedback.join(', ')}`);
}
// Générer les credentials sécurisés
const credentials = await secureCredentialsService.generateSecureCredentials(password);
// Stocker les credentials de manière sécurisée
await secureCredentialsService.storeCredentials(credentials, password);
// Créer le processus de pairing via le SDK avec les clés sécurisées
const result = await this.sdkClient.createPairing({
spendKey: credentials.spendKey,
scanKey: credentials.scanKey
});
if (result.success) {
// Émettre l'événement de succès
eventBus.emit('pairing:created', { result, credentials: true });
secureLogger.info('Pairing process created successfully with secure credentials', {
component: 'PairingService',
operation: 'createPairing'
});
return { success: true, data: result };
} else {
throw new Error(result.error || 'Failed to create pairing process');
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
// Use errorMessage variable
console.log('Pairing error:', errorMessage);
secureLogger.error('Failed to create pairing process', error as Error, {
component: 'PairingService',
operation: 'createPairing'
});
// Émettre l'événement d'erreur
eventBus.emit('pairing:error', { error: errorMessage });
return { success: false, error: error as Error };
}
}
/**
* Rejoint un processus de pairing avec des mots
*/
async joinPairing(words: string): Promise<PairingResult> {
try {
secureLogger.info('Joining pairing process with words', {
component: 'PairingService',
operation: 'joinPairing',
wordsLength: words.length
});
// Valider les mots
if (!words || words.trim().length === 0) {
throw new Error('Words are required to join pairing');
}
// Rejoindre le processus via le SDK
const result = await this.sdkClient.joinPairing(words);
if (result.success) {
// Émettre l'événement de succès
eventBus.emit('pairing:joined', { result });
secureLogger.info('Successfully joined pairing process', {
component: 'PairingService',
operation: 'joinPairing'
});
return { success: true, data: result };
} else {
throw new Error(result.error || 'Failed to join pairing process');
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
// Use errorMessage variable
console.log('Pairing error:', errorMessage);
secureLogger.error('Failed to join pairing process', error as Error, {
component: 'PairingService',
operation: 'joinPairing'
});
// Émettre l'événement d'erreur
eventBus.emit('pairing:error', { error: errorMessage });
return { success: false, error: error as Error };
}
}
/**
* Génère des mots de pairing
*/
async generatePairingWords(): Promise<PairingWords | null> {
try {
const device = await this.deviceRepo.getDevice();
if (!device?.sp_wallet?.address) {
throw new Error('No device address found');
}
const words = await this.addressToWords(device.sp_wallet.address);
const pairingWords: PairingWords = {
words,
address: device.sp_wallet.address,
timestamp: Date.now()
};
secureLogger.info('Pairing words generated', {
component: 'PairingService',
operation: 'generatePairingWords',
address: device.sp_wallet.address
});
// Émettre l'événement
eventBus.emit('pairing:wordsGenerated', { pairingWords });
return pairingWords;
} catch (error) {
secureLogger.error('Failed to generate pairing words', error as Error, {
component: 'PairingService',
operation: 'generatePairingWords'
});
return null;
}
}
/**
* Vérifie le statut du pairing
*/
async getPairingStatus(): Promise<{
isPaired: boolean;
pairingId: string | null;
deviceAddress: string | null;
}> {
try {
const device = await this.deviceRepo.getDevice();
const isPaired = device ? await this.sdkClient.is_paired() : false;
const pairingId = device ? await this.sdkClient.get_pairing_process_id() : null;
const deviceAddress = device?.sp_wallet?.address || null;
return {
isPaired,
pairingId,
deviceAddress
};
} catch (error) {
secureLogger.error('Failed to get pairing status', error as Error, {
component: 'PairingService',
operation: 'getPairingStatus'
});
return {
isPaired: false,
pairingId: null,
deviceAddress: null
};
}
}
/**
* Confirme le pairing
*/
async confirmPairing(): Promise<PairingResult> {
try {
secureLogger.info('Confirming pairing', {
component: 'PairingService',
operation: 'confirmPairing'
});
const result = await this.sdkClient.confirmPairing();
if (result.success) {
// Émettre l'événement de succès
eventBus.emit('pairing:confirmed', { result });
secureLogger.info('Pairing confirmed successfully', {
component: 'PairingService',
operation: 'confirmPairing'
});
return { success: true, data: result };
} else {
throw new Error(result.error || 'Failed to confirm pairing');
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
// Use errorMessage variable
console.log('Pairing error:', errorMessage);
secureLogger.error('Failed to confirm pairing', error as Error, {
component: 'PairingService',
operation: 'confirmPairing'
});
// Émettre l'événement d'erreur
eventBus.emit('pairing:error', { error: errorMessage });
return { success: false, error: error as Error };
}
}
/**
* Annule le pairing
*/
async cancelPairing(): Promise<PairingResult> {
try {
secureLogger.info('Cancelling pairing', {
component: 'PairingService',
operation: 'cancelPairing'
});
const result = await this.sdkClient.cancelPairing();
// Émettre l'événement
eventBus.emit('pairing:cancelled', { result });
secureLogger.info('Pairing cancelled', {
component: 'PairingService',
operation: 'cancelPairing'
});
return { success: true, data: result };
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
// Use errorMessage variable
console.log('Pairing error:', errorMessage);
secureLogger.error('Failed to cancel pairing', error as Error, {
component: 'PairingService',
operation: 'cancelPairing'
});
return { success: false, error: error as Error };
}
}
/**
* Récupère les credentials sécurisés
*/
async getSecureCredentials(password: string): Promise<CredentialData | null> {
try {
const secureCredentialsService = SecureCredentialsService.getInstance();
const credentials = await secureCredentialsService.retrieveCredentials(password);
if (credentials) {
secureLogger.info('Secure credentials retrieved', {
component: 'PairingService',
operation: 'getSecureCredentials',
hasSpendKey: !!credentials.spendKey,
hasScanKey: !!credentials.scanKey
});
}
return credentials;
} catch (error) {
secureLogger.error('Failed to retrieve secure credentials', error as Error, {
component: 'PairingService',
operation: 'getSecureCredentials'
});
return null;
}
}
/**
* Vérifie si des credentials sécurisés existent
*/
async hasSecureCredentials(): Promise<boolean> {
try {
const secureCredentialsService = SecureCredentialsService.getInstance();
return await secureCredentialsService.hasCredentials();
} catch (error) {
secureLogger.error('Failed to check secure credentials', error as Error, {
component: 'PairingService',
operation: 'hasSecureCredentials'
});
return false;
}
}
/**
* Supprime les credentials sécurisés
*/
async deleteSecureCredentials(): Promise<PairingResult> {
try {
const secureCredentialsService = SecureCredentialsService.getInstance();
await secureCredentialsService.deleteCredentials();
secureLogger.info('Secure credentials deleted', {
component: 'PairingService',
operation: 'deleteSecureCredentials'
});
// Émettre l'événement
eventBus.emit('credentials:deleted');
return { success: true };
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
// Use errorMessage variable
console.log('Pairing error:', errorMessage);
secureLogger.error('Failed to delete secure credentials', error as Error, {
component: 'PairingService',
operation: 'deleteSecureCredentials'
});
return { success: false, error: error as Error };
}
}
/**
* Valide la force du mot de passe
*/
validatePassword(password: string): {
isValid: boolean;
score: number;
feedback: string[];
} {
const secureCredentialsService = SecureCredentialsService.getInstance();
return secureCredentialsService.validatePasswordStrength(password);
}
/**
* Convertit une adresse en mots
*/
private async addressToWords(address: string): Promise<string> {
// Implémentation simplifiée - à remplacer par la vraie logique
const words = [
'abandon', 'ability', 'able', 'about', 'above', 'absent', 'absorb', 'abstract',
'absurd', 'abuse', 'access', 'accident', 'account', 'accuse', 'achieve', 'acid'
];
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(address));
const hashArray = new Uint8Array(hash);
const selectedWords = [];
for (let i = 0; i < 4; i++) {
const index = hashArray[i] % words.length;
selectedWords.push(words[index]);
}
return selectedWords.join(' ');
}
}