From b5c652b8211adbf12dc0103b0df458392302e237 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Wed, 11 Feb 2026 21:14:58 +0800 Subject: [PATCH] :recycle: https://github.com/siyuan-note/siyuan/pull/17007 --- app/src/plugin/index.ts | 33 ++++----------------------------- app/src/util/pathName.ts | 11 ++++------- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/app/src/plugin/index.ts b/app/src/plugin/index.ts index d63c25c27..4b4676d76 100644 --- a/app/src/plugin/index.ts +++ b/app/src/plugin/index.ts @@ -260,20 +260,12 @@ export class Plugin { } public loadData(storageName: string): Promise { - const safePath = normalizeStoragePath(storageName); - if (safePath === null) { - return Promise.reject({ - code: 403, - msg: `For plugin [${this.name}], storage path [${storageName}] is invalid: empty or path traversal not allowed.`, - data: null - } as IWebSocketData); - } if (typeof this.data[storageName] === "undefined") { this.data[storageName] = ""; } return new Promise((resolve) => { fetchPost("/api/file/getFile", { - path: `/data/storage/petal/${this.name}/${safePath}` + path: `/data/storage/petal/${this.name}/${normalizeStoragePath(storageName)}` }, (response) => { this.data[storageName] = response; resolve(this.data[storageName]); @@ -291,19 +283,11 @@ export class Plugin { data: null }); } - const safePath = normalizeStoragePath(storageName); - if (safePath === null) { - return Promise.reject({ - code: 403, - msg: `For plugin [${this.name}], storage path [${storageName}] is invalid: empty or path traversal not allowed.`, - data: null - } as IWebSocketData); - } return new Promise((resolve, reject) => { - const pathString = `/data/storage/petal/${this.name}/${safePath}`; + const pathString = `/data/storage/petal/${this.name}/${normalizeStoragePath(storageName)}`; let file: File; try { - const fileName = safePath.split("/").pop(); + const fileName = pathString.split("/").pop(); if (typeof data === "object") { file = new File([new Blob([JSON.stringify(data)], { type: "application/json" @@ -338,20 +322,11 @@ export class Plugin { data: null } as IWebSocketData); } - const safePath = normalizeStoragePath(storageName); - if (safePath === null) { - return Promise.reject({ - code: 403, - msg: `For plugin [${this.name}], storage path [${storageName}] is invalid: empty or path traversal not allowed.`, - data: null - } as IWebSocketData); - } - return new Promise((resolve) => { if (!this.data) { this.data = {}; } - fetchPost("/api/file/removeFile", {path: `/data/storage/petal/${this.name}/${safePath}`}, (response) => { + fetchPost("/api/file/removeFile", {path: `/data/storage/petal/${this.name}/${normalizeStoragePath(storageName)}`}, (response) => { delete this.data[storageName]; resolve(response); }); diff --git a/app/src/util/pathName.ts b/app/src/util/pathName.ts index 7471ffb6f..12e9658b7 100644 --- a/app/src/util/pathName.ts +++ b/app/src/util/pathName.ts @@ -719,22 +719,19 @@ export const setNoteBook = (cb?: (notebook: INotebook[]) => void, flashcard = fa /** * 规范化并校验相对路径:允许子目录,但禁止通过 ".." 穿越到根外。 * 用于插件存储,确保路径不逃出指定根目录。 - * @returns 规范化后的相对路径(使用 /),若路径非法则返回 null + * @returns 规范化后的相对路径(使用 /),若路径非法则返回替换后的合法路径 */ export const normalizeStoragePath = (storageName: string): string | null => { - const normalized = storageName.replace(/\\/g, "/"); - const parts = normalized.split("/").filter(Boolean); + const parts = storageName.replace(/\\/g, "/").split("/"); const resolved: string[] = []; for (const part of parts) { if (part === "..") { if (resolved.length > 0) { resolved.pop(); - } else { - return null; } - } else if (part !== ".") { + } else if (part && part !== ".") { resolved.push(part); } } - return resolved.length > 0 ? resolved.join("/") : null; + return resolved.length > 0 ? resolved.join("/") : storageName.replace(/[\/\\]+/g, ""); };