@bantis/local-cipher 1.0.1 → 2.0.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/README.md CHANGED
@@ -1,27 +1,26 @@
1
- # @bantis/local-cipher
1
+ # @bantis/local-cipher v2.0.0
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
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
  [![GitHub](https://img.shields.io/badge/GitHub-master--tech--team-blue)](https://github.com/master-tech-team/-bantis-local-cipher)
6
6
 
7
- Librería de cifrado local AES-256-GCM para proteger datos sensibles en localStorage. Compatible con **Angular**, **React** y **JavaScript vanilla**.
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
8
 
9
- ## 🔐 Características
9
+ ## Novedades v2.0.0
10
10
 
11
- - **Cifrado AES-256-GCM** - Estándar de cifrado avanzado con autenticación
12
- - **Derivación de claves PBKDF2** - 100,000 iteraciones con SHA-256
13
- - **Browser Fingerprinting** - Claves únicas por navegador
14
- - **Ofuscación de nombres** - Los nombres de las claves también se encriptan
15
- - **TypeScript** - Tipado completo
16
- - **Framework Agnostic** - Funciona con cualquier proyecto JavaScript
17
- - **Integraciones específicas** - Hooks de React y servicio de Angular
18
- - **Migración automática** - Convierte datos existentes a formato encriptado
19
- - ✅ **Fallback transparente** - Funciona en navegadores sin Web Crypto API
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
20
19
 
21
20
  ## 📦 Instalación
22
21
 
23
22
  ```bash
24
- npm install @mtt/local-cipher
23
+ npm install @bantis/local-cipher
25
24
  ```
26
25
 
27
26
  ## 🚀 Uso Rápido
@@ -29,28 +28,71 @@ npm install @mtt/local-cipher
29
28
  ### JavaScript Vanilla
30
29
 
31
30
  ```javascript
32
- import { secureStorage } from '@mtt/local-cipher';
31
+ import { SecureStorage } from '@bantis/local-cipher';
32
+
33
+ const storage = SecureStorage.getInstance();
33
34
 
34
35
  // Guardar datos encriptados
35
- await secureStorage.setItem('accessToken', 'mi-token-secreto');
36
+ await storage.setItem('accessToken', 'mi-token-secreto');
36
37
 
37
38
  // Leer datos desencriptados
38
- const token = await secureStorage.getItem('accessToken');
39
+ const token = await storage.getItem('accessToken');
40
+
41
+ // Con expiración (1 hora)
42
+ await storage.setItemWithExpiry('session', sessionData, { expiresIn: 3600000 });
39
43
 
40
44
  // Eliminar datos
41
- await secureStorage.removeItem('accessToken');
45
+ await storage.removeItem('accessToken');
46
+ ```
47
+
48
+ ### Con Configuración Personalizada
42
49
 
43
- // Limpiar todo
44
- secureStorage.clear();
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
+ });
45
71
  ```
46
72
 
47
73
  ### React
48
74
 
49
75
  ```jsx
50
- import { useSecureStorage } from '@mtt/local-cipher';
76
+ import { useSecureStorage, useSecureStorageWithExpiry, useSecureStorageEvents } from '@bantis/local-cipher';
51
77
 
