refactor(template): Enhance template loading security and error messages

This commit is contained in:
2025-10-15 16:40:07 +11:00
parent fce75baed4
commit 23a85f573b
4 changed files with 27 additions and 11 deletions

View File

@@ -133,8 +133,8 @@ func NewTemplateLoadError(template string, cause error) *CommonError {
return NewError(ErrTemplateLoad, fmt.Sprintf("failed to load template: %s", template), cause)
}
func NewTemplateParseError(cause error) *CommonError {
return NewError(ErrTemplateParse, "failed to parse template", cause)
func NewTemplateParseError(data []byte, cause error) *CommonError {
return NewError(ErrTemplateParse, fmt.Sprintf("failed to parse template: %s", data), cause)
}
// Subscription errors
@@ -142,8 +142,8 @@ func NewSubscriptionLoadError(url string, cause error) *CommonError {
return NewError(ErrSubscriptionLoad, fmt.Sprintf("failed to load subscription: %s", url), cause)
}
func NewSubscriptionParseError(cause error) *CommonError {
return NewError(ErrSubscriptionParse, "failed to parse subscription", cause)
func NewSubscriptionParseError(data []byte, cause error) *CommonError {
return NewError(ErrSubscriptionParse, fmt.Sprintf("failed to parse subscription: %s", string(data)), cause)
}
// Regex errors

View File

@@ -129,7 +129,7 @@ func BuildSub(clashType model.ClashType, query model.ConvertConfig, template str
err = yaml.Unmarshal(templateBytes, &temp)
if err != nil {
logger.Logger.Debug("parse template failed", zap.Error(err))
return nil, NewTemplateParseError(err)
return nil, NewTemplateParseError(templateBytes, err)
}
var proxyList []P.Proxy
@@ -168,7 +168,7 @@ func BuildSub(clashType model.ClashType, query model.ConvertConfig, template str
zap.String("data", string(data)),
zap.Error(err),
)
return nil, NewSubscriptionParseError(err)
return nil, NewSubscriptionParseError(data, err)
}
p, err := parser.ParseProxies(parser.ParseConfig{UseUDP: query.UseUDP}, strings.Split(base64, "\n")...)
if err != nil {

View File

@@ -3,11 +3,27 @@ package common
import (
"io"
"os"
"path/filepath"
"strings"
)
func LoadTemplate(templatePath string) ([]byte, error) {
if _, err := os.Stat(templatePath); err == nil {
file, err := os.Open(templatePath)
const templatesDir = "templates"
// LoadTemplate 只读取运行目录下的 templates 目录,防止其他文件内容泄漏
func LoadTemplate(templateName string) ([]byte, error) {
// 清理路径,防止目录遍历攻击
cleanTemplateName := filepath.Clean(templateName)
// 检查是否尝试访问父目录
if strings.HasPrefix(cleanTemplateName, "..") || strings.Contains(cleanTemplateName, string(filepath.Separator)+".."+string(filepath.Separator)) {
return nil, NewFileNotFoundError(templateName) // 拒绝包含父目录的路径
}
// 构建完整路径,确保只从 templates 目录读取
fullPath := filepath.Join(templatesDir, cleanTemplateName)
if _, err := os.Stat(fullPath); err == nil {
file, err := os.Open(fullPath)
if err != nil {
return nil, err
}
@@ -22,5 +38,5 @@ func LoadTemplate(templatePath string) ([]byte, error) {
}
return result, nil
}
return nil, NewFileNotFoundError(templatePath)
return nil, NewFileNotFoundError(templateName)
}

View File

@@ -89,7 +89,7 @@
<!-- Template -->
<div class="form-group mb-3">
<label for="template">模板链接或名称:</label>
<input class="form-control" id="template" name="template" placeholder="输入外部模板链接或内部模板名称(可选)" type="text" />
<input class="form-control" id="template" name="template" placeholder="输入模板链接(可选)" type="text" />
</div>
<!-- Subscription Link -->
<div class="form-group mb-3">