From 09f0fce4f42629e10e7e6b1ae5bcffaa4af6d87a Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 16 Jun 2025 11:43:09 +0800 Subject: [PATCH 1/7] :art: Database gallery view https://github.com/siyuan-note/siyuan/issues/10414 --- kernel/model/attribute_view.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index e8ad1b471..35f8f3935 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -45,7 +45,7 @@ import ( ) func (tx *Transaction) doSetAttrViewBlockView(operation *Operation) (ret *TxErr) { - err := SetDatabaseBlockView(operation.BlockID, operation.ID, operation.AvID) + err := SetDatabaseBlockView(operation.BlockID, operation.AvID, operation.ID) if err != nil { return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()} } From 95ae34c7b11574d7cf7d34fdeaba512e69410eeb Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 16 Jun 2025 17:01:22 +0800 Subject: [PATCH 2/7] :lock: XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 --- kernel/api/system.go | 1 + kernel/model/import.go | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/kernel/api/system.go b/kernel/api/system.go index 79fb64e65..80c4b9748 100644 --- a/kernel/api/system.go +++ b/kernel/api/system.go @@ -173,6 +173,7 @@ func getEmojiConf(c *gin.Context) { if !util.IsValidUploadFileName(html.UnescapeString(name)) { // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 logging.LogWarnf("invalid custom emoji name [%s]", name) + continue } if customEmoji.IsDir() { diff --git a/kernel/model/import.go b/kernel/model/import.go index 96ecbe1be..c53cea4bd 100644 --- a/kernel/model/import.go +++ b/kernel/model/import.go @@ -22,7 +22,6 @@ import ( "encoding/json" "errors" "fmt" - util2 "github.com/88250/lute/util" "image" "image/jpeg" "image/png" @@ -44,6 +43,7 @@ import ( "github.com/88250/lute/html/atom" "github.com/88250/lute/parse" "github.com/88250/lute/render" + util2 "github.com/88250/lute/util" "github.com/siyuan-note/filelock" "github.com/siyuan-note/logging" "github.com/siyuan-note/riff" @@ -557,6 +557,17 @@ func ImportSY(zipPath, boxID, toPath string) (err error) { } // 将包含的自定义表情统一移动到 data/emojis/ 下 + filelock.Walk(filepath.Join(unzipRootPath, "emojis"), func(path string, d fs.DirEntry, err error) error { + if !util.IsValidUploadFileName(d.Name()) { + // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 + logging.LogErrorf("remove invalid file [%s] in emojis", path) + if removeErr := os.Remove(path); nil != removeErr { + logging.LogErrorf("remove invalid file [%s] failed: %s", path, removeErr) + return nil + } + } + return nil + }) var emojiDirs []string filelock.Walk(unzipRootPath, func(path string, d fs.DirEntry, err error) error { if strings.Contains(path, "emojis") && d.IsDir() { From 8eb37bd735918454e9d259ddd5de79d6f7829342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E8=80=81=E5=B1=81?= Date: Mon, 16 Jun 2025 17:22:59 +0800 Subject: [PATCH 3/7] :memo: Update README_zh_CN.md (#15039) Add XP Panel Deployment Method Co-authored-by: guoweiqiang <453122747@qq.com> --- README_zh_CN.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README_zh_CN.md b/README_zh_CN.md index ece108df9..8a7cfe6bb 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -45,6 +45,7 @@ * [Docker 部署](#docker-部署) * [Unraid 部署](#unraid-部署) * [宝塔面板 部署](#宝塔面板部署) + * [小皮面板 部署](#小皮面板部署) * [内部预览版](#内部预览版) * [🏘️ 社区](#️-社区) * [🛠️ 开发指南](#️-开发指南) @@ -338,6 +339,29 @@ Publish parameters: --accessAuthCode=******(访问授权码) +### 小皮面板部署 + +
+小皮面板 部署文档 + +#### 前提 + +* 需要安装小皮面板,前往[小皮面板](https://www.xp.cn/download),选择对应的脚本执行安装 + +#### 部署 + +1. 登录小皮面板后,点击左侧菜单的 **Docker** +2. 首次打开会提示安装 Docker,点击 **点击安装 Docker** +3. 按照提示安装 Docker +4. 点击 **应用商店**,找到 **思源笔记**,点击 **安装** -> **立即安装** +5. 等待安装结束后,可在 **任务队列** 界面的 **已结束** 中点击 **详情** 查看安装信息 + +#### 访问思源笔记 + +* 在浏览器输入 `http://<小皮面板机器IP>:6806` 访问 + +
+ ### 内部预览版 我们会在有重大更新前发布内部预览版,请访问 [https://github.com/siyuan-note/insider](https://github.com/siyuan-note/insider)。 From 218bbe2000a26538bdb847a42d6adce8ad506f8b Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 16 Jun 2025 21:07:45 +0800 Subject: [PATCH 4/7] :art: Database gallery view https://github.com/siyuan-note/siyuan/issues/10414 --- kernel/api/av.go | 35 +++++++++++++++++++++++++++++++--- kernel/api/router.go | 1 + kernel/model/attribute_view.go | 10 +++++----- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/kernel/api/av.go b/kernel/api/av.go index 59e757597..c7e24dfd4 100644 --- a/kernel/api/av.go +++ b/kernel/api/av.go @@ -27,6 +27,29 @@ import ( "github.com/siyuan-note/siyuan/kernel/util" ) +func changeAttrViewLayout(c *gin.Context) { + ret := gulu.Ret.NewResult() + arg, ok := util.JsonArg(c, ret) + if !ok { + c.JSON(http.StatusOK, ret) + return + } + + blockID := arg["blockID"].(string) + avID := arg["avID"].(string) + layoutType := arg["layoutType"].(av.LayoutType) + err := model.ChangeAttrViewLayout(blockID, avID, layoutType) + if err != nil { + ret.Code = -1 + ret.Msg = err.Error() + c.JSON(http.StatusOK, ret) + return + } + + ret = renderAttrView(avID, "", "", 1, -1) + c.JSON(http.StatusOK, ret) +} + func duplicateAttributeViewBlock(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) @@ -532,10 +555,9 @@ func renderHistoryAttributeView(c *gin.Context) { func renderAttributeView(c *gin.Context) { ret := gulu.Ret.NewResult() - defer c.JSON(http.StatusOK, ret) - arg, ok := util.JsonArg(c, ret) if !ok { + c.JSON(http.StatusOK, ret) return } @@ -563,7 +585,13 @@ func renderAttributeView(c *gin.Context) { query = queryArg.(string) } - view, attrView, err := model.RenderAttributeView(id, viewID, query, page, pageSize) + ret = renderAttrView(id, viewID, query, page, pageSize) + c.JSON(http.StatusOK, ret) +} + +func renderAttrView(avID, viewID, query string, page, pageSize int) (ret *gulu.Result) { + ret = gulu.Ret.NewResult() + view, attrView, err := model.RenderAttributeView(avID, viewID, query, page, pageSize) if err != nil { ret.Code = -1 ret.Msg = err.Error() @@ -602,6 +630,7 @@ func renderAttributeView(c *gin.Context) { "view": view, "isMirror": av.IsMirror(attrView.ID), } + return } func getCurrentAttrViewImages(c *gin.Context) { diff --git a/kernel/api/router.go b/kernel/api/router.go index dc0c7fa5f..0c3d8f0dd 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -455,6 +455,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/av/duplicateAttributeViewBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, duplicateAttributeViewBlock) ginServer.Handle("POST", "/api/av/appendAttributeViewDetachedBlocksWithValues", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, appendAttributeViewDetachedBlocksWithValues) ginServer.Handle("POST", "/api/av/getCurrentAttrViewImages", model.CheckAuth, getCurrentAttrViewImages) + ginServer.Handle("POST", "/api/av/changeAttrViewLayout", model.CheckAuth, changeAttrViewLayout) ginServer.Handle("POST", "/api/ai/chatGPT", model.CheckAuth, model.CheckAdminRole, chatGPT) ginServer.Handle("POST", "/api/ai/chatGPTWithAction", model.CheckAuth, model.CheckAdminRole, chatGPTWithAction) diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 35f8f3935..d92571d6f 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -53,25 +53,25 @@ func (tx *Transaction) doSetAttrViewBlockView(operation *Operation) (ret *TxErr) } func (tx *Transaction) doChangeAttrViewLayout(operation *Operation) (ret *TxErr) { - err := changeAttrViewLayout(operation) + err := ChangeAttrViewLayout(operation.BlockID, operation.AvID, operation.Layout) if err != nil { return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()} } return } -func changeAttrViewLayout(operation *Operation) (err error) { - attrView, err := av.ParseAttributeView(operation.AvID) +func ChangeAttrViewLayout(blockID, avID string, layout av.LayoutType) (err error) { + attrView, err := av.ParseAttributeView(avID) if err != nil { return } - view, err := getAttrViewViewByBlockID(attrView, operation.BlockID) + view, err := getAttrViewViewByBlockID(attrView, blockID) if err != nil { return } - newLayout := operation.Layout + newLayout := layout if newLayout == view.LayoutType { return } From 724cddf7cb078d04246033d5f7da04d0e4e81d56 Mon Sep 17 00:00:00 2001 From: syr1ne <167830358+syr1ne@users.noreply.github.com> Date: Mon, 16 Jun 2025 19:49:15 +0530 Subject: [PATCH 5/7] :lock: emoji xss fix (#15041) --- kernel/api/system.go | 14 ++++++++++++-- kernel/model/import.go | 10 ++++++---- kernel/util/file.go | 1 + 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/kernel/api/system.go b/kernel/api/system.go index 80c4b9748..955066675 100644 --- a/kernel/api/system.go +++ b/kernel/api/system.go @@ -171,9 +171,14 @@ func getEmojiConf(c *gin.Context) { } if !util.IsValidUploadFileName(html.UnescapeString(name)) { + emojiFullName := customConfDir + "/" + name + fullPathFilteredName := customConfDir + "/" + util.FilterUploadFileName(name) // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 logging.LogWarnf("invalid custom emoji name [%s]", name) - continue + logging.LogErrorf("renaming invalid file to [%s] in emojis", fullPathFilteredName) + if removeErr := os.Rename(emojiFullName, fullPathFilteredName); nil != removeErr { + logging.LogErrorf("renaming invalid file to [%s] failed: %s", fullPathFilteredName, removeErr) + } } if customEmoji.IsDir() { @@ -195,9 +200,14 @@ func getEmojiConf(c *gin.Context) { } if !util.IsValidUploadFileName(html.UnescapeString(name)) { + emojiFullName := customConfDir + "/" + name + fullPathFilteredName := customConfDir + "/" + util.FilterUploadFileName(name) // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 logging.LogWarnf("invalid custom emoji name [%s]", name) - continue + logging.LogErrorf("renaming invalid file to [%s] in emojis", fullPathFilteredName) + if removeErr := os.Rename(emojiFullName, fullPathFilteredName); nil != removeErr { + logging.LogErrorf("renaming invalid file to [%s] failed: %s", fullPathFilteredName, removeErr) + } } addCustomEmoji(customEmoji.Name()+"/"+name, &items) diff --git a/kernel/model/import.go b/kernel/model/import.go index c53cea4bd..51af0b4da 100644 --- a/kernel/model/import.go +++ b/kernel/model/import.go @@ -559,11 +559,13 @@ func ImportSY(zipPath, boxID, toPath string) (err error) { // 将包含的自定义表情统一移动到 data/emojis/ 下 filelock.Walk(filepath.Join(unzipRootPath, "emojis"), func(path string, d fs.DirEntry, err error) error { if !util.IsValidUploadFileName(d.Name()) { + emojiFullName := unzipRootPath + "emojis/" + name + fullPathFilteredName := unzipRootPath + "emojis/" + util.FilterUploadFileName(name) // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 - logging.LogErrorf("remove invalid file [%s] in emojis", path) - if removeErr := os.Remove(path); nil != removeErr { - logging.LogErrorf("remove invalid file [%s] failed: %s", path, removeErr) - return nil + logging.LogWarnf("invalid custom emoji name [%s]", name) + logging.LogErrorf("renaming invalid file to [%s] in emojis", fullPathFilteredName) + if removeErr := os.Rename(emojiFullName, fullPathFilteredName); nil != removeErr { + logging.LogErrorf("renaming invalid file to [%s] failed: %s", fullPathFilteredName, removeErr) } } return nil diff --git a/kernel/util/file.go b/kernel/util/file.go index 5b792ed64..92fe70765 100644 --- a/kernel/util/file.go +++ b/kernel/util/file.go @@ -207,6 +207,7 @@ func FilterUploadFileName(name string) string { ret = strings.ReplaceAll(ret, "#", "") ret = strings.ReplaceAll(ret, "%", "") ret = strings.ReplaceAll(ret, "$", "") + ret = strings.ReplaceAll(ret, ";", "") ret = TruncateLenFileName(ret) return ret } From e5a634d90c09c8ab5460f7f708db34b317df58e8 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 16 Jun 2025 22:32:36 +0800 Subject: [PATCH 6/7] :lock: XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 https://github.com/siyuan-note/siyuan/pull/15041 --- kernel/api/system.go | 23 +++++++++++------------ kernel/model/import.go | 11 +++++------ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/kernel/api/system.go b/kernel/api/system.go index 955066675..a52b76e90 100644 --- a/kernel/api/system.go +++ b/kernel/api/system.go @@ -28,6 +28,7 @@ import ( "github.com/88250/lute" "github.com/88250/lute/html" "github.com/gin-gonic/gin" + "github.com/siyuan-note/filelock" "github.com/siyuan-note/logging" "github.com/siyuan-note/siyuan/kernel/conf" "github.com/siyuan-note/siyuan/kernel/model" @@ -171,13 +172,12 @@ func getEmojiConf(c *gin.Context) { } if !util.IsValidUploadFileName(html.UnescapeString(name)) { - emojiFullName := customConfDir + "/" + name - fullPathFilteredName := customConfDir + "/" + util.FilterUploadFileName(name) + emojiFullName := filepath.Join(customConfDir, name) + fullPathFilteredName := filepath.Join(customConfDir, util.FilterUploadFileName(name)) // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 - logging.LogWarnf("invalid custom emoji name [%s]", name) - logging.LogErrorf("renaming invalid file to [%s] in emojis", fullPathFilteredName) - if removeErr := os.Rename(emojiFullName, fullPathFilteredName); nil != removeErr { - logging.LogErrorf("renaming invalid file to [%s] failed: %s", fullPathFilteredName, removeErr) + logging.LogWarnf("renaming invalid custom emoji file [%s] to [%s]", name, fullPathFilteredName) + if removeErr := filelock.Rename(emojiFullName, fullPathFilteredName); nil != removeErr { + logging.LogErrorf("renaming invalid custom emoji file to [%s] failed: %s", fullPathFilteredName, removeErr) } } @@ -200,13 +200,12 @@ func getEmojiConf(c *gin.Context) { } if !util.IsValidUploadFileName(html.UnescapeString(name)) { - emojiFullName := customConfDir + "/" + name - fullPathFilteredName := customConfDir + "/" + util.FilterUploadFileName(name) + emojiFullName := filepath.Join(customConfDir, name) + fullPathFilteredName := filepath.Join(customConfDir, util.FilterUploadFileName(name)) // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 - logging.LogWarnf("invalid custom emoji name [%s]", name) - logging.LogErrorf("renaming invalid file to [%s] in emojis", fullPathFilteredName) - if removeErr := os.Rename(emojiFullName, fullPathFilteredName); nil != removeErr { - logging.LogErrorf("renaming invalid file to [%s] failed: %s", fullPathFilteredName, removeErr) + logging.LogWarnf("renaming invalid custom emoji file [%s] to [%s]", name, fullPathFilteredName) + if removeErr := filelock.Rename(emojiFullName, fullPathFilteredName); nil != removeErr { + logging.LogErrorf("renaming invalid custom emoji file to [%s] failed: %s", fullPathFilteredName, removeErr) } } diff --git a/kernel/model/import.go b/kernel/model/import.go index 51af0b4da..f0b560ef3 100644 --- a/kernel/model/import.go +++ b/kernel/model/import.go @@ -559,13 +559,12 @@ func ImportSY(zipPath, boxID, toPath string) (err error) { // 将包含的自定义表情统一移动到 data/emojis/ 下 filelock.Walk(filepath.Join(unzipRootPath, "emojis"), func(path string, d fs.DirEntry, err error) error { if !util.IsValidUploadFileName(d.Name()) { - emojiFullName := unzipRootPath + "emojis/" + name - fullPathFilteredName := unzipRootPath + "emojis/" + util.FilterUploadFileName(name) + emojiFullName := filepath.Join(unzipRootPath, "emojis", d.Name()) + fullPathFilteredName := filepath.Join(unzipRootPath, "emojis", util.FilterUploadFileName(d.Name())) // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 - logging.LogWarnf("invalid custom emoji name [%s]", name) - logging.LogErrorf("renaming invalid file to [%s] in emojis", fullPathFilteredName) - if removeErr := os.Rename(emojiFullName, fullPathFilteredName); nil != removeErr { - logging.LogErrorf("renaming invalid file to [%s] failed: %s", fullPathFilteredName, removeErr) + logging.LogWarnf("renaming invalid custom emoji file [%s] to [%s]", d.Name(), fullPathFilteredName) + if removeErr := filelock.Rename(emojiFullName, fullPathFilteredName); nil != removeErr { + logging.LogErrorf("renaming invalid custom emoji file to [%s] failed: %s", fullPathFilteredName, removeErr) } } return nil From 5fad080fc3460410b51f78958f18e0edff69dc90 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 16 Jun 2025 22:49:07 +0800 Subject: [PATCH 7/7] :lock: XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 https://github.com/siyuan-note/siyuan/pull/15041 --- kernel/model/import.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/kernel/model/import.go b/kernel/model/import.go index f0b560ef3..8bc6b4dae 100644 --- a/kernel/model/import.go +++ b/kernel/model/import.go @@ -557,10 +557,11 @@ func ImportSY(zipPath, boxID, toPath string) (err error) { } // 将包含的自定义表情统一移动到 data/emojis/ 下 - filelock.Walk(filepath.Join(unzipRootPath, "emojis"), func(path string, d fs.DirEntry, err error) error { + unzipRootEmojisPath := filepath.Join(unzipRootPath, "emojis") + filelock.Walk(unzipRootEmojisPath, func(path string, d fs.DirEntry, err error) error { if !util.IsValidUploadFileName(d.Name()) { - emojiFullName := filepath.Join(unzipRootPath, "emojis", d.Name()) - fullPathFilteredName := filepath.Join(unzipRootPath, "emojis", util.FilterUploadFileName(d.Name())) + emojiFullName := filepath.Join(unzipRootEmojisPath, d.Name()) + fullPathFilteredName := filepath.Join(unzipRootEmojisPath, util.FilterUploadFileName(d.Name())) // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 logging.LogWarnf("renaming invalid custom emoji file [%s] to [%s]", d.Name(), fullPathFilteredName) if removeErr := filelock.Rename(emojiFullName, fullPathFilteredName); nil != removeErr { @@ -687,6 +688,19 @@ func ImportData(zipPath string) (err error) { } tmpDataPath := filepath.Join(unzipPath, dirs[0].Name()) + tmpDataEmojisPath := filepath.Join(tmpDataPath, "emojis") + filelock.Walk(tmpDataEmojisPath, func(path string, d fs.DirEntry, err error) error { + if !util.IsValidUploadFileName(d.Name()) { + emojiFullName := filepath.Join(tmpDataEmojisPath, d.Name()) + fullPathFilteredName := filepath.Join(tmpDataEmojisPath, util.FilterUploadFileName(d.Name())) + // XSS through emoji name https://github.com/siyuan-note/siyuan/issues/15034 + logging.LogWarnf("renaming invalid custom emoji file [%s] to [%s]", d.Name(), fullPathFilteredName) + if removeErr := filelock.Rename(emojiFullName, fullPathFilteredName); nil != removeErr { + logging.LogErrorf("renaming invalid custom emoji file to [%s] failed: %s", fullPathFilteredName, removeErr) + } + } + return nil + }) if err = filelock.Copy(tmpDataPath, util.DataDir); err != nil { logging.LogErrorf("copy data dir from [%s] to [%s] failed: %s", tmpDataPath, util.DataDir, err) err = errors.New("copy data failed")