Skip to content

Commit

Permalink
[full-ci] disable DEPTH infinity in PROPFIND (#4278)
Browse files Browse the repository at this point in the history
* disable DEPTH infinity in PROPFIND

* [full-ci] use ocis

* [full-ci use ocis master]

---------

Co-authored-by: Roman Perekhod <rperekhod@owncloud.com>
  • Loading branch information
2403905 and 2403905 authored Nov 16, 2023
1 parent 4c665a7 commit a5f1195
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 37 deletions.
9 changes: 9 additions & 0 deletions changelog/unreleased/disable-depth-infinity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Bugfix: Disable DEPTH infinity in PROPFIND

Disabled DEPTH infinity in PROPFIND for
Personal /remote.php/dav/files/admin
Public link share /remote.php/dav/public-files/<token>
Trashbin /remote.php/dav/spaces/trash-bin/<personal-space-id>

https://github.com/cs3org/reva/pull/4278
https://github.com/owncloud/ocis/issues/7359
43 changes: 30 additions & 13 deletions internal/http/services/owncloud/ocdav/propfind/propfind.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,33 @@ func (p *Handler) HandlePathPropfind(w http.ResponseWriter, r *http.Request, ns
fn := path.Join(ns, r.URL.Path) // TODO do we still need to jail if we query the registry about the spaces?

sublog := appctx.GetLogger(ctx).With().Str("path", fn).Logger()
dh := r.Header.Get(net.HeaderDepth)

depth, err := net.ParseDepth(dh)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, "Invalid Depth header value")
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
sublog.Debug().Str("depth", dh).Msg(err.Error())
w.WriteHeader(http.StatusBadRequest)
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
b, err := errors.Marshal(http.StatusBadRequest, m, "")
errors.HandleWebdavError(&sublog, w, b, err)
return
}

if depth == net.DepthInfinity && !p.c.AllowPropfindDepthInfinitiy {
span.RecordError(errors.ErrInvalidDepth)
span.SetStatus(codes.Error, "DEPTH: infinity is not supported")
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
sublog.Debug().Str("depth", dh).Msg(errors.ErrInvalidDepth.Error())
w.WriteHeader(http.StatusBadRequest)
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
b, err := errors.Marshal(http.StatusBadRequest, m, "")
errors.HandleWebdavError(&sublog, w, b, err)
return
}

