返回 DeepSeek-Reasonix
open_local_path_test.go
根目录 / desktop / open_local_path_test.go
1 package main
2
3 import (
4 "errors"
5 "os"
6 "path/filepath"
7 "runtime"
8 "strings"
9 "testing"
10 )
11
12 func TestNormalizeLocalOpenPath(t *testing.T) {
13 abs := filepath.Join(t.TempDir(), "report.md")
14 fileURL := "file://" + filepath.ToSlash(abs)
15 if runtime.GOOS == "windows" {
16 fileURL = "file:///" + filepath.ToSlash(abs)
17 }
18
19 tests := []struct {
20 name string
21 in string
22 want string
23 }{
24 {"empty", "", ""},
25 {"blank", " ", ""},
26 {"plain absolute", abs, abs},
27 {"file URL", fileURL, abs},
28 }
29 for _, tc := range tests {
30 t.Run(tc.name, func(t *testing.T) {
31 got, err := normalizeLocalOpenPath(tc.in)
32 if tc.want == "" {
33 if err == nil {
34 t.Fatalf("normalizeLocalOpenPath(%q) = %q, want error", tc.in, got)
35 }
36 return
37 }
38 if err != nil {
39 t.Fatalf("normalizeLocalOpenPath(%q): %v", tc.in, err)
40 }
41 if got != tc.want {
42 t.Fatalf("normalizeLocalOpenPath(%q) = %q, want %q", tc.in, got, tc.want)
43 }
44 })
45 }
46 }
47
48 func TestNormalizeLocalOpenPathAuthorityUNC(t *testing.T) {
49 want := filepath.FromSlash("//server/share/docs/report.md")
50 got, err := normalizeLocalOpenPath("file://server/share/docs/report.md")
51 if err != nil {
52 t.Fatalf("authority-form UNC URL rejected: %v", err)
53 }
54 if got != want {
55 t.Fatalf("authority-form UNC URL = %q, want %q", got, want)
56 }
57 }
58
59 func TestNormalizeLocalOpenPathRejectsUnsafeWindowsSyntax(t *testing.T) {
60 unsafePaths := []string{
61 `\\.\PhysicalDrive0`,
62 `\\?\C:\Windows\System32`,
63 `//./PhysicalDrive0`,
64 `//?/C:/Windows/System32`,
65 `C:/safe.txt:payload`,
66 `C:/docs/NUL.txt`,
67 `C:/docs/COM1.log`,
68 `//server/share/CON.md`,
69 "C:/safe.txt\x00payload",
70 }
71 for _, path := range unsafePaths {
72 if !hasDisallowedWindowsPathSyntax(path) {
73 t.Errorf("hasDisallowedWindowsPathSyntax(%q) = false, want true", path)
74 }
75 }
76
77 unsafeURLs := []string{
78 "file://./PhysicalDrive0",
79 "file:////./PhysicalDrive0",
80 "file:////?/C:/Windows/System32",
81 "file:////%3F/C:/Windows/System32",
82 "file:///C:/safe.txt:payload",
83 "file:///C:/safe.txt%3Apayload",
84 "file://user@server/share/report.md",
85 "file://server:445/share/report.md",
86 "file:///tmp/report.md?download=1",
87 "file:///tmp/report.md#section",
88 }
89 for _, value := range unsafeURLs {
90 if got, err := normalizeLocalOpenPath(value); err == nil {
91 t.Errorf("normalizeLocalOpenPath(%q) = %q, want error", value, got)
92 }
93 }
94 }
95
96 func TestNormalizeLocalOpenPathRejectsRelative(t *testing.T) {
97 for _, in := range []string{"report.md", "dir/report.md"} {
98 if _, err := normalizeLocalOpenPath(in); err == nil || !strings.Contains(err.Error(), "not absolute") {
99 t.Fatalf("normalizeLocalOpenPath(%q) err = %v, want not-absolute error", in, err)
100 }
101 }
102 }
103
104 func TestNormalizeLocalOpenPathWindowsUNC(t *testing.T) {
105 if runtime.GOOS != "windows" {
106 t.Skip("UNC paths are Windows-only")
107 }
108 got, err := normalizeLocalOpenPath(`\\server\share\docs\report.md`)
109 if err != nil {
110 t.Fatalf("UNC path rejected: %v", err)
111 }
112 if got != `\\server\share\docs\report.md` {
113 t.Fatalf("UNC path = %q, want unchanged", got)
114 }
115 }
116
117 func TestOpenLocalPathRejectsMissingFile(t *testing.T) {
118 a := &App{}
119 missing := filepath.Join(t.TempDir(), "does-not-exist.md")
120 if err := a.OpenLocalPath(missing); err == nil {
121 t.Fatal("OpenLocalPath on a missing path succeeded, want error")
122 }
123 }
124
125 func TestOpenLocalPathRejectsRelativeAndEmpty(t *testing.T) {
126 a := &App{}
127 if err := a.OpenLocalPath(""); !errors.Is(err, os.ErrInvalid) {
128 t.Fatalf("OpenLocalPath(\"\") err = %v, want os.ErrInvalid", err)
129 }
130 if err := a.OpenLocalPath("relative.md"); err == nil {
131 t.Fatal("OpenLocalPath(relative) succeeded, want error")
132 }
133 }
134
135 func TestOpenTargetAllowed(t *testing.T) {
136 for _, name := range []string{"report.md", "report.docx", "report.pdf", "diagram.png"} {
137 if !openTargetAllowed(filepath.Join("C:", "docs", name), false, 0o644) {
138 t.Fatalf("document %q should be openable", name)
139 }
140 }
141 if !openTargetAllowed(filepath.Join("C:", "docs"), true, os.ModeDir|0o755) {
142 t.Fatal("directory should be openable")
143 }
144 for _, name := range []string{
145 "evil.bat", "evil.cmd", "evil.exe", "evil.exe.", "evil.exe ", "evil.ps1", "evil.lnk", "evil.url",
146 "evil.msi", "run.BAT", "EVIL.Scr", "launcher.desktop",
147 } {
148 if openTargetAllowed(filepath.Join("C:", "temp", name), false, 0o644) {
149 t.Fatalf("executable target %q should be refused", name)
150 }
151 }
152 if openTargetAllowed(filepath.Join("Applications", "Unsafe.app"), true, os.ModeDir|0o755) {
153 t.Fatal("macOS application bundle should be refused")
154 }
155 if openTargetAllowed(filepath.Join("Applications", "Unsafe.app")+string(filepath.Separator), true, os.ModeDir|0o755) {
156 t.Fatal("macOS application bundle with trailing separator should be refused")
157 }
158 if openTargetAllowed(filepath.Join("tmp", "script"), false, 0o755) {
159 t.Fatal("executable-mode regular file should be refused")
160 }
161 }
162
163 func TestOpenLocalPathRejectsExecutable(t *testing.T) {
164 a := &App{}
165 dir := t.TempDir()
166 script := filepath.Join(dir, "clicked.bat")
167 if err := os.WriteFile(script, []byte("@echo off"), 0o644); err != nil {
168 t.Fatal(err)
169 }
170 if err := a.OpenLocalPath(script); err == nil || !strings.Contains(err.Error(), "executable") {
171 t.Fatalf("OpenLocalPath(.bat) err = %v, want executable refusal", err)
172 }
173 }
174
174 lines GO