mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-31 22:08:48 +01:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
6c6a266df7
2 changed files with 75 additions and 0 deletions
|
|
@ -28,6 +28,8 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/88250/lute"
|
||||
"github.com/88250/lute/ast"
|
||||
"github.com/88250/lute/html"
|
||||
"github.com/88250/lute/parse"
|
||||
"github.com/88250/lute/render"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
|
|
@ -292,6 +294,12 @@ func parseJSON2Tree(boxID, p string, jsonData []byte, luteEngine *lute.Lute) (re
|
|||
needFix = true
|
||||
}
|
||||
|
||||
if escapeAttributeValues(ret) { // TODO 计划于 2026 年 6 月 30 日后删除
|
||||
// v3.5.1 https://github.com/siyuan-note/siyuan/pull/16657 引入的问题,属性值未转义
|
||||
// v3.5.2 https://github.com/siyuan-note/siyuan/issues/16686 进行了修复,并加了订正逻辑 https://github.com/siyuan-note/siyuan/pull/16712
|
||||
needFix = true
|
||||
}
|
||||
|
||||
if pathID := util.GetTreeID(p); pathID != ret.Root.ID {
|
||||
needFix = true
|
||||
logging.LogInfof("reset tree id from [%s] to [%s]", ret.Root.ID, pathID)
|
||||
|
|
@ -324,3 +332,62 @@ func parseJSON2Tree(boxID, p string, jsonData []byte, luteEngine *lute.Lute) (re
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// escapeAttributeValues 转义属性值
|
||||
func escapeAttributeValues(tree *parse.Tree) (hasEscaped bool) {
|
||||
if util.ReadOnly || nil == tree || nil == tree.Root {
|
||||
return false
|
||||
}
|
||||
|
||||
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
|
||||
if !entering || !n.IsBlock() || "" == n.ID || 0 == len(n.KramdownIAL) {
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
if escaped := escapeNodeAttributeValues(n); escaped {
|
||||
hasEscaped = true
|
||||
}
|
||||
return ast.WalkContinue
|
||||
})
|
||||
return hasEscaped
|
||||
}
|
||||
|
||||
// escapeNodeAttributeValues 转义节点的属性值
|
||||
func escapeNodeAttributeValues(node *ast.Node) (escaped bool) {
|
||||
if nil == node || 0 == len(node.KramdownIAL) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, kv := range node.KramdownIAL {
|
||||
if value := kv[1]; needsEscapeForValue(value) {
|
||||
kv[1] = html.EscapeAttrVal(value)
|
||||
escaped = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// needsEscapeForValue 检查值是否需要转义(包含需要转义的特殊字符但尚未被转义)
|
||||
func needsEscapeForValue(value string) bool {
|
||||
hasSpecialChars := false
|
||||
for _, char := range value {
|
||||
switch char {
|
||||
case '<', '>', '&', '"', '{', '}':
|
||||
hasSpecialChars = true
|
||||
}
|
||||
if hasSpecialChars {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasSpecialChars {
|
||||
return false
|
||||
}
|
||||
|
||||
entities := []string{""", "{", "}", "&", "<", ">"}
|
||||
for _, entity := range entities {
|
||||
if strings.Contains(value, entity) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,6 +165,14 @@ func IsRelativePath(dest string) bool {
|
|||
if '/' == dest[0] {
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查特定协议前缀
|
||||
lowerDest := strings.ToLower(dest)
|
||||
if strings.HasPrefix(lowerDest, "mailto:") ||
|
||||
strings.HasPrefix(lowerDest, "tel:") ||
|
||||
strings.HasPrefix(lowerDest, "sms:") {
|
||||
return false
|
||||
}
|
||||
return !strings.Contains(dest, ":/") && !strings.Contains(dest, ":\\")
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue