mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-24 04:00:59 +01:00
web: allow locked notes to stay unlocked if keep vault note unlocked is enabled
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
This commit is contained in:
@@ -193,4 +193,15 @@ export class SettingsViewModel {
|
||||
.locator("input");
|
||||
await titleFormatInput.fill(format);
|
||||
}
|
||||
|
||||
async toggleKeepVaultNotesUnlocked() {
|
||||
const item = await this.navigation.findItem("Vault");
|
||||
await item?.click();
|
||||
|
||||
const keepVaultNotesUnlocked = this.page
|
||||
.locator(getTestId("setting-keep-note-unlocked"))
|
||||
.locator("label");
|
||||
|
||||
await keepVaultNotesUnlocked.click();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,3 +125,42 @@ test("clicking on vault unlocked status should lock the readonly note", async ({
|
||||
|
||||
expect(await note?.isLockedNotePasswordFieldVisible()).toBe(true);
|
||||
});
|
||||
|
||||
test("when keep note unlocked setting is disabled (default), locked note should be locked again when it is closed after opening", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
|
||||
await note?.contextMenu.lock(PASSWORD);
|
||||
await note?.openLockedNote(PASSWORD);
|
||||
const tabs = await notes.editor.getTabs();
|
||||
await tabs[0].close();
|
||||
|
||||
await note?.click();
|
||||
|
||||
expect(await note?.isLockedNotePasswordFieldVisible()).toBe(true);
|
||||
});
|
||||
|
||||
test("when keep note unlocked setting is enabled, locked note should not be locked again when it is closed after opening", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
|
||||
await note?.contextMenu.lock(PASSWORD);
|
||||
const settings = await app.goToSettings();
|
||||
await settings.toggleKeepVaultNotesUnlocked();
|
||||
await settings.close();
|
||||
await note?.openLockedNote(PASSWORD);
|
||||
const tabs = await notes.editor.getTabs();
|
||||
await tabs[0].close();
|
||||
|
||||
await note?.click();
|
||||
|
||||
expect(await note?.isLockedNotePasswordFieldVisible()).toBe(false);
|
||||
});
|
||||
|
||||
@@ -22,6 +22,7 @@ import { showPasswordDialog } from "../dialogs/password-dialog";
|
||||
import { showToast } from "../utils/toast";
|
||||
import { VAULT_ERRORS } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useStore as useAppStore } from "../stores/app-store";
|
||||
|
||||
class Vault {
|
||||
static async createVault() {
|
||||
@@ -34,6 +35,7 @@ class Vault {
|
||||
},
|
||||
validate: async ({ password }) => {
|
||||
await db.vault.create(password);
|
||||
useAppStore.getState().setIsVaultCreated(true);
|
||||
showToast("success", strings.vaultCreated());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ function StatusBar() {
|
||||
}}
|
||||
data-test-id="vault-unlocked"
|
||||
>
|
||||
<Unlock size={10} />
|
||||
<Unlock size={12} />
|
||||
<Text variant="subBody" ml={1} sx={{ color: "paragraph" }}>
|
||||
{strings.vaultUnlocked()}
|
||||
</Text>
|
||||
|
||||
@@ -42,14 +42,29 @@ export const VaultSettings: SettingsGroup[] = [
|
||||
type: "button",
|
||||
title: strings.create(),
|
||||
action: () => {
|
||||
Vault.createVault().then((res) => {
|
||||
useAppStore.getState().setIsVaultCreated(res);
|
||||
});
|
||||
Vault.createVault();
|
||||
},
|
||||
variant: "secondary"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "keep-note-unlocked",
|
||||
title: strings.keepNoteUnlocked(),
|
||||
description: strings.keepNoteUnlockedDesc(),
|
||||
isHidden: () => !useAppStore.getState().isVaultCreated,
|
||||
onStateChange: (listener) =>
|
||||
useAppStore.subscribe((s) => s.isVaultCreated, listener),
|
||||
components: [
|
||||
{
|
||||
type: "toggle",
|
||||
isToggled: () => useAppStore.getState().keepVaultNotesUnlocked,
|
||||
toggle: () => {
|
||||
useAppStore.getState().toggleKeepVaultNotesUnlocked();
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "change-vault-password",
|
||||
title: strings.changeVaultPassword(),
|
||||
|
||||
@@ -68,6 +68,7 @@ class AppStore extends BaseStore<AppStore> {
|
||||
isListPaneVisible = true;
|
||||
isNavPaneCollapsed = false;
|
||||
isVaultCreated = false;
|
||||
keepVaultNotesUnlocked = Config.get("vault:keepNotesUnlocked", false);
|
||||
isAutoSyncEnabled = Config.get("autoSyncEnabled", true);
|
||||
isSyncEnabled = Config.get("syncEnabled", true);
|
||||
isRealtimeSyncEnabled = Config.get("isRealtimeSyncEnabled", true);
|
||||
@@ -373,6 +374,12 @@ class AppStore extends BaseStore<AppStore> {
|
||||
setNavigationTab = (tab: NavigationTabItem["id"]) => {
|
||||
this.set((state) => (state.navigationTab = tab));
|
||||
};
|
||||
|
||||
toggleKeepVaultNotesUnlocked = () => {
|
||||
const newValue = !this.get().keepVaultNotesUnlocked;
|
||||
Config.set("vault:keepNotesUnlocked", newValue);
|
||||
this.set({ keepVaultNotesUnlocked: newValue });
|
||||
};
|
||||
}
|
||||
|
||||
const [useStore, store] = createStore<AppStore>(
|
||||
|
||||
@@ -777,16 +777,37 @@ class EditorStore extends BaseStore<EditorStore> {
|
||||
options
|
||||
);
|
||||
} else if (isLocked && note.type !== "trash") {
|
||||
this.addSession(
|
||||
{
|
||||
type: "locked",
|
||||
id: sessionId,
|
||||
note,
|
||||
activeBlockId: options.activeBlockId,
|
||||
tabId
|
||||
},
|
||||
options
|
||||
);
|
||||
if (
|
||||
appStore.get().keepVaultNotesUnlocked &&
|
||||
db.vault.isNoteOpened(note.id)
|
||||
) {
|
||||
const tags = await db.notes.tags(note.id);
|
||||
const noteFromVault = await db.vault.open(note.id);
|
||||
if (noteFromVault) {
|
||||
this.addSession({
|
||||
type: note.readonly ? "readonly" : "default",
|
||||
locked: true,
|
||||
id: sessionId,
|
||||
note: noteFromVault,
|
||||
saveState: SaveState.Saved,
|
||||
sessionId: `${Date.now()}`,
|
||||
tags: tags,
|
||||
tabId: tabId,
|
||||
content: noteFromVault.content
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.addSession(
|
||||
{
|
||||
type: "locked",
|
||||
id: sessionId,
|
||||
note,
|
||||
activeBlockId: options.activeBlockId,
|
||||
tabId
|
||||
},
|
||||
options
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const content = note.contentId
|
||||
? await db.content.get(note.contentId)
|
||||
|
||||
@@ -51,6 +51,16 @@ Adding notes to private vault is useful when you do not want anyone to read your
|
||||
|
||||
To open, edit or delete a locked note, you must provide the password for the vault to unlock it.
|
||||
|
||||
## Keep note unlocked when it is opened
|
||||
|
||||
By default, when you open a locked note, it will be locked again after you close the note or lock the vault. You can change this behavior, so that the note remains unlocked even after you close it. Now the note will only be locked when the vault is locked.
|
||||
|
||||
# [Desktop/Web](#/tab/web)
|
||||
|
||||
1. Go to Settings
|
||||
2. Go to `Vault` in `Security & privacy` section
|
||||
3. Toggle `Keep note unlocked`
|
||||
|
||||
## Unlock a note permanently
|
||||
|
||||
# [Desktop/Web](#/tab/web)
|
||||
|
||||
@@ -83,6 +83,7 @@ test("lock a note", () =>
|
||||
expect(content.data.cipher).toBeDefined();
|
||||
|
||||
expect(await db.relations.from(vault, "note").has(id)).toBe(true);
|
||||
expect(db.vault.isNoteOpened(id)).toBeFalsy();
|
||||
}));
|
||||
|
||||
test("locked note is not favorited", () =>
|
||||
@@ -106,6 +107,7 @@ test("unlock a note", () =>
|
||||
expect(note.content.data).toBeDefined();
|
||||
expect(note.content.type).toBe(TEST_NOTE.content.type);
|
||||
expect(await db.relations.from(vault, "note").has(id)).toBe(true);
|
||||
expect(db.vault.isNoteOpened(id)).toBeTruthy();
|
||||
}));
|
||||
|
||||
test("unlock a note permanently", () =>
|
||||
@@ -124,6 +126,7 @@ test("unlock a note permanently", () =>
|
||||
expect(content.data).toBeDefined();
|
||||
expect(typeof content.data).toBe("string");
|
||||
expect(await db.relations.from(vault, "note").has(id)).toBe(false);
|
||||
expect(db.vault.isNoteOpened(id)).toBeFalsy();
|
||||
}));
|
||||
|
||||
test("lock an empty note", () =>
|
||||
@@ -141,6 +144,7 @@ test("lock an empty note", () =>
|
||||
expect(content.data.iv).toBeDefined();
|
||||
expect(content.data.cipher).toBeDefined();
|
||||
expect(await db.relations.from(vault, "note").has(id)).toBe(true);
|
||||
expect(db.vault.isNoteOpened(id)).toBeFalsy();
|
||||
}));
|
||||
|
||||
test("save a locked note", () =>
|
||||
@@ -154,6 +158,7 @@ test("save a locked note", () =>
|
||||
const content = await db.content.get(note.contentId);
|
||||
|
||||
expect(content.data.cipher).toBeTypeOf("string");
|
||||
expect(db.vault.isNoteOpened(id)).toBeFalsy();
|
||||
}));
|
||||
|
||||
test("save an edited locked note", () =>
|
||||
@@ -173,6 +178,7 @@ test("save an edited locked note", () =>
|
||||
expect(() => JSON.parse(content.data.cipher)).toThrow();
|
||||
expect(note.dateEdited).toBeLessThan((await db.notes.note(id)).dateEdited);
|
||||
expect(note.dateEdited).toBeLessThan(content.dateEdited);
|
||||
expect(db.vault.isNoteOpened(id)).toBeFalsy();
|
||||
}));
|
||||
|
||||
test("change vault password", () =>
|
||||
|
||||
@@ -23,6 +23,7 @@ import { EV, EVENTS } from "../common.js";
|
||||
import { isCipher } from "../utils/crypto.js";
|
||||
import { Note, NoteContent } from "../types.js";
|
||||
import { logger } from "../logger.js";
|
||||
import { addItem } from "../utils/array.js";
|
||||
|
||||
export const VAULT_ERRORS = {
|
||||
noVault: "ERR_NO_VAULT",
|
||||
@@ -35,6 +36,7 @@ export default class Vault {
|
||||
private vaultPassword?: string;
|
||||
private erasureTimeout = 0;
|
||||
private key = "svvaads1212#2123";
|
||||
private openedNotes: string[] = [];
|
||||
|
||||
private get password() {
|
||||
return this.vaultPassword;
|
||||
@@ -66,6 +68,10 @@ export default class Vault {
|
||||
return !!this.vaultPassword;
|
||||
}
|
||||
|
||||
isNoteOpened(noteId: string) {
|
||||
return this.openedNotes.includes(noteId);
|
||||
}
|
||||
|
||||
async create(password: string) {
|
||||
const vaultKey = await this.getKey();
|
||||
if (!vaultKey || !isCipher(vaultKey)) {
|
||||
@@ -80,6 +86,7 @@ export default class Vault {
|
||||
|
||||
async lock() {
|
||||
this.password = undefined;
|
||||
this.openedNotes = [];
|
||||
EV.publish(EVENTS.vaultLocked);
|
||||
return true;
|
||||
}
|
||||
@@ -202,6 +209,8 @@ export default class Vault {
|
||||
false
|
||||
);
|
||||
|
||||
addItem(this.openedNotes, noteId);
|
||||
|
||||
if (password) {
|
||||
this.password = password;
|
||||
if (!(await this.exists())) await this.create(password);
|
||||
|
||||
@@ -3510,6 +3510,14 @@ msgstr "Jump to group"
|
||||
msgid "Keep"
|
||||
msgstr "Keep"
|
||||
|
||||
#: src/strings.ts:2639
|
||||
msgid "Keep a vault note unlocked once it is opened. Note will be locked back once vault is locked."
|
||||
msgstr "Keep a vault note unlocked once it is opened. Note will be locked back once vault is locked."
|
||||
|
||||
#: src/strings.ts:2637
|
||||
msgid "Keep note unlocked"
|
||||
msgstr "Keep note unlocked"
|
||||
|
||||
#: src/strings.ts:2021
|
||||
msgid "Keep open"
|
||||
msgstr "Keep open"
|
||||
|
||||
@@ -3490,6 +3490,14 @@ msgstr ""
|
||||
msgid "Keep"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2639
|
||||
msgid "Keep a vault note unlocked once it is opened. Note will be locked back once vault is locked."
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2637
|
||||
msgid "Keep note unlocked"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2021
|
||||
msgid "Keep open"
|
||||
msgstr ""
|
||||
|
||||
@@ -2633,5 +2633,8 @@ Use this if changes from other devices are not appearing on this device. This wi
|
||||
exportCsv: () => t`Export CSV`,
|
||||
importCsv: () => t`Import CSV`,
|
||||
noContent: () => t`This note is empty`,
|
||||
deleteData: () => t`Delete data`
|
||||
deleteData: () => t`Delete data`,
|
||||
keepNoteUnlocked: () => t`Keep note unlocked`,
|
||||
keepNoteUnlockedDesc: () =>
|
||||
t`Keep a vault note unlocked once it is opened. Note will be locked back once vault is locked.`
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user