@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/dist/index.js ADDED
@@ -0,0 +1,779 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var core = require('@angular/core');
5
+ var rxjs = require('rxjs');
6
+ var operators = require('rxjs/operators');
7
+
8
+ /**
9
+ * EncryptionHelper - Clase responsable de todas las operaciones criptográficas
10
+ * Implementa AES-256-GCM con derivación de claves PBKDF2 y fingerprinting del navegador
11
+ */
12
+ class EncryptionHelper {
13
+ constructor() {
14
+ // Propiedades privadas
15
+ this.key = null;
16
+ this.baseKey = '';
17
+ this.baseKeyPromise = null;
18
+ }
19
+ /**
20
+ * Genera un fingerprint único del navegador
21
+ * Combina múltiples características del navegador para crear una huella digital
22
+ */
23
+ async generateBaseKey() {
24
+ if (this.baseKeyPromise) {
25
+ return this.baseKeyPromise;
26
+ }
27
+ this.baseKeyPromise = (async () => {
28
+ const components = [
29
+ navigator.userAgent,
30
+ navigator.language,
31
+ screen.width.toString(),
32
+ screen.height.toString(),
33
+ screen.colorDepth.toString(),
34
+ new Intl.DateTimeFormat().resolvedOptions().timeZone,
35
+ EncryptionHelper.APP_IDENTIFIER,
36
+ ];
37
+ const fingerprint = components.join('|');
38
+ this.baseKey = await this.hashString(fingerprint);
39
+ return this.baseKey;
40
+ })();
41
+ return this.baseKeyPromise;
42
+ }
43
+ /**
44
+ * Hashea un string usando SHA-256
45
+ * @param str - String a hashear
46
+ * @returns Hash hexadecimal
47
+ */
48
+ async hashString(str) {
49
+ const encoder = new TextEncoder();
50
+ const data = encoder.encode(str);
51
+ const hashBuffer = await crypto.subtle.digest(EncryptionHelper.HASH_ALGORITHM, data);
52
+ return this.arrayBufferToHex(hashBuffer);
53
+ }
54
+ /**
55
+ * Deriva una clave criptográfica usando PBKDF2
56
+ * @param password - Password base (fingerprint)
57
+ * @param salt - Salt aleatorio
58
+ * @returns CryptoKey para AES-GCM
59
+ */
60
+ async deriveKey(password, salt) {
61
+ const encoder = new TextEncoder();
62
+ const passwordBuffer = encoder.encode(password);
63
+ // Importar el password como material de clave
64
+ const keyMaterial = await crypto.subtle.importKey('raw', passwordBuffer, 'PBKDF2', false, ['deriveBits', 'deriveKey']);
65
+ // Derivar la clave AES-GCM
66
+ return crypto.subtle.deriveKey({
67
+ name: 'PBKDF2',
68
+ salt,
69
+ iterations: EncryptionHelper.ITERATIONS,
70
+ hash: EncryptionHelper.HASH_ALGORITHM,
71
+ }, keyMaterial, {
72
+ name: EncryptionHelper.ALGORITHM,
73
+ length: EncryptionHelper.KEY_LENGTH,
74
+ }, false, ['encrypt', 'decrypt']);
75
+ }
76
+ /**
77
+ * Inicializa el sistema de encriptación generando un nuevo salt
78
+ */
79
+ async initialize() {
80
+ // Generar salt aleatorio
81
+ const salt = crypto.getRandomValues(new Uint8Array(EncryptionHelper.SALT_LENGTH));
82
+ // Obtener y hashear el baseKey
83
+ const baseKey = await this.generateBaseKey();
84
+ // Derivar la clave
85
+ this.key = await this.deriveKey(baseKey, salt);
86
+ // Guardar el salt en localStorage
87
+ localStorage.setItem(EncryptionHelper.SALT_STORAGE_KEY, this.arrayBufferToBase64(salt.buffer));
88
+ }
89
+ /**
90
+ * Inicializa desde un salt almacenado previamente
91
+ */
92
+ async initializeFromStored() {
93
+ const storedSalt = localStorage.getItem(EncryptionHelper.SALT_STORAGE_KEY);
94
+ if (!storedSalt) {
95
+ // Si no hay salt almacenado, inicializar uno nuevo
96
+ await this.initialize();
97
+ return;
98
+ }
99
+ // Recuperar el salt
100
+ const salt = new Uint8Array(this.base64ToArrayBuffer(storedSalt));
101
+ // Obtener el baseKey
102
+ const baseKey = await this.generateBaseKey();
103
+ // Derivar la misma clave
104
+ this.key = await this.deriveKey(baseKey, salt);
105
+ }
106
+ /**
107
+ * Encripta un texto plano usando AES-256-GCM
108
+ * @param plaintext - Texto a encriptar
109
+ * @returns Texto encriptado en Base64 (IV + datos encriptados)
110
+ */
111
+ async encrypt(plaintext) {
112
+ if (!this.key) {
113
+ await this.initializeFromStored();
114
+ }
115
+ if (!this.key) {
116
+ throw new Error('No se pudo inicializar la clave de encriptación');
117
+ }
118
+ // Convertir texto a bytes
119
+ const encoder = new TextEncoder();
120
+ const data = encoder.encode(plaintext);
121
+ // Generar IV aleatorio
122
+ const iv = crypto.getRandomValues(new Uint8Array(EncryptionHelper.IV_LENGTH));
123
+ // Encriptar
124
+ const encryptedBuffer = await crypto.subtle.encrypt({
125
+ name: EncryptionHelper.ALGORITHM,
126
+ iv,
127
+ }, this.key, data);
128
+ // Combinar IV + datos encriptados
129
+ const combined = new Uint8Array(iv.length + encryptedBuffer.byteLength);
130
+ combined.set(iv, 0);
131
+ combined.set(new Uint8Array(encryptedBuffer), iv.length);
132
+ // Retornar en Base64
133
+ return this.arrayBufferToBase64(combined.buffer);
134
+ }
135
+ /**
136
+ * Desencripta un texto encriptado
137
+ * @param ciphertext - Texto encriptado en Base64
138
+ * @returns Texto plano
139
+ */
140
+ async decrypt(ciphertext) {
141
+ if (!this.key) {
142
+ await this.initializeFromStored();
143
+ }
144
+ if (!this.key) {
145
+ throw new Error('No se pudo inicializar la clave de encriptación');
146
+ }
147
+ try {
148
+ // Decodificar de Base64
149
+ const combined = new Uint8Array(this.base64ToArrayBuffer(ciphertext));
150
+ // Extraer IV y datos encriptados
151
+ const iv = combined.slice(0, EncryptionHelper.IV_LENGTH);
152
+ const encryptedData = combined.slice(EncryptionHelper.IV_LENGTH);
153
+ // Desencriptar
154
+ const decryptedBuffer = await crypto.subtle.decrypt({
155
+ name: EncryptionHelper.ALGORITHM,
156
+ iv,
157
+ }, this.key, encryptedData);
158
+ // Convertir bytes a texto
159
+ const decoder = new TextDecoder();
160
+ return decoder.decode(decryptedBuffer);
161
+ }
162
+ catch (error) {
163
+ throw new Error(`Error al desencriptar: ${error instanceof Error ? error.message : 'Error desconocido'}`);
164
+ }
165
+ }
166
+ /**
167
+ * Encripta el nombre de una clave para ofuscar nombres en localStorage
168
+ * @param keyName - Nombre original de la clave
169
+ * @returns Nombre encriptado con prefijo __enc_
170
+ */
171
+ async encryptKey(keyName) {
172
+ const baseKey = await this.generateBaseKey();
173
+ const combined = keyName + baseKey;
174
+ const hash = await this.hashString(combined);
175
+ return `__enc_${hash.substring(0, 16)}`;
176
+ }
177
+ /**
178
+ * Limpia todos los datos encriptados del localStorage
179
+ */
180
+ clearEncryptedData() {
181
+ const keysToRemove = [];
182
+ // Identificar todas las claves encriptadas
183
+ for (let i = 0; i < localStorage.length; i++) {
184
+ const key = localStorage.key(i);
185
+ if (key && key.startsWith('__enc_')) {
186
+ keysToRemove.push(key);
187
+ }
188
+ }
189
+ // Eliminar claves encriptadas
190
+ keysToRemove.forEach(key => localStorage.removeItem(key));
191
+ // Eliminar salt
192
+ localStorage.removeItem(EncryptionHelper.SALT_STORAGE_KEY);
193
+ // Resetear clave en memoria
194
+ this.key = null;
195
+ this.baseKey = '';
196
+ this.baseKeyPromise = null;
197
+ }
198
+ /**
199
+ * Verifica si el navegador soporta Web Crypto API
200
+ */
201
+ static isSupported() {
202
+ return !!(typeof crypto !== 'undefined' &&
203
+ crypto.subtle &&
204
+ crypto.getRandomValues);
205
+ }
206
+ // Métodos auxiliares para conversión de datos
207
+ arrayBufferToBase64(buffer) {
208
+ const bytes = new Uint8Array(buffer);
209
+ let binary = '';
210
+ for (let i = 0; i < bytes.length; i++) {
211
+ binary += String.fromCharCode(bytes[i]);
212
+ }
213
+ return btoa(binary);
214
+ }
215
+ base64ToArrayBuffer(base64) {
216
+ const binary = atob(base64);
217
+ const bytes = new Uint8Array(binary.length);
218
+ for (let i = 0; i < binary.length; i++) {
219
+ bytes[i] = binary.charCodeAt(i);
220
+ }
221
+ return bytes.buffer;
222
+ }
223
+ arrayBufferToHex(buffer) {
224
+ const bytes = new Uint8Array(buffer);
225
+ return Array.from(bytes)
226
+ .map(b => b.toString(16).padStart(2, '0'))
227
+ .join('');
228
+ }
229
+ }
230
+ // Constantes criptográficas
231
+ EncryptionHelper.ALGORITHM = 'AES-GCM';
232
+ EncryptionHelper.KEY_LENGTH = 256;
233
+ EncryptionHelper.IV_LENGTH = 12; // 96 bits para GCM
234
+ EncryptionHelper.SALT_LENGTH = 16; // 128 bits
235
+ EncryptionHelper.ITERATIONS = 100000;
236
+ EncryptionHelper.HASH_ALGORITHM = 'SHA-256';
237
+ EncryptionHelper.SALT_STORAGE_KEY = '__app_salt';
238
+ EncryptionHelper.APP_IDENTIFIER = 'mtt-local-cipher-v1'; // Identificador único de la app
239
+
240
+ /**
241
+ * SecureStorage - API de alto nivel que imita localStorage con cifrado automático
242
+ * Implementa el patrón Singleton
243
+ */
244
+ class SecureStorage {
245
+ constructor() {
246
+ this.encryptionHelper = new EncryptionHelper();
247
+ }
248
+ /**
249
+ * Obtiene la instancia singleton de SecureStorage
250
+ */
251
+ static getInstance() {
252
+ if (!SecureStorage.instance) {
253
+ SecureStorage.instance = new SecureStorage();
254
+ }
255
+ return SecureStorage.instance;
256
+ }
257
+ /**
258
+ * Guarda un valor encriptado en localStorage
259
+ * @param key - Clave para almacenar
260
+ * @param value - Valor a encriptar y almacenar
261
+ */
262
+ async setItem(key, value) {
263
+ if (!EncryptionHelper.isSupported()) {
264
+ console.warn('Web Crypto API no soportada, usando localStorage sin encriptar');
265
+ localStorage.setItem(key, value);
266
+ return;
267
+ }
268
+ try {
269
+ // Encriptar el nombre de la clave
270
+ const encryptedKey = await this.encryptionHelper.encryptKey(key);
271
+ // Encriptar el valor
272
+ const encryptedValue = await this.encryptionHelper.encrypt(value);
273
+ // Guardar en localStorage
274
+ localStorage.setItem(encryptedKey, encryptedValue);
275
+ }
276
+ catch (error) {
277
+ console.error('Error al guardar dato encriptado, usando fallback:', error);
278
+ localStorage.setItem(key, value);
279
+ }
280
+ }
281
+ /**
282
+ * Recupera y desencripta un valor de localStorage
283
+ * @param key - Clave a buscar
284
+ * @returns Valor desencriptado o null si no existe
285
+ */
286
+ async getItem(key) {
287
+ if (!EncryptionHelper.isSupported()) {
288
+ return localStorage.getItem(key);
289
+ }
290
+ try {
291
+ // Encriptar el nombre de la clave
292
+ const encryptedKey = await this.encryptionHelper.encryptKey(key);
293
+ // Buscar el valor encriptado
294
+ let encryptedValue = localStorage.getItem(encryptedKey);
295
+ // Retrocompatibilidad: si no existe con clave encriptada, buscar con clave normal
296
+ if (!encryptedValue) {
297
+ encryptedValue = localStorage.getItem(key);
298
+ if (!encryptedValue) {
299
+ return null;
300
+ }
301
+ // Si encontramos un valor con clave normal, intentar desencriptarlo
302
+ // (podría ser un valor ya encriptado pero con clave antigua)
303
+ }
304
+ // Desencriptar el valor
305
+ return await this.encryptionHelper.decrypt(encryptedValue);
306
+ }
307
+ catch (error) {
308
+ console.error('Error al recuperar dato encriptado:', error);
309
+ // Fallback: intentar leer directamente
310
+ return localStorage.getItem(key);
311
+ }
312
+ }
313
+ /**
314
+ * Elimina un valor de localStorage
315
+ * @param key - Clave a eliminar
316
+ */
317
+ async removeItem(key) {
318
+ if (!EncryptionHelper.isSupported()) {
319
+ localStorage.removeItem(key);
320
+ return;
321
+ }
322
+ try {
323
+ // Encriptar el nombre de la clave
324
+ const encryptedKey = await this.encryptionHelper.encryptKey(key);
325
+ // Eliminar ambas versiones (encriptada y normal) por seguridad
326
+ localStorage.removeItem(encryptedKey);
327
+ localStorage.removeItem(key);
328
+ }
329
+ catch (error) {
330
+ console.error('Error al eliminar dato encriptado:', error);
331
+ localStorage.removeItem(key);
332
+ }
333
+ }
334
+ /**
335
+ * Verifica si existe un valor para la clave dada
336
+ * @param key - Clave a verificar
337
+ * @returns true si existe, false si no
338
+ */
339
+ async hasItem(key) {
340
+ const value = await this.getItem(key);
341
+ return value !== null;
342
+ }
343
+ /**
344
+ * Limpia todos los datos encriptados
345
+ */
346
+ clear() {
347
+ this.encryptionHelper.clearEncryptedData();
348
+ }
349
+ /**
350
+ * Migra datos existentes no encriptados a formato encriptado
351
+ * @param keys - Array de claves a migrar
352
+ */
353
+ async migrateExistingData(keys) {
354
+ if (!EncryptionHelper.isSupported()) {
355
+ console.warn('Web Crypto API no soportada, no se puede migrar');
356
+ return;
357
+ }
358
+ console.log(`🔄 Iniciando migración de ${keys.length} claves...`);
359
+ for (const key of keys) {
360
+ try {
361
+ // Leer el valor no encriptado
362
+ const value = localStorage.getItem(key);
363
+ if (value === null) {
364
+ continue; // La clave no existe, saltar
365
+ }
366
+ // Verificar si ya está encriptado intentando desencriptarlo
367
+ try {
368
+ await this.encryptionHelper.decrypt(value);
369
+ console.log(`✓ ${key} ya está encriptado, saltando`);
370
+ continue;
371
+ }
372
+ catch {
373
+ // No está encriptado, proceder con la migración
374
+ }
375
+ // Guardar usando setItem (que encriptará automáticamente)
376
+ await this.setItem(key, value);
377
+ // Eliminar la versión no encriptada
378
+ localStorage.removeItem(key);
379
+ console.log(`✓ ${key} migrado exitosamente`);
380
+ }
381
+ catch (error) {
382
+ console.error(`✗ Error al migrar ${key}:`, error);
383
+ }
384
+ }
385
+ console.log('✅ Migración completada');
386
+ }
387
+ /**
388
+ * Obtiene información de debug sobre el estado del almacenamiento
389
+ */
390
+ getDebugInfo() {
391
+ const allKeys = [];
392
+ for (let i = 0; i < localStorage.length; i++) {
393
+ const key = localStorage.key(i);
394
+ if (key)
395
+ allKeys.push(key);
396
+ }
397
+ const encryptedKeys = allKeys.filter(key => key.startsWith('__enc_'));
398
+ const unencryptedKeys = allKeys.filter(key => !key.startsWith('__enc_') && key !== '__app_salt');
399
+ return {
400
+ cryptoSupported: EncryptionHelper.isSupported(),
401
+ encryptedKeys,
402
+ unencryptedKeys,
403
+ totalKeys: allKeys.length,
404
+ };
405
+ }
406
+ }
407
+ SecureStorage.instance = null;
408
+
409
+ const secureStorage$2 = SecureStorage.getInstance();
410
+ /**
411
+ * Hook de React para usar SecureStorage de forma reactiva
412
+ * Similar a useState pero con persistencia encriptada
413
+ *
414
+ * @param key - Clave para almacenar en localStorage
415
+ * @param initialValue - Valor inicial si no existe en storage
416
+ * @returns [value, setValue, loading, error]
417
+ *
418
+ * @example
419
+ * const [token, setToken, loading] = useSecureStorage('accessToken', '');
420
+ */
421
+ function useSecureStorage(key, initialValue) {
422
+ const [storedValue, setStoredValue] = react.useState(initialValue);
423
+ const [loading, setLoading] = react.useState(true);
424
+ const [error, setError] = react.useState(null);
425
+ // Cargar valor inicial
426
+ react.useEffect(() => {
427
+ const loadValue = async () => {
428
+ try {
429
+ setLoading(true);
430
+ setError(null);
431
+ const item = await secureStorage$2.getItem(key);
432
+ if (item !== null) {
433
+ // Si T es un objeto, parsear JSON
434
+ if (typeof initialValue === 'object') {
435
+ setStoredValue(JSON.parse(item));
436
+ }
437
+ else {
438
+ setStoredValue(item);
439
+ }
440
+ }
441
+ else {
442
+ setStoredValue(initialValue);
443
+ }
444
+ }
445
+ catch (err) {
446
+ setError(err instanceof Error ? err : new Error('Error al cargar valor'));
447
+ setStoredValue(initialValue);
448
+ }
449
+ finally {
450
+ setLoading(false);
451
+ }
452
+ };
453
+ loadValue();
454
+ }, [key]); // Solo recargar si cambia la clave
455
+ // Función para actualizar el valor
456
+ const setValue = react.useCallback(async (value) => {
457
+ try {
458
+ setError(null);
459
+ setStoredValue(value);
460
+ // Si T es un objeto, convertir a JSON
461
+ const valueToStore = typeof value === 'object'
462
+ ? JSON.stringify(value)
463
+ : String(value);
464
+ await secureStorage$2.setItem(key, valueToStore);
465
+ }
466
+ catch (err) {
467
+ setError(err instanceof Error ? err : new Error('Error al guardar valor'));
468
+ throw err;
469
+ }
470
+ }, [key]);
471
+ return [storedValue, setValue, loading, error];
472
+ }
473
+ /**
474
+ * Hook para verificar si una clave existe en SecureStorage
475
+ *
476
+ * @param key - Clave a verificar
477
+ * @returns [exists, loading, error]
478
+ *
479
+ * @example
480
+ * const [hasToken, loading] = useSecureStorageItem('accessToken');
481
+ */
482
+ function useSecureStorageItem(key) {
483
+ const [exists, setExists] = react.useState(false);
484
+ const [loading, setLoading] = react.useState(true);
485
+ const [error, setError] = react.useState(null);
486
+ react.useEffect(() => {
487
+ const checkExists = async () => {
488
+ try {
489
+ setLoading(true);
490
+ setError(null);
491
+ const hasItem = await secureStorage$2.hasItem(key);
492
+ setExists(hasItem);
493
+ }
494
+ catch (err) {
495
+ setError(err instanceof Error ? err : new Error('Error al verificar clave'));
496
+ setExists(false);
497
+ }
498
+ finally {
499
+ setLoading(false);
500
+ }
501
+ };
502
+ checkExists();
503
+ }, [key]);
504
+ return [exists, loading, error];
505
+ }
506
+ /**
507
+ * Hook para obtener información de debug del almacenamiento
508
+ *
509
+ * @returns Información de debug
510
+ *
511
+ * @example
512
+ * const debugInfo = useSecureStorageDebug();
513
+ * console.log(`Claves encriptadas: ${debugInfo.encryptedKeys.length}`);
514
+ */
515
+ function useSecureStorageDebug() {
516
+ const [debugInfo, setDebugInfo] = react.useState(secureStorage$2.getDebugInfo());
517
+ react.useEffect(() => {
518
+ // Actualizar cada segundo
519
+ const interval = setInterval(() => {
520
+ setDebugInfo(secureStorage$2.getDebugInfo());
521
+ }, 1000);
522
+ return () => clearInterval(interval);
523
+ }, []);
524
+ return debugInfo;
525
+ }
526
+
527
+ /******************************************************************************
528
+ Copyright (c) Microsoft Corporation.
529
+
530
+ Permission to use, copy, modify, and/or distribute this software for any
531
+ purpose with or without fee is hereby granted.
532
+
533
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
534
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
535
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
536
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
537
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
538
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
539
+ PERFORMANCE OF THIS SOFTWARE.
540
+ ***************************************************************************** */
541
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
542
+
543
+
544
+ function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
545
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
546
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
547
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
548
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
549
+ var _, done = false;
550
+ for (var i = decorators.length - 1; i >= 0; i--) {
551
+ var context = {};
552
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
553
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
554
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
555
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
556
+ if (kind === "accessor") {
557
+ if (result === void 0) continue;
558
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
559
+ if (_ = accept(result.get)) descriptor.get = _;
560
+ if (_ = accept(result.set)) descriptor.set = _;
561
+ if (_ = accept(result.init)) initializers.unshift(_);
562
+ }
563
+ else if (_ = accept(result)) {
564
+ if (kind === "field") initializers.unshift(_);
565
+ else descriptor[key] = _;
566
+ }
567
+ }
568
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
569
+ done = true;
570
+ }
571
+ function __runInitializers(thisArg, initializers, value) {
572
+ var useValue = arguments.length > 2;
573
+ for (var i = 0; i < initializers.length; i++) {
574
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
575
+ }
576
+ return useValue ? value : void 0;
577
+ }
578
+ function __setFunctionName(f, name, prefix) {
579
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
580
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
581
+ }
582
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
583
+ var e = new Error(message);
584
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
585
+ };
586
+
587
+ /**
588
+ * Servicio de Angular para SecureStorage
589
+ * Proporciona una API reactiva usando RxJS Observables
590
+ *
591
+ * @example
592
+ * constructor(private secureStorage: SecureStorageService) {}
593
+ *
594
+ * // Guardar
595
+ * this.secureStorage.setItem('token', 'abc123').subscribe();
596
+ *
597
+ * // Leer
598
+ * this.secureStorage.getItem('token').subscribe(token => console.log(token));
599
+ */
600
+ let SecureStorageService = (() => {
601
+ let _classDecorators = [core.Injectable({
602
+ providedIn: 'root'
603
+ })];
604
+ let _classDescriptor;
605
+ let _classExtraInitializers = [];
606
+ let _classThis;
607
+ _classThis = class {
608
+ constructor() {
609
+ this.debugInfo$ = new rxjs.BehaviorSubject(this.getDebugInfo());
610
+ this.storage = SecureStorage.getInstance();
611
+ // Actualizar debug info cada segundo
612
+ setInterval(() => {
613
+ this.debugInfo$.next(this.getDebugInfo());
614
+ }, 1000);
615
+ }
616
+ /**
617
+ * Guarda un valor encriptado
618
+ * @param key - Clave
619
+ * @param value - Valor a guardar
620
+ * @returns Observable que completa cuando se guarda
621
+ */
622
+ setItem(key, value) {
623
+ return rxjs.from(this.storage.setItem(key, value));
624
+ }
625
+ /**
626
+ * Recupera un valor desencriptado
627
+ * @param key - Clave
628
+ * @returns Observable con el valor o null
629
+ */
630
+ getItem(key) {
631
+ return rxjs.from(this.storage.getItem(key));
632
+ }
633
+ /**
634
+ * Elimina un valor
635
+ * @param key - Clave a eliminar
636
+ * @returns Observable que completa cuando se elimina
637
+ */
638
+ removeItem(key) {
639
+ return rxjs.from(this.storage.removeItem(key));
640
+ }
641
+ /**
642
+ * Verifica si existe una clave
643
+ * @param key - Clave a verificar
644
+ * @returns Observable con true/false
645
+ */
646
+ hasItem(key) {
647
+ return rxjs.from(this.storage.hasItem(key));
648
+ }
649
+ /**
650
+ * Limpia todos los datos encriptados
651
+ */
652
+ clear() {
653
+ this.storage.clear();
654
+ }
655
+ /**
656
+ * Migra datos existentes a formato encriptado
657
+ * @param keys - Array de claves a migrar
658
+ * @returns Observable que completa cuando termina la migración
659
+ */
660
+ migrateExistingData(keys) {
661
+ return rxjs.from(this.storage.migrateExistingData(keys));
662
+ }
663
+ /**
664
+ * Obtiene información de debug como Observable
665
+ * @returns Observable con información de debug que se actualiza automáticamente
666
+ */
667
+ getDebugInfo$() {
668
+ return this.debugInfo$.asObservable();
669
+ }
670
+ /**
671
+ * Obtiene información de debug de forma síncrona
672
+ */
673
+ getDebugInfo() {
674
+ return this.storage.getDebugInfo();
675
+ }
676
+ /**
677
+ * Helper para guardar objetos JSON
678
+ * @param key - Clave
679
+ * @param value - Objeto a guardar
680
+ */
681
+ setObject(key, value) {
682
+ return this.setItem(key, JSON.stringify(value));
683
+ }
684
+ /**
685
+ * Helper para recuperar objetos JSON
686
+ * @param key - Clave
687
+ * @returns Observable con el objeto parseado o null
688
+ */
689
+ getObject(key) {
690
+ return this.getItem(key).pipe(operators.map(value => value ? JSON.parse(value) : null), operators.catchError(() => rxjs.from([null])));
691
+ }
692
+ };
693
+ __setFunctionName(_classThis, "SecureStorageService");
694
+ (() => {
695
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
696
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
697
+ _classThis = _classDescriptor.value;
698
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
699
+ __runInitializers(_classThis, _classExtraInitializers);
700
+ })();
701
+ return _classThis;
702
+ })();
703
+
704
+ const secureStorage$1 = SecureStorage.getInstance();
705
+ /**
706
+ * Función de debug para verificar el estado del sistema de encriptación
707
+ * Muestra información detallada en la consola
708
+ */
709
+ async function debugEncryptionState() {
710
+ console.group('🔐 Estado del Sistema de Encriptación');
711
+ console.log('Soporte Crypto API:', EncryptionHelper.isSupported());
712
+ // Obtener información de debug
713
+ const debugInfo = secureStorage$1.getDebugInfo();
714
+ console.log('Claves encriptadas:', debugInfo.encryptedKeys.length);
715
+ console.log('Claves sin encriptar:', debugInfo.unencryptedKeys);
716
+ console.log('Total de claves:', debugInfo.totalKeys);
717
+ if (debugInfo.encryptedKeys.length > 0) {
718
+ console.log('✅ Datos encriptados encontrados:');
719
+ debugInfo.encryptedKeys.forEach(key => {
720
+ const value = localStorage.getItem(key);
721
+ console.log(` ${key}: ${value?.substring(0, 30)}...`);
722
+ });
723
+ }
724
+ else {
725
+ console.log('⚠️ No se encontraron datos encriptados');
726
+ }
727
+ if (debugInfo.unencryptedKeys.length > 0) {
728
+ console.log('⚠️ Claves sin encriptar encontradas:');
729
+ debugInfo.unencryptedKeys.forEach(key => {
730
+ console.log(` ${key}`);
731
+ });
732
+ }
733
+ console.groupEnd();
734
+ }
735
+ /**
736
+ * Fuerza la migración de claves comunes a formato encriptado
737
+ * Útil para desarrollo y testing
738
+ */
739
+ async function forceMigration(customKeys) {
740
+ const defaultKeys = [
741
+ 'accessToken',
742
+ 'refreshToken',
743
+ 'user',
744
+ 'sessionId',
745
+ 'authToken',
746
+ 'userData',
747
+ ];
748
+ const keysToMigrate = customKeys || defaultKeys;
749
+ console.log(`🔄 Iniciando migración forzada de ${keysToMigrate.length} claves...`);
750
+ await secureStorage$1.migrateExistingData(keysToMigrate);
751
+ console.log('✅ Migración forzada completada');
752
+ // Mostrar estado después de la migración
753
+ await debugEncryptionState();
754
+ }
755
+
756
+ /**
757
+ * @mtt/local-cipher
758
+ * Librería de cifrado local AES-256-GCM para Angular, React y JavaScript
759
+ *
760
+ * @author MTT
761
+ * @license MIT
762
+ */
763
+ // Core exports
764
+ const secureStorage = SecureStorage.getInstance();
765
+ // Version
766
+ const VERSION = '1.0.0';
767
+
768
+ exports.EncryptionHelper = EncryptionHelper;
769
+ exports.SecureStorage = SecureStorage;
770
+ exports.SecureStorageService = SecureStorageService;
771
+ exports.VERSION = VERSION;
772
+ exports.debugEncryptionState = debugEncryptionState;
773
+ exports.forceMigration = forceMigration;
774
+ exports.reactSecureStorage = secureStorage$2;
775
+ exports.secureStorage = secureStorage;
776
+ exports.useSecureStorage = useSecureStorage;
777
+ exports.useSecureStorageDebug = useSecureStorageDebug;
778
+ exports.useSecureStorageItem = useSecureStorageItem;
779
+ //# sourceMappingURL=index.js.map