clearlove2.1
1package handlers
2
3import (
4 "os"
5 "path/filepath"
6 "testing"
7
8 "clearlove/internal/config"
9)
10
11// TestRemovePluginAsset 素材清理必须定位到 <UploadDir>/plugins/ 下的真实文件。
12// 曾经漏掉 plugins 一段,导致重新上传后旧文件一直留在磁盘上。
13func TestRemovePluginAsset(t *testing.T) {
14 root := t.TempDir()
15 config.Cfg.UploadDir = filepath.Join(root, "uploads")
16 dir := filepath.Join(config.Cfg.UploadDir, "plugins", "bgm")
17 if err := os.MkdirAll(dir, 0o755); err != nil {
18 t.Fatal(err)
19 }
20 target := filepath.Join(dir, "audio-abc.mp3")
21 if err := os.WriteFile(target, []byte("music"), 0o644); err != nil {
22 t.Fatal(err)
23 }
24
25 removePluginAsset("/uploads/plugins/bgm/audio-abc.mp3")
26 if _, err := os.Stat(target); !os.IsNotExist(err) {
27 t.Fatalf("旧素材未被删除: %v", err)
28 }
29
30 // 重复删除不应报错,也不应影响其他文件
31 removePluginAsset("/uploads/plugins/bgm/audio-abc.mp3")
32}
33
34// TestRemovePluginAssetGuards 只清理插件素材目录内的文件,拒绝越权路径
35func TestRemovePluginAssetGuards(t *testing.T) {
36 root := t.TempDir()
37 config.Cfg.UploadDir = filepath.Join(root, "uploads")
38 if err := os.MkdirAll(config.Cfg.UploadDir, 0o755); err != nil {
39 t.Fatal(err)
40 }
41 keep := filepath.Join(config.Cfg.UploadDir, "keep.webp")
42 if err := os.WriteFile(keep, []byte("keep"), 0o644); err != nil {
43 t.Fatal(err)
44 }
45
46 for _, u := range []string{
47 "",
48 "/uploads/keep.webp", // 不在插件目录内
49 "/uploads/plugins/../../keep.webp", // 路径穿越
50 "/uploads/plugins/", // 目录本身
51 "https://example.com/x.mp3", // 外部地址
52 "/uploads/plugins/../../../etc/passwd", // 绝对越权
53 } {
54 removePluginAsset(u)
55 }
56 if _, err := os.Stat(keep); err != nil {
57 t.Fatalf("不应删除插件素材目录之外的文件: %v", err)
58 }
59}
60
61// TestSanitizePluginAsset 素材地址要能安全地注入页面(不含引号与尖括号)
62func TestSanitizePluginAsset(t *testing.T) {
63 cases := map[string]string{
64 `/uploads/plugins/bgm/a.mp3`: `/uploads/plugins/bgm/a.mp3`,
65 `/uploads/plugins/bgm/a'.mp3`: `/uploads/plugins/bgm/a.mp3`,
66 `"/uploads/plugins/bgm/a.mp3"`: `/uploads/plugins/bgm/a.mp3`,
67 `x"><script>alert(1)</script>`: `xalert(1)`, // StripHTML 去掉标签,尖括号与引号也会被清除
68 }
69 for in, want := range cases {
70 if got := sanitizePluginAsset(in); got != want {
71 t.Errorf("sanitizePluginAsset(%q) = %q, 期望 %q", in, got, want)
72 }
73 }
74}