package verifyfiles import ( "os" "path/filepath" "testing" ) // newTestResolver 造一个临时验证目录,返回 resolver。 func newTestResolver(t *testing.T, cfg Config) *Resolver { t.Helper() r, err := New(cfg) if err != nil { t.Fatalf("创建 Resolver 失败: %v", err) } if r == nil { t.Fatal("Resolver 不应为 nil") } return r } // TestResolveAllowed 确认合法验证文件能被解析到磁盘路径。 func TestResolveAllowed(t *testing.T) { dir := t.TempDir() if err := os.WriteFile(filepath.Join(dir, "1XXl8fPHr9.txt"), []byte("1XXl8fPHr9"), 0o644); err != nil { t.Fatalf("准备测试文件失败: %v", err) } if err := os.WriteFile(filepath.Join(dir, "baidu_verify_codexxx.html"), []byte(""), 0o644); err != nil { t.Fatalf("准备测试文件失败: %v", err) } r := newTestResolver(t, Config{Dir: dir}) for _, name := range []string{"1XXl8fPHr9.txt", "baidu_verify_codexxx.html"} { got, ok := r.Resolve("/" + name) if !ok { t.Fatalf("合法验证文件 /%s 未被解析出来", name) } want := filepath.Join(dir, name) if got != want { t.Fatalf("路径不对,期望 %s,实际 %s", want, got) } } } // TestResolveRejected 确认非法/敏感/不存在的路径一律不放行。 func TestResolveRejected(t *testing.T) { dir := t.TempDir() for _, name := range []string{"secret.env", "notes.md", "index.html", "app.conf"} { if err := os.WriteFile(filepath.Join(dir, name), []byte("x"), 0o644); err != nil { t.Fatalf("准备测试文件失败: %v", err) } } if err := os.Mkdir(filepath.Join(dir, "sub.txt"), 0o755); err != nil { t.Fatalf("准备测试目录失败: %v", err) } r := newTestResolver(t, Config{Dir: dir}) cases := []string{ "/", "", "/secret.env", // 敏感后缀不在白名单 "/notes.md", // 后缀不在白名单 "/app.conf", // 配置文件不得外泄 "/index.html", // 会被 ServeFile 重定向 "/sub/dir.txt", // 只允许根路径单段文件名 "/../secret.env", // 路径穿越 "/1XXl8fPHr9.txt/../..", // 路径穿越 "/missing.txt", // 文件不存在 "/sub.txt", // 目录不是文件 } for _, c := range cases { if got, ok := r.Resolve(c); ok { t.Fatalf("路径 %q 不应被放行,实际解析为 %s", c, got) } } } // TestAllowHost 确认域名白名单按「忽略端口 + 忽略大小写」匹配。 func TestAllowHost(t *testing.T) { r := newTestResolver(t, Config{Dir: t.TempDir(), Hosts: "api.yunzer.cn"}) if !r.AllowHost("api.yunzer.cn") { t.Fatal("api.yunzer.cn 应被允许") } if !r.AllowHost("API.Yunzer.cn:443") { t.Fatal("带端口与大写的 api.yunzer.cn 应被允许") } if r.AllowHost("other.com") { t.Fatal("未在白名单里的域名不应被允许") } // 未配置 hosts 时,所有走本服务的域名都生效 all := newTestResolver(t, Config{Dir: t.TempDir()}) if !all.AllowHost("api.yunzer.cn") || !all.AllowHost("dh2.fun") { t.Fatal("未配置 verify_hosts 时应允许所有域名") } } // TestNewDisabled 确认 dir = "-" 表示关闭该功能。 func TestNewDisabled(t *testing.T) { r, err := New(Config{Dir: "-"}) if err != nil { t.Fatalf("不应报错: %v", err) } if r != nil { t.Fatal("dir = \"-\" 时 Resolver 应为 nil") } } // TestDefaultExts 确认默认扩展名包含 .txt。 func TestDefaultExts(t *testing.T) { r := newTestResolver(t, Config{Dir: t.TempDir()}) found := false for _, e := range r.Exts() { if e == ".txt" { found = true } } if !found { t.Fatalf("默认扩展名应包含 .txt,实际 %v", r.Exts()) } }