diff --git a/packages/core/__tests__/vault.test.js b/packages/core/__tests__/vault.test.js index 0073c8d69..89c732bd9 100644 --- a/packages/core/__tests__/vault.test.js +++ b/packages/core/__tests__/vault.test.js @@ -231,6 +231,80 @@ test("delete vault and delete all locked notes", () => expect(await db.vaults.default()).toBeUndefined(); })); +test("delete all vaults and their locked notes", () => + noteTest().then(async ({ db, id: note1Id }) => { + /** + * simulating the case where multiple vaults have been created + * and each vault has a locked note + */ + const key = { + format: "base64", + alg: "aes-256-gcm", + cipher: "key", + iv: "iv", + salt: "salt", + length: 16 + }; + const vault1Id = await db.vaults.add({ + title: "Vault 1", + key + }); + const vault2Id = await db.vaults.add({ + title: "Vault 2", + key + }); + await db.relations.add( + { + id: vault1Id, + type: "vault" + }, + { + id: note1Id, + type: "note" + } + ); + const note2Id = await db.notes.add(TEST_NOTE); + await db.relations.add( + { + id: vault2Id, + type: "vault" + }, + { + id: note2Id, + type: "note" + } + ); + + await db.vault.delete(true); + + expect( + await db.relations + .from( + { + id: vault1Id, + type: "vault" + }, + "note" + ) + .has(note1Id) + ).toBe(false); + expect( + await db.relations + .from( + { + id: vault2Id, + type: "vault" + }, + "note" + ) + .has(note2Id) + ).toBe(false); + expect(await db.notes.exists(note1Id)).toBe(false); + expect(await db.notes.exists(note2Id)).toBe(false); + expect(await db.vaults.default()).toBeUndefined(); + expect(await db.vaults.all.count()).toBe(0); + })); + test("vault password is cleared after specified time", () => databaseTest().then(async (db) => { await expect(db.vault.create("password")).resolves.toBe(true); diff --git a/packages/core/__tests__/vaults.test.ts b/packages/core/__tests__/vaults.test.ts new file mode 100644 index 000000000..fc95b85bd --- /dev/null +++ b/packages/core/__tests__/vaults.test.ts @@ -0,0 +1,50 @@ +/* +This file is part of the Notesnook project (https://notesnook.com/) + +Copyright (C) 2023 Streetwriters (Private) Limited + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +import { databaseTest } from "./utils/index.js"; +import { test, expect } from "vitest"; + +test("remove all vaults", () => + databaseTest().then(async (db) => { + const key = { + format: "base64" as const, + alg: "aes-256-gcm", + cipher: "key", + iv: "iv", + salt: "salt", + length: 16 + }; + + await db.vaults.add({ + title: "Vault 1", + key + }); + await db.vaults.add({ + title: "Vault 2", + key + }); + + expect(await db.vaults.all.count()).toBe(2); + expect(await db.vaults.default()).toBeDefined(); + + await db.vaults.removeAll(); + + expect(await db.vaults.all.count()).toBe(0); + expect(await db.vaults.default()).toBeUndefined(); + })); diff --git a/packages/core/src/api/vault.ts b/packages/core/src/api/vault.ts index 363806bcc..bc6377672 100644 --- a/packages/core/src/api/vault.ts +++ b/packages/core/src/api/vault.ts @@ -161,17 +161,30 @@ export default class Vault { } } + /** + * + * There's an unintentional and unrelated bug where multiple vaults + * can be created. + * So when user triggers delete, we should delete all vaults. + */ async delete(deleteAllLockedNotes = false) { - const vault = await this.db.vaults.default(); - if (!vault) return; + const vaults = await this.db.vaults.all.items(); + if (!vaults.length) return; if (deleteAllLockedNotes) { - const relations = await this.db.relations.from(vault, "note").get(); - const lockedIds = relations.map((r) => r.toId); - await this.db.notes.remove(...lockedIds); + const lockedIds = new Set(); + for (const vault of vaults) { + const relations = await this.db.relations.from(vault, "note").get(); + for (const { toId } of relations) { + lockedIds.add(toId); + } + } + if (lockedIds.size) { + await this.db.notes.remove(...lockedIds); + } } - await this.db.vaults.remove(vault.id); + await this.db.vaults.removeAll(); this.password = undefined; } diff --git a/packages/core/src/collections/vaults.ts b/packages/core/src/collections/vaults.ts index 96686dcc3..562db45db 100644 --- a/packages/core/src/collections/vaults.ts +++ b/packages/core/src/collections/vaults.ts @@ -87,4 +87,11 @@ export class Vaults implements ICollection { async itemExists(reference: ItemReference) { return (await this.db.relations.to(reference, "vault").count()) > 0; } + + async removeAll() { + const vaults = await this.all.items(); + for (const vault of vaults) { + await this.remove(vault.id); + } + } }