@dfinity/vetkeys
Version:
JavaScript and TypeScript library to use Internet Computer vetKeys
658 lines (657 loc) • 18.3 kB
JavaScript
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
};