core: delete all vaults when user triggers their vault deletion (#9939)

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
This commit is contained in:
01zulfi
2026-07-28 19:45:30 +05:00
committed by GitHub
parent 32070327f9
commit aafb6049b2
4 changed files with 150 additions and 6 deletions

View File

@@ -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);

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}));

View File

@@ -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<string>();
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;
}

View File

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