52
78
  function App() {
79
+ // Hook básico
53
80
  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');
54
96
 
55
97
  if (loading) return <div>Cargando...</div>;
56
98
 
@@ -68,169 +110,261 @@ function App() {
68
110
  ### Angular
69
111
 
70
112
  ```typescript
71
- import { SecureStorageService } from '@mtt/local-cipher';
113
+ import { SecureStorageService } from '@bantis/local-cipher';
72
114
 
73
115
  @Component({
74
116
  selector: 'app-root',
75
- template: `<div>{{ token$ | async }}</div>`
117
+ template: `
118
+ <div>{{ token$ | async }}</div>
119
+ <button (click)="saveToken()">Guardar</button>
120
+ `
76
121
  })
77
- export class AppComponent {
78
- token$ = this.secureStorage.getItem('accessToken');
79
-
80
- constructor(private secureStorage: SecureStorageService) {}
122
+ export class AppComponent implements OnInit {
123
+ token$ = this.storage.getItem('accessToken');
124
+
125
+ constructor(private storage: SecureStorageService) {}
126
+
127
+ ngOnInit() {
128
+ // Escuchar eventos
129
+ this.storage.events$.subscribe(event => {
130
+ console.log('Storage event:', event);
131
+ });
132
+
133
+ // Eventos específicos
134
+ this.storage.onEvent$('expired').subscribe(event => {
135
+ console.log('Item expired:', event.key);
136
+ });
137
+ }
81
138
 
82
- saveToken(token: string) {
83
- this.secureStorage.setItem('accessToken', token).subscribe();
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();
84
147
  }
85
148
  }
86
149
  ```
87
150
 
88
- ## 📚 Documentación Completa
151
+ ## 📚 API Completa
89
152
 
90
- ### API Principal
153
+ ### SecureStorage
91
154
 
92
- #### `SecureStorage`
155
+ #### Métodos Básicos
93
156
 
94
- **`setItem(key: string, value: string): Promise<void>`**
95
- Guarda un valor encriptado en localStorage.
157
+ ```typescript
158
+ setItem(key: string, value: string): Promise<void>
159
+ getItem(key: string): Promise<string | null>
160
+ removeItem(key: string): Promise<void>
161
+ hasItem(key: string): Promise<boolean>
162
+ clear(): void
163
+ ```
164
+
165
+ #### Expiración
96
166
 
97
- **`getItem(key: string): Promise<string | null>`**
98
- Recupera y desencripta un valor de localStorage.
167
+ ```typescript
168
+ setItemWithExpiry(key: string, value: string, options: ExpiryOptions): Promise<void>
169
+ cleanExpired(): Promise<number>
99
170
 
100
- **`removeItem(key: string): Promise<void>`**
101
- Elimina un valor de localStorage.
171
+ // Opciones
172
+ interface ExpiryOptions {
173
+ expiresIn?: number; // Milisegundos desde ahora
174
+ expiresAt?: Date; // Fecha absoluta
175
+ }
176
+ ```
102
177
 
103
- **`hasItem(key: string): Promise<boolean>`**
104
- Verifica si existe una clave.
178
+ #### Eventos
105
179
 
106
- **`clear(): void`**
107
- Limpia todos los datos encriptados.
180
+ ```typescript
181
+ on(event: StorageEventType, listener: EventListener): void
182
+ once(event: StorageEventType, listener: EventListener): void
183
+ off(event: StorageEventType, listener: EventListener): void
184
+ removeAllListeners(event?: StorageEventType): void
185
+
186
+ // Tipos de eventos
187
+ type StorageEventType =
188
+ | 'encrypted' | 'decrypted' | 'deleted' | 'cleared'
189
+ | 'expired' | 'error' | 'keyRotated' | 'compressed' | 'decompressed';
190
+ ```
108
191
 
109
- **`migrateExistingData(keys: string[]): Promise<void>`**
110
- Migra datos existentes no encriptados a formato encriptado.
192
+ #### Namespaces
111
193
 
112
- ### React Hooks
194
+ ```typescript
195
+ namespace(name: string): NamespacedStorage
113
196
 
114
- #### `useSecureStorage<T>(key: string, initialValue: T)`
115
- Hook principal para usar SecureStorage de forma reactiva.
197
+ // Ejemplo
198
+ const userStorage = storage.namespace('user');
199
+ const sessionStorage = storage.namespace('session');
116
200
 
117
- ```jsx
118
- const [user, setUser, loading, error] = useSecureStorage('user', null);
201
+ await userStorage.setItem('profile', data);
202
+ await userStorage.clearNamespace(); // Solo limpia este namespace
119
203
  ```
120
204
 
121
- **Retorna:** `[value, setValue, loading, error]`
122
-
123
- #### `useSecureStorageItem(key: string)`
124
- Verifica si existe una clave.
205
+ #### Integridad
125
206
 
126
- ```jsx
127
- const [hasToken, loading, error] = useSecureStorageItem('accessToken');
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
+ }
128
217
  ```
129
218
 
130
- **Retorna:** `[exists, loading, error]`
131
-
132
- #### `useSecureStorageDebug()`
133
- Obtiene información de debug del sistema.
219
+ #### Rotación de Claves
134
220
 
135
- ```jsx
136
- const debugInfo = useSecureStorageDebug();
137
- console.log(`Claves encriptadas: ${debugInfo.encryptedKeys.length}`);
221
+ ```typescript
222
+ rotateKeys(): Promise<void>
223
+ exportEncryptedData(): Promise<EncryptedBackup>
224
+ 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);
138
231
  ```
139
232
 
140
- ### Angular Service
141
-
142
- #### `SecureStorageService`
233
+ #### Debug
143
234
 
144
235
  ```typescript
145
- // Inyectar el servicio
146
- constructor(private secureStorage: SecureStorageService) {}
236
+ getDebugInfo(): {
237
+ cryptoSupported: boolean;
238
+ encryptedKeys: string[];
239
+ unencryptedKeys: string[];
240
+ totalKeys: number;
241
+ config: SecureStorageConfig;
242
+ }
243
+ ```
147
244
 
148
- // Guardar
149
- this.secureStorage.setItem('key', 'value').subscribe();
245
+ ## 🎯 Casos de Uso
150
246
 
151
- // Leer
152
- this.secureStorage.getItem('key').subscribe(value => console.log(value));
247
+ ### 1. Session Management con Expiración
153
248
 
154
- // Guardar objetos JSON
155
- this.secureStorage.setObject('user', { id: 1, name: 'Juan' }).subscribe();
249
+ ```javascript
250
+ // Guardar sesión que expira en 30 minutos
251
+ await storage.setItemWithExpiry('session', sessionData, {
252
+ expiresIn: 30 * 60 * 1000
253
+ });
254
+
255
+ // Auto-limpieza cada minuto
256
+ const storage = SecureStorage.getInstance({
257
+ storage: { autoCleanup: true, cleanupInterval: 60000 }
258
+ });
259
+ ```
156
260
 
157
- // Leer objetos JSON
158
- this.secureStorage.getObject<User>('user').subscribe(user => console.log(user));
261
+ ### 2. Organización con Namespaces
159
262
 
160
- // Obtener debug info como Observable
161
- this.secureStorage.getDebugInfo$().subscribe(info => console.log(info));
162
- ```
263
+ ```javascript
264
+ const userStorage = storage.namespace('user');
265
+ const appStorage = storage.namespace('app');
266
+ const tempStorage = storage.namespace('temp');
267
+
268
+ await userStorage.setItem('profile', userData);
269
+ await appStorage.setItem('settings', appSettings);
270
+ await tempStorage.setItem('cache', cacheData);
163
271
 
164
- ## 🔄 Migración de Datos Existentes
272
+ // Limpiar solo datos temporales
273
+ await tempStorage.clearNamespace();
274
+ ```
165
275
 
166
- Si ya tienes datos en localStorage sin encriptar, puedes migrarlos fácilmente:
276
+ ### 3. Monitoreo con Eventos
167
277
 
168
278
  ```javascript
169
- import { secureStorage } from '@mtt/local-cipher';
170
-
171
- // Migrar claves específicas
172
- await secureStorage.migrateExistingData([
173
- 'accessToken',
174
- 'refreshToken',
175
- 'user',
176
- 'sessionId'
177
- ]);
279
+ storage.on('encrypted', ({ key, metadata }) => {
280
+ console.log(`✅ Encrypted: ${key}`, metadata);
281
+ });
282
+
283
+ storage.on('expired', ({ key }) => {
284
+ console.warn(`⏰ Expired: ${key}`);
285
+ // Refrescar datos o redirigir a login
286
+ });
287
+
288
+ storage.on('error', ({ key, error }) => {
289
+ console.error(`❌ Error on ${key}:`, error);
290
+ // Enviar a sistema de logging
291
+ });
178
292
  ```
179
293
 
180
- **Recomendación:** Ejecuta esto al iniciar tu aplicación para migrar automáticamente.
294
+ ### 4. Rotación de Claves Programada
181
295
 
182
- ## 🛡️ Seguridad
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);
310
+ ```
183
311
 
184
- ### ¿Qué protege?
312
+ ## 🔄 Migración desde v1
185
313
 
186
- **XSS (Cross-Site Scripting)** - Los datos están encriptados incluso si un script malicioso accede a localStorage
187
- ✅ **Lectura de archivos locales** - Malware que lee archivos del navegador no puede descifrar los datos
188
- ✅ **Ofuscación** - Los nombres de las claves también están encriptados
314
+ ### Cambios Principales
189
315
 
190
- ### ¿Qué NO protege?
316
+ **v1:**
317
+ ```javascript
318
+ const storage = SecureStorage.getInstance();
319
+ ```
191
320
 
192
- **Ataques del lado del servidor** - La encriptación es solo del lado del cliente
193
- ❌ **Man-in-the-Middle** - Usa HTTPS para proteger datos en tránsito
194
- **Acceso físico durante sesión activa** - Si el navegador está abierto, la clave está en memoria
321
+ **v2 (compatible):**
322
+ ```javascript
323
+ // Funciona igual que v1
324
+ const storage = SecureStorage.getInstance();
195
325
 
196
- ### Cómo Funciona
326
+ // O con configuración
327
+ const storage = SecureStorage.getInstance({
328
+ encryption: { iterations: 150000 }
329
+ });
330
+ ```
197
331
 
198
- 1. **Fingerprinting del navegador** - Se genera una huella digital única combinando características del navegador
199
- 2. **Derivación de clave** - Se usa PBKDF2 con 100,000 iteraciones para derivar una clave AES-256
200
- 3. **Cifrado AES-GCM** - Cada valor se encripta con un IV aleatorio único
201
- 4. **Almacenamiento** - Se guarda `IV + datos encriptados` en Base64
332
+ ### Migración Automática
202
333
 
203
- **Ejemplo de localStorage:**
334
+ Los datos de v1 se migran automáticamente al leerlos. No requiere acción del usuario.
204
335
 
205
- ```
206
- Antes:
207
- accessToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
208
- user: '{"id":1,"name":"Juan"}'
336
+ ```javascript
337
+ // v1 data format: plain encrypted string
338
+ // v2 data format: JSON with metadata
209
339
 
210
- Después:
211
- __enc_a7f5d8e2c1b4: "Qm9keUVuY3J5cHRlZERhdGE..."
212
- __enc_9c3e7b1a5f8d: "QW5vdGhlckVuY3J5cHRlZA..."
213
- __app_salt: "cmFuZG9tU2FsdEhlcmU="
340
+ // Al hacer getItem(), v1 data se detecta y migra automáticamente
341
+ const value = await storage.getItem('oldKey'); // ✅ Migrado a v2
214
342
  ```
215
343
 
216
- ## 🧪 Utilidades de Debug
344
+ ## 🛡️ Seguridad
217
345
 
218
- ```javascript
219
- import { debugEncryptionState, testEncryption, forceMigration } from '@mtt/local-cipher';
346
+ ### Protección
220
347
 
221
- // Ver estado del sistema
222
- await debugEncryptionState();
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
223
352
 
224
- // Probar encriptación
225
- await testEncryption();
353
+ ### Limitaciones
226
354
 
227
- // Forzar migración
228
- await forceMigration(['accessToken', 'refreshToken']);
229
- ```
355
+ **Servidor** - Encriptación solo cliente
356
+ **MITM** - Usa HTTPS
357
+ ❌ **Sesión activa** - Clave en memoria durante uso
230
358
 
231
- ## 🌐 Compatibilidad
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
232
366
 
233
- Requiere navegadores con soporte para **Web Crypto API**:
367
+ ## 🌐 Compatibilidad
234
368
 
235
369
  - ✅ Chrome 37+
236
370
  - ✅ Firefox 34+
@@ -238,16 +372,18 @@ Requiere navegadores con soporte para **Web Crypto API**:
238
372
  - ✅ Edge 12+
239
373
  - ✅ Opera 24+
240
374
 
241
- **Nota:** En navegadores sin soporte, la librería hace fallback automático a localStorage normal.
375
+ **Fallback:** En navegadores sin Web Crypto API, usa localStorage normal.
242
376
 
243
377
  ## 📄 Licencia
244
378
 
245
379
  MIT © MTT
246
380
 
247
- ## 🤝 Contribuir
381
+ ## 🔗 Enlaces
248
382
 
249
- Las contribuciones son bienvenidas. Por favor abre un issue o pull request en GitHub.
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)
250
386
 
251
- ## 📞 Soporte
387
+ ## 🤝 Contribuir
252
388
 
253
- Si encuentras algún problema o tienes preguntas, abre un issue en GitHub.
389
+ Las contribuciones son bienvenidas. Abre un issue o pull request en GitHub.