fix: update keystore nullish check

This commit is contained in:
Your Name
2026-04-12 14:40:23 +05:30
parent 118a73d4aa
commit 6d5bc3ca09
3 changed files with 69 additions and 16 deletions
+56
View File
@@ -0,0 +1,56 @@
import { afterEach, describe, expect, it } from "vitest";
import { CryptoUtils } from "./crypto";
import { clearMasterKey, loadMasterKey, saveMasterKey } from "./keystore";
afterEach(async () => {
// clear to avoid in-memory db conflicts when running tests in parallel
await clearMasterKey();
});
async function makeMasterKey() {
return CryptoUtils.deriveMasterKey("test-password", "test@example.com");
}
describe("keystore", () => {
it("should save and load a CryptoKey successfully", async () => {
const key = await makeMasterKey();
await saveMasterKey(key);
const keyfromMemory = await loadMasterKey();
expect(keyfromMemory).toBeInstanceOf(CryptoKey);
expect(keyfromMemory).toEqual(key);
});
it("should remove the stored key from memory", async () => {
await saveMasterKey(await makeMasterKey());
await clearMasterKey();
const keyfromMemory = await loadMasterKey();
expect(keyfromMemory).toBeNull();
});
async function generateTestKey() {
// generate a random 'extractable' key for testing
return crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, true, [
"encrypt",
"decrypt",
]);
}
it("should overwrite the previous key when calling saveMasterKey twice", async () => {
const key1 = await generateTestKey();
const key2 = await generateTestKey();
await saveMasterKey(key1);
await saveMasterKey(key2);
const loadedKey = await loadMasterKey();
const loadedJwk = await crypto.subtle.exportKey("jwk", loadedKey);
const key1Jwk = await crypto.subtle.exportKey("jwk", key1);
const key2Jwk = await crypto.subtle.exportKey("jwk", key2);
expect(loadedJwk).toStrictEqual(key2Jwk);
expect(loadedJwk).not.toStrictEqual(key1Jwk);
});
});
+12 -6
View File
@@ -7,11 +7,17 @@ const db = openDB("piku-keys", 1, {
}, },
}); });
export const saveMasterKey = async (key: CryptoKey) => export const saveMasterKey = async (key: CryptoKey) => {
(await db).put("master-key", key, "masterKey"); const database = await db;
return await database.put("master-key", key, "masterKey");
};
export const loadMasterKey = async (): Promise<CryptoKey | null> => export const loadMasterKey = async (): Promise<CryptoKey | null> => {
(await db).get("master-key", "masterKey") ?? null; const database = await db;
return (await database.get("master-key", "masterKey")) || null;
};
export const clearMasterKey = async () => export const clearMasterKey = async () => {
(await db).delete("master-key", "masterKey"); const database = await db;
return await database.delete("master-key", "masterKey");
};
+1 -10
View File
@@ -1,17 +1,8 @@
import "@testing-library/jest-dom"; import "@testing-library/jest-dom";
import { IDBFactory } from "fake-indexeddb"; import "fake-indexeddb/auto"; // auto configures the indexedDB
import { afterAll, afterEach, beforeAll } from "vitest"; import { afterAll, afterEach, beforeAll } from "vitest";
import { server } from "./mocks/server"; import { server } from "./mocks/server";
/**
* faking indexeddb in memory for testing crypto key storage
*/
Object.defineProperty(globalThis, "indexedDB", {
value: new IDBFactory(),
writable: true,
configurable: true,
});
beforeAll(() => server.listen({ onUnhandledRequest: "warn" })); beforeAll(() => server.listen({ onUnhandledRequest: "warn" }));
afterEach(() => server.resetHandlers()); afterEach(() => server.resetHandlers());
afterAll(() => server.close()); afterAll(() => server.close());