🎨 Improve the security of the kernel API /api/file/getFile on the publish service https://github.com/siyuan-note/siyuan/issues/16603

Signed-off-by: Daniel <845765@qq.com>
This commit is contained in:
Daniel 2026-01-18 18:59:35 +08:00
parent 0be7e1d4e0
commit 1f02650b38
No known key found for this signature in database
GPG key ID: 86211BA83DF03017

View file

@ -167,6 +167,13 @@ func getFile(c *gin.Context) {
c.JSON(http.StatusAccepted, ret)
return
}
if !filelock.IsExist(fileAbsPath) {
ret.Code = http.StatusNotFound
ret.Msg = "file does not exist"
c.JSON(http.StatusAccepted, ret)
return
}
info, err := os.Stat(fileAbsPath)
if os.IsNotExist(err) {
ret.Code = http.StatusNotFound
@ -190,19 +197,8 @@ func getFile(c *gin.Context) {
}
// REF: https://github.com/siyuan-note/siyuan/issues/11364
if role := model.GetGinContextRole(c); !model.IsValidRole(role, []model.Role{
model.RoleAdministrator,
}) {
if relPath, err := filepath.Rel(util.ConfDir, fileAbsPath); err != nil {
logging.LogErrorf("Get a relative path from [%s] to [%s] failed: %s", util.ConfDir, fileAbsPath, err)
ret.Code = http.StatusInternalServerError
ret.Msg = err.Error()
c.JSON(http.StatusAccepted, ret)
return
} else if relPath == "conf.json" {
ret.Code = http.StatusForbidden
ret.Msg = http.StatusText(http.StatusForbidden)
c.JSON(http.StatusAccepted, ret)
if !model.IsAdminRoleContext(c) {
if refuseToAccess(c, fileAbsPath, ret) {
return
}
}
@ -228,6 +224,33 @@ func getFile(c *gin.Context) {
c.Data(http.StatusOK, contentType, data)
}
func refuseToAccess(c *gin.Context, fileAbsPath string, ret *gulu.Result) bool {
// 禁止访问配置文件 conf/conf.json
if filepath.Join(util.ConfDir, "conf.json") == fileAbsPath {
ret.Code = http.StatusForbidden
ret.Msg = http.StatusText(http.StatusForbidden)
c.JSON(http.StatusAccepted, ret)
return true
}
// 禁止访问 data/snippets/conf.json
if filepath.Join(util.DataDir, "snippets", "conf.json") == fileAbsPath {
ret.Code = http.StatusForbidden
ret.Msg = http.StatusText(http.StatusForbidden)
c.JSON(http.StatusAccepted, ret)
return true
}
// 禁止访问 data/templates 目录
if util.IsSubPath(filepath.Join(util.DataDir, "templates"), fileAbsPath) {
ret.Code = http.StatusForbidden
ret.Msg = http.StatusText(http.StatusForbidden)
c.JSON(http.StatusAccepted, ret)
return true
}
return false
}
func readDir(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)