pf, status, err := ReadPropfind(r.Body)
if err != nil {
sublog.Debug().Err(err).Msg("error reading propfind request")
Expand Down Expand Up @@ -218,7 +245,7 @@ func (p *Handler) HandlePathPropfind(w http.ResponseWriter, r *http.Request, ns
return
}

resourceInfos, sendTusHeaders, ok := p.getResourceInfos(ctx, w, r, pf, spaces, fn, sublog)
resourceInfos, sendTusHeaders, ok := p.getResourceInfos(ctx, w, r, pf, spaces, fn, depth, sublog)
if !ok {
// getResourceInfos handles responses in case of an error so we can just return here.
return
Expand Down Expand Up @@ -462,21 +489,11 @@ func (p *Handler) statSpace(ctx context.Context, client gateway.GatewayAPIClient
return res.GetInfo(), res.GetStatus(), nil
}

func (p *Handler) getResourceInfos(ctx context.Context, w http.ResponseWriter, r *http.Request, pf XML, spaces []*provider.StorageSpace, requestPath string, log zerolog.Logger) ([]*provider.ResourceInfo, bool, bool) {
func (p *Handler) getResourceInfos(ctx context.Context, w http.ResponseWriter, r *http.Request, pf XML, spaces []*provider.StorageSpace, requestPath string, depth net.Depth, log zerolog.Logger) ([]*provider.ResourceInfo, bool, bool) {
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "get_resource_infos")
span.SetAttributes(attribute.KeyValue{Key: "requestPath", Value: attribute.StringValue(requestPath)})
defer span.End()

dh := r.Header.Get(net.HeaderDepth)
depth, err := net.ParseDepth(dh)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
b, err := errors.Marshal(http.StatusBadRequest, m, "")
errors.HandleWebdavError(&log, w, b, err)
return nil, false, false
}
span.SetAttributes(attribute.KeyValue{Key: "depth", Value: attribute.StringValue(depth.String())})
defer span.End()

client, err := p.selector.Next()
if err != nil {
Expand Down
22 changes: 1 addition & 21 deletions internal/http/services/owncloud/ocdav/propfind/propfind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1460,27 +1460,7 @@ var _ = Describe("PropfindWithoutDepthInfinity", func() {
req.Header.Add(net.HeaderDepth, "infinity")

handler.HandlePathPropfind(rr, req, "/")
Expect(rr.Code).To(Equal(http.StatusMultiStatus))

res, _, err := readResponse(rr.Result().Body)
Expect(err).ToNot(HaveOccurred())
Expect(len(res.Responses)).To(Equal(9))

paths := []string{}
for _, r := range res.Responses {
paths = append(paths, r.Href)
}
Expect(paths).To(ConsistOf(
"http:/127.0.0.1:3000/foo/",
"http:/127.0.0.1:3000/foo/bar",
"http:/127.0.0.1:3000/foo/baz",
"http:/127.0.0.1:3000/foo/dir/",
"http:/127.0.0.1:3000/foo/dir/entry",
"http:/127.0.0.1:3000/foo/Shares/sharedFile",
"http:/127.0.0.1:3000/foo/Shares/sharedFile2",
"http:/127.0.0.1:3000/foo/Shares/sharedDir/",
"http:/127.0.0.1:3000/foo/Shares/sharedDir/something",
))
Expect(rr.Code).To(Equal(http.StatusBadRequest))
})
})

Expand Down
24 changes: 23 additions & 1 deletion internal/http/services/owncloud/ocdav/publicfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@ package ocdav

import (
"context"
"fmt"
"net/http"
"path"

provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/rhttp/router"
"go.opentelemetry.io/otel/codes"
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
)

// PublicFileHandler handles requests on a shared file. it needs to be wrapped in a collection
Expand Down Expand Up @@ -99,8 +103,26 @@ func (s *svc) handlePropfindOnToken(w http.ResponseWriter, r *http.Request, ns s
dh := r.Header.Get(net.HeaderDepth)
depth, err := net.ParseDepth(dh)
if err != nil {
sublog.Debug().Msg(err.Error())
span.RecordError(err)
span.SetStatus(codes.Error, "Invalid Depth header value")
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
sublog.Debug().Str("depth", dh).Msg(err.Error())
w.WriteHeader(http.StatusBadRequest)
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
b, err := errors.Marshal(http.StatusBadRequest, m, "")
errors.HandleWebdavError(&sublog, w, b, err)
return
}

if depth == net.DepthInfinity && !s.c.AllowPropfindDepthInfinitiy {
span.RecordError(errors.ErrInvalidDepth)
span.SetStatus(codes.Error, "DEPTH: infinity is not supported")
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
sublog.Debug().Str("depth", dh).Msg(errors.ErrInvalidDepth.Error())
w.WriteHeader(http.StatusBadRequest)
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
b, err := errors.Marshal(http.StatusBadRequest, m, "")
errors.HandleWebdavError(&sublog, w, b, err)
return
}

Expand Down
26 changes: 24 additions & 2 deletions internal/http/services/owncloud/ocdav/trashbin.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/spacelookup"
"github.com/cs3org/reva/v2/pkg/storagespace"
"go.opentelemetry.io/otel/codes"

rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
Expand All @@ -44,17 +45,20 @@ import (
rstatus "github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/cs3org/reva/v2/pkg/rhttp/router"
"github.com/cs3org/reva/v2/pkg/utils"
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
)

// TrashbinHandler handles trashbin requests
type TrashbinHandler struct {
gatewaySvc string
namespace string
gatewaySvc string
namespace string
allowPropfindDepthInfinitiy bool
}

func (h *TrashbinHandler) init(c *config.Config) error {
h.gatewaySvc = c.GatewaySvc
h.namespace = path.Join("/", c.FilesNamespace)
h.allowPropfindDepthInfinitiy = c.AllowPropfindDepthInfinitiy
return nil
}

Expand Down Expand Up @@ -186,8 +190,26 @@ func (h *TrashbinHandler) listTrashbin(w http.ResponseWriter, r *http.Request, s
dh := r.Header.Get(net.HeaderDepth)
depth, err := net.ParseDepth(dh)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, "Invalid Depth header value")
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
sublog.Debug().Str("depth", dh).Msg(err.Error())
w.WriteHeader(http.StatusBadRequest)
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
b, err := errors.Marshal(http.StatusBadRequest, m, "")
errors.HandleWebdavError(&sublog, w, b, err)
return
}

if depth == net.DepthInfinity && !h.allowPropfindDepthInfinitiy {
span.RecordError(errors.ErrInvalidDepth)
span.SetStatus(codes.Error, "DEPTH: infinity is not supported")
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
sublog.Debug().Str("depth", dh).Msg(errors.ErrInvalidDepth.Error())
w.WriteHeader(http.StatusBadRequest)
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
b, err := errors.Marshal(http.StatusBadRequest, m, "")
errors.HandleWebdavError(&sublog, w, b, err)
return
}

Expand Down

0 comments on commit a5f1195

Please sign in to comment.