diff --git a/internal/http/services/owncloud/ocdav/copy.go b/internal/http/services/owncloud/ocdav/copy.go index d38d3f0d64..6c710f7847 100644 --- a/internal/http/services/owncloud/ocdav/copy.go +++ b/internal/http/services/owncloud/ocdav/copy.go @@ -486,6 +486,25 @@ func (s *svc) executeSpacesCopy(ctx context.Context, w http.ResponseWriter, clie } func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, srcRef, dstRef *provider.Reference, log *zerolog.Logger) *copy { + client, err := s.getClient() + if err != nil { + log.Error().Err(err).Msg("error getting grpc client") + w.WriteHeader(http.StatusInternalServerError) + return nil + } + + isChild, err := s.referenceIsChildOf(ctx, client, dstRef, srcRef) + if err != nil { + log.Error().Err(err).Msg("error while trying to detect recursive move operation") + w.WriteHeader(http.StatusInternalServerError) + } + if isChild { + w.WriteHeader(http.StatusBadRequest) + b, err := errors.Marshal(http.StatusBadRequest, "can not copy a folder into one of its children", "") + errors.HandleWebdavError(log, w, b, err) + return nil + } + oh := r.Header.Get(net.HeaderOverwrite) overwrite, err := net.ParseOverwrite(oh) if err != nil { @@ -513,13 +532,6 @@ func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Re log.Debug().Bool("overwrite", overwrite).Str("depth", depth.String()).Msg("copy") - client, err := s.getClient() - if err != nil { - log.Error().Err(err).Msg("error getting grpc client") - w.WriteHeader(http.StatusInternalServerError) - return nil - } - srcStatReq := &provider.StatRequest{Ref: srcRef} srcStatRes, err := client.Stat(ctx, srcStatReq) if err != nil { diff --git a/internal/http/services/owncloud/ocdav/move.go b/internal/http/services/owncloud/ocdav/move.go index 562df4b254..e7ec160ad4 100644 --- a/internal/http/services/owncloud/ocdav/move.go +++ b/internal/http/services/owncloud/ocdav/move.go @@ -132,19 +132,31 @@ func (s *svc) handleSpacesMove(w http.ResponseWriter, r *http.Request, srcSpaceI } func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Request, src, dst *provider.Reference, log zerolog.Logger) { - oh := r.Header.Get(net.HeaderOverwrite) - log.Debug().Str("overwrite", oh).Msg("move") + client, err := s.getClient() + if err != nil { + log.Error().Err(err).Msg("error getting grpc client") + w.WriteHeader(http.StatusInternalServerError) + return + } - overwrite, err := net.ParseOverwrite(oh) + isChild, err := s.referenceIsChildOf(ctx, client, dst, src) if err != nil { + log.Error().Err(err).Msg("error while trying to detect recursive move operation") + w.WriteHeader(http.StatusInternalServerError) + } + if isChild { w.WriteHeader(http.StatusBadRequest) + b, err := errors.Marshal(http.StatusBadRequest, "can not move a folder into one of its children", "") + errors.HandleWebdavError(&log, w, b, err) return } - client, err := s.getClient() + oh := r.Header.Get(net.HeaderOverwrite) + log.Debug().Str("overwrite", oh).Msg("move") + + overwrite, err := net.ParseOverwrite(oh) if err != nil { - log.Error().Err(err).Msg("error getting grpc client") - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusBadRequest) return } diff --git a/internal/http/services/owncloud/ocdav/ocdav.go b/internal/http/services/owncloud/ocdav/ocdav.go index 1de9831c88..acf1b63cf3 100644 --- a/internal/http/services/owncloud/ocdav/ocdav.go +++ b/internal/http/services/owncloud/ocdav/ocdav.go @@ -27,8 +27,10 @@ import ( "github.com/ReneKroon/ttlcache/v2" gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net" "github.com/cs3org/reva/v2/pkg/appctx" ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" @@ -42,6 +44,7 @@ import ( "github.com/cs3org/reva/v2/pkg/storage/favorite/registry" "github.com/cs3org/reva/v2/pkg/storage/utils/templates" rtrace "github.com/cs3org/reva/v2/pkg/trace" + "github.com/cs3org/reva/v2/pkg/utils" "github.com/mitchellh/mapstructure" "github.com/rs/zerolog" "go.opentelemetry.io/otel/trace" @@ -384,3 +387,28 @@ func addAccessHeaders(w http.ResponseWriter, r *http.Request) { headers.Set("Strict-Transport-Security", "max-age=63072000") } } + +func (s *svc) referenceIsChildOf(ctx context.Context, client gatewayv1beta1.GatewayAPIClient, child, parent *provider.Reference) (bool, error) { + if utils.ResourceIDEqual(child.ResourceId, parent.ResourceId) { + return strings.HasPrefix(child.Path, parent.Path+"/"), nil // Relative to the same resource -> compare paths + } + + if child.ResourceId.StorageId != parent.ResourceId.StorageId { + return false, nil // Not on the same storage -> not a child + } + + // the references are on the same storage but relative to different resources + // -> we need to get the path for both resources + childPathRes, err := client.GetPath(ctx, &provider.GetPathRequest{ResourceId: child.ResourceId}) + if err != nil { + return false, err + } + parentPathRes, err := client.GetPath(ctx, &provider.GetPathRequest{ResourceId: parent.ResourceId}) + if err != nil { + return false, err + } + + return strings.HasPrefix( + path.Join(childPathRes.Path, child.Path), + path.Join(parentPathRes.Path, parent.Path)+"/"), nil +}