You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

62 lines
1.8 KiB

package browser
import (
"errors"
"io"
"os"
"path/filepath"
"testing"
"webfilebrowser/internal/config"
)
func TestOpenFileReturnsOnlyARegularFileWithinTheConfiguredRoot(t *testing.T) {
rootPath := t.TempDir()
contents := []byte("byte-identical download")
if err := os.WriteFile(filepath.Join(rootPath, "report.txt"), contents, 0o600); err != nil {
t.Fatal(err)
}
browser, err := New([]config.Root{{Name: "Media", Path: rootPath}})
if err != nil {
t.Fatal(err)
}
file, metadata, err := browser.OpenFile("Media", "report.txt")
if err != nil {
t.Fatalf("OpenFile() error = %v", err)
}
t.Cleanup(func() { _ = file.Close() })
actual, err := io.ReadAll(file)
if err != nil {
t.Fatal(err)
}
if string(actual) != string(contents) {
t.Errorf("OpenFile() bytes = %q, want %q", actual, contents)
}
if metadata.Name != "report.txt" || metadata.Size != int64(len(contents)) {
t.Errorf("OpenFile() metadata = %#v, want report.txt with its byte size", metadata)
}
}
func TestOpenFileRejectsTraversalAndSymlinkEscapes(t *testing.T) {
rootPath := t.TempDir()
outsidePath := t.TempDir()
if err := os.WriteFile(filepath.Join(outsidePath, "secret.txt"), []byte("outside-root"), 0o600); err != nil {
t.Fatal(err)
}
if err := os.Symlink(filepath.Join(outsidePath, "secret.txt"), filepath.Join(rootPath, "escape.txt")); err != nil {
t.Fatal(err)
}
browser, err := New([]config.Root{{Name: "Media", Path: rootPath}})
if err != nil {
t.Fatal(err)
}
for _, relativePath := range []string{"../" + filepath.Base(outsidePath) + "/secret.txt", "escape.txt"} {
t.Run(relativePath, func(t *testing.T) {
if _, _, err := browser.OpenFile("Media", relativePath); !errors.Is(err, ErrPathOutsideRoot) {
t.Errorf("OpenFile(%q) error = %v, want ErrPathOutsideRoot", relativePath, err)
}
})
}
}