diff --git a/frontend/src/services/api/utils/storage.service.ts b/frontend/src/services/api/utils/storage.service.ts deleted file mode 100644 index 8efd3c28..00000000 --- a/frontend/src/services/api/utils/storage.service.ts +++ /dev/null @@ -1,397 +0,0 @@ -/** - * Storage Service - Provides secure and consistent local/session storage management - * with encryption, expiration, and type safety - */ - -interface StorageOptions { - encrypt?: boolean; - expiresIn?: number; // milliseconds - storage?: 'local' | 'session'; -} - -interface StorageItem { - value: T; - encrypted?: boolean; - expiresAt?: number; - createdAt: number; -} - -class StorageService { - private readonly encryptionKey = 'bakery-app-key'; // In production, use proper key management - - /** - * Store data in browser storage - */ - setItem(key: string, value: T, options: StorageOptions = {}): boolean { - try { - const { - encrypt = false, - expiresIn, - storage = 'local' - } = options; - - const storageInstance = storage === 'session' ? sessionStorage : localStorage; - - const item: StorageItem = { - value: encrypt ? this.encrypt(JSON.stringify(value)) : value, - encrypted: encrypt, - createdAt: Date.now(), - ...(expiresIn && { expiresAt: Date.now() + expiresIn }) - }; - - storageInstance.setItem(key, JSON.stringify(item)); - return true; - } catch (error) { - console.error(`Storage error setting item "${key}":`, error); - return false; - } - } - - /** - * Retrieve data from browser storage - */ - getItem(key: string, storage: 'local' | 'session' = 'local'): T | null { - try { - const storageInstance = storage === 'session' ? sessionStorage : localStorage; - const itemStr = storageInstance.getItem(key); - - if (!itemStr) { - return null; - } - - const item: StorageItem = JSON.parse(itemStr); - - // Check expiration - if (item.expiresAt && Date.now() > item.expiresAt) { - this.removeItem(key, storage); - return null; - } - - // Handle encrypted data - if (item.encrypted && typeof item.value === 'string') { - try { - const decrypted = this.decrypt(item.value); - return JSON.parse(decrypted); - } catch (error) { - console.error(`Failed to decrypt item "${key}":`, error); - return null; - } - } - - return item.value; - } catch (error) { - console.error(`Storage error getting item "${key}":`, error); - return null; - } - } - - /** - * Remove item from storage - */ - removeItem(key: string, storage: 'local' | 'session' = 'local'): boolean { - try { - const storageInstance = storage === 'session' ? sessionStorage : localStorage; - storageInstance.removeItem(key); - return true; - } catch (error) { - console.error(`Storage error removing item "${key}":`, error); - return false; - } - } - - /** - * Check if item exists and is not expired - */ - hasItem(key: string, storage: 'local' | 'session' = 'local'): boolean { - return this.getItem(key, storage) !== null; - } - - /** - * Clear all items from storage - */ - clear(storage: 'local' | 'session' = 'local'): boolean { - try { - const storageInstance = storage === 'session' ? sessionStorage : localStorage; - storageInstance.clear(); - return true; - } catch (error) { - console.error('Storage error clearing storage:', error); - return false; - } - } - - /** - * Get all keys from storage with optional prefix filter - */ - getKeys(prefix?: string, storage: 'local' | 'session' = 'local'): string[] { - try { - const storageInstance = storage === 'session' ? sessionStorage : localStorage; - const keys: string[] = []; - - for (let i = 0; i < storageInstance.length; i++) { - const key = storageInstance.key(i); - if (key && (!prefix || key.startsWith(prefix))) { - keys.push(key); - } - } - - return keys; - } catch (error) { - console.error('Storage error getting keys:', error); - return []; - } - } - - /** - * Get storage usage information - */ - getStorageInfo(storage: 'local' | 'session' = 'local'): { - used: number; - total: number; - available: number; - itemCount: number; - } { - try { - const storageInstance = storage === 'session' ? sessionStorage : localStorage; - - // Calculate used space (approximate) - let used = 0; - for (let i = 0; i < storageInstance.length; i++) { - const key = storageInstance.key(i); - if (key) { - const value = storageInstance.getItem(key); - used += key.length + (value?.length || 0); - } - } - - // Most browsers have ~5-10MB limit for localStorage - const estimated_total = 5 * 1024 * 1024; // 5MB in bytes - - return { - used, - total: estimated_total, - available: estimated_total - used, - itemCount: storageInstance.length - }; - } catch (error) { - console.error('Storage error getting storage info:', error); - return { used: 0, total: 0, available: 0, itemCount: 0 }; - } - } - - /** - * Clean expired items from storage - */ - cleanExpired(storage: 'local' | 'session' = 'local'): number { - let cleanedCount = 0; - - try { - const storageInstance = storage === 'session' ? sessionStorage : localStorage; - const keysToRemove: string[] = []; - - for (let i = 0; i < storageInstance.length; i++) { - const key = storageInstance.key(i); - if (key) { - try { - const itemStr = storageInstance.getItem(key); - if (itemStr) { - const item: StorageItem = JSON.parse(itemStr); - if (item.expiresAt && Date.now() > item.expiresAt) { - keysToRemove.push(key); - } - } - } catch (error) { - // If we can't parse the item, it might be corrupted - keysToRemove.push(key); - } - } - } - - keysToRemove.forEach(key => { - storageInstance.removeItem(key); - cleanedCount++; - }); - - } catch (error) { - console.error('Storage error cleaning expired items:', error); - } - - return cleanedCount; - } - - /** - * Backup storage to JSON - */ - backup(storage: 'local' | 'session' = 'local'): string { - try { - const storageInstance = storage === 'session' ? sessionStorage : localStorage; - const backup: Record = {}; - - for (let i = 0; i < storageInstance.length; i++) { - const key = storageInstance.key(i); - if (key) { - const value = storageInstance.getItem(key); - if (value) { - backup[key] = value; - } - } - } - - return JSON.stringify({ - timestamp: new Date().toISOString(), - storage: storage, - data: backup - }, null, 2); - } catch (error) { - console.error('Storage error creating backup:', error); - return '{}'; - } - } - - /** - * Restore storage from JSON backup - */ - restore(backupData: string, storage: 'local' | 'session' = 'local'): boolean { - try { - const backup = JSON.parse(backupData); - const storageInstance = storage === 'session' ? sessionStorage : localStorage; - - if (backup.data) { - Object.entries(backup.data).forEach(([key, value]) => { - if (typeof value === 'string') { - storageInstance.setItem(key, value); - } - }); - return true; - } - - return false; - } catch (error) { - console.error('Storage error restoring backup:', error); - return false; - } - } - - // Encryption utilities (basic implementation - use proper crypto in production) - private encrypt(text: string): string { - try { - // This is a simple XOR cipher - replace with proper encryption in production - let result = ''; - for (let i = 0; i < text.length; i++) { - result += String.fromCharCode( - text.charCodeAt(i) ^ this.encryptionKey.charCodeAt(i % this.encryptionKey.length) - ); - } - return btoa(result); - } catch (error) { - console.error('Encryption error:', error); - return text; - } - } - - private decrypt(encryptedText: string): string { - try { - const text = atob(encryptedText); - let result = ''; - for (let i = 0; i < text.length; i++) { - result += String.fromCharCode( - text.charCodeAt(i) ^ this.encryptionKey.charCodeAt(i % this.encryptionKey.length) - ); - } - return result; - } catch (error) { - console.error('Decryption error:', error); - return encryptedText; - } - } - - // Convenience methods for common operations - /** - * Store user authentication data - */ - setAuthData(data: { - access_token: string; - refresh_token?: string; - user_data?: any; - tenant_id?: string; - }): boolean { - const success = [ - this.setItem('access_token', data.access_token, { encrypt: true }), - data.refresh_token ? this.setItem('refresh_token', data.refresh_token, { encrypt: true }) : true, - data.user_data ? this.setItem('user_data', data.user_data) : true, - data.tenant_id ? this.setItem('tenant_id', data.tenant_id) : true, - ].every(Boolean); - - return success; - } - - /** - * Clear all authentication data - */ - clearAuthData(): boolean { - return [ - this.removeItem('access_token'), - this.removeItem('refresh_token'), - this.removeItem('user_data'), - this.removeItem('tenant_id'), - ].every(Boolean); - } - - /** - * Store app preferences - */ - setPreferences(preferences: Record): boolean { - return this.setItem('app_preferences', preferences); - } - - /** - * Get app preferences - */ - getPreferences>(): T | null { - return this.getItem('app_preferences'); - } - - /** - * Store temporary session data with automatic expiration - */ - setSessionData(key: string, data: any, expiresInMinutes: number = 30): boolean { - return this.setItem(key, data, { - storage: 'session', - expiresIn: expiresInMinutes * 60 * 1000 - }); - } - - /** - * Get temporary session data - */ - getSessionData(key: string): T | null { - return this.getItem(key, 'session'); - } - - /** - * Check storage availability - */ - isStorageAvailable(storage: 'local' | 'session' = 'local'): boolean { - try { - const storageInstance = storage === 'session' ? sessionStorage : localStorage; - const test = '__storage_test__'; - storageInstance.setItem(test, test); - storageInstance.removeItem(test); - return true; - } catch (error) { - return false; - } - } -} - -// Export singleton instance -export const storageService = new StorageService(); - -// Export class for testing or multiple instances -export { StorageService }; - -// Legacy compatibility functions -export const getStorageItem = (key: string): T | null => storageService.getItem(key); -export const setStorageItem = (key: string, value: T, options?: StorageOptions): boolean => - storageService.setItem(key, value, options); -export const removeStorageItem = (key: string): boolean => storageService.removeItem(key); \ No newline at end of file