151 lines
3.9 KiB
TypeScript
151 lines
3.9 KiB
TypeScript
/**
|
|
* Utilitaire de stockage sécurisé pour BTP Xpress
|
|
* Gestion des tokens et données sensibles
|
|
*/
|
|
|
|
export interface StorageItem {
|
|
value: any;
|
|
timestamp: number;
|
|
expiry?: number;
|
|
}
|
|
|
|
export class SecureStorage {
|
|
private static readonly PREFIX = 'btpxpress_';
|
|
|
|
/**
|
|
* Stocke une valeur de manière sécurisée
|
|
*/
|
|
static set(key: string, value: any, expiryMinutes?: number): void {
|
|
try {
|
|
const item: StorageItem = {
|
|
value,
|
|
timestamp: Date.now(),
|
|
expiry: expiryMinutes ? Date.now() + (expiryMinutes * 60 * 1000) : undefined
|
|
};
|
|
|
|
const storageKey = this.PREFIX + key;
|
|
const encrypted = this.encrypt(JSON.stringify(item));
|
|
|
|
// Utiliser sessionStorage par défaut pour plus de sécurité
|
|
sessionStorage.setItem(storageKey, encrypted);
|
|
} catch (error) {
|
|
console.error('Erreur lors du stockage sécurisé:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Récupère une valeur stockée
|
|
*/
|
|
static get(key: string): any {
|
|
try {
|
|
const storageKey = this.PREFIX + key;
|
|
const encrypted = sessionStorage.getItem(storageKey) || localStorage.getItem(storageKey);
|
|
|
|
if (!encrypted) {
|
|
return null;
|
|
}
|
|
|
|
const decrypted = this.decrypt(encrypted);
|
|
const item: StorageItem = JSON.parse(decrypted);
|
|
|
|
// Vérifier l'expiration
|
|
if (item.expiry && Date.now() > item.expiry) {
|
|
this.remove(key);
|
|
return null;
|
|
}
|
|
|
|
return item.value;
|
|
} catch (error) {
|
|
console.error('Erreur lors de la récupération sécurisée:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Supprime une valeur stockée
|
|
*/
|
|
static remove(key: string): void {
|
|
try {
|
|
const storageKey = this.PREFIX + key;
|
|
sessionStorage.removeItem(storageKey);
|
|
localStorage.removeItem(storageKey);
|
|
} catch (error) {
|
|
console.error('Erreur lors de la suppression sécurisée:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Vide tout le stockage sécurisé
|
|
*/
|
|
static clearAll(): void {
|
|
try {
|
|
// Nettoyer sessionStorage
|
|
Object.keys(sessionStorage).forEach(key => {
|
|
if (key.startsWith(this.PREFIX)) {
|
|
sessionStorage.removeItem(key);
|
|
}
|
|
});
|
|
|
|
// Nettoyer localStorage
|
|
Object.keys(localStorage).forEach(key => {
|
|
if (key.startsWith(this.PREFIX)) {
|
|
localStorage.removeItem(key);
|
|
}
|
|
});
|
|
|
|
// Nettoyer aussi les anciens tokens
|
|
sessionStorage.removeItem('auth_token');
|
|
localStorage.removeItem('auth_token');
|
|
localStorage.removeItem('token');
|
|
localStorage.removeItem('user');
|
|
} catch (error) {
|
|
console.error('Erreur lors du nettoyage sécurisé:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Vérifie si une clé existe et n'est pas expirée
|
|
*/
|
|
static exists(key: string): boolean {
|
|
return this.get(key) !== null;
|
|
}
|
|
|
|
/**
|
|
* Chiffrement simple (Base64 + rotation)
|
|
* Note: Pour un vrai projet, utiliser une vraie bibliothèque de chiffrement
|
|
*/
|
|
private static encrypt(data: string): string {
|
|
try {
|
|
// Chiffrement simple avec Base64 et rotation de caractères
|
|
const rotated = data.split('').map(char =>
|
|
String.fromCharCode(char.charCodeAt(0) + 3)
|
|
).join('');
|
|
|
|
return btoa(rotated);
|
|
} catch (error) {
|
|
console.error('Erreur de chiffrement:', error);
|
|
return btoa(data); // Fallback vers Base64 simple
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Déchiffrement simple
|
|
*/
|
|
private static decrypt(encrypted: string): string {
|
|
try {
|
|
const decoded = atob(encrypted);
|
|
|
|
// Dérotation des caractères
|
|
return decoded.split('').map(char =>
|
|
String.fromCharCode(char.charCodeAt(0) - 3)
|
|
).join('');
|
|
} catch (error) {
|
|
console.error('Erreur de déchiffrement:', error);
|
|
return atob(encrypted); // Fallback vers Base64 simple
|
|
}
|
|
}
|
|
}
|
|
|
|
// Export par défaut pour compatibilité
|
|
export default SecureStorage;
|