package server import ( "net/http" "net/url" "os" "path/filepath" "testing" "time" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/pkg/fs" ) func TestJoinUnderBase(t *testing.T) { base := t.TempDir() // Normal join out, err := joinUnderBase(base, "a/b/c.txt") assert.NoError(t, err) assert.Equal(t, filepath.Join(base, "a/b/c.txt"), out) // Absolute rejected _, err = joinUnderBase(base, "/etc/passwd") assert.Error(t, err) // Parent traversal rejected _, err = joinUnderBase(base, "../../etc/passwd") assert.Error(t, err) } func TestWebDAVFileName_PathTraversalRejected(t *testing.T) { dir := t.TempDir() // Create a legitimate file inside base to ensure happy-path works later. insideFile := filepath.Join(dir, "ok.txt") assert.NoError(t, fs.WriteString(insideFile, "ok")) conf := newWebDAVTestConfig(t) conf.Options().OriginalsPath = dir r := gin.New() grp := r.Group(conf.BaseUri(WebDAVOriginals)) // Attempt traversal to outside path. req := &http.Request{Method: http.MethodPut} req.URL = &url.URL{Path: conf.BaseUri(WebDAVOriginals) + "/../../etc/passwd"} got := WebDAVFileName(req, grp, conf) assert.Equal(t, "", got, "should reject traversal") // Happy path: file under base resolves and exists. req2 := &http.Request{Method: http.MethodPut} req2.URL = &url.URL{Path: conf.BaseUri(WebDAVOriginals) + "/ok.txt"} got = WebDAVFileName(req2, grp, conf) assert.Equal(t, insideFile, got) } func TestWebDAVFileName_MethodNotPut(t *testing.T) { conf := newWebDAVTestConfig(t) r := gin.New() grp := r.Group(conf.BaseUri(WebDAVOriginals)) req := &http.Request{Method: http.MethodGet} req.URL = &url.URL{Path: conf.BaseUri(WebDAVOriginals) + "/anything.jpg"} got := WebDAVFileName(req, grp, conf) assert.Equal(t, "", got) } func TestWebDAVFileName_ImportBasePath(t *testing.T) { conf := newWebDAVTestConfig(t) r := gin.New() grp := r.Group(conf.BaseUri(WebDAVImport)) // create a real file under import file := filepath.Join(conf.ImportPath(), "in.jpg") assert.NoError(t, fs.MkdirAll(filepath.Dir(file))) assert.NoError(t, fs.WriteString(file, "x")) req := &http.Request{Method: http.MethodPut} req.URL = &url.URL{Path: conf.BaseUri(WebDAVImport) + "/in.jpg"} got := WebDAVFileName(req, grp, conf) assert.Equal(t, file, got) } func TestWebDAVSetFileMtime_FutureIgnored(t *testing.T) { dir := t.TempDir() file := filepath.Join(dir, "a.txt") assert.NoError(t, fs.WriteString(file, "x")) before, _ := os.Stat(file) future := time.Now().Add(2 * time.Hour).Unix() WebDAVSetFileMtime(file, future) after, _ := os.Stat(file) assert.Equal(t, before.ModTime().Unix(), after.ModTime().Unix()) } func newWebDAVTestConfig(t *testing.T) *config.Config { return config.NewMinimalTestConfig(t.TempDir()) }