UNPKG

@dfinity/vetkeys

Version:

JavaScript and TypeScript library to use Internet Computer vetKeys

658 lines (657 loc) 18.3 kB
import { T as f, E as v, D as m, a as w } from "./index-DeK1G2V9.mjs"; import { H as E, A as k } from "./actor-DZk8-pAg.mjs"; function y(r) { return new Promise((e, t) => { r.oncomplete = r.onsuccess = () => e(r.result), r.onabort = r.onerror = () => t(r.error); }); } function A(r, e) { let t; const n = () => { if (t) return t; const a = indexedDB.open(r); return a.onupgradeneeded = () => a.result.createObjectStore(e), t = y(a), t.then((i) => { i.onclose = () => t = void 0; }, () => { }), t; }; return (a, i) => n().then((s) => i(s.transaction(e, a).objectStore(e))); } let u; function h() { return u || (u = A("keyval-store", "keyval")), u; } function V(r, e = h()) { return e("readonly", (t) => y(t.get(r))); } function K(r, e, t = h()) { return t("readwrite", (n) => (n.put(e, r), y(n.transaction))); } const F = ({ IDL: r }) => { const e = r.Record({ inner: r.Vec(r.Nat8) }), t = r.Variant({ Read: r.Null, ReadWrite: r.Null, ReadWriteManage: r.Null }), n = r.Record({ access_control: r.Vec(r.Tuple(r.Principal, t)), keyvals: r.Vec(r.Tuple(e, e)), map_name: e, map_owner: r.Principal }), a = r.Variant({ Ok: r.Opt(e), Err: r.Text }), i = r.Variant({ Ok: r.Vec(r.Tuple(e, e)), Err: r.Text }), s = r.Variant({ Ok: e, Err: r.Text }), l = r.Variant({ Ok: r.Vec(r.Tuple(r.Principal, t)), Err: r.Text }), o = r.Variant({ Ok: r.Opt(t), Err: r.Text }), _ = r.Variant({ Ok: r.Vec(e), Err: r.Text }); return r.Service({ get_accessible_shared_map_names: r.Func( [], [r.Vec(r.Tuple(r.Principal, e))], ["query"] ), get_all_accessible_encrypted_maps: r.Func( [], [r.Vec(n)], ["query"] ), get_all_accessible_encrypted_values: r.Func( [], [ r.Vec( r.Tuple( r.Tuple(r.Principal, e), r.Vec(r.Tuple(e, e)) ) ) ], ["query"] ), get_encrypted_value: r.Func( [r.Principal, e, e], [a], ["query"] ), get_encrypted_values_for_map: r.Func( [r.Principal, e], [i], ["query"] ), get_encrypted_vetkey: r.Func( [r.Principal, e, e], [s], [] ), get_owned_non_empty_map_names: r.Func( [], [r.Vec(e)], ["query"] ), get_shared_user_access_for_map: r.Func( [r.Principal, e], [l], ["query"] ), get_user_rights: r.Func( [r.Principal, e, r.Principal], [o], ["query"] ), get_vetkey_verification_key: r.Func([], [e], []), insert_encrypted_value: r.Func( [r.Principal, e, e, e], [a], [] ), remove_encrypted_value: r.Func( [r.Principal, e, e], [a], [] ), remove_map_values: r.Func([r.Principal, e], [_], []), remove_user: r.Func( [r.Principal, e, r.Principal], [o], [] ), set_user_rights: r.Func( [r.Principal, e, r.Principal, t], [o], [] ) }); }, d = process.env.CANISTER_ID_IC_VETKEYS_ENCRYPTED_MAPS_CANISTER, g = (r, e = {}) => { const t = e.agent || new E({ ...e.agentOptions }); return e.agent && e.agentOptions && console.warn( "Detected both agent and agentOptions passed to createActor. Ignoring agentOptions and proceeding with the provided agent." ), process.env.DFX_NETWORK !== "ic" && t.fetchRootKey().catch((n) => { console.warn( "Unable to fetch root key. Check to ensure that your local replica is running" ), console.error(n); }), k.createActor(F, { agent: t, canisterId: r, ...e.actorOptions }); }; d && g(d); class O { actor; constructor(e, t) { this.actor = g(t, { agent: e }); } get_accessible_shared_map_names() { return this.actor.get_accessible_shared_map_names(); } get_shared_user_access_for_map(e, t) { return this.actor.get_shared_user_access_for_map(e, t); } get_owned_non_empty_map_names() { return this.actor.get_owned_non_empty_map_names(); } get_all_accessible_encrypted_values() { return this.actor.get_all_accessible_encrypted_values(); } get_all_accessible_encrypted_maps() { return this.actor.get_all_accessible_encrypted_maps(); } get_encrypted_value(e, t, n) { return this.actor.get_encrypted_value(e, t, n); } get_encrypted_values_for_map(e, t) { return this.actor.get_encrypted_values_for_map(e, t); } get_encrypted_vetkey(e, t, n) { return this.actor.get_encrypted_vetkey(e, t, n); } insert_encrypted_value(e, t, n, a) { return this.actor.insert_encrypted_value( e, t, n, a ); } remove_encrypted_value(e, t, n) { return this.actor.remove_encrypted_value(e, t, n); } remove_map_values(e, t) { return this.actor.remove_map_values(e, t); } get_vetkey_verification_key() { return this.actor.get_vetkey_verification_key(); } set_user_rights(e, t, n, a) { return this.actor.set_user_rights(e, t, n, a); } get_user_rights(e, t, n) { return this.actor.get_user_rights(e, t, n); } remove_user(e, t, n) { return this.actor.remove_user(e, t, n); } } class M { /** * The client instance for interacting with the EncryptedMaps canister. */ canisterClient; /** * The cached verification key for validating encrypted VetKeys. */ verificationKey = void 0; /** * Creates a new instance of the EncryptedMaps client. * * @example * ```ts * import { EncryptedMaps } from "@dfinity/vetkeys/encrypted_maps"; * * const encryptedMaps = new EncryptedMaps(encryptedMapsClientInstance); * ``` */ constructor(e) { this.canisterClient = e; } /** * Retrieves a list of maps that were shared with the user and the user still has access to. * * @example * ```ts * const sharedMaps = await encryptedMaps.getAccessibleSharedMapNames(); * console.log("Shared Maps:", sharedMaps); * ``` * * @returns Promise resolving to an array of `[Principal, Uint8Array]` pairs representing accessible map identifiers. */ async getAccessibleSharedMapNames() { return (await this.canisterClient.get_accessible_shared_map_names()).map(([e, t]) => [e, Uint8Array.from(t.inner)]); } /** * Retrieves a list of non-empty maps owned by the caller. * * @returns Promise resolving to an array of map names */ async getOwnedNonEmptyMapNames() { return (await this.canisterClient.get_owned_non_empty_map_names()).map( (e) => Uint8Array.from(e.inner) ); } /** * Retrieves all accessible values across all maps the user has access to. * * @returns Promise resolving to an array of map data with decrypted values */ async getAllAccessibleValues() { const e = await this.canisterClient.get_all_accessible_encrypted_values(), t = []; for (const [n, a] of e) { const i = Uint8Array.from(n[1].inner), s = []; for (const [l, o] of a) { const _ = Uint8Array.from(l.inner), p = await this.decryptFor( n[0], i, _, Uint8Array.from(o.inner) ); s.push([_, p]); } t.push([ [n[0], Uint8Array.from(n[1].inner)], s ]); } return t; } /** * Retrieves all accessible maps with their decrypted values. * * @returns Promise resolving to an array of map data */ async getAllAccessibleMaps() { const e = await this.canisterClient.get_all_accessible_encrypted_maps(), t = []; for (const n of e) { const a = Uint8Array.from(n.map_name.inner), i = []; for (const [ s, l ] of n.keyvals) { const o = Uint8Array.from(s.inner), _ = await this.decryptFor( n.map_owner, a, o, Uint8Array.from(l.inner) ); i.push([o, _]); } t.push({ accessControl: n.access_control, keyvals: i, mapName: a, mapOwner: n.map_owner }); } return t; } /** * Retrieves and decrypts a stored value from a map. * * @example * ```ts * const mapOwner = Principal.fromText("aaaaa-aa"); * const mapName = "passwords"; * const mapKey = "email_account"; * * const storedValue = await encryptedMaps.getValue(mapOwner, mapName, mapKey); * console.log("Decrypted Value:", new TextDecoder().decode(storedValue)); * ``` * * @param mapOwner - The principal of the map owner * @param mapName - The name/identifier of the map * @param mapKey - The key to retrieve * @returns Promise resolving to the decrypted value * @throws Error if the operation fails */ async getValue(e, t, n) { const a = await this.canisterClient.get_encrypted_value( e, c(t), c(n) ); if ("Err" in a) throw Error(a.Err); return a.Ok.length === 0 ? new Uint8Array(0) : await this.decryptFor( e, t, n, Uint8Array.from(a.Ok[0].inner) ); } /** * Retrieves all values from a specific map. * * @param mapOwner - The principal of the map owner * @param mapName - The name/identifier of the map * @returns Promise resolving to an array of key-value pairs * @throws Error if the operation fails */ async getValuesForMap(e, t) { const n = await this.canisterClient.get_encrypted_values_for_map( e, c(t) ); if ("Err" in n) throw Error(n.Err); const a = new Array(); for (const [s, l] of n.Ok) a.push([ Uint8Array.from(s.inner), Uint8Array.from(l.inner) ]); const i = new Array(); for (const [s, l] of n.Ok) { const o = Uint8Array.from(s.inner), _ = await this.decryptFor( e, t, o, Uint8Array.from(l.inner) ); i.push([o, _]); } return i; } /** * Stores an encrypted value in a map. * * @example * ```ts * const value = new TextEncoder().encode("my_secure_password"); * const result = await encryptedMaps.setValue(mapOwner, mapName, mapKey, value); * console.log("Replaced Value:", result); * ``` * * @param mapOwner - The principal of the map owner * @param mapName - The name/identifier of the map * @param mapKey - The key to store * @param data - The value to store * @returns Promise resolving to the previous value if it existed * @throws Error if the operation fails */ async setValue(e, t, n, a) { const i = await this.encryptFor( e, t, n, a ), s = await this.canisterClient.insert_encrypted_value( e, c(t), c(n), { inner: i } ); if ("Err" in s) throw Error(s.Err); return s.Ok.length === 0 ? void 0 : await this.decryptFor( e, t, n, Uint8Array.from(s.Ok[0].inner) ); } /** * Removes a value from a map. * * @param mapOwner - The principal of the map owner * @param mapName - The name/identifier of the map * @param mapKey - The key to remove * @returns Promise resolving to the removed value if it existed * @throws Error if the operation fails */ async removeEncryptedValue(e, t, n) { const a = await this.canisterClient.remove_encrypted_value( e, c(t), c(n) ); if ("Err" in a) throw Error(a.Err); return a.Ok.length === 0 ? void 0 : await this.decryptFor( e, t, n, Uint8Array.from(a.Ok[0].inner) ); } /** * Removes all values from a map. * * @param mapOwner - The principal of the map owner * @param mapName - The name/identifier of the map * @returns Promise resolving to an array of removed keys * @throws Error if the operation fails */ async removeMapValues(e, t) { const n = await this.canisterClient.remove_map_values( e, c(t) ); if ("Err" in n) throw Error(n.Err); return n.Ok.map( (a) => Uint8Array.from(a.inner) ); } /** * Retrieves the public verification key for validating encrypted VetKeys. * The vetkeys obtained via `getVetkey` are verified using this key, * and, therefore, this method is not needed for using `getVetkey`. * * @example * ```ts * const verificationKey = await encryptedMaps.getVetkeyVerificationKey(); * console.log("Verification Key:", verificationKey); * ``` * * @returns Promise resolving to the verification key bytes */ async getVetkeyVerificationKey() { if (!this.verificationKey) { const e = await this.canisterClient.get_vetkey_verification_key(); this.verificationKey = Uint8Array.from(e.inner); } return this.verificationKey; } /** * Grants or modifies access rights for a user. * * @example * ```ts * const owner = Principal.fromText("aaaaa-aa"); * const user = Principal.fromText("bbbbbb-bb"); * const accessRights = { ReadWrite: null }; * * const result = await encryptedMaps.setUserRights( * owner, * mapName, * user, * accessRights, * ); * console.log("Access Rights Updated:", result); * ``` * * @param owner - The principal of the map owner * @param mapName - The name/identifier of the map * @param user - The principal of the user to grant/modify rights for * @param userRights - The access rights to grant * @returns Promise resolving to the previous access rights if they existed * @throws Error if the operation fails */ async setUserRights(e, t, n, a) { const i = await this.canisterClient.set_user_rights( e, c(t), n, a ); if ("Err" in i) throw Error(i.Err); if (i.Ok.length > 1) throw Error("Unexpected result from set_user_rights"); return i.Ok.length === 0 ? void 0 : i.Ok[0]; } /** * Checks a user's access rights. * * @example * ```ts * const userRights = await encryptedMaps.get_user_rights(owner, mapName, user); * console.log("User Access Rights:", userRights); * ``` * * @param owner - The principal of the map owner * @param mapName - The name/identifier of the map * @param user - The principal of the user to check rights for * @returns Promise resolving to the user's access rights if they exist * @throws Error if the operation fails */ async getUserRights(e, t, n) { const a = await this.canisterClient.get_user_rights( e, c(t), n ); if ("Err" in a) throw Error(a.Err); if (a.Ok.length > 1) throw Error("Unexpected result from set_user_rights"); return a.Ok.length === 0 ? void 0 : a.Ok[0]; } /** * Gets all users that have access to a map and their access rights. * * @param owner - The principal of the map owner * @param mapName - The name/identifier of the map * @returns Promise resolving to an array of user-access rights pairs * @throws Error if the operation fails */ async getSharedUserAccessForMap(e, t) { const n = await this.canisterClient.get_shared_user_access_for_map( e, c(t) ); if ("Err" in n) throw Error(n.Err); return n.Ok; } /** * Revokes a user's access. * * @example * ```ts * const removalResult = await encryptedMaps.remove_user(owner, mapName, user); * console.log("User Removed:", removalResult); * ``` * * @param owner - The principal of the map owner * @param mapName - The name/identifier of the map * @param user - The principal of the user to remove * @returns Promise resolving to the previous access rights if they existed * @throws Error if the operation fails */ async removeUser(e, t, n) { const a = await this.canisterClient.remove_user( e, c(t), n ); if ("Err" in a) throw Error(a.Err); return a.Ok.length === 0 ? void 0 : a.Ok[0]; } /** * Derives a key material for a specific map. * * @param mapOwner - The principal of the map owner * @param mapName - The name/identifier of the map * @returns Promise resolving to the derived key material * @throws Error if the operation fails */ async getDerivedKeyMaterial(e, t) { const n = f.random(), a = await this.canisterClient.get_encrypted_vetkey( e, c(t), c(n.publicKeyBytes()) ); if ("Err" in a) throw Error(a.Err); { const i = Uint8Array.from(a.Ok.inner), s = await this.getVetkeyVerificationKey(), l = new Uint8Array([ e.toUint8Array().length, ...e.toUint8Array(), ...t ]), o = v.deserialize(i), _ = m.deserialize(s); return await o.decryptAndVerify( n, _, l ).asDerivedKeyMaterial(); } } /** * Encrypts a value for a specific map and key. * * @param mapOwner - The principal of the map owner * @param mapName - The name/identifier of the map * @param mapKey - The key to encrypt for * @param cleartext - The value to encrypt * @returns Promise resolving to the encrypted value */ async encryptFor(e, t, n, a) { return await (await this.getDerivedKeyMaterialOrFetchIfNeeded(e, t)).encryptMessage(a, n); } /** * Decrypts a value for a specific map and key. * * @param mapOwner - The principal of the map owner * @param mapName - The name/identifier of the map * @param mapKey - The key to decrypt for * @param encryptedValue - The value to decrypt * @returns Promise resolving to the decrypted value */ async decryptFor(e, t, n, a) { return await (await this.getDerivedKeyMaterialOrFetchIfNeeded(e, t)).decryptMessage(a, n); } /** * Gets or fetches the derived key material for a map. * * @param mapOwner - The principal of the map owner * @param mapName - The name/identifier of the map * @returns Promise resolving to the derived key material */ async getDerivedKeyMaterialOrFetchIfNeeded(e, t) { const n = await V([ e.toString(), t ]); if (n) return w.fromCryptoKey( n ); const a = await this.getDerivedKeyMaterial( e, t ); return await K( [e.toString(), t], a.getCryptoKey() ), a; } } function c(r) { return { inner: r }; } export { O as DefaultEncryptedMapsClient, M as EncryptedMaps };