ng-secure-storage 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/README.md +63 -0
- package/fesm2022/ng-secure-storage.mjs +249 -0
- package/fesm2022/ng-secure-storage.mjs.map +1 -0
- package/index.d.ts +70 -0
- package/package.json +23 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# NgSecureStorage
|
|
2
|
+
|
|
3
|
+
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.3.0.
|
|
4
|
+
|
|
5
|
+
## Code scaffolding
|
|
6
|
+
|
|
7
|
+
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
ng generate component component-name
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
ng generate --help
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Building
|
|
20
|
+
|
|
21
|
+
To build the library, run:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ng build ng-secure-storage
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
|
|
28
|
+
|
|
29
|
+
### Publishing the Library
|
|
30
|
+
|
|
31
|
+
Once the project is built, you can publish your library by following these steps:
|
|
32
|
+
|
|
33
|
+
1. Navigate to the `dist` directory:
|
|
34
|
+
```bash
|
|
35
|
+
cd dist/ng-secure-storage
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
2. Run the `npm publish` command to publish your library to the npm registry:
|
|
39
|
+
```bash
|
|
40
|
+
npm publish
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Running unit tests
|
|
44
|
+
|
|
45
|
+
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
ng test
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Running end-to-end tests
|
|
52
|
+
|
|
53
|
+
For end-to-end (e2e) testing, run:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
ng e2e
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
|
60
|
+
|
|
61
|
+
## Additional Resources
|
|
62
|
+
|
|
63
|
+
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, Inject, Injectable, signal, Optional, NgModule } from '@angular/core';
|
|
3
|
+
import { BehaviorSubject } from 'rxjs';
|
|
4
|
+
|
|
5
|
+
const SECURE_STORAGE_CONFIG = new InjectionToken('SecureStorageConfig');
|
|
6
|
+
|
|
7
|
+
class CryptoService {
|
|
8
|
+
config;
|
|
9
|
+
encoder = new TextEncoder();
|
|
10
|
+
decoder = new TextDecoder();
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
if (!config) {
|
|
14
|
+
throw new Error('SecureStorageConfig is missing. Did you forget provideSecureStorage()?');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
getOrCreateSalt() {
|
|
18
|
+
let salt = this.encoder.encode(localStorage.getItem('cs_r'));
|
|
19
|
+
if (!salt) {
|
|
20
|
+
salt = crypto.getRandomValues(new Uint8Array(16)); // 16 bytes is standard
|
|
21
|
+
localStorage.setItem('cs_r', this.decoder.decode(salt));
|
|
22
|
+
}
|
|
23
|
+
return salt;
|
|
24
|
+
}
|
|
25
|
+
async derivedKey() {
|
|
26
|
+
let salt = this.getOrCreateSalt();
|
|
27
|
+
const cryptokey = await crypto.subtle.importKey('raw', this.encoder.encode(this.config?.storeName), 'PBKDF2', false, ['deriveKey']);
|
|
28
|
+
return crypto.subtle.deriveKey({
|
|
29
|
+
name: 'PBKDF2',
|
|
30
|
+
salt,
|
|
31
|
+
iterations: this.config?.iterations || 100_000,
|
|
32
|
+
hash: 'SHA-256',
|
|
33
|
+
}, cryptokey, { name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt']);
|
|
34
|
+
}
|
|
35
|
+
async encrypt(data) {
|
|
36
|
+
const iv = this.getOrCreateSalt();
|
|
37
|
+
const key = await this.derivedKey();
|
|
38
|
+
const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, this.encoder.encode(data));
|
|
39
|
+
return { iv, encrypted };
|
|
40
|
+
}
|
|
41
|
+
async decrypt(payload, iv) {
|
|
42
|
+
const key = await this.derivedKey();
|
|
43
|
+
const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: iv }, key, payload);
|
|
44
|
+
return this.decoder.decode(decrypted);
|
|
45
|
+
}
|
|
46
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CryptoService, deps: [{ token: SECURE_STORAGE_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
47
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CryptoService });
|
|
48
|
+
}
|
|
49
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CryptoService, decorators: [{
|
|
50
|
+
type: Injectable
|
|
51
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
52
|
+
type: Inject,
|
|
53
|
+
args: [SECURE_STORAGE_CONFIG]
|
|
54
|
+
}] }] });
|
|
55
|
+
|
|
56
|
+
class IndexeddbService {
|
|
57
|
+
config;
|
|
58
|
+
dbName;
|
|
59
|
+
storeName;
|
|
60
|
+
db;
|
|
61
|
+
dbPromise;
|
|
62
|
+
isReady = new BehaviorSubject(false);
|
|
63
|
+
constructor(config) {
|
|
64
|
+
this.config = config;
|
|
65
|
+
if (!config) {
|
|
66
|
+
throw new Error('SecureStorageConfig is missing. Did you forget provideSecureStorage()?');
|
|
67
|
+
}
|
|
68
|
+
this.dbName = config?.dbName || 'secure-storage-db';
|
|
69
|
+
this.storeName = config?.storeName || 'data';
|
|
70
|
+
this.dbPromise = this.initDb();
|
|
71
|
+
}
|
|
72
|
+
initDb() {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const request = indexedDB.open(this.dbName);
|
|
75
|
+
request.onsuccess = () => {
|
|
76
|
+
this.db = request.result;
|
|
77
|
+
this.isReady.next(true);
|
|
78
|
+
resolve(this.db);
|
|
79
|
+
};
|
|
80
|
+
request.onupgradeneeded = (event) => {
|
|
81
|
+
const db = request.result;
|
|
82
|
+
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
83
|
+
db.createObjectStore(this.storeName);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
request.onerror = () => reject(request.error);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async getDb() {
|
|
90
|
+
if (this.db)
|
|
91
|
+
return this.db;
|
|
92
|
+
// Wait for DB ready
|
|
93
|
+
const db = await this.dbPromise;
|
|
94
|
+
// Double-check the store exists (for old DB versions)
|
|
95
|
+
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
96
|
+
db.close();
|
|
97
|
+
// Increase version to trigger onupgradeneeded
|
|
98
|
+
const newVersion = (db.version || 1) + 1;
|
|
99
|
+
this.dbPromise = new Promise((resolve, reject) => {
|
|
100
|
+
const request = indexedDB.open(this.dbName, newVersion);
|
|
101
|
+
request.onupgradeneeded = () => {
|
|
102
|
+
const upgradedDb = request.result;
|
|
103
|
+
if (!upgradedDb.objectStoreNames.contains(this.storeName)) {
|
|
104
|
+
upgradedDb.createObjectStore(this.storeName);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
request.onsuccess = () => {
|
|
108
|
+
this.db = request.result;
|
|
109
|
+
resolve(this.db);
|
|
110
|
+
};
|
|
111
|
+
request.onerror = () => reject(request.error);
|
|
112
|
+
});
|
|
113
|
+
return this.dbPromise;
|
|
114
|
+
}
|
|
115
|
+
return db;
|
|
116
|
+
}
|
|
117
|
+
async set(key, value) {
|
|
118
|
+
const db = await this.getDb();
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
const tx = db.transaction(this.storeName, 'readwrite');
|
|
121
|
+
const store = tx.objectStore(this.storeName);
|
|
122
|
+
const request = store.put(value, key); // use put instead of add
|
|
123
|
+
request.onsuccess = () => resolve();
|
|
124
|
+
request.onerror = () => reject(request.error);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
async get(key) {
|
|
128
|
+
const db = await this.getDb();
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
const tx = db.transaction(this.storeName, 'readonly');
|
|
131
|
+
const store = tx.objectStore(this.storeName);
|
|
132
|
+
const request = store.get(key);
|
|
133
|
+
request.onsuccess = () => resolve(request.result ?? null);
|
|
134
|
+
request.onerror = () => reject(request.error);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
async delete(key) {
|
|
138
|
+
const db = await this.getDb();
|
|
139
|
+
return new Promise((resolve, reject) => {
|
|
140
|
+
const tx = db.transaction(this.storeName, 'readwrite');
|
|
141
|
+
const store = tx.objectStore(this.storeName);
|
|
142
|
+
const request = store.delete(key);
|
|
143
|
+
request.onsuccess = () => resolve();
|
|
144
|
+
request.onerror = () => reject(request.error);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: IndexeddbService, deps: [{ token: SECURE_STORAGE_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
148
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: IndexeddbService });
|
|
149
|
+
}
|
|
150
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: IndexeddbService, decorators: [{
|
|
151
|
+
type: Injectable
|
|
152
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
153
|
+
type: Inject,
|
|
154
|
+
args: [SECURE_STORAGE_CONFIG]
|
|
155
|
+
}] }] });
|
|
156
|
+
|
|
157
|
+
class SecureStorageService {
|
|
158
|
+
cryptoX;
|
|
159
|
+
db;
|
|
160
|
+
constructor(cryptoX, db) {
|
|
161
|
+
this.cryptoX = cryptoX;
|
|
162
|
+
this.db = db;
|
|
163
|
+
}
|
|
164
|
+
signal(key, initial) {
|
|
165
|
+
const _state = signal(initial, ...(ngDevMode ? [{ debugName: "_state" }] : []));
|
|
166
|
+
// 🔹 Hydrate once
|
|
167
|
+
this.load(key).then((value) => {
|
|
168
|
+
if (value !== undefined) {
|
|
169
|
+
_state.set(value);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
return {
|
|
173
|
+
state: _state,
|
|
174
|
+
set: (val) => {
|
|
175
|
+
_state.set(val); // instant
|
|
176
|
+
this.save(key, val); // async persist
|
|
177
|
+
},
|
|
178
|
+
load: () => _state(),
|
|
179
|
+
update: (updater) => {
|
|
180
|
+
const next = updater(_state());
|
|
181
|
+
_state.set(next);
|
|
182
|
+
this.save(key, next);
|
|
183
|
+
},
|
|
184
|
+
remove: () => {
|
|
185
|
+
_state.set(initial);
|
|
186
|
+
this.save(key, null);
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
async load(key) {
|
|
191
|
+
const encrypted = await this.db.get(key);
|
|
192
|
+
if (!encrypted)
|
|
193
|
+
return;
|
|
194
|
+
else {
|
|
195
|
+
try {
|
|
196
|
+
const decrypted = await this.cryptoX.decrypt(encrypted.encrypted, encrypted.iv);
|
|
197
|
+
return JSON.parse(decrypted);
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
console.error('Decryption failed', err);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
async save(key, value) {
|
|
205
|
+
try {
|
|
206
|
+
const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(value));
|
|
207
|
+
await this.db.set(key, { iv, encrypted });
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
console.error('Encryption failed', err);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SecureStorageService, deps: [{ token: CryptoService }, { token: IndexeddbService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
214
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SecureStorageService });
|
|
215
|
+
}
|
|
216
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SecureStorageService, decorators: [{
|
|
217
|
+
type: Injectable
|
|
218
|
+
}], ctorParameters: () => [{ type: CryptoService }, { type: IndexeddbService }] });
|
|
219
|
+
|
|
220
|
+
class SecureStorageModule {
|
|
221
|
+
static forRoot(config) {
|
|
222
|
+
return {
|
|
223
|
+
ngModule: SecureStorageModule,
|
|
224
|
+
providers: [
|
|
225
|
+
{ provide: SECURE_STORAGE_CONFIG, useValue: config },
|
|
226
|
+
{ provide: CryptoService, deps: [[new Optional(), SECURE_STORAGE_CONFIG]] },
|
|
227
|
+
{ provide: IndexeddbService, deps: [[new Optional(), SECURE_STORAGE_CONFIG]] },
|
|
228
|
+
{
|
|
229
|
+
provide: SecureStorageService,
|
|
230
|
+
deps: [CryptoService, IndexeddbService],
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SecureStorageModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
236
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SecureStorageModule });
|
|
237
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SecureStorageModule });
|
|
238
|
+
}
|
|
239
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SecureStorageModule, decorators: [{
|
|
240
|
+
type: NgModule,
|
|
241
|
+
args: [{}]
|
|
242
|
+
}] });
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Generated bundle index. Do not edit.
|
|
246
|
+
*/
|
|
247
|
+
|
|
248
|
+
export { SecureStorageModule, SecureStorageService };
|
|
249
|
+
//# sourceMappingURL=ng-secure-storage.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ng-secure-storage.mjs","sources":["../../../projects/ng-secure-storage/src/lib/tokens/secure-storage.config.ts","../../../projects/ng-secure-storage/src/lib/services/crypto.service.ts","../../../projects/ng-secure-storage/src/lib/services/indexeddb.service.ts","../../../projects/ng-secure-storage/src/lib/services/secure-storage.service.ts","../../../projects/ng-secure-storage/src/lib/public.module.ts","../../../projects/ng-secure-storage/src/ng-secure-storage.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\n\r\nexport interface SecureStorageConfig {\r\n dbName?: string;\r\n storeName?: string;\r\n iterations?: number;\r\n version?: number;\r\n}\r\n\r\nexport const SECURE_STORAGE_CONFIG = new InjectionToken<SecureStorageConfig>('SecureStorageConfig');\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { SECURE_STORAGE_CONFIG, SecureStorageConfig } from '../tokens/secure-storage.config';\r\n\r\n@Injectable()\r\nexport class CryptoService {\r\n private encoder = new TextEncoder();\r\n private decoder = new TextDecoder();\r\n constructor(@Inject(SECURE_STORAGE_CONFIG) private readonly config?: SecureStorageConfig) {\r\n if (!config) {\r\n throw new Error('SecureStorageConfig is missing. Did you forget provideSecureStorage()?');\r\n }\r\n }\r\n\r\n getOrCreateSalt(): Uint8Array<ArrayBuffer> {\r\n let salt = this.encoder.encode(localStorage.getItem('cs_r')!);\r\n\r\n if (!salt) {\r\n salt = crypto.getRandomValues(new Uint8Array(16)); // 16 bytes is standard\r\n localStorage.setItem('cs_r', this.decoder.decode(salt));\r\n }\r\n\r\n return salt;\r\n }\r\n\r\n async derivedKey() {\r\n let salt = this.getOrCreateSalt();\r\n const cryptokey = await crypto.subtle.importKey(\r\n 'raw',\r\n this.encoder.encode(this.config?.storeName),\r\n 'PBKDF2',\r\n false,\r\n ['deriveKey']\r\n );\r\n return crypto.subtle.deriveKey(\r\n {\r\n name: 'PBKDF2',\r\n salt,\r\n iterations: this.config?.iterations || 100_000,\r\n hash: 'SHA-256',\r\n },\r\n cryptokey,\r\n { name: 'AES-GCM', length: 256 },\r\n false,\r\n ['encrypt', 'decrypt']\r\n );\r\n }\r\n\r\n async encrypt(data: string) {\r\n const iv = this.getOrCreateSalt();\r\n const key = await this.derivedKey();\r\n const encrypted = await crypto.subtle.encrypt(\r\n { name: 'AES-GCM', iv },\r\n key,\r\n this.encoder.encode(data)\r\n );\r\n return { iv, encrypted };\r\n }\r\n\r\n async decrypt(payload: Uint8Array<ArrayBuffer>, iv: Uint8Array) {\r\n const key = await this.derivedKey();\r\n const decrypted = await crypto.subtle.decrypt(\r\n { name: 'AES-GCM', iv: iv as Uint8Array<ArrayBuffer> },\r\n key,\r\n payload\r\n );\r\n return this.decoder.decode(decrypted);\r\n }\r\n}\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { SECURE_STORAGE_CONFIG, SecureStorageConfig } from '../tokens/secure-storage.config';\r\nimport { BehaviorSubject } from 'rxjs';\r\n\r\n@Injectable()\r\nexport class IndexeddbService {\r\n private dbName: string;\r\n private storeName: string;\r\n private db!: IDBDatabase;\r\n private dbPromise!: Promise<IDBDatabase>;\r\n public isReady = new BehaviorSubject<boolean>(false);\r\n\r\n constructor(@Inject(SECURE_STORAGE_CONFIG) private readonly config?: SecureStorageConfig) {\r\n if (!config) {\r\n throw new Error('SecureStorageConfig is missing. Did you forget provideSecureStorage()?');\r\n }\r\n this.dbName = config?.dbName || 'secure-storage-db';\r\n this.storeName = config?.storeName || 'data';\r\n this.dbPromise = this.initDb();\r\n }\r\n\r\n private initDb(): Promise<IDBDatabase> {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(this.dbName);\r\n request.onsuccess = () => {\r\n this.db = request.result;\r\n this.isReady.next(true);\r\n resolve(this.db);\r\n };\r\n\r\n request.onupgradeneeded = (event) => {\r\n const db = request.result;\r\n if (!db.objectStoreNames.contains(this.storeName)) {\r\n db.createObjectStore(this.storeName);\r\n }\r\n };\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n private async getDb(): Promise<IDBDatabase> {\r\n if (this.db) return this.db;\r\n\r\n // Wait for DB ready\r\n const db = await this.dbPromise;\r\n\r\n // Double-check the store exists (for old DB versions)\r\n if (!db.objectStoreNames.contains(this.storeName)) {\r\n db.close();\r\n // Increase version to trigger onupgradeneeded\r\n const newVersion = (db.version || 1) + 1;\r\n this.dbPromise = new Promise<IDBDatabase>((resolve, reject) => {\r\n const request = indexedDB.open(this.dbName, newVersion);\r\n request.onupgradeneeded = () => {\r\n const upgradedDb = request.result;\r\n if (!upgradedDb.objectStoreNames.contains(this.storeName)) {\r\n upgradedDb.createObjectStore(this.storeName);\r\n }\r\n };\r\n request.onsuccess = () => {\r\n this.db = request.result;\r\n resolve(this.db);\r\n };\r\n request.onerror = () => reject(request.error);\r\n });\r\n return this.dbPromise;\r\n }\r\n\r\n return db;\r\n }\r\n\r\n async set(key: string, value: any): Promise<void> {\r\n const db = await this.getDb();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readwrite');\r\n const store = tx.objectStore(this.storeName);\r\n const request = store.put(value, key); // use put instead of add\r\n request.onsuccess = () => resolve();\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n const db = await this.getDb();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readonly');\r\n const store = tx.objectStore(this.storeName);\r\n const request = store.get(key);\r\n request.onsuccess = () => resolve((request.result as T) ?? null);\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n const db = await this.getDb();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readwrite');\r\n const store = tx.objectStore(this.storeName);\r\n const request = store.delete(key);\r\n request.onsuccess = () => resolve();\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n}\r\n","import { Injectable, signal, WritableSignal } from '@angular/core';\r\nimport { CryptoService } from './crypto.service';\r\nimport { IndexeddbService } from './indexeddb.service';\r\n\r\n@Injectable()\r\nexport class SecureStorageService {\r\n constructor(private readonly cryptoX: CryptoService, private readonly db: IndexeddbService) {}\r\n signal<T>(key: string, initial: T): PersistedSignalStore<T> {\r\n const _state = signal<T>(initial);\r\n\r\n // 🔹 Hydrate once\r\n this.load(key).then((value) => {\r\n if (value !== undefined) {\r\n _state.set(value);\r\n }\r\n });\r\n\r\n return {\r\n state: _state,\r\n set: (val: T) => {\r\n _state.set(val); // instant\r\n this.save(key, val); // async persist\r\n },\r\n load: () => _state(),\r\n update: (updater: (curr: T) => T) => {\r\n const next = updater(_state());\r\n _state.set(next);\r\n this.save(key, next);\r\n },\r\n\r\n remove: () => {\r\n _state.set(initial);\r\n this.save(key, null);\r\n },\r\n };\r\n }\r\n async load<T>(key: string) {\r\n const encrypted = await this.db.get<any>(key);\r\n if (!encrypted) return;\r\n else {\r\n try {\r\n const decrypted = await this.cryptoX.decrypt(encrypted.encrypted, encrypted.iv);\r\n return JSON.parse(decrypted);\r\n } catch (err) {\r\n console.error('Decryption failed', err);\r\n }\r\n }\r\n }\r\n\r\n private async save<T>(key: string, value: T) {\r\n try {\r\n const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(value));\r\n await this.db.set(key, { iv, encrypted });\r\n } catch (err) {\r\n console.error('Encryption failed', err);\r\n }\r\n }\r\n}\r\n\r\ninterface PersistedSignalStore<T> {\r\n state: WritableSignal<T>;\r\n set: (val: T) => void;\r\n load: () => T;\r\n update: (updater: (curr: T) => T) => void;\r\n remove: () => void;\r\n}\r\n","import { NgModule, ModuleWithProviders, Optional } from '@angular/core';\r\nimport { SECURE_STORAGE_CONFIG, SecureStorageConfig } from './tokens/secure-storage.config';\r\nimport { CryptoService } from './services/crypto.service';\r\nimport { IndexeddbService } from './services/indexeddb.service';\r\nimport { SecureStorageService } from '../public-api';\r\n\r\n@NgModule({})\r\nexport class SecureStorageModule {\r\n static forRoot(config: SecureStorageConfig): ModuleWithProviders<SecureStorageModule> {\r\n return {\r\n ngModule: SecureStorageModule,\r\n providers: [\r\n { provide: SECURE_STORAGE_CONFIG, useValue: config },\r\n { provide: CryptoService, deps: [[new Optional(), SECURE_STORAGE_CONFIG]] },\r\n { provide: IndexeddbService, deps: [[new Optional(), SECURE_STORAGE_CONFIG]] },\r\n {\r\n provide: SecureStorageService,\r\n deps: [CryptoService, IndexeddbService],\r\n },\r\n ],\r\n };\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.CryptoService","i2.IndexeddbService"],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { WritableSignal, ModuleWithProviders } from '@angular/core';
|
|
3
|
+
import { BehaviorSubject } from 'rxjs';
|
|
4
|
+
|
|
5
|
+
interface SecureStorageConfig {
|
|
6
|
+
dbName?: string;
|
|
7
|
+
storeName?: string;
|
|
8
|
+
iterations?: number;
|
|
9
|
+
version?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare class CryptoService {
|
|
13
|
+
private readonly config?;
|
|
14
|
+
private encoder;
|
|
15
|
+
private decoder;
|
|
16
|
+
constructor(config?: SecureStorageConfig | undefined);
|
|
17
|
+
getOrCreateSalt(): Uint8Array<ArrayBuffer>;
|
|
18
|
+
derivedKey(): Promise<CryptoKey>;
|
|
19
|
+
encrypt(data: string): Promise<{
|
|
20
|
+
iv: Uint8Array<ArrayBuffer>;
|
|
21
|
+
encrypted: ArrayBuffer;
|
|
22
|
+
}>;
|
|
23
|
+
decrypt(payload: Uint8Array<ArrayBuffer>, iv: Uint8Array): Promise<string>;
|
|
24
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<CryptoService, never>;
|
|
25
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<CryptoService>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare class IndexeddbService {
|
|
29
|
+
private readonly config?;
|
|
30
|
+
private dbName;
|
|
31
|
+
private storeName;
|
|
32
|
+
private db;
|
|
33
|
+
private dbPromise;
|
|
34
|
+
isReady: BehaviorSubject<boolean>;
|
|
35
|
+
constructor(config?: SecureStorageConfig | undefined);
|
|
36
|
+
private initDb;
|
|
37
|
+
private getDb;
|
|
38
|
+
set(key: string, value: any): Promise<void>;
|
|
39
|
+
get<T>(key: string): Promise<T | null>;
|
|
40
|
+
delete(key: string): Promise<void>;
|
|
41
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<IndexeddbService, never>;
|
|
42
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<IndexeddbService>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
declare class SecureStorageService {
|
|
46
|
+
private readonly cryptoX;
|
|
47
|
+
private readonly db;
|
|
48
|
+
constructor(cryptoX: CryptoService, db: IndexeddbService);
|
|
49
|
+
signal<T>(key: string, initial: T): PersistedSignalStore<T>;
|
|
50
|
+
load<T>(key: string): Promise<any>;
|
|
51
|
+
private save;
|
|
52
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SecureStorageService, never>;
|
|
53
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SecureStorageService>;
|
|
54
|
+
}
|
|
55
|
+
interface PersistedSignalStore<T> {
|
|
56
|
+
state: WritableSignal<T>;
|
|
57
|
+
set: (val: T) => void;
|
|
58
|
+
load: () => T;
|
|
59
|
+
update: (updater: (curr: T) => T) => void;
|
|
60
|
+
remove: () => void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
declare class SecureStorageModule {
|
|
64
|
+
static forRoot(config: SecureStorageConfig): ModuleWithProviders<SecureStorageModule>;
|
|
65
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SecureStorageModule, never>;
|
|
66
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<SecureStorageModule, never, never, never>;
|
|
67
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<SecureStorageModule>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { SecureStorageModule, SecureStorageService };
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ng-secure-storage",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"peerDependencies": {
|
|
5
|
+
"@angular/common": "^20.3.0",
|
|
6
|
+
"@angular/core": "^20.3.0"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"tslib": "^2.3.0"
|
|
10
|
+
},
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"module": "fesm2022/ng-secure-storage.mjs",
|
|
13
|
+
"typings": "index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
"./package.json": {
|
|
16
|
+
"default": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./index.d.ts",
|
|
20
|
+
"default": "./fesm2022/ng-secure-storage.mjs"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|