diff --git a/http/http.go b/http/http.go index 6afda6fa..bc798561 100644 --- a/http/http.go +++ b/http/http.go @@ -57,7 +57,7 @@ func NewHandler( api.PathPrefix("/resources").Handler(monkey(resourceDeleteHandler(fileCache), "/api/resources")).Methods("DELETE") api.PathPrefix("/resources").Handler(monkey(resourcePostHandler(fileCache), "/api/resources")).Methods("POST") api.PathPrefix("/resources").Handler(monkey(resourcePutHandler, "/api/resources")).Methods("PUT") - api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler, "/api/resources")).Methods("PATCH") + api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler(fileCache), "/api/resources")).Methods("PATCH") api.Path("/shares").Handler(monkey(shareListHandler, "/api/shares")).Methods("GET") api.PathPrefix("/share").Handler(monkey(shareGetsHandler, "/api/share")).Methods("GET") diff --git a/http/resource.go b/http/resource.go index c6902476..1b4e180e 100644 --- a/http/resource.go +++ b/http/resource.go @@ -180,64 +180,84 @@ var resourcePutHandler = withUser(func(w http.ResponseWriter, r *http.Request, d return errToStatus(err), err }) -var resourcePatchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { - src := r.URL.Path - dst := r.URL.Query().Get("destination") - action := r.URL.Query().Get("action") - dst, err := url.QueryUnescape(dst) - if !d.Check(src) || !d.Check(dst) { - return http.StatusForbidden, nil - } - if err != nil { +func resourcePatchHandler(fileCache FileCache) handleFunc { + return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { + src := r.URL.Path + dst := r.URL.Query().Get("destination") + action := r.URL.Query().Get("action") + dst, err := url.QueryUnescape(dst) + if !d.Check(src) || !d.Check(dst) { + return http.StatusForbidden, nil + } + if err != nil { + return errToStatus(err), err + } + if dst == "/" || src == "/" { + return http.StatusForbidden, nil + } + if err = checkParent(src, dst); err != nil { + return http.StatusBadRequest, err + } + + override := r.URL.Query().Get("override") == "true" + rename := r.URL.Query().Get("rename") == "true" + if !override && !rename { + if _, err = d.user.Fs.Stat(dst); err == nil { + return http.StatusConflict, nil + } + } + if rename { + dst = addVersionSuffix(dst, d.user.Fs) + } + + // Permission for overwriting the file + if override && !d.user.Perm.Modify { + return http.StatusForbidden, nil + } + + file, err := files.NewFileInfo(files.FileOptions{ + Fs: d.user.Fs, + Path: r.URL.Path, + Modify: d.user.Perm.Modify, + Expand: false, + ReadHeader: d.server.TypeDetectionByHeader, + Checker: d, + }) + if err != nil { + return errToStatus(err), err + } + + err = d.RunHook(func() error { + switch action { + // TODO: use enum + case "copy": + if !d.user.Perm.Create { + return errors.ErrPermissionDenied + } + + return fileutils.Copy(d.user.Fs, src, dst) + case "rename": + if !d.user.Perm.Rename { + return errors.ErrPermissionDenied + } + src = path.Clean("/" + src) + dst = path.Clean("/" + dst) + + // delete thumbnails + err = delThumbs(r.Context(), fileCache, file) + if err != nil { + return err + } + + return fileutils.MoveFile(d.user.Fs, src, dst) + default: + return fmt.Errorf("unsupported action %s: %w", action, errors.ErrInvalidRequestParams) + } + }, action, src, dst, d.user) + return errToStatus(err), err - } - if dst == "/" || src == "/" { - return http.StatusForbidden, nil - } - if err = checkParent(src, dst); err != nil { - return http.StatusBadRequest, err - } - - override := r.URL.Query().Get("override") == "true" - rename := r.URL.Query().Get("rename") == "true" - if !override && !rename { - if _, err = d.user.Fs.Stat(dst); err == nil { - return http.StatusConflict, nil - } - } - if rename { - dst = addVersionSuffix(dst, d.user.Fs) - } - - // Permission for overwriting the file - if override && !d.user.Perm.Modify { - return http.StatusForbidden, nil - } - - err = d.RunHook(func() error { - switch action { - // TODO: use enum - case "copy": - if !d.user.Perm.Create { - return errors.ErrPermissionDenied - } - - return fileutils.Copy(d.user.Fs, src, dst) - case "rename": - if !d.user.Perm.Rename { - return errors.ErrPermissionDenied - } - src = path.Clean("/" + src) - dst = path.Clean("/" + dst) - - return fileutils.MoveFile(d.user.Fs, src, dst) - default: - return fmt.Errorf("unsupported action %s: %w", action, errors.ErrInvalidRequestParams) - } - }, action, src, dst, d.user) - - return errToStatus(err), err -}) + }) +} func checkParent(src, dst string) error { rel, err := filepath.Rel(src, dst)