@bantis/local-cipher 2.0.0 → 2.0.1
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 +1 -1
- package/README.md +207 -282
- package/package.json +21 -7
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,158 +1,210 @@
|
|
|
1
|
-
# @bantis/local-cipher
|
|
1
|
+
# @bantis/local-cipher
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@bantis/local-cipher)
|
|
4
|
+
[](https://www.npmjs.com/package/@bantis/local-cipher)
|
|
4
5
|
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://www.typescriptlang.org/)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
**Client-side encryption for localStorage using AES-256-GCM**
|
|
8
9
|
|
|
9
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
### JavaScript Vanilla
|
|
29
|
-
|
|
30
|
-
```javascript
|
|
30
|
+
```typescript
|
|
31
31
|
import { SecureStorage } from '@bantis/local-cipher';
|
|
32
32
|
|
|
33
33
|
const storage = SecureStorage.getInstance();
|
|
34
34
|
|
|
35
|
-
//
|
|
36
|
-
await storage.setItem('
|
|
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
|
|
37
57
|
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
40
69
|
|
|
41
|
-
|
|
42
|
-
await storage.setItemWithExpiry('session', sessionData, { expiresIn: 3600000 });
|
|
70
|
+
## Use Cases
|
|
43
71
|
|
|
44
|
-
|
|
45
|
-
|
|
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');
|
|
46
96
|
```
|
|
47
97
|
|
|
48
|
-
###
|
|
98
|
+
### 3. Cache Sensitive API Responses
|
|
49
99
|
|
|
50
|
-
```
|
|
100
|
+
```typescript
|
|
101
|
+
// Store with compression for large data
|
|
51
102
|
const storage = SecureStorage.getInstance({
|
|
52
|
-
|
|
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
|
-
}
|
|
103
|
+
storage: { compression: true, compressionThreshold: 512 }
|
|
70
104
|
});
|
|
105
|
+
|
|
106
|
+
await storage.setItem('userData', JSON.stringify(largeObject));
|
|
71
107
|
```
|
|
72
108
|
|
|
73
|
-
|
|
109
|
+
## React Integration
|
|
74
110
|
|
|
75
|
-
```
|
|
76
|
-
import { useSecureStorage,
|
|
111
|
+
```tsx
|
|
112
|
+
import { useSecureStorage, useSecureStorageEvents } from '@bantis/local-cipher';
|
|
77
113
|
|
|
78
114
|
function App() {
|
|
79
|
-
|
|
80
|
-
const [token, setToken, loading] = useSecureStorage('accessToken', '');
|
|
115
|
+
const [token, setToken, loading] = useSecureStorage('token', '');
|
|
81
116
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
'session',
|
|
85
|
-
null,
|
|
86
|
-
{ expiresIn: 3600000 }
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
// Escuchar eventos
|
|
90
|
-
useSecureStorageEvents('expired', (data) => {
|
|
91
|
-
console.log('Item expired:', data.key);
|
|
117
|
+
useSecureStorageEvents('expired', () => {
|
|
118
|
+
// Handle expiration
|
|
92
119
|
});
|
|
120
|
+
|
|
121
|
+
if (loading) return <div>Loading...</div>;
|
|
93
122
|
|
|
94
|
-
|
|
95
|
-
const userStorage = useNamespace('user');
|
|
96
|
-
|
|
97
|
-
if (loading) return <div>Cargando...</div>;
|
|
98
|
-
|
|
99
|
-
return (
|
|
100
|
-
<div>
|
|
101
|
-
<p>Token: {token}</p>
|
|
102
|
-
<button onClick={() => setToken('nuevo-token')}>
|
|
103
|
-
Actualizar Token
|
|
104
|
-
</button>
|
|
105
|
-
</div>
|
|
106
|
-
);
|
|
123
|
+
return <div>Token: {token}</div>;
|
|
107
124
|
}
|
|
108
125
|
```
|
|
109
126
|
|
|
110
|
-
|
|
127
|
+
## Angular Integration
|
|
111
128
|
|
|
112
129
|
```typescript
|
|
113
130
|
import { SecureStorageService } from '@bantis/local-cipher';
|
|
114
131
|
|
|
115
|
-
@Component({
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
`
|
|
121
|
-
})
|
|
122
|
-
export class AppComponent implements OnInit {
|
|
123
|
-
token$ = this.storage.getItem('accessToken');
|
|
124
|
-
|
|
125
|
-
constructor(private storage: SecureStorageService) {}
|
|
126
|
-
|
|
127
|
-
ngOnInit() {
|
|
128
|
-
// Escuchar eventos
|
|
132
|
+
@Component({...})
|
|
133
|
+
export class AppComponent {
|
|
134
|
+
token$ = this.storage.getItem('token');
|
|
135
|
+
|
|
136
|
+
constructor(private storage: SecureStorageService) {
|
|
129
137
|
this.storage.events$.subscribe(event => {
|
|
130
138
|
console.log('Storage event:', event);
|
|
131
139
|
});
|
|
132
|
-
|
|
133
|
-
// Eventos específicos
|
|
134
|
-
this.storage.onEvent$('expired').subscribe(event => {
|
|
135
|
-
console.log('Item expired:', event.key);
|
|
136
|
-
});
|
|
137
140
|
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
138
143
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
## Configuration
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
const storage = SecureStorage.getInstance({
|
|
148
|
+
encryption: {
|
|
149
|
+
iterations: 150000, // PBKDF2 iterations
|
|
150
|
+
keyLength: 256, // 128, 192, or 256 bits
|
|
151
|
+
saltLength: 16, // Salt size in bytes
|
|
152
|
+
ivLength: 12, // IV size in bytes
|
|
153
|
+
},
|
|
154
|
+
storage: {
|
|
155
|
+
compression: true, // Enable gzip compression
|
|
156
|
+
compressionThreshold: 1024, // Compress if > 1KB
|
|
157
|
+
autoCleanup: true, // Auto-delete expired items
|
|
158
|
+
cleanupInterval: 60000 // Cleanup every 60s
|
|
159
|
+
},
|
|
160
|
+
debug: {
|
|
161
|
+
enabled: false, // Enable debug logging
|
|
162
|
+
logLevel: 'info' // silent, error, warn, info, debug, verbose
|
|
147
163
|
}
|
|
148
|
-
}
|
|
164
|
+
});
|
|
149
165
|
```
|
|
150
166
|
|
|
151
|
-
##
|
|
167
|
+
## Security
|
|
168
|
+
|
|
169
|
+
### What This Protects Against
|
|
170
|
+
|
|
171
|
+
✅ **XSS attacks** - Encrypted data is useless without the browser-specific key
|
|
172
|
+
✅ **Local file access** - Malware reading browser files gets encrypted data
|
|
173
|
+
✅ **Casual inspection** - DevTools shows encrypted values
|
|
174
|
+
✅ **Data tampering** - Integrity checks detect modifications
|
|
152
175
|
|
|
153
|
-
###
|
|
176
|
+
### What This Does NOT Protect Against
|
|
154
177
|
|
|
155
|
-
|
|
178
|
+
❌ **Server-side attacks** - Encryption is client-side only
|
|
179
|
+
❌ **Man-in-the-Middle** - Use HTTPS for data in transit
|
|
180
|
+
❌ **Memory dumps** - Keys exist in memory during runtime
|
|
181
|
+
❌ **Compromised browser** - If the browser is compromised, all bets are off
|
|
182
|
+
❌ **Physical access during active session** - Data is decrypted when accessed
|
|
183
|
+
|
|
184
|
+
### Best Practices
|
|
185
|
+
|
|
186
|
+
1. **Use HTTPS** - Always transmit data over secure connections
|
|
187
|
+
2. **Short TTLs** - Set expiration on sensitive data
|
|
188
|
+
3. **Clear on logout** - Call `storage.clear()` when user logs out
|
|
189
|
+
4. **Monitor events** - Track suspicious activity via event listeners
|
|
190
|
+
5. **Rotate keys** - Periodically call `storage.rotateKeys()`
|
|
191
|
+
6. **Don't store passwords** - Never store plaintext passwords, even encrypted
|
|
192
|
+
|
|
193
|
+
## Browser Support
|
|
194
|
+
|
|
195
|
+
Requires [Web Crypto API](https://caniuse.com/cryptography):
|
|
196
|
+
|
|
197
|
+
- Chrome 37+
|
|
198
|
+
- Firefox 34+
|
|
199
|
+
- Safari 11+
|
|
200
|
+
- Edge 12+
|
|
201
|
+
- Opera 24+
|
|
202
|
+
|
|
203
|
+
**Fallback:** Gracefully degrades to unencrypted localStorage in unsupported browsers.
|
|
204
|
+
|
|
205
|
+
## API Reference
|
|
206
|
+
|
|
207
|
+
### Core Methods
|
|
156
208
|
|
|
157
209
|
```typescript
|
|
158
210
|
setItem(key: string, value: string): Promise<void>
|
|
@@ -162,228 +214,101 @@ hasItem(key: string): Promise<boolean>
|
|
|
162
214
|
clear(): void
|
|
163
215
|
```
|
|
164
216
|
|
|
165
|
-
|
|
217
|
+
### Expiration
|
|
166
218
|
|
|
167
219
|
```typescript
|
|
168
|
-
setItemWithExpiry(key: string, value: string, options:
|
|
169
|
-
|
|
220
|
+
setItemWithExpiry(key: string, value: string, options: {
|
|
221
|
+
expiresIn?: number; // milliseconds from now
|
|
222
|
+
expiresAt?: Date; // absolute date
|
|
223
|
+
}): Promise<void>
|
|
170
224
|
|
|
171
|
-
//
|
|
172
|
-
interface ExpiryOptions {
|
|
173
|
-
expiresIn?: number; // Milisegundos desde ahora
|
|
174
|
-
expiresAt?: Date; // Fecha absoluta
|
|
175
|
-
}
|
|
225
|
+
cleanExpired(): Promise<number> // Returns count of deleted items
|
|
176
226
|
```
|
|
177
227
|
|
|
178
|
-
|
|
228
|
+
### Events
|
|
179
229
|
|
|
180
230
|
```typescript
|
|
181
231
|
on(event: StorageEventType, listener: EventListener): void
|
|
182
|
-
once(event: StorageEventType, listener: EventListener): void
|
|
183
232
|
off(event: StorageEventType, listener: EventListener): void
|
|
184
|
-
|
|
233
|
+
once(event: StorageEventType, listener: EventListener): void
|
|
185
234
|
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
| 'encrypted' | 'decrypted' | 'deleted' | 'cleared'
|
|
189
|
-
| 'expired' | 'error' | 'keyRotated' | 'compressed' | 'decompressed';
|
|
235
|
+
// Event types: 'encrypted', 'decrypted', 'deleted', 'cleared',
|
|
236
|
+
// 'expired', 'error', 'keyRotated', 'compressed'
|
|
190
237
|
```
|
|
191
238
|
|
|
192
|
-
|
|
239
|
+
### Namespaces
|
|
193
240
|
|
|
194
241
|
```typescript
|
|
195
242
|
namespace(name: string): NamespacedStorage
|
|
196
243
|
|
|
197
|
-
// Ejemplo
|
|
198
244
|
const userStorage = storage.namespace('user');
|
|
199
|
-
const sessionStorage = storage.namespace('session');
|
|
200
|
-
|
|
201
245
|
await userStorage.setItem('profile', data);
|
|
202
|
-
await userStorage.clearNamespace();
|
|
203
|
-
```
|
|
204
|
-
|
|
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
|
-
}
|
|
246
|
+
await userStorage.clearNamespace();
|
|
217
247
|
```
|
|
218
248
|
|
|
219
|
-
|
|
249
|
+
### Key Rotation
|
|
220
250
|
|
|
221
251
|
```typescript
|
|
222
252
|
rotateKeys(): Promise<void>
|
|
223
253
|
exportEncryptedData(): Promise<EncryptedBackup>
|
|
224
254
|
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
|
-
```
|
|
232
|
-
|
|
233
|
-
#### Debug
|
|
234
|
-
|
|
235
|
-
```typescript
|
|
236
|
-
getDebugInfo(): {
|
|
237
|
-
cryptoSupported: boolean;
|
|
238
|
-
encryptedKeys: string[];
|
|
239
|
-
unencryptedKeys: string[];
|
|
240
|
-
totalKeys: number;
|
|
241
|
-
config: SecureStorageConfig;
|
|
242
|
-
}
|
|
243
255
|
```
|
|
244
256
|
|
|
245
|
-
##
|
|
257
|
+
## FAQ
|
|
246
258
|
|
|
247
|
-
|
|
259
|
+
**Q: Is this secure enough for passwords?**
|
|
260
|
+
A: No. Never store passwords in localStorage, even encrypted. Use secure, httpOnly cookies or sessionStorage with server-side session management.
|
|
248
261
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
await storage.setItemWithExpiry('session', sessionData, {
|
|
252
|
-
expiresIn: 30 * 60 * 1000
|
|
253
|
-
});
|
|
262
|
+
**Q: Can data be decrypted on another device?**
|
|
263
|
+
A: No. Keys are derived from browser fingerprinting. Data encrypted on Chrome/Windows cannot be decrypted on Firefox/Mac.
|
|
254
264
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
storage: { autoCleanup: true, cleanupInterval: 60000 }
|
|
258
|
-
});
|
|
259
|
-
```
|
|
265
|
+
**Q: What happens if Web Crypto API is unavailable?**
|
|
266
|
+
A: The library falls back to unencrypted localStorage with a console warning. Check `EncryptionHelper.isSupported()` to detect support.
|
|
260
267
|
|
|
261
|
-
|
|
268
|
+
**Q: Does this protect against XSS?**
|
|
269
|
+
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.
|
|
262
270
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const appStorage = storage.namespace('app');
|
|
266
|
-
const tempStorage = storage.namespace('temp');
|
|
271
|
+
**Q: How is this different from sessionStorage?**
|
|
272
|
+
A: sessionStorage is cleared on tab close. This provides persistent, encrypted storage across sessions.
|
|
267
273
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
await tempStorage.setItem('cache', cacheData);
|
|
274
|
+
**Q: Can I use this in Node.js?**
|
|
275
|
+
A: No. This library requires browser APIs (Web Crypto, localStorage). For Node.js, use native `crypto` module.
|
|
271
276
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
```
|
|
277
|
+
**Q: What's the performance impact?**
|
|
278
|
+
A: Encryption adds ~2-5ms per operation. Compression adds ~5-10ms for large values. Negligible for most use cases.
|
|
275
279
|
|
|
276
|
-
|
|
280
|
+
## Migration from v1
|
|
277
281
|
|
|
278
|
-
|
|
279
|
-
storage.on('encrypted', ({ key, metadata }) => {
|
|
280
|
-
console.log(`✅ Encrypted: ${key}`, metadata);
|
|
281
|
-
});
|
|
282
|
+
v1 data is automatically migrated to v2 format on first read. No action required.
|
|
282
283
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
storage.on('error', ({ key, error }) => {
|
|
289
|
-
console.error(`❌ Error on ${key}:`, error);
|
|
290
|
-
// Enviar a sistema de logging
|
|
291
|
-
});
|
|
292
|
-
```
|
|
293
|
-
|
|
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);
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
## 🔄 Migración desde v1
|
|
313
|
-
|
|
314
|
-
### Cambios Principales
|
|
315
|
-
|
|
316
|
-
**v1:**
|
|
317
|
-
```javascript
|
|
318
|
-
const storage = SecureStorage.getInstance();
|
|
319
|
-
```
|
|
320
|
-
|
|
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
|
-
});
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
### Migración Automática
|
|
333
|
-
|
|
334
|
-
Los datos de v1 se migran automáticamente al leerlos. No requiere acción del usuario.
|
|
335
|
-
|
|
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
|
|
284
|
+
```typescript
|
|
285
|
+
// v1 and v2 are API-compatible
|
|
286
|
+
const storage = SecureStorage.getInstance(); // Works with both
|
|
342
287
|
```
|
|
343
288
|
|
|
344
|
-
##
|
|
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
|
|
289
|
+
## Examples
|
|
354
290
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
291
|
+
See [/examples](./examples) directory for:
|
|
292
|
+
- Basic usage
|
|
293
|
+
- React integration
|
|
294
|
+
- Angular integration
|
|
295
|
+
- Advanced features (TTL, events, namespaces)
|
|
358
296
|
|
|
359
|
-
|
|
297
|
+
## Contributing
|
|
360
298
|
|
|
361
|
-
|
|
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
|
|
299
|
+
Contributions welcome! Please read [CONTRIBUTING.md](./CONTRIBUTING.md) first.
|
|
366
300
|
|
|
367
|
-
##
|
|
301
|
+
## Security Issues
|
|
368
302
|
|
|
369
|
-
|
|
370
|
-
- ✅ Firefox 34+
|
|
371
|
-
- ✅ Safari 11+
|
|
372
|
-
- ✅ Edge 12+
|
|
373
|
-
- ✅ Opera 24+
|
|
303
|
+
Report security vulnerabilities to [security@example.com](mailto:security@example.com). See [SECURITY.md](./SECURITY.md) for details.
|
|
374
304
|
|
|
375
|
-
|
|
305
|
+
## License
|
|
376
306
|
|
|
377
|
-
|
|
307
|
+
MIT © MTT - See [LICENSE](./LICENSE) for details.
|
|
378
308
|
|
|
379
|
-
|
|
309
|
+
## Links
|
|
380
310
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
- [GitHub](https://github.com/master-tech-team/-bantis-local-cipher)
|
|
384
|
-
- [npm](https://www.npmjs.com/package/@bantis/local-cipher)
|
|
311
|
+
- [npm package](https://www.npmjs.com/package/@bantis/local-cipher)
|
|
312
|
+
- [GitHub repository](https://github.com/master-tech-team/-bantis-local-cipher)
|
|
385
313
|
- [Changelog](./CHANGELOG.md)
|
|
386
|
-
|
|
387
|
-
## 🤝 Contribuir
|
|
388
|
-
|
|
389
|
-
Las contribuciones son bienvenidas. Abre un issue o pull request en GitHub.
|
|
314
|
+
- [Security Policy](./SECURITY.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bantis/local-cipher",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Librería de cifrado local AES-256-GCM v2 con configuración personalizable, eventos, compresión, expiración, namespaces y rotación de claves para Angular, React y JavaScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,15 +21,29 @@
|
|
|
21
21
|
},
|
|
22
22
|
"keywords": [
|
|
23
23
|
"encryption",
|
|
24
|
-
"aes-256-gcm",
|
|
25
|
-
"pbkdf2",
|
|
26
24
|
"localstorage",
|
|
27
25
|
"security",
|
|
26
|
+
"aes-256-gcm",
|
|
28
27
|
"crypto",
|
|
29
|
-
"angular",
|
|
30
|
-
"react",
|
|
31
28
|
"typescript",
|
|
32
|
-
"
|
|
29
|
+
"react",
|
|
30
|
+
"angular",
|
|
31
|
+
"web-crypto-api",
|
|
32
|
+
"client-side-encryption",
|
|
33
|
+
"browser-storage",
|
|
34
|
+
"pbkdf2",
|
|
35
|
+
"secure-storage",
|
|
36
|
+
"data-encryption",
|
|
37
|
+
"xss-protection",
|
|
38
|
+
"frontend-security",
|
|
39
|
+
"storage-encryption",
|
|
40
|
+
"encrypted-storage",
|
|
41
|
+
"browser-encryption",
|
|
42
|
+
"javascript-encryption",
|
|
43
|
+
"secure-localstorage",
|
|
44
|
+
"aes-encryption",
|
|
45
|
+
"token-storage",
|
|
46
|
+
"jwt-encryption"
|
|
33
47
|
],
|
|
34
48
|
"author": "MTT",
|
|
35
49
|
"license": "MIT",
|
|
@@ -69,4 +83,4 @@
|
|
|
69
83
|
"optional": true
|
|
70
84
|
}
|
|
71
85
|
}
|
|
72
|
-
}
|
|
86
|
+
}
|