vault backup: 2026-09-28 07:57:07

This commit is contained in:
CrazyJasonwell
2026-09-28 07:57:09 +08:00
parent 69f2d43baf
commit 25d3bdda0a
173 changed files with 24012 additions and 190181 deletions
+1 -1
View File
@@ -10,6 +10,6 @@
"autoLockInterval": 0,
"pwdHintQuestion": "",
"isLastVerifyPasswordCorrect": false,
"timeOnUnload": "2026-01-13T06:43:44.115Z",
"timeOnUnload": "2026-09-21T02:29:36.398Z",
"forbidClosePassVerifyModal": false
}
+250 -11
View File
@@ -528,6 +528,8 @@ var en_default = {
setting_pwd_hint_question_name: "Password prompt",
setting_pwd_hint_question_desc: "Please type a question to help you remember your password.",
place_holder_enter_pwd_hint_question: "Password prompt question",
setting_verify_password_blur_name: "Password modal background blur",
setting_verify_password_blur_desc: "Background blur applied when the password verification modal opens. Unit: px.",
setting_more_path: "More folders or files to be protected (up to 6)",
setting_add_path: "Add protected path",
setting_add_path_name: "Protected path",
@@ -569,6 +571,8 @@ var es_default = {
setting_pwd_hint_question_name: "Mensaje para recordar",
setting_pwd_hint_question_desc: "Escribe una frase para ayudarte recordar la contrase\xF1a.",
place_holder_enter_pwd_hint_question: "Mensaje para recordar",
setting_verify_password_blur_name: "Desenfoque del modal de contrase\xF1a",
setting_verify_password_blur_desc: "Desenfoque aplicado al fondo cuando se abre el modal de verificaci\xF3n de contrase\xF1a. Unidad: px.",
setting_more_path: "M\xE1s carpetas o archivos a proteger (hasta 6)",
setting_add_path: "A\xF1adir ruta protegida",
setting_add_path_name: "Ruta protegida",
@@ -609,6 +613,8 @@ var zh_cn_default = {
setting_pwd_hint_question_name: "\u5BC6\u7801\u63D0\u793A\u95EE\u9898",
setting_pwd_hint_question_desc: "\u5F53\u4F60\u5FD8\u8BB0\u5BC6\u7801\u65F6\uFF0C\u53EF\u4EE5\u901A\u8FC7\u8FD9\u4E2A\u95EE\u9898\u6765\u63D0\u793A\u4F60\u7684\u5BC6\u7801.",
place_holder_enter_pwd_hint_question: "\u8F93\u5165\u5BC6\u7801\u63D0\u793A\u95EE\u9898",
setting_verify_password_blur_name: "\u5BC6\u7801\u9A8C\u8BC1\u6846\u80CC\u666F\u6A21\u7CCA",
setting_verify_password_blur_desc: "\u5BC6\u7801\u9A8C\u8BC1\u6846\u5F39\u51FA\u65F6\u80CC\u666F\u7684\u6A21\u7CCA\u7A0B\u5EA6\uFF0C\u5355\u4F4D\uFF1Apx\u3002",
setting_more_path: "\u66F4\u591A\u9700\u8981\u4FDD\u62A4\u7684\u6587\u4EF6\u5939\u6216\u6587\u4EF6(\u6700\u591A6\u4E2A)",
setting_add_path: "\u6DFB\u52A0\u4FDD\u62A4\u8DEF\u5F84",
setting_add_path_name: "\u4FDD\u62A4\u8DEF\u5F84",
@@ -649,6 +655,8 @@ var zh_tw_default = {
setting_pwd_hint_question_name: "\u5BC6\u78BC\u63D0\u793A\u554F\u984C",
setting_pwd_hint_question_desc: "\u7576\u4F60\u5FD8\u8A18\u5BC6\u78BC\u6642\uFF0C\u53EF\u4EE5\u901A\u904E\u9019\u500B\u554F\u984C\u4F86\u63D0\u793A\u4F60\u7684\u5BC6\u78BC.",
place_holder_enter_pwd_hint_question: "\u8F38\u5165\u5BC6\u78BC\u63D0\u793A\u554F\u984C",
setting_verify_password_blur_name: "\u5BC6\u78BC\u9A57\u8B49\u6846\u80CC\u666F\u6A21\u7CCA",
setting_verify_password_blur_desc: "\u5BC6\u78BC\u9A57\u8B49\u6846\u5F48\u51FA\u6642\u80CC\u666F\u7684\u6A21\u7CCA\u7A0B\u5EA6\uFF0C\u55AE\u4F4D\uFF1Apx\u3002",
setting_more_path: "\u66F4\u591A\u9700\u8981\u4FDD\u8B77\u7684\u6587\u4EF6\u593E\u6216\u6587\u4EF6(\u6700\u591A6\u500B)",
setting_add_path: "\u6DFB\u52A0\u4FDD\u8B77\u8DEF\u5F91",
setting_add_path_name: "\u4FDD\u8B77\u8DEF\u5F91",
@@ -707,6 +715,7 @@ var DEFAULT_SETTINGS = {
lang: "auto",
autoLockInterval: 0,
pwdHintQuestion: "",
verifyPasswordBlurPx: 8,
isLastVerifyPasswordCorrect: false,
timeOnUnload: 0
};
@@ -717,6 +726,8 @@ var PasswordPlugin = class extends import_obsidian2.Plugin {
this.isVerifyPasswordCorrect = false;
this.isAutoLockRegistered = false;
this.lastUnlockOrOpenFileTime = null;
this.onceActionTimeoutId = null;
this.fileExplorerProtectionRegistered = false;
this.t = (x, vars) => {
return this.i18n.t(x, vars);
};
@@ -765,14 +776,13 @@ var PasswordPlugin = class extends import_obsidian2.Plugin {
});
this.addSettingTab(new PasswordSettingTab(this.app, this));
this.app.workspace.onLayoutReady(() => {
if (this.settings.protectEnabled && this.isIncludeRootPath()) {
if (!this.isVerifyPasswordCorrect) {
let curTime = (0, import_obsidian2.moment)();
if (curTime.diff(this.settings.timeOnUnload, "second") <= 2 && this.settings.isLastVerifyPasswordCorrect) {
this.isVerifyPasswordCorrect = true;
} else {
this.verifyPasswordProtection(false);
}
this.registerFileExplorerProtection();
if (this.settings.protectEnabled && !this.isVerifyPasswordCorrect && this.isIncludeRootPath()) {
let curTime = (0, import_obsidian2.moment)();
if (curTime.diff(this.settings.timeOnUnload, "second") <= 2 && this.settings.isLastVerifyPasswordCorrect) {
this.isVerifyPasswordCorrect = true;
} else {
this.verifyPasswordProtection(false);
}
}
});
@@ -790,7 +800,7 @@ var PasswordPlugin = class extends import_obsidian2.Plugin {
this.registerEvent(this.app.workspace.on("active-leaf-change", (leaf) => {
if (leaf != null && leaf.view != null) {
let viewType = leaf.view.getViewType();
if (viewType == "search") {
if (this.isPasswordProtectedView(viewType)) {
this.autoLockCheck();
if (this.settings.protectEnabled && !this.isVerifyPasswordCorrect) {
this.verifyPasswordProtection(true);
@@ -804,8 +814,10 @@ var PasswordPlugin = class extends import_obsidian2.Plugin {
this.app.vault.on("rename", this.handleRename);
this.app.vault.on("modify", this.handleFileModify);
this.registerAutoLock();
this.registerOnceAction();
}
async onunload() {
this.unregisterOnceAction();
this.app.vault.off("modify", this.handleFileModify);
this.app.vault.off("rename", this.handleRename);
this.settings.isLastVerifyPasswordCorrect = this.isVerifyPasswordCorrect;
@@ -831,6 +843,216 @@ var PasswordPlugin = class extends import_obsidian2.Plugin {
}
}
}
registerOnceAction() {
if (this.onceActionTimeoutId != null) {
return;
}
this.onceActionTimeoutId = window.setTimeout(() => this.onceAction(), 1 * 1e3);
}
onceAction() {
this.unregisterOnceAction();
this.collapseAllProtectedFolders();
}
unregisterOnceAction() {
if (this.onceActionTimeoutId == null) {
return;
}
window.clearTimeout(this.onceActionTimeoutId);
this.onceActionTimeoutId = null;
}
// Check if the workspace view exposing protected note metadata is a password protected view, such as search or file-explorer.
isPasswordProtectedView(viewType) {
return viewType == "search" || viewType == "bookmarks";
}
// Check if any workspace view exposing protected note metadata is opened, such as search or file-explorer.
isPasswordProtectedViewOpened() {
let isOpened = false;
this.app.workspace.iterateAllLeaves((leaf) => {
if (leaf.view != null && this.isPasswordProtectedView(leaf.view.getViewType())) {
isOpened = true;
}
});
return isOpened;
}
// Register capture-phase handlers on the file explorer so protected folders can be checked before Obsidian expands them.
registerFileExplorerProtection() {
if (this.fileExplorerProtectionRegistered) {
return;
}
this.fileExplorerProtectionRegistered = true;
const captureOptions = { capture: true, passive: false };
this.registerDomEvent(window, "pointerdown", (event) => {
this.handleFileExplorerFolderExpand(event);
}, captureOptions);
this.registerDomEvent(window, "touchstart", (event) => {
this.handleFileExplorerFolderExpand(event);
}, captureOptions);
this.registerDomEvent(window, "keydown", (event) => {
this.handleFileExplorerFolderExpand(event);
}, captureOptions);
}
// Stop attempts to expand a protected folder until the password has been verified.
handleFileExplorerFolderExpand(event) {
if (!this.settings.protectEnabled || this.isVerifyPasswordCorrect || this.isVerifyPasswordWaitting) {
return;
}
console.log(`handleFileExplorerFolderExpand: event type: ${event.type}, key: ${event instanceof KeyboardEvent ? event.key : "N/A"}`);
if (event instanceof KeyboardEvent && event.key != "Enter" && event.key != " " && event.key != "Spacebar" && event.key != "ArrowRight") {
return;
}
const item = this.getFileExplorerFolderItemFromEvent(event);
if (item == null || item.file == null || !(item.file instanceof import_obsidian2.TFolder)) {
return;
}
if (!this.isFileExplorerItemCollapsed(item)) {
return;
}
if (!this.isProtectedFile(item.file.path)) {
return;
}
event.preventDefault();
event.stopImmediatePropagation();
this.verifyPasswordBeforeAction(() => {
this.expandFileExplorerFolder(item);
});
}
// Map a click or keyboard event in the file explorer DOM back to Obsidian's internal folder item.
getFileExplorerFolderItemFromEvent(event) {
let matchedItem = null;
this.app.workspace.iterateAllLeaves((leaf) => {
if (matchedItem != null || leaf.view == null || leaf.view.getViewType() != "file-explorer") {
return;
}
const fileExplorerView = leaf.view;
const item = this.getFileExplorerFolderItemFromEventInView(event, fileExplorerView);
if (item != null) {
matchedItem = item;
}
});
return matchedItem;
}
getFileExplorerFolderItemFromEventInView(event, fileExplorerView) {
var _a;
const folderTitleEl = this.getFocusedFileExplorerFolderTitleEl(event, fileExplorerView);
if (folderTitleEl == null || fileExplorerView.fileItems == null || !fileExplorerView.containerEl.contains(folderTitleEl)) {
return null;
}
const path = folderTitleEl.getAttribute("data-path");
if (path != null) {
const item = fileExplorerView.fileItems[path];
if ((item == null ? void 0 : item.file) instanceof import_obsidian2.TFolder) {
return item;
}
}
const folderEl = folderTitleEl.closest(".nav-folder");
for (const fileItem of Object.values(fileExplorerView.fileItems)) {
if (fileItem.file instanceof import_obsidian2.TFolder && (fileItem.titleEl == folderTitleEl || ((_a = fileItem.titleEl) == null ? void 0 : _a.contains(folderTitleEl)) || fileItem.selfEl == folderEl)) {
return fileItem;
}
}
return null;
}
getFocusedFileExplorerFolderTitleEl(event, fileExplorerView) {
var _a, _b;
const candidates = [];
const uiEvent = event;
const eventDoc = (_a = uiEvent.doc) != null ? _a : document;
const pushCandidate = (value) => {
if (value != null && typeof value === "object" && "instanceOf" in value) {
candidates.push(value);
}
};
pushCandidate(event.target);
pushCandidate(uiEvent.targetNode);
pushCandidate(eventDoc.activeElement);
const activeDescendantId = (_b = eventDoc.activeElement) == null ? void 0 : _b.getAttribute("aria-activedescendant");
if (activeDescendantId != null) {
pushCandidate(eventDoc.getElementById(activeDescendantId));
}
for (const value of event.composedPath()) {
pushCandidate(value);
}
pushCandidate(fileExplorerView.containerEl.querySelector(".nav-folder-title.is-active, .tree-item-self.is-active"));
for (const candidate of candidates) {
const folderTitleEl = this.getFolderTitleElFromNode(candidate);
if (folderTitleEl != null) {
return folderTitleEl;
}
}
return null;
}
getFolderTitleElFromNode(node) {
if (node == null || !node.instanceOf(Element)) {
return null;
}
const element = node;
if (element.hasClass("nav-folder-title") || element.hasClass("tree-item-self") || element.hasAttribute("data-path")) {
return element;
}
const folderTitleEl = element.matchParent(".nav-folder-title, .tree-item-self, [data-path]");
if (folderTitleEl != null && folderTitleEl.instanceOf(HTMLElement)) {
return folderTitleEl;
}
return null;
}
// Prefer Obsidian's internal state, then fall back to the rendered DOM class.
isFileExplorerItemCollapsed(item) {
var _a, _b, _c;
if (typeof item.collapsed == "boolean") {
return item.collapsed;
}
if (typeof item.isCollapsed == "boolean") {
return item.isCollapsed;
}
const folderEl = (_c = (_a = item.selfEl) == null ? void 0 : _a.closest(".nav-folder")) != null ? _c : (_b = item.titleEl) == null ? void 0 : _b.closest(".nav-folder");
const isCollapsed = folderEl == null ? void 0 : folderEl.classList.contains("is-collapsed");
return isCollapsed != null ? isCollapsed : false;
}
// Run an action only after a password modal completes successfully.
verifyPasswordBeforeAction(onVerified) {
if (!this.isVerifyPasswordWaitting) {
const setModal = new VerifyPasswordModal(this.app, this, false, () => {
if (this.isVerifyPasswordCorrect) {
onVerified();
}
}).open();
}
}
// Expand a folder through Obsidian's internal method, falling back to a title click for compatibility.
expandFileExplorerFolder(item) {
var _a;
if (item.setCollapsed != null) {
item.setCollapsed.call(item, false);
return;
}
(_a = item.titleEl) == null ? void 0 : _a.click();
}
// Hide restored expanded protected folders before the user has verified the password.
collapseProtectedFileExplorerFolders(fileExplorerView) {
var _a;
if (!this.settings.protectEnabled || this.isVerifyPasswordCorrect || fileExplorerView.fileItems == null) {
return;
}
for (const fileItem of Object.values(fileExplorerView.fileItems)) {
if (!this.isFileExplorerItemCollapsed(fileItem)) {
if (fileItem.file instanceof import_obsidian2.TFolder && this.isProtectedFile(fileItem.file.path)) {
if (fileItem.setCollapsed != null) {
fileItem.setCollapsed.call(fileItem, true);
} else {
(_a = fileItem.titleEl) == null ? void 0 : _a.click();
}
}
}
}
}
collapseAllProtectedFolders() {
this.app.workspace.iterateAllLeaves((leaf) => {
if (leaf.view != null && leaf.view.getViewType() == "file-explorer") {
const fileExplorerView = leaf.view;
this.collapseProtectedFileExplorerFolders(fileExplorerView);
}
});
}
// check if the file opened need to be protected.
isProtectFileOpened() {
let leaves = [];
@@ -871,6 +1093,7 @@ var PasswordPlugin = class extends import_obsidian2.Plugin {
if (this.isVerifyPasswordCorrect) {
this.isVerifyPasswordCorrect = false;
this.closeLeaves();
this.collapseAllProtectedFolders();
}
}
}
@@ -893,6 +1116,7 @@ var PasswordPlugin = class extends import_obsidian2.Plugin {
new import_obsidian2.Notice(this.t("password_protection_closed"));
} else {
this.closeLeaves();
this.collapseAllProtectedFolders();
}
}).open();
}
@@ -1048,6 +1272,7 @@ var PasswordSettingTab = class extends import_obsidian2.PluginSettingTab {
this.plugin.saveSettings();
this.plugin.closeLeaves();
this.plugin.registerAutoLock();
this.plugin.collapseAllProtectedFolders();
}
this.display();
}).open();
@@ -1080,6 +1305,16 @@ var PasswordSettingTab = class extends import_obsidian2.PluginSettingTab {
}
this.plugin.settings.pwdHintQuestion = value;
})).setDisabled(this.plugin.settings.protectEnabled);
new import_obsidian2.Setting(containerEl).setName(this.plugin.t("setting_verify_password_blur_name")).setDesc(this.plugin.t("setting_verify_password_blur_desc")).addText((text) => text.setPlaceholder("8").setValue(this.plugin.settings.verifyPasswordBlurPx.toString()).onChange(async (value) => {
value = value.replace(/[^0-9]/g, "");
if (!value) {
return;
}
const blurPx = parseInt(value);
if (blurPx != null && blurPx >= 0) {
this.plugin.settings.verifyPasswordBlurPx = blurPx;
}
})).setDisabled(this.plugin.settings.protectEnabled);
new import_obsidian2.Setting(containerEl).setName(this.plugin.t("setting_folder_name")).setDesc(this.plugin.t("setting_folder_desc")).addText((text) => text.setPlaceholder(this.plugin.t("place_holder_enter_path")).setValue(this.plugin.settings.protectedPath).onChange(async (value) => {
let path = value.trim();
if (path == "") {
@@ -1233,13 +1468,17 @@ var VerifyPasswordModal = class extends import_obsidian2.Modal {
onOpen() {
if (this.forbidCloseModal) {
const { modalEl } = this;
const closeButton = modalEl.getElementsByClassName("modal-close-button")[0];
let closeButton = modalEl.getElementsByClassName("modal-close-button")[0];
if (closeButton == null) {
closeButton = modalEl.getElementsByClassName("modal-header-button")[0];
}
if (closeButton != null) {
closeButton.setAttribute("style", "display: none;");
}
}
const blurPx = this.plugin.settings.verifyPasswordBlurPx;
Object.assign(this.app.workspace.containerEl.style, {
filter: "blur(8px)"
filter: `blur(${blurPx}px)`
});
const { contentEl } = this;
contentEl.empty();
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "password-protection",
"name": "Password Protection",
"version": "1.1.33",
"version": "1.1.34",
"minAppVersion": "0.15.0",
"description": "Lock and protect your private notes and diary with a password, no encrypt, no decrypt.",
"author": "Qing Li",