diff --git a/changelog/unreleased/space-metafiles.md b/changelog/unreleased/space-metafiles.md new file mode 100644 index 0000000000..021b0d0668 --- /dev/null +++ b/changelog/unreleased/space-metafiles.md @@ -0,0 +1,6 @@ +Enhancement: Prevent the space metafiles manipulation + +Prevent the space metafiles deleting and movin `.space` and `.space/readme.md` via webdav prevent deleting .space + +https://github.com/cs3org/reva/pull/4826 +https://github.com/owncloud/ocis/issues/8719 diff --git a/internal/http/services/owncloud/ocdav/delete.go b/internal/http/services/owncloud/ocdav/delete.go index fd080cf7d9..c454e25177 100644 --- a/internal/http/services/owncloud/ocdav/delete.go +++ b/internal/http/services/owncloud/ocdav/delete.go @@ -23,7 +23,10 @@ import ( "errors" "net/http" "path" + "slices" + "strings" + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/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" @@ -81,6 +84,17 @@ func (s *svc) handleDelete(ctx context.Context, w http.ResponseWriter, r *http.R return http.StatusInternalServerError, errtypes.InternalError(err.Error()) } + sRes, err := client.Stat(ctx, &provider.StatRequest{Ref: ref}) + switch { + case err != nil: + span.RecordError(err) + return http.StatusInternalServerError, err + case sRes.GetStatus().GetCode() == rpc.Code_CODE_OK: + if sRes.GetInfo().GetSpace().GetSpaceType() == "project" && isPathInList(ctx, client, ref, ".space", ".space/readme.md") { + return http.StatusMethodNotAllowed, errors.New("deleting spaces meta file is not allowed") + } + } + res, err := client.Delete(ctx, req) switch { case err != nil: @@ -147,3 +161,17 @@ func (s *svc) handleSpacesDelete(w http.ResponseWriter, r *http.Request, spaceID return s.handleDelete(ctx, w, r, &ref) } + +func isPathInList(ctx context.Context, client gateway.GatewayAPIClient, ref *provider.Reference, paths ...string) bool { + resPath := strings.TrimPrefix(ref.GetPath(), "./") + if ref.GetResourceId().GetOpaqueId() != "" && ref.Path == "." { + gpRes, err := client.GetPath(ctx, &provider.GetPathRequest{ + ResourceId: ref.GetResourceId(), + }) + if err != nil || gpRes.GetStatus().GetCode() != rpc.Code_CODE_OK { + return false + } + resPath = strings.TrimPrefix(gpRes.GetPath(), "/") + } + return slices.Contains(paths, resPath) +} diff --git a/internal/http/services/owncloud/ocdav/move.go b/internal/http/services/owncloud/ocdav/move.go index 79a6bbd563..af173e9eaa 100644 --- a/internal/http/services/owncloud/ocdav/move.go +++ b/internal/http/services/owncloud/ocdav/move.go @@ -224,6 +224,11 @@ func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Req w.WriteHeader(http.StatusBadRequest) return } + if srcStatRes.GetInfo().GetSpace().GetSpaceType() == "project" && isPathInList(ctx, client, src, ".space", ".space/readme.md") { + log.Error().Msg("moving spaces meta file is not allowed") + w.WriteHeader(http.StatusMethodNotAllowed) + return + } // check dst exists dstStatReq := &provider.StatRequest{Ref: dst}