package logic import ( "path/filepath" "strings" "testing" ) // 校验存储目录拼接不会越出上传根目录 func TestSafeJoin(t *testing.T) { root := "./uploader/" cleanRoot := filepath.Clean(root) cases := []struct { name string sub []string }{ {"正常相对路径", []string{"frc", "2026-01/ab"}}, {"bucket穿越", []string{"../../etc/cron.d", "2026-01/ab"}}, {"子目录穿越", []string{"frc", "../../../etc"}}, {"绝对路径bucket", []string{"/etc/cron.d", "2026-01/ab"}}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { got, err := safeJoin(root, c.sub...) if err != nil { return // 被拒绝同样是安全的 } if got != cleanRoot && !strings.HasPrefix(got, cleanRoot+string(filepath.Separator)) { t.Fatalf("路径越出上传根目录: %s", got) } }) } if _, err := safeJoin(root, "../../etc/cron.d", "2026-01/ab"); err == nil { t.Fatal("路径穿越未被拒绝") } } // 校验 bucket 名称白名单 func TestBucketPattern(t *testing.T) { valid := []string{"frc", "my-bucket", "my_bucket", "A1"} for _, v := range valid { if !bucketPattern.MatchString(v) { t.Errorf("应允许的 bucket 被拒绝: %q", v) } } invalid := []string{"", "../etc", "a/b", "a\\b", "a b", "a.b", strings.Repeat("a", 65)} for _, v := range invalid { if bucketPattern.MatchString(v) { t.Errorf("应拒绝的 bucket 被放行: %q", v) } } }