rules_test.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package main
  2. import (
  3. "os"
  4. "path/filepath"
  5. "testing"
  6. )
  7. func TestRuleProblem(t *testing.T) {
  8. roots := []string{"/home", "/mnt", "/media"}
  9. ok := []string{"/home/u/docs", "/mnt/nas/a", "/media/u/Data/资料", "/mnt/x"}
  10. bad := map[string]string{
  11. "/etc": "只能选择",
  12. "/home": "本身",
  13. "/mnt": "本身",
  14. "/home/u": "用户主目录",
  15. "/home/u/.ssh": "隐藏",
  16. "/home/u/a/.git/x": "隐藏",
  17. "/homex/u/a": "只能选择",
  18. "/home/u/../../etc": "规范",
  19. "relative/path": "规范",
  20. "/srv/agent-server": "只能选择",
  21. "/media/u/Data/.env": "隐藏",
  22. }
  23. for _, p := range ok {
  24. if msg := ruleProblem(p, roots); msg != "" {
  25. t.Errorf("%s 应该允许,实际:%s", p, msg)
  26. }
  27. }
  28. for p, want := range bad {
  29. if msg := ruleProblem(p, roots); msg == "" || !contains(msg, want) {
  30. t.Errorf("%s 应该拒绝(%s),实际:%q", p, want, msg)
  31. }
  32. }
  33. }
  34. func contains(s, sub string) bool { return len(sub) == 0 || (len(s) >= len(sub) && indexOf(s, sub) >= 0) }
  35. func indexOf(s, sub string) int {
  36. for i := 0; i+len(sub) <= len(s); i++ {
  37. if s[i:i+len(sub)] == sub {
  38. return i
  39. }
  40. }
  41. return -1
  42. }
  43. // 用临时目录模拟允许的根目录
  44. func tempRoots(t *testing.T) (string, []string) {
  45. base, _ := filepath.EvalSymlinks(t.TempDir())
  46. root := filepath.Join(base, "mnt")
  47. if err := os.MkdirAll(filepath.Join(root, "data", "docs"), 0o755); err != nil {
  48. t.Fatal(err)
  49. }
  50. return base, []string{root}
  51. }
  52. func TestCheckSourceAndBrowse(t *testing.T) {
  53. base, roots := tempRoots(t)
  54. root := roots[0]
  55. os.MkdirAll(filepath.Join(root, "data", ".hidden"), 0o755)
  56. os.MkdirAll(filepath.Join(base, "outside"), 0o755)
  57. os.Symlink(filepath.Join(base, "outside"), filepath.Join(root, "escape"))
  58. os.Symlink(filepath.Join(root, "data", "docs"), filepath.Join(root, "inner"))
  59. os.WriteFile(filepath.Join(root, "file.txt"), []byte("x"), 0o644)
  60. if real, err := checkSource(filepath.Join(root, "data", "docs"), roots); err != nil || real != filepath.Join(root, "data", "docs") {
  61. t.Fatalf("应该通过:%v %v", real, err)
  62. }
  63. if real, err := checkSource(filepath.Join(root, "inner"), roots); err != nil || real != filepath.Join(root, "data", "docs") {
  64. t.Fatalf("范围内的符号链接解析为真实路径:%v %v", real, err)
  65. }
  66. cases := map[string]string{
  67. filepath.Join(root, "escape"): "not_allowed",
  68. filepath.Join(root, "data", ".hidden"): "not_allowed",
  69. filepath.Join(root, "file.txt"): "not_allowed",
  70. filepath.Join(root, "nope"): "path_missing",
  71. root: "not_allowed",
  72. "relative": "not_allowed",
  73. }
  74. for p, state := range cases {
  75. if _, err := checkSource(p, roots); err == nil || err.State != state {
  76. t.Errorf("%s 应该是 %s,实际 %v", p, state, err)
  77. }
  78. }
  79. res, cerr := browse(root, roots)
  80. if cerr != nil {
  81. t.Fatal(cerr)
  82. }
  83. got := map[string]browseEntry{}
  84. for _, e := range res.Entries {
  85. got[e.Name] = e
  86. }
  87. if _, ok := got["file.txt"]; ok {
  88. t.Error("文件不应出现在目录选择中")
  89. }
  90. if !got["data"].Selectable || got["escape"].Selectable || !got["inner"].Selectable {
  91. t.Errorf("可选状态不正确:%+v", got)
  92. }
  93. if res.Parent != "" {
  94. t.Errorf("根目录的上级应为空:%q", res.Parent)
  95. }
  96. sub, _ := browse(filepath.Join(root, "data"), roots)
  97. for _, e := range sub.Entries {
  98. if e.Name == ".hidden" {
  99. t.Error("隐藏目录不应出现")
  100. }
  101. }
  102. if _, cerr := browse(filepath.Join(base, "outside"), roots); cerr == nil {
  103. t.Error("不能浏览范围以外的目录")
  104. }
  105. if _, cerr := browse(filepath.Join(root, "escape"), roots); cerr == nil {
  106. t.Error("不能经由符号链接浏览范围以外的目录")
  107. }
  108. top, _ := browse("", roots)
  109. if len(top.Entries) != 1 || top.Entries[0].Selectable {
  110. t.Errorf("顶层列出允许的根目录且不能直接选择:%+v", top.Entries)
  111. }
  112. }