@bantis/local-cipher 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MTT
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # @bantis/local-cipher
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@bantis/local-cipher.svg)](https://www.npmjs.com/package/@bantis/local-cipher)
4
+ [![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/-mtt-local-cipher)
6
+
7
+ Librería de cifrado local AES-256-GCM para proteger datos sensibles en localStorage. Compatible con **Angular**, **React** y **JavaScript vanilla**.
8
+
9
+ ## 🔐 Características
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
20
+
21
+ ## 📦 Instalación
22
+
23
+ ```bash
24
+ npm install @mtt/local-cipher
25
+ ```
26
+
27
+ ## 🚀 Uso Rápido
28
+
29
+ ### JavaScript Vanilla
30
+
31
+ ```javascript
32
+ import { secureStorage } from '@mtt/local-cipher';
33
+
34
+ // Guardar datos encriptados
35
+ await secureStorage.setItem('accessToken', 'mi-token-secreto');
36
+
37
+ // Leer datos desencriptados
38
+ const token = await secureStorage.getItem('accessToken');
39
+
40
+ // Eliminar datos
41
+ await secureStorage.removeItem('accessToken');
42
+
43
+ // Limpiar todo
44
+ secureStorage.clear();
45
+ ```
46
+
47
+ ### React
48
+
49
+ ```jsx
50
+ import { useSecureStorage } from '@mtt/local-cipher';
51
+
52
+ function App() {
53
+ const [token, setToken, loading] = useSecureStorage('accessToken', '');
54
+
55
+ if (loading) return <div>Cargando...</div>;
56
+
57
+ return (
58
+ <div>
59
+ <p>Token: {token}</p>
60
+ <button onClick={() => setToken('nuevo-token')}>
61
+ Actualizar Token
62
+ </button>
63
+ </div>
64
+ );
65
+ }
66
+ ```
67
+
68
+ ### Angular
69
+
70
+ ```typescript
71
+ import { SecureStorageService } from '@mtt/local-cipher';
72
+
73
+ @Component({
74
+ selector: 'app-root',
75
+ template: `<div>{{ token$ | async }}</div>`
76
+ })
77
+ export class AppComponent {
78
+ token$ = this.secureStorage.getItem('accessToken');
79
+
80
+ constructor(private secureStorage: SecureStorageService) {}
81
+
82
+ saveToken(token: string) {
83
+ this.secureStorage.setItem('accessToken', token).subscribe();
84
+ }
85
+ }
86
+ ```
87
+
88
+ ## 📚 Documentación Completa
89
+
90
+ ### API Principal
91
+
92
+ #### `SecureStorage`
93
+
94
+ **`setItem(key: string, value: string): Promise<void>`**
95
+ Guarda un valor encriptado en localStorage.
96
+
97
+ **`getItem(key: string): Promise<string | null>`**
98
+ Recupera y desencripta un valor de localStorage.
99
+
100
+ **`removeItem(key: string): Promise<void>`**
101
+ Elimina un valor de localStorage.
102
+
103
+ **`hasItem(key: string): Promise<boolean>`**
104
+ Verifica si existe una clave.
105
+
106
+ **`clear(): void`**
107
+ Limpia todos los datos encriptados.
108
+
109
+ **`migrateExistingData(keys: string[]): Promise<void>`**
110
+ Migra datos existentes no encriptados a formato encriptado.
111
+
112
+ ### React Hooks
113
+
114
+ #### `useSecureStorage<T>(key: string, initialValue: T)`
115
+ Hook principal para usar SecureStorage de forma reactiva.
116
+
117
+ ```jsx
118
+ const [user, setUser, loading, error] = useSecureStorage('user', null);
119
+ ```
120
+
121
+ **Retorna:** `[value, setValue, loading, error]`
122
+
123
+ #### `useSecureStorageItem(key: string)`
124
+ Verifica si existe una clave.
125
+
126
+ ```jsx
127
+ const [hasToken, loading, error] = useSecureStorageItem('accessToken');
128
+ ```
129
+
130
+ **Retorna:** `[exists, loading, error]`
131
+
132
+ #### `useSecureStorageDebug()`
133
+ Obtiene información de debug del sistema.
134
+
135
+ ```jsx
136
+ const debugInfo = useSecureStorageDebug();
137
+ console.log(`Claves encriptadas: ${debugInfo.encryptedKeys.length}`);
138
+ ```
139
+
140
+ ### Angular Service
141
+
142
+ #### `SecureStorageService`
143
+
144
+ ```typescript
145
+ // Inyectar el servicio
146
+ constructor(private secureStorage: SecureStorageService) {}
147
+
148
+ // Guardar
149
+ this.secureStorage.setItem('key', 'value').subscribe();
150
+
151
+ // Leer
152
+ this.secureStorage.getItem('key').subscribe(value => console.log(value));
153
+
154
+ // Guardar objetos JSON
155
+ this.secureStorage.setObject('user', { id: 1, name: 'Juan' }).subscribe();
156
+
157
+ // Leer objetos JSON
158
+ this.secureStorage.getObject<User>('user').subscribe(user => console.log(user));
159
+
160
+ // Obtener debug info como Observable
161
+ this.secureStorage.getDebugInfo$().subscribe(info => console.log(info));
162
+ ```
163
+
164
+ ## 🔄 Migración de Datos Existentes
165
+
166
+ Si ya tienes datos en localStorage sin encriptar, puedes migrarlos fácilmente:
167
+
168
+ ```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
+ ]);
178
+ ```
179
+
180
+ **Recomendación:** Ejecuta esto al iniciar tu aplicación para migrar automáticamente.
181
+
182
+ ## 🛡️ Seguridad
183
+
184
+ ### ¿Qué protege?
185
+
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
189
+
190
+ ### ¿Qué NO protege?
191
+
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
195
+
196
+ ### Cómo Funciona
197
+
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
202
+
203
+ **Ejemplo de localStorage:**
204
+
205
+ ```
206
+ Antes:
207
+ accessToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
208
+ user: '{"id":1,"name":"Juan"}'
209
+
210
+ Después:
211
+ __enc_a7f5d8e2c1b4: "Qm9keUVuY3J5cHRlZERhdGE..."
212
+ __enc_9c3e7b1a5f8d: "QW5vdGhlckVuY3J5cHRlZA..."
213
+ __app_salt: "cmFuZG9tU2FsdEhlcmU="
214
+ ```
215
+
216
+ ## 🧪 Utilidades de Debug
217
+
218
+ ```javascript
219
+ import { debugEncryptionState, testEncryption, forceMigration } from '@mtt/local-cipher';
220
+
221
+ // Ver estado del sistema
222
+ await debugEncryptionState();
223
+
224
+ // Probar encriptación
225
+ await testEncryption();
226
+
227
+ // Forzar migración
228
+ await forceMigration(['accessToken', 'refreshToken']);
229
+ ```
230
+
231
+ ## 🌐 Compatibilidad
232
+
233
+ Requiere navegadores con soporte para **Web Crypto API**:
234
+
235
+ - ✅ Chrome 37+
236
+ - ✅ Firefox 34+
237
+ - ✅ Safari 11+
238
+ - ✅ Edge 12+
239
+ - ✅ Opera 24+
240
+
241
+ **Nota:** En navegadores sin soporte, la librería hace fallback automático a localStorage normal.
242
+
243
+ ## 📄 Licencia
244
+
245
+ MIT © MTT
246
+
247
+ ## 🤝 Contribuir
248
+
249
+ Las contribuciones son bienvenidas. Por favor abre un issue o pull request en GitHub.
250
+
251
+ ## 📞 Soporte
252
+
253
+ Si encuentras algún problema o tienes preguntas, abre un issue en GitHub.
@@ -0,0 +1,267 @@
1
+ import { Observable } from 'rxjs';
2
+
3
+ /**
4
+ * EncryptionHelper - Clase responsable de todas las operaciones criptográficas
5
+ * Implementa AES-256-GCM con derivación de claves PBKDF2 y fingerprinting del navegador
6
+ */
7
+ declare class EncryptionHelper {
8
+ private static readonly ALGORITHM;
9
+ private static readonly KEY_LENGTH;
10
+ private static readonly IV_LENGTH;
11
+ private static readonly SALT_LENGTH;
12
+ private static readonly ITERATIONS;
13
+ private static readonly HASH_ALGORITHM;
14
+ private static readonly SALT_STORAGE_KEY;
15
+ private static readonly APP_IDENTIFIER;
16
+ private key;
17
+ private baseKey;
18
+ private baseKeyPromise;
19
+ /**
20
+ * Genera un fingerprint único del navegador
21
+ * Combina múltiples características del navegador para crear una huella digital
22
+ */
23
+ private generateBaseKey;
24
+ /**
25
+ * Hashea un string usando SHA-256
26
+ * @param str - String a hashear
27
+ * @returns Hash hexadecimal
28
+ */
29
+ private hashString;
30
+ /**
31
+ * Deriva una clave criptográfica usando PBKDF2
32
+ * @param password - Password base (fingerprint)
33
+ * @param salt - Salt aleatorio
34
+ * @returns CryptoKey para AES-GCM
35
+ */
36
+ private deriveKey;
37
+ /**
38
+ * Inicializa el sistema de encriptación generando un nuevo salt
39
+ */
40
+ initialize(): Promise<void>;
41
+ /**
42
+ * Inicializa desde un salt almacenado previamente
43
+ */
44
+ initializeFromStored(): Promise<void>;
45
+ /**
46
+ * Encripta un texto plano usando AES-256-GCM
47
+ * @param plaintext - Texto a encriptar
48
+ * @returns Texto encriptado en Base64 (IV + datos encriptados)
49
+ */
50
+ encrypt(plaintext: string): Promise<string>;
51
+ /**
52
+ * Desencripta un texto encriptado
53
+ * @param ciphertext - Texto encriptado en Base64
54
+ * @returns Texto plano
55
+ */
56
+ decrypt(ciphertext: string): Promise<string>;
57
+ /**
58
+ * Encripta el nombre de una clave para ofuscar nombres en localStorage
59
+ * @param keyName - Nombre original de la clave
60
+ * @returns Nombre encriptado con prefijo __enc_
61
+ */
62
+ encryptKey(keyName: string): Promise<string>;
63
+ /**
64
+ * Limpia todos los datos encriptados del localStorage
65
+ */
66
+ clearEncryptedData(): void;
67
+ /**
68
+ * Verifica si el navegador soporta Web Crypto API
69
+ */
70
+ static isSupported(): boolean;
71
+ private arrayBufferToBase64;
72
+ private base64ToArrayBuffer;
73
+ private arrayBufferToHex;
74
+ }
75
+
76
+ /**
77
+ * SecureStorage - API de alto nivel que imita localStorage con cifrado automático
78
+ * Implementa el patrón Singleton
79
+ */
80
+ declare class SecureStorage {
81
+ private static instance;
82
+ private encryptionHelper;
83
+ private constructor();
84
+ /**
85
+ * Obtiene la instancia singleton de SecureStorage
86
+ */
87
+ static getInstance(): SecureStorage;
88
+ /**
89
+ * Guarda un valor encriptado en localStorage
90
+ * @param key - Clave para almacenar
91
+ * @param value - Valor a encriptar y almacenar
92
+ */
93
+ setItem(key: string, value: string): Promise<void>;
94
+ /**
95
+ * Recupera y desencripta un valor de localStorage
96
+ * @param key - Clave a buscar
97
+ * @returns Valor desencriptado o null si no existe
98
+ */
99
+ getItem(key: string): Promise<string | null>;
100
+ /**
101
+ * Elimina un valor de localStorage
102
+ * @param key - Clave a eliminar
103
+ */
104
+ removeItem(key: string): Promise<void>;
105
+ /**
106
+ * Verifica si existe un valor para la clave dada
107
+ * @param key - Clave a verificar
108
+ * @returns true si existe, false si no
109
+ */
110
+ hasItem(key: string): Promise<boolean>;
111
+ /**
112
+ * Limpia todos los datos encriptados
113
+ */
114
+ clear(): void;
115
+ /**
116
+ * Migra datos existentes no encriptados a formato encriptado
117
+ * @param keys - Array de claves a migrar
118
+ */
119
+ migrateExistingData(keys: string[]): Promise<void>;
120
+ /**
121
+ * Obtiene información de debug sobre el estado del almacenamiento
122
+ */
123
+ getDebugInfo(): {
124
+ cryptoSupported: boolean;
125
+ encryptedKeys: string[];
126
+ unencryptedKeys: string[];
127
+ totalKeys: number;
128
+ };
129
+ }
130
+
131
+ declare const secureStorage$1: SecureStorage;
132
+ /**
133
+ * Hook de React para usar SecureStorage de forma reactiva
134
+ * Similar a useState pero con persistencia encriptada
135
+ *
136
+ * @param key - Clave para almacenar en localStorage
137
+ * @param initialValue - Valor inicial si no existe en storage
138
+ * @returns [value, setValue, loading, error]
139
+ *
140
+ * @example
141
+ * const [token, setToken, loading] = useSecureStorage('accessToken', '');
142
+ */
143
+ declare function useSecureStorage<T = string>(key: string, initialValue: T): [T, (value: T) => Promise<void>, boolean, Error | null];
144
+ /**
145
+ * Hook para verificar si una clave existe en SecureStorage
146
+ *
147
+ * @param key - Clave a verificar
148
+ * @returns [exists, loading, error]
149
+ *
150
+ * @example
151
+ * const [hasToken, loading] = useSecureStorageItem('accessToken');
152
+ */
153
+ declare function useSecureStorageItem(key: string): [boolean, boolean, Error | null];
154
+ /**
155
+ * Hook para obtener información de debug del almacenamiento
156
+ *
157
+ * @returns Información de debug
158
+ *
159
+ * @example
160
+ * const debugInfo = useSecureStorageDebug();
161
+ * console.log(`Claves encriptadas: ${debugInfo.encryptedKeys.length}`);
162
+ */
163
+ declare function useSecureStorageDebug(): any;
164
+
165
+ /**
166
+ * Servicio de Angular para SecureStorage
167
+ * Proporciona una API reactiva usando RxJS Observables
168
+ *
169
+ * @example
170
+ * constructor(private secureStorage: SecureStorageService) {}
171
+ *
172
+ * // Guardar
173
+ * this.secureStorage.setItem('token', 'abc123').subscribe();
174
+ *
175
+ * // Leer
176
+ * this.secureStorage.getItem('token').subscribe(token => console.log(token));
177
+ */
178
+ declare class SecureStorageService {
179
+ private storage;
180
+ private debugInfo$;
181
+ constructor();
182
+ /**
183
+ * Guarda un valor encriptado
184
+ * @param key - Clave
185
+ * @param value - Valor a guardar
186
+ * @returns Observable que completa cuando se guarda
187
+ */
188
+ setItem(key: string, value: string): Observable<void>;
189
+ /**
190
+ * Recupera un valor desencriptado
191
+ * @param key - Clave
192
+ * @returns Observable con el valor o null
193
+ */
194
+ getItem(key: string): Observable<string | null>;
195
+ /**
196
+ * Elimina un valor
197
+ * @param key - Clave a eliminar
198
+ * @returns Observable que completa cuando se elimina
199
+ */
200
+ removeItem(key: string): Observable<void>;
201
+ /**
202
+ * Verifica si existe una clave
203
+ * @param key - Clave a verificar
204
+ * @returns Observable con true/false
205
+ */
206
+ hasItem(key: string): Observable<boolean>;
207
+ /**
208
+ * Limpia todos los datos encriptados
209
+ */
210
+ clear(): void;
211
+ /**
212
+ * Migra datos existentes a formato encriptado
213
+ * @param keys - Array de claves a migrar
214
+ * @returns Observable que completa cuando termina la migración
215
+ */
216
+ migrateExistingData(keys: string[]): Observable<void>;
217
+ /**
218
+ * Obtiene información de debug como Observable
219
+ * @returns Observable con información de debug que se actualiza automáticamente
220
+ */
221
+ getDebugInfo$(): Observable<{
222
+ cryptoSupported: boolean;
223
+ encryptedKeys: string[];
224
+ unencryptedKeys: string[];
225
+ totalKeys: number;
226
+ }>;
227
+ /**
228
+ * Obtiene información de debug de forma síncrona
229
+ */
230
+ private getDebugInfo;
231
+ /**
232
+ * Helper para guardar objetos JSON
233
+ * @param key - Clave
234
+ * @param value - Objeto a guardar
235
+ */
236
+ setObject<T>(key: string, value: T): Observable<void>;
237
+ /**
238
+ * Helper para recuperar objetos JSON
239
+ * @param key - Clave
240
+ * @returns Observable con el objeto parseado o null
241
+ */
242
+ getObject<T>(key: string): Observable<T | null>;
243
+ }
244
+
245
+ /**
246
+ * Función de debug para verificar el estado del sistema de encriptación
247
+ * Muestra información detallada en la consola
248
+ */
249
+ declare function debugEncryptionState(): Promise<void>;
250
+ /**
251
+ * Fuerza la migración de claves comunes a formato encriptado
252
+ * Útil para desarrollo y testing
253
+ */
254
+ declare function forceMigration(customKeys?: string[]): Promise<void>;
255
+
256
+ /**
257
+ * @mtt/local-cipher
258
+ * Librería de cifrado local AES-256-GCM para Angular, React y JavaScript
259
+ *
260
+ * @author MTT
261
+ * @license MIT
262
+ */
263
+
264
+ declare const secureStorage: SecureStorage;
265
+ declare const VERSION = "1.0.0";
266
+
267
+ export { EncryptionHelper, SecureStorage, SecureStorageService, VERSION, debugEncryptionState, forceMigration, secureStorage$1 as reactSecureStorage, secureStorage, useSecureStorage, useSecureStorageDebug, useSecureStorageItem };