@icp-sdk/vetkeys 0.5.0-beta.0 → 0.6.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.
@@ -1,5 +1,5 @@
1
- import { T as u, D as _, E as l } from "./index-BUXhtQhx.mjs";
2
- import { A as h } from "./actor-4fotMNaR.mjs";
1
+ import { TransportSecretKey as u, DerivedPublicKey as _, EncryptedVetKey as l } from "./index.es.js";
2
+ import { A as h } from "./actor-CFYb2LZx.mjs";
3
3
  const g = ({ IDL: e }) => {
4
4
  const r = e.Record({ inner: e.Vec(e.Nat8) }), t = e.Variant({ Ok: r, Err: e.Text }), s = e.Variant({
5
5
  Read: e.Null,
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @module @icp-sdk/vetkeys/encrypted_maps
3
+ *
4
+ * @description Caching strategies for derived key material. See
5
+ * {@link DerivedKeyMaterialCache}.
6
+ */
7
+ /**
8
+ * Strategy for caching the per-map derived key material handles used by
9
+ * {@link EncryptedMaps}.
10
+ *
11
+ * Deriving key material requires a canister round-trip and threshold
12
+ * cryptography, so it is cached and reused. The cached value is a
13
+ * non-extractable {@link CryptoKey} handle: its raw bytes can never be read
14
+ * back (`crypto.subtle.exportKey` throws), but the handle can still be *used*
15
+ * to decrypt. Where that handle lives therefore matters for security — see the
16
+ * provided implementations.
17
+ *
18
+ * Cache entries are keyed by an opaque string derived from the map owner and
19
+ * map name. Derived key material is per map, not per caller, so the key does
20
+ * not encode the identity. Isolating one identity's cached keys from another's
21
+ * on the same origin is therefore a property of the cache instance: use a fresh
22
+ * cache per identity (the in-memory default is naturally per-instance), or give
23
+ * a persistent cache a per-identity namespace (see
24
+ * {@link IndexedDbDerivedKeyMaterialCache}).
25
+ */
26
+ export interface DerivedKeyMaterialCache {
27
+ /**
28
+ * Returns the cached key handle for the given key, or `undefined` on a miss.
29
+ */
30
+ get(key: string): Promise<CryptoKey | undefined>;
31
+ /**
32
+ * Stores a key handle under the given key.
33
+ */
34
+ set(key: string, value: CryptoKey): Promise<void>;
35
+ /**
36
+ * Removes every cached key handle.
37
+ *
38
+ * Call this on logout or whenever the authenticated identity changes to
39
+ * avoid leaving usable decryption capability behind.
40
+ */
41
+ clear(): Promise<void>;
42
+ }
43
+ /**
44
+ * Default {@link DerivedKeyMaterialCache} that keeps key handles in memory only.
45
+ *
46
+ * Nothing is written to disk, so the cache is discarded when the page is
47
+ * reloaded or the tab is closed and there is no at-rest exposure. The trade-off
48
+ * is one extra key derivation per map per page load.
49
+ */
50
+ export declare class InMemoryDerivedKeyMaterialCache implements DerivedKeyMaterialCache {
51
+ #private;
52
+ get(key: string): Promise<CryptoKey | undefined>;
53
+ set(key: string, value: CryptoKey): Promise<void>;
54
+ clear(): Promise<void>;
55
+ }
56
+ /**
57
+ * Opt-in {@link DerivedKeyMaterialCache} that persists key handles in IndexedDB.
58
+ *
59
+ * Key handles survive page reloads, avoiding repeated key derivation, but this
60
+ * is a deliberate security trade-off: the persisted handle is non-extractable
61
+ * (its raw bytes cannot be stolen), yet any same-origin code — e.g. via XSS, a
62
+ * malicious extension, or a shared browser profile — can read the handle and
63
+ * use it to decrypt the user's data without an authenticated session, for as
64
+ * long as it remains stored.
65
+ *
66
+ * Prefer {@link InMemoryDerivedKeyMaterialCache} (the default) unless you need
67
+ * cross-reload persistence and accept this exposure. When using this cache, be
68
+ * sure to call {@link EncryptedMaps.clearCache} on logout or identity change.
69
+ *
70
+ * Because the cache key does not encode the identity, **give the store a
71
+ * per-identity namespace** to keep one identity's persisted keys from being
72
+ * served to another on the same origin — e.g. include the caller's principal in
73
+ * the database name:
74
+ *
75
+ * ```ts
76
+ * new IndexedDbDerivedKeyMaterialCache(`vetkeys-${principal}`);
77
+ * ```
78
+ *
79
+ * A dedicated IndexedDB store is used, so {@link clear} only removes entries
80
+ * written by this cache and never touches other application data.
81
+ */
82
+ export declare class IndexedDbDerivedKeyMaterialCache implements DerivedKeyMaterialCache {
83
+ #private;
84
+ /**
85
+ * @param dbName - IndexedDB database name. Defaults to `"ic-vetkeys"`. This
86
+ * is the isolation knob: give each identity its own database name (e.g.
87
+ * `` `vetkeys-${principal}` ``) so one identity's persisted keys are never
88
+ * served to another. The object store name is fixed, because `idb-keyval`
89
+ * supports only a single object store per database.
90
+ */
91
+ constructor(dbName?: string);
92
+ get(key: string): Promise<CryptoKey | undefined>;
93
+ set(key: string, value: CryptoKey): Promise<void>;
94
+ clear(): Promise<void>;
95
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,7 +1,9 @@
1
1
  import { Principal } from '@icp-sdk/core/principal';
2
2
  import { DerivedKeyMaterial } from '../utils/utils';
3
+ import { DerivedKeyMaterialCache } from './cache';
3
4
  import { AccessRights, ByteBuf } from '../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js';
4
5
  export { DefaultEncryptedMapsClient } from './encrypted_maps_canister';
6
+ export { type DerivedKeyMaterialCache, InMemoryDerivedKeyMaterialCache, IndexedDbDerivedKeyMaterialCache, } from './cache';
5
7
  export type { AccessRights, ByteBuf, } from '../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js';
6
8
  /**
7
9
  * The **EncryptedMaps** frontend library facilitates interaction with an [**EncryptedMaps-enabled canister**](https://docs.rs/ic-vetkeys/latest/ic_vetkeys/encrypted_maps/struct.EncryptedMaps.html) on the **Internet Computer (ICP)**.
@@ -19,9 +21,23 @@ export type { AccessRights, ByteBuf, } from '../declarations/ic_vetkeys_manager_
19
21
  *
20
22
  * - **Access Rights** should be carefully managed to prevent unauthorized access.
21
23
  * - VetKeys should be decrypted **only in trusted environments** such as user browsers to prevent leaks.
24
+ * - Derived key material is cached **in memory by default** ({@link InMemoryDerivedKeyMaterialCache}),
25
+ * so it never touches disk and is discarded on page reload. Persisting it across
26
+ * reloads with {@link IndexedDbDerivedKeyMaterialCache} is an explicit, opt-in trade-off:
27
+ * the persisted handle is non-extractable, but any same-origin code can use it to decrypt
28
+ * without an authenticated session for as long as it is stored.
29
+ * - The cache belongs to a single authenticated identity. Identity lifecycle is the
30
+ * caller's responsibility, so to avoid serving one identity's key material to another
31
+ * on the same origin:
32
+ * - with the in-memory default, use a **fresh `EncryptedMaps` instance per identity**
33
+ * (or call {@link EncryptedMaps.clearCache} on logout / identity change);
34
+ * - with {@link IndexedDbDerivedKeyMaterialCache}, give the store a **per-identity
35
+ * namespace** (e.g. include the caller's principal in the database name) so entries
36
+ * are physically separated, and call {@link EncryptedMaps.clearCache} on logout.
22
37
  *
23
38
  */
24
39
  export declare class EncryptedMaps {
40
+ #private;
25
41
  /**
26
42
  * The client instance for interacting with the EncryptedMaps canister.
27
43
  */
@@ -33,14 +49,38 @@ export declare class EncryptedMaps {
33
49
  /**
34
50
  * Creates a new instance of the EncryptedMaps client.
35
51
  *
52
+ * @param canisterClient - The client used to talk to the EncryptedMaps canister.
53
+ * @param options - Optional configuration.
54
+ * @param options.cache - Strategy for caching derived key material. Defaults to
55
+ * {@link InMemoryDerivedKeyMaterialCache} (in-memory only, never persisted).
56
+ * Pass {@link IndexedDbDerivedKeyMaterialCache} to persist across page reloads —
57
+ * see the security note in the class description.
58
+ *
36
59
  * @example
37
60
  * ```ts
38
61
  * import { EncryptedMaps } from "@icp-sdk/vetkeys/encrypted_maps";
39
62
  *
40
63
  * const encryptedMaps = new EncryptedMaps(encryptedMapsClientInstance);
41
64
  * ```
65
+ *
66
+ * @example Opt into persistent caching, namespaced per identity
67
+ * ```ts
68
+ * import {
69
+ * EncryptedMaps,
70
+ * IndexedDbDerivedKeyMaterialCache,
71
+ * } from "@icp-sdk/vetkeys/encrypted_maps";
72
+ *
73
+ * const encryptedMaps = new EncryptedMaps(encryptedMapsClientInstance, {
74
+ * // Namespace the store per identity so one identity's cached keys are
75
+ * // never served to another on the same origin.
76
+ * cache: new IndexedDbDerivedKeyMaterialCache(`vetkeys-${myPrincipal}`),
77
+ * });
78
+ * // Remember to call encryptedMaps.clearCache() on logout / identity change.
79
+ * ```
42
80
  */
43
- constructor(canisterClient: EncryptedMapsClient);
81
+ constructor(canisterClient: EncryptedMapsClient, options?: {
82
+ cache?: DerivedKeyMaterialCache;
83
+ });
44
84
  /**
45
85
  * Retrieves a list of maps that were shared with the user and the user still has access to.
46
86
  *
@@ -255,6 +295,18 @@ export declare class EncryptedMaps {
255
295
  * @returns Promise resolving to the derived key material
256
296
  */
257
297
  getDerivedKeyMaterialOrFetchIfNeeded(mapOwner: Principal, mapName: Uint8Array): Promise<DerivedKeyMaterial>;
298
+ /**
299
+ * Clears all cached derived key material.
300
+ *
301
+ * Strongly recommended on logout or whenever the authenticated identity
302
+ * changes: the cache belongs to a single identity, so clearing it (or
303
+ * discarding the `EncryptedMaps` instance) prevents one identity's key
304
+ * material from being served to another, and drops the still-usable
305
+ * decryption capability that otherwise lingers. This matters most with
306
+ * {@link IndexedDbDerivedKeyMaterialCache}, where cached key handles persist
307
+ * across sessions until cleared.
308
+ */
309
+ clearCache(): Promise<void>;
258
310
  }
259
311
  /**
260
312
  * Interface for map data structure.
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "@icp-sdk/vetkeys",
3
- "version": "0.5.0-beta.0",
4
- "packageManager": "pnpm@10.10.0",
3
+ "version": "0.6.0",
5
4
  "author": "DFINITY Stiftung",
6
5
  "description": "JavaScript and TypeScript library to use Internet Computer vetKeys",
7
6
  "homepage": "https://internetcomputer.org/docs/building-apps/network-features/vetkeys/introduction",
@@ -58,26 +57,26 @@
58
57
  "module": "dist/lib/index.es.js",
59
58
  "typings": "dist/types/index.d.ts",
60
59
  "dependencies": {
61
- "@icp-sdk/core": "^5.2.1",
62
- "idb-keyval": "^6.2.1"
60
+ "@icp-sdk/core": "^6.1.0",
61
+ "idb-keyval": "^6.3.0"
63
62
  },
64
63
  "devDependencies": {
64
+ "@eslint/js": "^9.39.5",
65
65
  "@noble/curves": "^1.9.7",
66
66
  "@noble/hashes": "^1.8.0",
67
- "@eslint/js": "^9.22.0",
68
- "@types/node": "^24.0.4",
69
- "@vitest/coverage-v8": "^3.0.5",
70
- "eslint": "^9.22",
71
- "eslint-config-prettier": "^10.1.5",
72
- "eslint-plugin-prettier": "^5.2.6",
73
- "fake-indexeddb": "^6.0.0",
74
- "prettier": "^3.5.3",
75
- "typedoc": "^0.28.3",
67
+ "@types/node": "^24.13.3",
68
+ "@vitest/coverage-v8": "^3.2.7",
69
+ "eslint": "^9.39.5",
70
+ "eslint-config-prettier": "^10.1.8",
71
+ "eslint-plugin-prettier": "^5.5.6",
72
+ "fake-indexeddb": "^6.2.5",
73
+ "prettier": "^3.9.6",
74
+ "typedoc": "^0.28.20",
76
75
  "typescript": "^5.9.3",
77
- "typescript-eslint": "^8.59.0",
78
- "vite": "^7.0.8",
79
- "vite-plugin-dts": "^4.5.3",
80
- "vitest": "^3.0.5"
76
+ "typescript-eslint": "^8.68.0",
77
+ "vite": "^7.3.6",
78
+ "vite-plugin-dts": "^4.5.4",
79
+ "vitest": "^3.2.7"
81
80
  },
82
81
  "scripts": {
83
82
  "build": "tsc && vite build",