@bantis/local-cipher 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 MTT
3
+ Copyright (c) 2026 MTT (Master Tech Team)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,29 +1,130 @@
1
- # @bantis/local-cipher v2.0.0
1
+ # @bantis/local-cipher
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@bantis/local-cipher.svg)](https://www.npmjs.com/package/@bantis/local-cipher)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@bantis/local-cipher.svg)](https://www.npmjs.com/package/@bantis/local-cipher)
4
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
- [![GitHub](https://img.shields.io/badge/GitHub-master--tech--team-blue)](https://github.com/master-tech-team/-bantis-local-cipher)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue)](https://www.typescriptlang.org/)
6
7
 
7
- Librería enterprise de cifrado local AES-256-GCM con **configuración personalizable**, **eventos**, **compresión**, **expiración**, **namespaces** y **rotación de claves**. Compatible con **Angular**, **React** y **JavaScript vanilla**.
8
+ **Client-side encryption for localStorage using AES-256-GCM**
8
9
 
9
- ## Novedades v2.0.0
10
+ Protect sensitive data in browser storage from XSS attacks, local file access, and casual inspection. Drop-in replacement for localStorage with automatic encryption/decryption.
10
11
 
11
- - 🎛️ **Configuración Personalizable** - Ajusta iteraciones, longitud de clave, salt e IV
12
- - 🎯 **Sistema de Eventos** - Escucha eventos de cifrado, expiración, errores, etc.
13
- - 🗜️ **Compresión Automática** - Gzip para valores > 1KB (configurable)
14
- - ⏰ **Expiración/TTL** - Establece tiempo de vida con auto-limpieza
15
- - 🔐 **Validación de Integridad** - Checksums SHA-256 automáticos
16
- - 📦 **Namespaces** - Organiza datos en espacios aislados
17
- - 🔄 **Rotación de Claves** - Re-encripta datos con nuevas claves
18
- - 📊 **Modo Debug** - Logging configurable con niveles
12
+ ## Problem
19
13
 
20
- ## 📦 Instalación
14
+ localStorage stores data in **plain text**. Anyone with access to DevTools, browser files, or malicious scripts can read:
15
+ - Authentication tokens
16
+ - User credentials
17
+ - API keys
18
+ - Personal information
19
+
20
+ ## Solution
21
+
22
+ Transparent AES-256-GCM encryption with browser fingerprinting. Data is encrypted before storage and decrypted on retrieval. Keys are derived from browser characteristics, making data unreadable outside the original browser context.
23
+
24
+ ## Quick Start
21
25
 
22
26
  ```bash
23
27
  npm install @bantis/local-cipher
24
28
  ```
25
29
 
26
- ## 🚀 Uso Rápido
30
+ ```typescript
31
+ import { SecureStorage } from '@bantis/local-cipher';
32
+
33
+ const storage = SecureStorage.getInstance();
34
+
35
+ // Store encrypted
36
+ await storage.setItem('token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
37
+
38
+ // Retrieve decrypted
39
+ const token = await storage.getItem('token');
40
+
41
+ // Works like localStorage
42
+ await storage.removeItem('token');
43
+ storage.clear();
44
+ ```
45
+
46
+ **Before:**
47
+ ```
48
+ localStorage: { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
49
+ ```
50
+
51
+ **After:**
52
+ ```
53
+ localStorage: { "__enc_a7f5d8e2": "Qm9keUVuY3J5cHRlZERhdGE..." }
54
+ ```
55
+
56
+ ## Features
57
+
58
+ - ✅ **AES-256-GCM** encryption with authentication
59
+ - ✅ **PBKDF2** key derivation (100k+ iterations)
60
+ - ✅ **Browser fingerprinting** for unique keys per device
61
+ - ✅ **Key obfuscation** - even key names are encrypted
62
+ - ✅ **TTL/Expiration** - auto-delete expired data
63
+ - ✅ **Event system** - monitor storage operations
64
+ - ✅ **Compression** - automatic gzip for large values
65
+ - ✅ **Namespaces** - organize data in isolated spaces
66
+ - ✅ **Integrity checks** - SHA-256 checksums
67
+ - ✅ **TypeScript** - full type definitions
68
+ - ✅ **Framework support** - React hooks, Angular service
69
+
70
+ ## Use Cases
71
+
72
+ ### 1. Protect Authentication Tokens
73
+
74
+ ```typescript
75
+ // Store JWT with 1-hour expiration
76
+ await storage.setItemWithExpiry('accessToken', jwt, {
77
+ expiresIn: 3600000
78
+ });
79
+
80
+ // Auto-cleanup expired tokens
81
+ storage.on('expired', ({ key }) => {
82
+ console.log(`Token ${key} expired, redirecting to login`);
83
+ window.location.href = '/login';
84
+ });
85
+ ```
86
+
87
+ ### 2. Secure User Preferences
88
+
89
+ ```typescript
90
+ const userStorage = storage.namespace('user');
91
+ await userStorage.setItem('theme', 'dark');
92
+ await userStorage.setItem('language', 'en');
93
+
94
+ // Isolated from other namespaces
95
+ const appStorage = storage.namespace('app');
96
+ ```
97
+
98
+ ### 3. Cache Sensitive API Responses
99
+
100
+ ```typescript
101
+ // Store with compression for large data
102
+ const storage = SecureStorage.getInstance({
103
+ storage: { compression: true, compressionThreshold: 512 }
104
+ });
105
+
106
+ await storage.setItem('userData', JSON.stringify(largeObject));
107
+ ```
108
+
109
+ ## React Integration
110
+
111
+ ```tsx
112
+ import { useSecureStorage, useSecureStorageEvents } from '@bantis/local-cipher';
113
+
114
+ function App() {
115
+ const [token, setToken, loading] = useSecureStorage('token', '');
116
+
117
+ useSecureStorageEvents('expired', () => {
118
+ // Handle expiration
119
+ });
120
+
121
+ if (loading) return <div>Loading...</div>;
122
+
123
+ return <div>Token: {token}</div>;
124
+ }
125
+ ```
126
+
127
+ ## 🚀 Quick Start
27
128
 
28
129
  ### JavaScript Vanilla
29
130
 
@@ -32,75 +133,44 @@ import { SecureStorage } from '@bantis/local-cipher';
32
133
 
33
134
  const storage = SecureStorage.getInstance();
34
135
 
35
- // Guardar datos encriptados
136
+ // Store encrypted
36
137
  await storage.setItem('accessToken', 'mi-token-secreto');
37
138
 
38
- // Leer datos desencriptados
139
+ // Retrieve decrypted
39
140
  const token = await storage.getItem('accessToken');
40
141
 
41
- // Con expiración (1 hora)
142
+ // With expiration (1 hour)
42
143
  await storage.setItemWithExpiry('session', sessionData, { expiresIn: 3600000 });
43
144
 
44
- // Eliminar datos
145
+ // Remove
45
146
  await storage.removeItem('accessToken');
46
147
  ```
47
148
 
48
- ### Con Configuración Personalizada
149
+ **Before:**
150
+ ```
151
+ localStorage: { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
152
+ ```
49
153
 
50
- ```javascript
51
- const storage = SecureStorage.getInstance({
52
- encryption: {
53
- iterations: 150000, // PBKDF2 iterations (default: 100000)
54
- keyLength: 256, // 128, 192, or 256 bits
55
- saltLength: 16, // Salt size in bytes
56
- ivLength: 12, // IV size in bytes
57
- appIdentifier: 'my-app' // Custom app identifier
58
- },
59
- storage: {
60
- compression: true, // Enable compression
61
- compressionThreshold: 1024, // Compress if > 1KB
62
- autoCleanup: true, // Auto-clean expired items
63
- cleanupInterval: 60000 // Cleanup every 60s
64
- },
65
- debug: {
66
- enabled: true, // Enable debug logging
67
- logLevel: 'verbose', // silent, error, warn, info, debug, verbose
68
- prefix: 'MyApp' // Log prefix
69
- }
70
- });
154
+ **After:**
155
+ ```
156
+ localStorage: { "__enc_a7f5d8e2": "Qm9keUVuY3J5cHRlZERhdGE..." }
71
157
  ```
72
158
 
73
159
  ### React
74
160
 
75
161
  ```jsx
76
- import { useSecureStorage, useSecureStorageWithExpiry, useSecureStorageEvents } from '@bantis/local-cipher';
162
+ import { useSecureStorage } from '@bantis/local-cipher/react';
77
163
 
78
164
  function App() {
79
- // Hook básico
80
165
  const [token, setToken, loading] = useSecureStorage('accessToken', '');
81
-
82
- // Hook con expiración
83
- const [session, setSession] = useSecureStorageWithExpiry(
84
- 'session',
85
- null,
86
- { expiresIn: 3600000 }
87
- );
88
-
89
- // Escuchar eventos
90
- useSecureStorageEvents('expired', (data) => {
91
- console.log('Item expired:', data.key);
92
- });
93
-
94
- // Usar namespace
95
- const userStorage = useNamespace('user');
96
166
 
97
- if (loading) return <div>Cargando...</div>;
167
+ if (loading) return <div>Loading...</div>;
98
168
 
99
169
  return (
100
170
  <div>
101
171
  <p>Token: {token}</p>
102
172
  <button onClick={() => setToken('nuevo-token')}>
103
- Actualizar Token
173
+ Update Token
104
174
  </button>
105
175
  </div>
106
176
  );
@@ -110,49 +180,103 @@ function App() {
110
180
  ### Angular
111
181
 
112
182
  ```typescript
113
- import { SecureStorageService } from '@bantis/local-cipher';
183
+ import { SecureStorageService } from '@bantis/local-cipher/angular';
114
184
 
115
185
  @Component({
116
186
  selector: 'app-root',
117
- template: `
118
- <div>{{ token$ | async }}</div>
119
- <button (click)="saveToken()">Guardar</button>
120
- `
187
+ template: `<div>{{ token$ | async }}</div>`
121
188
  })
122
- export class AppComponent implements OnInit {
189
+ export class AppComponent {
123
190
  token$ = this.storage.getItem('accessToken');
124
191
 
125
192
  constructor(private storage: SecureStorageService) {}
126
-
127
- ngOnInit() {
128
- // Escuchar eventos
193
+
194
+ saveToken(token: string) {
195
+ this.storage.setItem('accessToken', token).subscribe();
196
+ }
197
+ }
198
+ ```
199
+ ## Angular Integration
200
+
201
+ ```typescript
202
+ import { SecureStorageService } from '@bantis/local-cipher';
203
+
204
+ @Component({...})
205
+ export class AppComponent {
206
+ token$ = this.storage.getItem('token');
207
+
208
+ constructor(private storage: SecureStorageService) {
129
209
  this.storage.events$.subscribe(event => {
130
210
  console.log('Storage event:', event);
131
211
  });
132
-
133
- // Eventos específicos
134
- this.storage.onEvent$('expired').subscribe(event => {
135
- console.log('Item expired:', event.key);
136
- });
137
212
  }
213
+ }
214
+ ```
138
215
 
139
- saveToken() {
140
- this.storage.setItemWithExpiry('token', 'value', { expiresIn: 3600000 })
141
- .subscribe();
142
- }
143
-
144
- saveObject() {
145
- this.storage.setObjectWithExpiry('user', { id: 1 }, { expiresIn: 7200000 })
146
- .subscribe();
216
+ ## Configuration
217
+
218
+ ```typescript
219
+ const storage = SecureStorage.getInstance({
220
+ encryption: {
221
+ iterations: 150000, // PBKDF2 iterations
222
+ keyLength: 256, // 128, 192, or 256 bits
223
+ saltLength: 16, // Salt size in bytes
224
+ ivLength: 12, // IV size in bytes
225
+ },
226
+ storage: {
227
+ compression: true, // Enable gzip compression
228
+ compressionThreshold: 1024, // Compress if > 1KB
229
+ autoCleanup: true, // Auto-delete expired items
230
+ cleanupInterval: 60000 // Cleanup every 60s
231
+ },
232
+ debug: {
233
+ enabled: false, // Enable debug logging
234
+ logLevel: 'info' // silent, error, warn, info, debug, verbose
147
235
  }
148
- }
236
+ });
149
237
  ```
150
238
 
151
- ## 📚 API Completa
239
+ ## Security
240
+
241
+ ### What This Protects Against
242
+
243
+ ✅ **XSS attacks** - Encrypted data is useless without the browser-specific key
244
+ ✅ **Local file access** - Malware reading browser files gets encrypted data
245
+ ✅ **Casual inspection** - DevTools shows encrypted values
246
+ ✅ **Data tampering** - Integrity checks detect modifications
247
+
248
+ ### What This Does NOT Protect Against
249
+
250
+ ❌ **Server-side attacks** - Encryption is client-side only
251
+ ❌ **Man-in-the-Middle** - Use HTTPS for data in transit
252
+ ❌ **Memory dumps** - Keys exist in memory during runtime
253
+ ❌ **Compromised browser** - If the browser is compromised, all bets are off
254
+ ❌ **Physical access during active session** - Data is decrypted when accessed
255
+
256
+ ### Best Practices
257
+
258
+ 1. **Use HTTPS** - Always transmit data over secure connections
259
+ 2. **Short TTLs** - Set expiration on sensitive data
260
+ 3. **Clear on logout** - Call `storage.clear()` when user logs out
261
+ 4. **Monitor events** - Track suspicious activity via event listeners
262
+ 5. **Rotate keys** - Periodically call `storage.rotateKeys()`
263
+ 6. **Don't store passwords** - Never store plaintext passwords, even encrypted
264
+
265
+ ## Browser Support
152
266
 
153
- ### SecureStorage
267
+ Requires [Web Crypto API](https://caniuse.com/cryptography):
154
268
 
155
- #### Métodos Básicos
269
+ - Chrome 37+
270
+ - Firefox 34+
271
+ - Safari 11+
272
+ - Edge 12+
273
+ - Opera 24+
274
+
275
+ **Fallback:** Gracefully degrades to unencrypted localStorage in unsupported browsers.
276
+
277
+ ## API Reference
278
+
279
+ ### Core Methods
156
280
 
157
281
  ```typescript
158
282
  setItem(key: string, value: string): Promise<void>
@@ -162,228 +286,124 @@ hasItem(key: string): Promise<boolean>
162
286
  clear(): void
163
287
  ```
164
288
 
165
- #### Expiración
289
+ ### Expiration
166
290
 
167
291
  ```typescript
168
- setItemWithExpiry(key: string, value: string, options: ExpiryOptions): Promise<void>
169
- cleanExpired(): Promise<number>
292
+ setItemWithExpiry(key: string, value: string, options: {
293
+ expiresIn?: number; // milliseconds from now
294
+ expiresAt?: Date; // absolute date
295
+ }): Promise<void>
170
296
 
171
- // Opciones
172
- interface ExpiryOptions {
173
- expiresIn?: number; // Milisegundos desde ahora
174
- expiresAt?: Date; // Fecha absoluta
175
- }
297
+ cleanExpired(): Promise<number> // Returns count of deleted items
176
298
  ```
177
299
 
178
- #### Eventos
300
+ ### Events
179
301
 
180
302
  ```typescript
181
303
  on(event: StorageEventType, listener: EventListener): void
182
- once(event: StorageEventType, listener: EventListener): void
183
304
  off(event: StorageEventType, listener: EventListener): void
184
- removeAllListeners(event?: StorageEventType): void
305
+ once(event: StorageEventType, listener: EventListener): void
185
306
 
186
- // Tipos de eventos
187
- type StorageEventType =
188
- | 'encrypted' | 'decrypted' | 'deleted' | 'cleared'
189
- | 'expired' | 'error' | 'keyRotated' | 'compressed' | 'decompressed';
307
+ // Event types: 'encrypted', 'decrypted', 'deleted', 'cleared',
308
+ // 'expired', 'error', 'keyRotated', 'compressed'
190
309
  ```
191
310
 
192
- #### Namespaces
311
+ ### Namespaces
193
312
 
194
313
  ```typescript
195
314
  namespace(name: string): NamespacedStorage
196
315
 
197
- // Ejemplo
198
316
  const userStorage = storage.namespace('user');
199
- const sessionStorage = storage.namespace('session');
200
-
201
317
  await userStorage.setItem('profile', data);
202
- await userStorage.clearNamespace(); // Solo limpia este namespace
318
+ await userStorage.clearNamespace();
203
319
  ```
204
320
 
205
- #### Integridad
206
-
207
- ```typescript
208
- verifyIntegrity(key: string): Promise<boolean>
209
- getIntegrityInfo(key: string): Promise<IntegrityInfo>
210
-
211
- interface IntegrityInfo {
212
- valid: boolean;
213
- lastModified: number;
214
- checksum: string;
215
- version: number;
216
- }
217
- ```
218
-
219
- #### Rotación de Claves
321
+ ### Key Rotation
220
322
 
221
323
  ```typescript
222
324
  rotateKeys(): Promise<void>
223
325
  exportEncryptedData(): Promise<EncryptedBackup>
224
326
  importEncryptedData(backup: EncryptedBackup): Promise<void>
225
-
226
- // Ejemplo
227
- const backup = await storage.exportEncryptedData();
228
- await storage.rotateKeys();
229
- // Si algo sale mal:
230
- await storage.importEncryptedData(backup);
231
327
  ```
232
328
 
233
- #### Debug
329
+ ## FAQ
234
330
 
235
- ```typescript
236
- getDebugInfo(): {
237
- cryptoSupported: boolean;
238
- encryptedKeys: string[];
239
- unencryptedKeys: string[];
240
- totalKeys: number;
241
- config: SecureStorageConfig;
242
- }
243
- ```
331
+ **Q: Is this secure enough for passwords?**
332
+ A: No. Never store passwords in localStorage, even encrypted. Use secure, httpOnly cookies or sessionStorage with server-side session management.
244
333
 
245
- ## 🎯 Casos de Uso
334
+ **Q: Can data be decrypted on another device?**
335
+ A: No. Keys are derived from browser fingerprinting. Data encrypted on Chrome/Windows cannot be decrypted on Firefox/Mac.
246
336
 
247
- ### 1. Session Management con Expiración
337
+ **Q: What happens if Web Crypto API is unavailable?**
338
+ A: The library falls back to unencrypted localStorage with a console warning. Check `EncryptionHelper.isSupported()` to detect support.
248
339
 
249
- ```javascript
250
- // Guardar sesión que expira en 30 minutos
251
- await storage.setItemWithExpiry('session', sessionData, {
252
- expiresIn: 30 * 60 * 1000
253
- });
340
+ **Q: Does this protect against XSS?**
341
+ A: Partially. It makes stolen data harder to use, but XSS can still intercept data when it's decrypted in memory. Use CSP headers and sanitize inputs.
254
342
 
255
- // Auto-limpieza cada minuto
256
- const storage = SecureStorage.getInstance({
257
- storage: { autoCleanup: true, cleanupInterval: 60000 }
258
- });
259
- ```
343
+ **Q: How is this different from sessionStorage?**
344
+ A: sessionStorage is cleared on tab close. This provides persistent, encrypted storage across sessions.
260
345
 
261
- ### 2. Organización con Namespaces
346
+ **Q: Can I use this in Node.js?**
347
+ A: No. This library requires browser APIs (Web Crypto, localStorage). For Node.js, use native `crypto` module.
262
348
 
263
- ```javascript
264
- const userStorage = storage.namespace('user');
265
- const appStorage = storage.namespace('app');
266
- const tempStorage = storage.namespace('temp');
349
+ **Q: What's the performance impact?**
350
+ A: Encryption adds ~2-5ms per operation. Compression adds ~5-10ms for large values. Negligible for most use cases.
267
351
 
268
- await userStorage.setItem('profile', userData);
269
- await appStorage.setItem('settings', appSettings);
270
- await tempStorage.setItem('cache', cacheData);
352
+ ## Migration from v1
271
353
 
272
- // Limpiar solo datos temporales
273
- await tempStorage.clearNamespace();
354
+ v1 data is automatically migrated to v2 format on first read. No action required.
355
+
356
+ ```typescript
357
+ // v1 and v2 are API-compatible
358
+ const storage = SecureStorage.getInstance(); // Works with both
274
359
  ```
275
360
 
276
- ### 3. Monitoreo con Eventos
361
+ ## Migration from v2.0.x to v2.1.0
277
362
 
278
- ```javascript
279
- storage.on('encrypted', ({ key, metadata }) => {
280
- console.log(`✅ Encrypted: ${key}`, metadata);
281
- });
363
+ > [!WARNING]
364
+ > **Breaking Change:** Framework-specific imports required
282
365
 
283
- storage.on('expired', ({ key }) => {
284
- console.warn(`⏰ Expired: ${key}`);
285
- // Refrescar datos o redirigir a login
286
- });
366
+ ### For React Users
287
367
 
288
- storage.on('error', ({ key, error }) => {
289
- console.error(`❌ Error on ${key}:`, error);
290
- // Enviar a sistema de logging
291
- });
368
+ **Before (v2.0.x):**
369
+ ```typescript
370
+ import { useSecureStorage } from '@bantis/local-cipher';
292
371
  ```
293
372
 
294
- ### 4. Rotación de Claves Programada
295
-
296
- ```javascript
297
- // Rotar claves cada 30 días
298
- setInterval(async () => {
299
- console.log('Rotating encryption keys...');
300
- const backup = await storage.exportEncryptedData();
301
-
302
- try {
303
- await storage.rotateKeys();
304
- console.log('Keys rotated successfully');
305
- } catch (error) {
306
- console.error('Rotation failed, restoring backup');
307
- await storage.importEncryptedData(backup);
308
- }
309
- }, 30 * 24 * 60 * 60 * 1000);
373
+ **After (v2.1.0):**
374
+ ```typescript
375
+ import { useSecureStorage } from '@bantis/local-cipher/react';
310
376
  ```
311
377
 
312
- ## 🔄 Migración desde v1
313
-
314
- ### Cambios Principales
378
+ ### For Angular Users
315
379
 
316
- **v1:**
317
- ```javascript
318
- const storage = SecureStorage.getInstance();
380
+ **Before (v2.0.x):**
381
+ ```typescript
382
+ import { SecureStorageService } from '@bantis/local-cipher';
319
383
  ```
320
384
 
321
- **v2 (compatible):**
322
- ```javascript
323
- // Funciona igual que v1
324
- const storage = SecureStorage.getInstance();
325
-
326
- // O con configuración
327
- const storage = SecureStorage.getInstance({
328
- encryption: { iterations: 150000 }
329
- });
385
+ **After (v2.1.0):**
386
+ ```typescript
387
+ import { SecureStorageService } from '@bantis/local-cipher/angular';
330
388
  ```
331
389
 
332
- ### Migración Automática
333
-
334
- Los datos de v1 se migran automáticamente al leerlos. No requiere acción del usuario.
390
+ ### For Core/Vanilla JS Users
335
391
 
336
- ```javascript
337
- // v1 data format: plain encrypted string
338
- // v2 data format: JSON with metadata
339
-
340
- // Al hacer getItem(), v1 data se detecta y migra automáticamente
341
- const value = await storage.getItem('oldKey'); // ✅ Migrado a v2
392
+ **No changes required:**
393
+ ```typescript
394
+ import { SecureStorage } from '@bantis/local-cipher'; // Still works
342
395
  ```
343
396
 
344
- ## 🛡️ Seguridad
345
-
346
- ### Protección
347
-
348
- ✅ **XSS** - Datos encriptados incluso si script malicioso accede a localStorage
349
- ✅ **Lectura local** - Malware no puede descifrar sin la clave del navegador
350
- ✅ **Ofuscación** - Nombres de claves encriptados
351
- ✅ **Integridad** - Checksums SHA-256 detectan manipulación
352
-
353
- ### Limitaciones
354
-
355
- ❌ **Servidor** - Encriptación solo cliente
356
- ❌ **MITM** - Usa HTTPS
357
- ❌ **Sesión activa** - Clave en memoria durante uso
358
-
359
- ### Arquitectura
360
-
361
- 1. **Fingerprinting** - Huella única del navegador
362
- 2. **PBKDF2** - 100,000+ iteraciones para derivar clave
363
- 3. **AES-256-GCM** - Cifrado con autenticación
364
- 4. **SHA-256** - Checksums de integridad
365
- 5. **Gzip** - Compresión opcional
366
-
367
- ## 🌐 Compatibilidad
368
-
369
- - ✅ Chrome 37+
370
- - ✅ Firefox 34+
371
- - ✅ Safari 11+
372
- - ✅ Edge 12+
373
- - ✅ Opera 24+
374
-
375
- **Fallback:** En navegadores sin Web Crypto API, usa localStorage normal.
376
-
377
- ## 📄 Licencia
378
-
379
- MIT © MTT
380
-
381
- ## 🔗 Enlaces
397
+ ### Why This Change?
382
398
 
383
- - [GitHub](https://github.com/master-tech-team/-bantis-local-cipher)
384
- - [npm](https://www.npmjs.com/package/@bantis/local-cipher)
385
- - [Changelog](./CHANGELOG.md)
399
+ v2.0.x bundled all framework code together, causing dependency conflicts:
400
+ - React projects needed Angular dependencies (`@angular/core`, `rxjs`)
401
+ - Vanilla JS projects loaded unused React/Angular code
402
+ - 40% larger bundle size for non-framework users
386
403
 
387
- ## 🤝 Contribuir
404
+ v2.1.0 separates frameworks into independent bundles:
405
+ - ✅ Core: 42KB (no framework dependencies)
406
+ - ✅ React: 49KB (core + hooks)
407
+ - ✅ Angular: 55KB (core + service)
388
408
 
389
- Las contribuciones son bienvenidas. Abre un issue o pull request en GitHub.
409
+ ## FAQ