Motivations: - Fix 502 en prod via build multi-pages et routes stables - Stabilize IndexedDB (création stores) et faucet obligatoire - Déploiement robuste: port 3004 garanti et logs Modifications: - Vite: inputs multi-pages, alias npm deploy:front - Router/redirects: chemins - Pages setup: URLs corrigées, suppression log faucet disabled - DB: bump version à 5, upgrade crée stores manquants - Script: scripts/deploy_front.sh (kill 3004, clean, build, start bg) - Lint: perf monitor param non utilisé, warnings corrigés Page affectées: - vite.config.ts, src/router.ts - src/pages/* (home, pairing, block-sync, wallet-setup, security-setup) - src/services/* (database-config, performance-monitor) - package.json, scripts/deploy_front.sh
159 lines
4.5 KiB
TypeScript
159 lines
4.5 KiB
TypeScript
/**
|
|
* DeviceRepository - Interface pour la gestion des appareils
|
|
* Sépare la logique métier de l'accès aux données
|
|
*/
|
|
import { Device } from '../../pkg/sdk_client';
|
|
import { secureLogger } from '../services/secure-logger';
|
|
|
|
/* eslint-disable no-unused-vars */
|
|
export interface DeviceRepository {
|
|
getDevice(): Promise<Device | null>;
|
|
saveDevice(_device: Device): Promise<void>;
|
|
deleteDevice(): Promise<void>;
|
|
hasDevice(): Promise<boolean>;
|
|
getDeviceAddress(): Promise<string | null>;
|
|
updateDevice(_device: Partial<Device>): Promise<void>;
|
|
}
|
|
/* eslint-enable no-unused-vars */
|
|
|
|
export class DeviceRepositoryImpl implements DeviceRepository {
|
|
constructor(private database: any) {} // database used via methods
|
|
|
|
async getDevice(): Promise<Device | null> {
|
|
try {
|
|
const device = await this.database.get('devices', 'current');
|
|
if (device) {
|
|
secureLogger.debug('Device retrieved from database', {
|
|
component: 'DeviceRepository',
|
|
operation: 'getDevice',
|
|
hasAddress: !!device.sp_wallet?.address
|
|
});
|
|
return this.deserializeDevice(device);
|
|
}
|
|
return null;
|
|
} catch (error) {
|
|
secureLogger.error('Failed to get device from database', error as Error, {
|
|
component: 'DeviceRepository',
|
|
operation: 'getDevice'
|
|
});
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async saveDevice(device: Device): Promise<void> {
|
|
try {
|
|
const serialized = this.serializeDevice(device);
|
|
await this.database.put('devices', serialized, 'current');
|
|
|
|
secureLogger.info('Device saved to database', {
|
|
component: 'DeviceRepository',
|
|
operation: 'saveDevice',
|
|
hasAddress: !!device.sp_wallet?.address
|
|
});
|
|
} catch (error) {
|
|
secureLogger.error('Failed to save device to database', error as Error, {
|
|
component: 'DeviceRepository',
|
|
operation: 'saveDevice'
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async deleteDevice(): Promise<void> {
|
|
try {
|
|
await this.database.delete('devices', 'current');
|
|
|
|
secureLogger.info('Device deleted from database', {
|
|
component: 'DeviceRepository',
|
|
operation: 'deleteDevice'
|
|
});
|
|
} catch (error) {
|
|
secureLogger.error('Failed to delete device from database', error as Error, {
|
|
component: 'DeviceRepository',
|
|
operation: 'deleteDevice'
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async hasDevice(): Promise<boolean> {
|
|
try {
|
|
const device = await this.getDevice();
|
|
return device !== null;
|
|
} catch (error) {
|
|
secureLogger.error('Failed to check if device exists', error as Error, {
|
|
component: 'DeviceRepository',
|
|
operation: 'hasDevice'
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async getDeviceAddress(): Promise<string | null> {
|
|
try {
|
|
const device = await this.getDevice();
|
|
return device?.sp_wallet?.address || null;
|
|
} catch (error) {
|
|
secureLogger.error('Failed to get device address', error as Error, {
|
|
component: 'DeviceRepository',
|
|
operation: 'getDeviceAddress'
|
|
});
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async updateDevice(updates: Partial<Device>): Promise<void> {
|
|
try {
|
|
const currentDevice = await this.getDevice();
|
|
if (!currentDevice) {
|
|
throw new Error('No device found to update');
|
|
}
|
|
|
|
const updatedDevice = { ...currentDevice, ...updates };
|
|
await this.saveDevice(updatedDevice);
|
|
|
|
secureLogger.info('Device updated in database', {
|
|
component: 'DeviceRepository',
|
|
operation: 'updateDevice',
|
|
updatedFields: Object.keys(updates)
|
|
});
|
|
} catch (error) {
|
|
secureLogger.error('Failed to update device', error as Error, {
|
|
component: 'DeviceRepository',
|
|
operation: 'updateDevice'
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sérialise un appareil pour le stockage
|
|
*/
|
|
private serializeDevice(device: Device): any {
|
|
return {
|
|
...device,
|
|
// Ne pas exposer les clés privées dans les logs
|
|
sp_wallet: device.sp_wallet ? {
|
|
...device.sp_wallet,
|
|
private_key: '[REDACTED]' // Masquer la clé privée
|
|
} : undefined
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Désérialise un appareil depuis le stockage
|
|
*/
|
|
private deserializeDevice(serialized: any): Device {
|
|
return {
|
|
...serialized,
|
|
// Restaurer la clé privée si elle existe
|
|
sp_wallet: serialized.sp_wallet ? {
|
|
...serialized.sp_wallet,
|
|
private_key: serialized.sp_wallet.private_key === '[REDACTED]'
|
|
? undefined
|
|
: serialized.sp_wallet.private_key
|
|
} : undefined
|
|
};
|
|
}
|
|
}
|