ng-secure-storage 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,62 +2,32 @@
2
2
 
3
3
  This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.3.0.
4
4
 
5
- ## Code scaffolding
5
+ This package can be used with angular +16 version because of usage of signal
6
6
 
7
- Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
7
+ ## The Way Of usage
8
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:
9
+ 0- If You Use Older Version You Must Clear Cache from browsers to work with new version properly
32
10
 
33
- 1. Navigate to the `dist` directory:
34
- ```bash
35
- cd dist/ng-secure-storage
36
- ```
11
+ 1- Set SecureStorageModule
37
12
 
38
- 2. Run the `npm publish` command to publish your library to the npm registry:
39
- ```bash
40
- npm publish
41
- ```
13
+ ```ts
14
+ SecureStorageModule.forRoot({
15
+ dbName: 'your_db_name',
16
+ version: 1 or your version,
17
+ storeName: 'your_storage_name',
18
+ iterations: 100_000,
19
+ });
20
+ ``
42
21
 
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
22
  ```
50
23
 
51
- ## Running end-to-end tests
24
+ 2- Call service in your component or any where else
52
25
 
53
- For end-to-end (e2e) testing, run:
26
+ ```ts
27
+ constructor(private secureStorageService: SecureStorageService) {}
54
28
 
55
- ```bash
56
- ng e2e
57
29
  ```
58
30
 
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
31
  ## Additional Resources
62
32
 
63
33
  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.
@@ -154,6 +154,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
154
154
  args: [SECURE_STORAGE_CONFIG]
155
155
  }] }] });
156
156
 
157
+ /**
158
+ * this service provides secure storage capabilities using encryption and IndexedDB.
159
+ * It allows storing, retrieving, and managing data with optional expiration times.
160
+ * The service uses signals to manage state reactively.
161
+ * @example
162
+ * const userSettings = secureStorageService.signal<UserSettings>('userSettings', defaultSettings, 60);
163
+ * userSettings.set({ theme: 'dark', notifications: true });
164
+ * const settings = userSettings.state();
165
+ * userSettings.remove();
166
+ *
167
+ */
157
168
  class SecureStorageService {
158
169
  cryptoX;
159
170
  db;
@@ -161,29 +172,33 @@ class SecureStorageService {
161
172
  this.cryptoX = cryptoX;
162
173
  this.db = db;
163
174
  }
164
- signal(key, initial) {
175
+ now = signal(new Date(), ...(ngDevMode ? [{ debugName: "now" }] : []));
176
+ hydration = signal(false, ...(ngDevMode ? [{ debugName: "hydration" }] : []));
177
+ signal(key, initial, expiration = 1440) {
165
178
  const _state = signal(initial, ...(ngDevMode ? [{ debugName: "_state" }] : []));
166
179
  // 🔹 Hydrate once
167
180
  this.load(key).then((value) => {
168
- if (value !== undefined) {
169
- _state.set(value);
181
+ if (!this.hydration() && value !== undefined) {
182
+ _state.set(value ?? initial);
170
183
  }
171
184
  });
172
185
  return {
173
186
  state: _state,
174
187
  set: (val) => {
175
188
  _state.set(val); // instant
176
- this.save(key, val); // async persist
189
+ this.save(key, val, expiration); // async persist
190
+ this.hydration.set(true);
177
191
  },
178
- load: () => _state(),
179
192
  update: (updater) => {
180
193
  const next = updater(_state());
181
194
  _state.set(next);
182
- this.save(key, next);
195
+ this.save(key, next, expiration);
196
+ this.hydration.set(true);
183
197
  },
184
198
  remove: () => {
185
199
  _state.set(initial);
186
200
  this.save(key, null);
201
+ this.hydration.set(true);
187
202
  },
188
203
  };
189
204
  }
@@ -194,16 +209,28 @@ class SecureStorageService {
194
209
  else {
195
210
  try {
196
211
  const decrypted = await this.cryptoX.decrypt(encrypted.encrypted, encrypted.iv);
197
- return JSON.parse(decrypted);
212
+ let item = JSON.parse(decrypted);
213
+ if (item.expiresAt && this.now().getMinutes() > item.expiresAt) {
214
+ await this.db.delete(key);
215
+ return;
216
+ }
217
+ else {
218
+ return item.value;
219
+ }
198
220
  }
199
221
  catch (err) {
200
222
  console.error('Decryption failed', err);
223
+ return;
201
224
  }
202
225
  }
203
226
  }
204
- async save(key, value) {
227
+ async save(key, value, expiration) {
205
228
  try {
206
- const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(value));
229
+ if (expiration) {
230
+ expiration = this.now().getMinutes() + expiration;
231
+ }
232
+ let itemToSave = { value, expiresAt: expiration };
233
+ const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(itemToSave));
207
234
  await this.db.set(key, { iv, encrypted });
208
235
  }
209
236
  catch (err) {
@@ -1 +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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"}
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/**\r\n * this service provides secure storage capabilities using encryption and IndexedDB.\r\n * It allows storing, retrieving, and managing data with optional expiration times.\r\n * The service uses signals to manage state reactively.\r\n * @example\r\n * const userSettings = secureStorageService.signal<UserSettings>('userSettings', defaultSettings, 60);\r\n * userSettings.set({ theme: 'dark', notifications: true });\r\n * const settings = userSettings.state();\r\n * userSettings.remove();\r\n *\r\n */\r\n@Injectable()\r\nexport class SecureStorageService {\r\n constructor(private readonly cryptoX: CryptoService, private readonly db: IndexeddbService) {}\r\n now = signal<Date>(new Date());\r\n hydration = signal<boolean>(false);\r\n signal<T>(key: string, initial: T, expiration: number = 1440): PersistedSignalStore<T> {\r\n const _state = signal<T>(initial);\r\n\r\n // 🔹 Hydrate once\r\n this.load(key).then((value: any) => {\r\n if (!this.hydration() && value !== undefined) {\r\n _state.set(value ?? initial);\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, expiration); // async persist\r\n this.hydration.set(true);\r\n },\r\n update: (updater: (curr: T) => T) => {\r\n const next = updater(_state());\r\n _state.set(next);\r\n this.save(key, next, expiration);\r\n this.hydration.set(true);\r\n },\r\n\r\n remove: () => {\r\n _state.set(initial);\r\n this.save(key, null);\r\n this.hydration.set(true);\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 let item = JSON.parse(decrypted) as StoredItem<T>;\r\n if (item.expiresAt && this.now().getMinutes() > item.expiresAt) {\r\n await this.db.delete(key);\r\n return;\r\n } else {\r\n return item.value;\r\n }\r\n } catch (err) {\r\n console.error('Decryption failed', err);\r\n return;\r\n }\r\n }\r\n }\r\n\r\n private async save<T>(key: string, value: T, expiration?: number) {\r\n try {\r\n if (expiration) {\r\n expiration = this.now().getMinutes() + expiration;\r\n }\r\n let itemToSave: StoredItem<T> = { value, expiresAt: expiration };\r\n const { iv, encrypted } = await this.cryptoX.encrypt(JSON.stringify(itemToSave));\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 update: (updater: (curr: T) => T) => void;\r\n remove: () => void;\r\n}\r\n\r\ninterface StoredItem<T> {\r\n value: T;\r\n expiresAt?: number;\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 CHANGED
@@ -42,12 +42,25 @@ declare class IndexeddbService {
42
42
  static ɵprov: i0.ɵɵInjectableDeclaration<IndexeddbService>;
43
43
  }
44
44
 
45
+ /**
46
+ * this service provides secure storage capabilities using encryption and IndexedDB.
47
+ * It allows storing, retrieving, and managing data with optional expiration times.
48
+ * The service uses signals to manage state reactively.
49
+ * @example
50
+ * const userSettings = secureStorageService.signal<UserSettings>('userSettings', defaultSettings, 60);
51
+ * userSettings.set({ theme: 'dark', notifications: true });
52
+ * const settings = userSettings.state();
53
+ * userSettings.remove();
54
+ *
55
+ */
45
56
  declare class SecureStorageService {
46
57
  private readonly cryptoX;
47
58
  private readonly db;
48
59
  constructor(cryptoX: CryptoService, db: IndexeddbService);
49
- signal<T>(key: string, initial: T): PersistedSignalStore<T>;
50
- load<T>(key: string): Promise<any>;
60
+ now: WritableSignal<Date>;
61
+ hydration: WritableSignal<boolean>;
62
+ signal<T>(key: string, initial: T, expiration?: number): PersistedSignalStore<T>;
63
+ load<T>(key: string): Promise<T | undefined>;
51
64
  private save;
52
65
  static ɵfac: i0.ɵɵFactoryDeclaration<SecureStorageService, never>;
53
66
  static ɵprov: i0.ɵɵInjectableDeclaration<SecureStorageService>;
@@ -55,7 +68,6 @@ declare class SecureStorageService {
55
68
  interface PersistedSignalStore<T> {
56
69
  state: WritableSignal<T>;
57
70
  set: (val: T) => void;
58
- load: () => T;
59
71
  update: (updater: (curr: T) => T) => void;
60
72
  remove: () => void;
61
73
  }
package/index.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","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"],"sourcesContent":[null,null,null,null,null],"names":[],"mappings":";;;;;;;;;AAOC;;ACJD,cAAA,aAAA;AAI6C;;;;AAM3C,uBAAA,UAAA,CAAA,WAAA;;;;;;;;;AAsDD;;AC/DD,cAAA,gBAAA;AAQ6C;;;;;AAFpC,aAAA,eAAA;;AAWP;;AAmDM,kCAAA,OAAA;AAWA,yBAAA,OAAA;;;;AAqBP;;ACpGD;;;;;;;;;;AAUG;AACH,cAAA,oBAAA;;;AAE+B,yBAAA,aAAA,MAAA,gBAAA;AAC7B,SAAA,cAAA,CAAA,IAAA;AACA,eAAA,cAAA;AACA,6DAAA,oBAAA;AA+BM,0BAAA,OAAA;;;;AAgCP;AAED,UAAA,oBAAA;AACE,WAAA,cAAA;AACA;AACA;;AAED;;ACpFD,cAAA,mBAAA;;;;;AAgBC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "ng-secure-storage",
3
- "version": "1.0.0",
3
+ "description": "on this version expiration time is added to the stored items",
4
+ "version": "1.1.0",
4
5
  "peerDependencies": {
5
6
  "@angular/common": "^20.3.0",
6
7
  "@angular/core": "^20.3.0"