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);
+ }
+ }
}