package deploy import ( "path/filepath" "runtime" "strings" "testing" ) func TestSanitizeDesktopFilename(t *testing.T) { if got := sanitizeDesktopFilename(`..\..\etc\passwd`); got != "etc/passwd" && got != `etc\passwd` { // Join uses OS separator; at minimum no .. if strings.Contains(got, "..") { t.Fatalf("traversal leaked: %q", got) } } if got := sanitizeDesktopFilename("report.pdf"); got != "report.pdf" { t.Fatalf("got %q", got) } } func TestResolveRemotePathDesktopPrefix(t *testing.T) { p, err := ResolveRemotePath("@desktop/notes.txt") if err != nil { t.Fatal(err) } if !strings.HasSuffix(p, "notes.txt") { t.Fatalf("path %q should end with notes.txt", p) } if !strings.Contains(strings.ToLower(p), "desktop") && runtime.GOOS != "windows" { // Linux may use XDG path without "Desktop" in rare setups — allow if under home home, _ := filepath.Abs(".") _ = home } } func TestResolveRemotePathRejectsTraversalVariants(t *testing.T) { cases := []string{ "../../etc/passwd", `..\..\Windows\System32\config\sam`, "uploads/../../outside.txt", "/var/log/../../etc/shadow", "..", "~/../../etc/passwd", "@desktop/../../outside.txt", "desktop:../../payload.bin", "safe/inner/../../../etc/shadow", } for _, path := range cases { if _, err := ResolveRemotePath(path); err == nil { t.Fatalf("ResolveRemotePath(%q) should reject traversal", path) } else if !strings.Contains(err.Error(), "path traversal") { t.Fatalf("ResolveRemotePath(%q) error=%q", path, err.Error()) } } } func TestRemotePathHasTraversal(t *testing.T) { for _, path := range []string{"../x", "desktop:../../x", "foo/../bar"} { if !remotePathHasTraversal(path) { t.Fatalf("expected traversal for %q", path) } } for _, path := range []string{"~/Downloads", "notes.txt", "@desktop/report.pdf"} { if remotePathHasTraversal(path) { t.Fatalf("safe path flagged as traversal: %q", path) } } } func TestUserDesktopDir(t *testing.T) { dir, err := UserDesktopDir() if err != nil { t.Fatal(err) } if dir == "" { t.Fatal("empty desktop") } }