mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-09-22 09:20:58 +02:00
Add files via upload
This commit is contained in:
+9
-79
@@ -7,35 +7,26 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const chatUploadsDirName = "chat_uploads"
|
||||
|
||||
var allowedImageExt = map[string]struct{}{
|
||||
".png": {}, ".jpg": {}, ".jpeg": {}, ".webp": {}, ".gif": {},
|
||||
".bmp": {}, ".tif": {}, ".tiff": {},
|
||||
}
|
||||
|
||||
// PathOptions 图片路径白名单根目录。
|
||||
type PathOptions struct {
|
||||
CWD string
|
||||
ResultStorageDir string // 相对 CWD,如 tmp
|
||||
ExtraRoots []string // vision.allowed_roots 绝对路径
|
||||
}
|
||||
|
||||
// ResolveImagePath 解析并校验可读图片路径(防穿越、symlink 逃逸)。
|
||||
func ResolveImagePath(path string, opt PathOptions) (string, error) {
|
||||
// ResolveImagePath 解析并校验可读图片路径(支持任意目录;仍校验扩展名与常规文件)。
|
||||
func ResolveImagePath(path string, cwd string) (string, error) {
|
||||
p := strings.TrimSpace(path)
|
||||
if p == "" {
|
||||
return "", fmt.Errorf("path is empty")
|
||||
}
|
||||
cwd := strings.TrimSpace(opt.CWD)
|
||||
if cwd == "" {
|
||||
cwdTrim := strings.TrimSpace(cwd)
|
||||
if cwdTrim == "" {
|
||||
var err error
|
||||
cwd, err = os.Getwd()
|
||||
cwdTrim, err = os.Getwd()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getwd: %w", err)
|
||||
}
|
||||
}
|
||||
cwdAbs, err := filepath.Abs(filepath.Clean(cwd))
|
||||
cwdAbs, err := filepath.Abs(filepath.Clean(cwdTrim))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -46,22 +37,16 @@ func ResolveImagePath(path string, opt PathOptions) (string, error) {
|
||||
} else {
|
||||
candidate = filepath.Clean(filepath.Join(cwdAbs, p))
|
||||
}
|
||||
candidate = normalizeAbsPath(candidate)
|
||||
if candidate == "" {
|
||||
resolved := normalizeAbsPath(candidate)
|
||||
if resolved == "" {
|
||||
return "", fmt.Errorf("invalid path")
|
||||
}
|
||||
|
||||
ext := strings.ToLower(filepath.Ext(candidate))
|
||||
ext := strings.ToLower(filepath.Ext(resolved))
|
||||
if _, ok := allowedImageExt[ext]; !ok {
|
||||
return "", fmt.Errorf("unsupported image extension %q", ext)
|
||||
}
|
||||
|
||||
roots := buildAllowedRoots(cwdAbs, opt)
|
||||
resolved, err := evalUnderAllowedRoots(candidate, roots)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
st, err := os.Stat(resolved)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("stat: %w", err)
|
||||
@@ -85,58 +70,3 @@ func normalizeAbsPath(p string) string {
|
||||
}
|
||||
return abs
|
||||
}
|
||||
|
||||
func buildAllowedRoots(cwdAbs string, opt PathOptions) []string {
|
||||
seen := make(map[string]struct{})
|
||||
var roots []string
|
||||
add := func(r string) {
|
||||
r = strings.TrimSpace(r)
|
||||
if r == "" {
|
||||
return
|
||||
}
|
||||
abs := normalizeAbsPath(r)
|
||||
if abs == "" {
|
||||
return
|
||||
}
|
||||
if _, ok := seen[abs]; ok {
|
||||
return
|
||||
}
|
||||
seen[abs] = struct{}{}
|
||||
roots = append(roots, abs)
|
||||
}
|
||||
add(cwdAbs)
|
||||
add(filepath.Join(cwdAbs, chatUploadsDirName))
|
||||
rs := strings.TrimSpace(opt.ResultStorageDir)
|
||||
if rs == "" {
|
||||
rs = "tmp"
|
||||
}
|
||||
if filepath.IsAbs(rs) {
|
||||
add(rs)
|
||||
} else {
|
||||
add(filepath.Join(cwdAbs, rs))
|
||||
}
|
||||
for _, r := range opt.ExtraRoots {
|
||||
add(r)
|
||||
}
|
||||
return roots
|
||||
}
|
||||
|
||||
func evalUnderAllowedRoots(candidate string, roots []string) (string, error) {
|
||||
check := normalizeAbsPath(candidate)
|
||||
for _, root := range roots {
|
||||
if isUnderRoot(check, root) {
|
||||
return candidate, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("path %q is outside allowed directories", candidate)
|
||||
}
|
||||
|
||||
func isUnderRoot(path, root string) bool {
|
||||
path = filepath.Clean(path)
|
||||
root = filepath.Clean(root)
|
||||
if path == root {
|
||||
return true
|
||||
}
|
||||
sep := string(filepath.Separator)
|
||||
return strings.HasPrefix(path, root+sep)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user