mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-16 06:58:46 +00:00
82 lines
2.0 KiB
TypeScript
82 lines
2.0 KiB
TypeScript
import { Dexie, type EntityTable } from "dexie";
|
|
|
|
type ClientKeyUsage = "encrypt" | "decrypt" | "sign" | "verify";
|
|
|
|
interface ClientKey {
|
|
usage: ClientKeyUsage;
|
|
key: CryptoKey;
|
|
}
|
|
|
|
interface MasterKey {
|
|
version: number;
|
|
state: "active" | "retired";
|
|
key: CryptoKey;
|
|
}
|
|
|
|
interface HmacSecret {
|
|
version: number;
|
|
state: "active";
|
|
secret: CryptoKey;
|
|
}
|
|
|
|
const keyStore = new Dexie("keyStore") as Dexie & {
|
|
clientKey: EntityTable<ClientKey, "usage">;
|
|
masterKey: EntityTable<MasterKey, "version">;
|
|
hmacSecret: EntityTable<HmacSecret, "version">;
|
|
};
|
|
|
|
keyStore.version(1).stores({
|
|
clientKey: "usage",
|
|
masterKey: "version",
|
|
hmacSecret: "version",
|
|
});
|
|
|
|
export const getClientKey = async (usage: ClientKeyUsage) => {
|
|
const key = await keyStore.clientKey.get(usage);
|
|
return key?.key ?? null;
|
|
};
|
|
|
|
export const storeClientKey = async (key: CryptoKey, usage: ClientKeyUsage) => {
|
|
switch (usage) {
|
|
case "encrypt":
|
|
case "verify":
|
|
if (key.type !== "public") {
|
|
throw new Error("Public key required");
|
|
} else if (!key.extractable) {
|
|
throw new Error("Public key must be extractable");
|
|
}
|
|
break;
|
|
case "decrypt":
|
|
case "sign":
|
|
if (key.type !== "private") {
|
|
throw new Error("Private key required");
|
|
} else if (key.extractable) {
|
|
throw new Error("Private key must be nonextractable");
|
|
}
|
|
break;
|
|
}
|
|
await keyStore.clientKey.put({ usage, key });
|
|
};
|
|
|
|
export const getMasterKeys = async () => {
|
|
return await keyStore.masterKey.toArray();
|
|
};
|
|
|
|
export const storeMasterKeys = async (keys: MasterKey[]) => {
|
|
if (keys.some(({ key }) => key.extractable)) {
|
|
throw new Error("Master keys must be nonextractable");
|
|
}
|
|
await keyStore.masterKey.bulkPut(keys);
|
|
};
|
|
|
|
export const getHmacSecrets = async () => {
|
|
return await keyStore.hmacSecret.toArray();
|
|
};
|
|
|
|
export const storeHmacSecrets = async (secrets: HmacSecret[]) => {
|
|
if (secrets.some(({ secret }) => secret.extractable)) {
|
|
throw new Error("Hmac secrets must be nonextractable");
|
|
}
|
|
await keyStore.hmacSecret.bulkPut(secrets);
|
|
};
|