From c54e7aca8397b963395a38629b9c7ede9d4b4c9f Mon Sep 17 00:00:00 2001 From: qing <1776177662@qq.com> Date: Mon, 10 Aug 2026 10:52:30 +0000 Subject: [PATCH] =?UTF-8?q?dnfs2:=20=E7=89=B9=E6=AE=8A=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=20image=20=E7=B1=BB=E5=9E=8B=EF=BC=8C?= =?UTF-8?q?=E5=8F=91=E5=B8=83=E6=9D=83=E9=99=90=E6=94=BE=E5=AE=BD=E4=B8=BA?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E6=8B=A5=E6=9C=89=E8=80=85=E6=88=96=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dnfs2/src/dnfs2.cpp | 71 ++++++++++++++++++++++++++---------------- fsys/public/dnfs.html | 3 +- fsys/public/js/dnfs.js | 52 +++++++++++-------------------- 3 files changed, 65 insertions(+), 61 deletions(-) diff --git a/dnfs2/src/dnfs2.cpp b/dnfs2/src/dnfs2.cpp index 37f4526..6d0aa03 100644 --- a/dnfs2/src/dnfs2.cpp +++ b/dnfs2/src/dnfs2.cpp @@ -243,7 +243,7 @@ private: // 特殊节点校验 // ============================================================================ -static const std::vector kSpTypes = {"link", "js", "image", "file", "style", "theme"}; +static const std::vector kSpTypes = {"link", "js", "file", "style", "theme"}; // 识别特殊节点信封:合法信封返回 object;普通内容返回 nullptr; // 以 {"_sp" 开头但 JSON 非法视为格式错误(抛异常)。 @@ -295,14 +295,6 @@ static void validate_sp(const json::object& sp) { throw DnfsExp("前端代码不能为空", 400); if (code.size() > kSpMaxCode) throw DnfsExp("前端代码过大(上限 512KB)", 400); - } else if (t == "image") { - if (!sp.contains("data") || !sp.at("data").is_string()) - throw DnfsExp("图片节点缺少 data", 400); - std::string data = std::string(sp.at("data").as_string()); - if (data.rfind("data:image/", 0) != 0) - throw DnfsExp("图片节点 data 必须是 data:image/ 开头的 DataURL", 400); - if (data.size() > kSpMaxData) - throw DnfsExp("图片过大(上限约 2.6MB)", 400); } else if (t == "file") { if (!sp.contains("name") || !sp.at("name").is_string()) throw DnfsExp("文件节点缺少文件名", 400); @@ -652,6 +644,29 @@ private: return r.data.is_array() && !r.data.as_array().empty(); } + // 查询节点 owner:节点不存在返回 nullopt;存在但无 owner 字段返回空字符串(无人匹配,仅管理员有权) + std::optional _note_owner(int64_t id) { + json::object payload; + payload["action"] = "select"; + payload["table"] = "Notes"; + payload["where"] = json::object{{"id", id}}; + payload["limit"] = 1; + + DbResult r = _call_db(payload); + if (!r.success) { + _log("ERROR", "dnfs2", "查询节点 owner 失败 id=" + std::to_string(id) + + " err=" + r.error); + throw DnfsExp("查询节点失败", 500); + } + if (!r.data.is_array() || r.data.as_array().empty()) return std::nullopt; + const auto& note = r.data.as_array()[0]; + if (note.is_object() && note.as_object().contains("owner") + && note.as_object().at("owner").is_string()) { + return std::string(note.as_object().at("owner").as_string()); + } + return std::string(); + } + // ---- Token 验签(通过 gateway /whoami)--------------------------------- struct UserInfo { @@ -909,16 +924,21 @@ private: throw DnfsExp("未授权访问", 401); } - // 父节点是否存在 - if (pid != 0 && !_note_exists(pid)) { - throw DnfsExp("父节点不存在", 400); + // 父节点存在性 + 拥有者(特殊节点发布权限判定用) + std::optional parent_owner; + if (pid != 0) { + parent_owner = _note_owner(pid); + if (!parent_owner) { + throw DnfsExp("父节点不存在", 400); + } } - // 特殊节点校验(管理员专属) + // 特殊节点校验:父节点拥有者或管理员可发布(根层 pid=0 无拥有者,仅管理员) json::value sp = parse_sp(content); if (!sp.is_null()) { - if (!info->is_admin) { - throw DnfsExp("特殊节点仅管理员可发布", 403); + if (!info->is_admin + && !(parent_owner && *parent_owner == info->user)) { + throw DnfsExp("特殊节点仅当前节点拥有者或管理员可发布", 403); } validate_sp(sp.as_object()); } @@ -1103,30 +1123,29 @@ private: throw DnfsExp("节点不存在", 404); } - if (!info->is_admin) { + // 提取节点 owner(所有权校验与特殊节点发布判定共用) + std::string note_owner; + { const auto& note = owner_r.data.as_array()[0]; - std::string owner; if (note.is_object() && note.as_object().contains("owner") && note.as_object().at("owner").is_string()) { - owner = std::string(note.as_object().at("owner").as_string()); - } - if (owner != info->user) { - _log("WARNING", "dnfs2", "update_note 所有权拒绝 id=" + std::to_string(id)); - throw DnfsExp("It's not your note", 403); + note_owner = std::string(note.as_object().at("owner").as_string()); } } + if (!info->is_admin && note_owner != info->user) { + _log("WARNING", "dnfs2", "update_note 所有权拒绝 id=" + std::to_string(id)); + throw DnfsExp("It's not your note", 403); + } + // P1-8 修复:pid≠0 时校验父节点存在 if (pid != 0 && !_note_exists(pid)) { throw DnfsExp("父节点不存在", 400); } - // 特殊节点校验 + // 特殊节点校验:上方所有权校验已保证是节点拥有者或管理员,此处仅校验信封格式 json::value sp = parse_sp(content); if (!sp.is_null()) { - if (!info->is_admin) { - throw DnfsExp("特殊节点仅管理员可发布", 403); - } validate_sp(sp.as_object()); } diff --git a/fsys/public/dnfs.html b/fsys/public/dnfs.html index 75927e2..37d7a9f 100644 --- a/fsys/public/dnfs.html +++ b/fsys/public/dnfs.html @@ -26,14 +26,13 @@

节点操作

- +