From a04c5c2f6f0df0c61138454e30907171685c6afa Mon Sep 17 00:00:00 2001 From: Willy Kloucek Date: Fri, 22 Apr 2022 16:31:33 +0200 Subject: [PATCH] implement thumbnails also for webdav and non remote.php routes --- extensions/proxy/pkg/middleware/basic_auth.go | 1 + extensions/webdav/pkg/constants/constants.go | 8 ++ .../webdav/pkg/dav/requests/thumbnail.go | 43 ++----- extensions/webdav/pkg/service/v0/service.go | 107 +++++++++++++++--- 4 files changed, 111 insertions(+), 48 deletions(-) create mode 100644 extensions/webdav/pkg/constants/constants.go diff --git a/extensions/proxy/pkg/middleware/basic_auth.go b/extensions/proxy/pkg/middleware/basic_auth.go index 425fc4ca0a..4b810ae279 100644 --- a/extensions/proxy/pkg/middleware/basic_auth.go +++ b/extensions/proxy/pkg/middleware/basic_auth.go @@ -115,6 +115,7 @@ func (m basicAuth) isPublicLink(req *http.Request) bool { } publicPaths := []string{ + "/dav/public-files/", "/remote.php/dav/public-files/", "/remote.php/ocs/apps/files_sharing/api/v1/tokeninfo/unprotected", "/ocs/v1.php/cloud/capabilities", diff --git a/extensions/webdav/pkg/constants/constants.go b/extensions/webdav/pkg/constants/constants.go new file mode 100644 index 0000000000..3456ab8309 --- /dev/null +++ b/extensions/webdav/pkg/constants/constants.go @@ -0,0 +1,8 @@ +package constants + +type contextKey int + +const ( + ContextKeyID contextKey = iota + ContextKeyPath +) diff --git a/extensions/webdav/pkg/dav/requests/thumbnail.go b/extensions/webdav/pkg/dav/requests/thumbnail.go index 48b80ad488..ccb6016d3b 100644 --- a/extensions/webdav/pkg/dav/requests/thumbnail.go +++ b/extensions/webdav/pkg/dav/requests/thumbnail.go @@ -7,9 +7,10 @@ import ( "net/url" "path/filepath" "strconv" - "strings" "github.com/go-chi/chi/v5" + + "github.com/owncloud/ocis/extensions/webdav/pkg/constants" ) const ( @@ -39,12 +40,16 @@ type ThumbnailRequest struct { // ParseThumbnailRequest extracts all required parameters from a http request. func ParseThumbnailRequest(r *http.Request) (*ThumbnailRequest, error) { - fp, id, err := extractFilePath(r) - if err != nil { - return nil, err - } - q := r.URL.Query() + ctx := r.Context() + fp := ctx.Value(constants.ContextKeyPath).(string) + if fp == "" { + return nil, errors.New("invalid file path") + } + + id := ctx.Value(constants.ContextKeyID).(string) + + q := r.URL.Query() width, height, err := parseDimensions(q) if err != nil { return nil, err @@ -61,32 +66,6 @@ func ParseThumbnailRequest(r *http.Request) (*ThumbnailRequest, error) { }, nil } -// the url looks as followed -// -// /remote.php/dav/files// -// -// User and filepath are dynamic and filepath can contain slashes -// So using the URLParam function is not possible. -func extractFilePath(r *http.Request) (string, string, error) { - id := chi.URLParam(r, "id") - id, err := url.QueryUnescape(id) - if err != nil { - return "", "", errors.New("could not unescape user") - } - if id != "" { - parts := strings.SplitN(r.URL.Path, id, 2) - return parts[1], id, nil - } - - // This is for public links - token := chi.URLParam(r, "token") - if token != "" { - parts := strings.SplitN(r.URL.Path, token, 2) - return parts[1], "", nil - } - return "", "", errors.New("could not extract file path") -} - func parseDimensions(q url.Values) (int64, int64, error) { width, err := parseDimension(q.Get("x"), "width", DefaultWidth) if err != nil { diff --git a/extensions/webdav/pkg/service/v0/service.go b/extensions/webdav/pkg/service/v0/service.go index 844a252d8b..9e1e38882a 100644 --- a/extensions/webdav/pkg/service/v0/service.go +++ b/extensions/webdav/pkg/service/v0/service.go @@ -1,9 +1,14 @@ package svc import ( + "context" "encoding/xml" "io" "net/http" +<<<<<<< HEAD +======= + "net/url" +>>>>>>> 60f1081e8 (implement thumbnails also for webdav and non remote.php routes) "path" "path/filepath" "strings" @@ -11,6 +16,7 @@ import ( gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + revactx "github.com/cs3org/reva/v2/pkg/ctx" "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" "github.com/cs3org/reva/v2/pkg/storage/utils/templates" "github.com/go-chi/render" @@ -21,11 +27,19 @@ import ( "github.com/owncloud/ocis/v2/ocis-pkg/service/grpc" "github.com/go-chi/chi/v5" +<<<<<<< HEAD "github.com/owncloud/ocis/v2/extensions/webdav/pkg/config" "github.com/owncloud/ocis/v2/extensions/webdav/pkg/dav/requests" thumbnailsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/thumbnails/v0" searchsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/search/v0" thumbnailssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/thumbnails/v0" +======= + "github.com/owncloud/ocis/extensions/webdav/pkg/config" + "github.com/owncloud/ocis/extensions/webdav/pkg/constants" + "github.com/owncloud/ocis/extensions/webdav/pkg/dav/requests" + thumbnailsmsg "github.com/owncloud/ocis/protogen/gen/ocis/messages/thumbnails/v0" + thumbnailssvc "github.com/owncloud/ocis/protogen/gen/ocis/services/thumbnails/v0" +>>>>>>> 60f1081e8 (implement thumbnails also for webdav and non remote.php routes) ) const ( @@ -73,26 +87,30 @@ func NewService(opts ...Option) (Service, error) { } m.Route(options.Config.HTTP.Root, func(r chi.Router) { - r.Get("/remote.php/dav/spaces/{id}/*", svc.SpacesThumbnail) - r.Get("/remote.php/dav/files/{id}/*", svc.Thumbnail) - r.Get("/remote.php/dav/public-files/{token}/*", svc.PublicThumbnail) - r.Head("/remote.php/dav/public-files/{token}/*", svc.PublicThumbnailHead) - r.Get("/remote.php/webdav/spaces/{id}/*", svc.SpacesThumbnail) - r.Get("/remote.php/webdav/files/{id}/*", svc.Thumbnail) - r.Get("/remote.php/webdav/public-files/{token}/*", svc.PublicThumbnail) - r.Head("/remote.php/webdav/public-files/{token}/*", svc.PublicThumbnailHead) + r.Group(func(r chi.Router) { + r.Use(svc.DavContext()) - r.Get("/dav/spaces/{id}/*", svc.SpacesThumbnail) - r.Get("/dav/files/{id}/*", svc.Thumbnail) - r.Get("/dav/public-files/{token}/*", svc.PublicThumbnail) - r.Head("/dav/public-files/{token}/*", svc.PublicThumbnailHead) + r.Get("/remote.php/dav/spaces/{id}/*", svc.SpacesThumbnail) + r.Get("/dav/spaces/{id}/*", svc.SpacesThumbnail) - r.Get("/webdav/spaces/{id}/*", svc.SpacesThumbnail) - r.Get("/webdav/files/{id}/*", svc.Thumbnail) - r.Get("/webdav/public-files/{token}/*", svc.PublicThumbnail) - r.Head("/webdav/public-files/{token}/*", svc.PublicThumbnailHead) + r.Get("/remote.php/dav/files/{id}/*", svc.Thumbnail) + r.Get("/dav/files/{id}/*", svc.Thumbnail) + r.Head("/remote.php/dav/public-files/{token}/*", svc.PublicThumbnailHead) + r.Head("/dav/public-files/{token}/*", svc.PublicThumbnailHead) + + r.Get("/remote.php/dav/public-files/{token}/*", svc.PublicThumbnail) + r.Get("/dav/public-files/{token}/*", svc.PublicThumbnail) + }) + + r.Group(func(r chi.Router) { + r.Use(svc.WebdavContext()) + + r.Get("/remote.php/webdav/*", svc.Thumbnail) + r.Get("/webdav/*", svc.Thumbnail) + }) + // r.MethodFunc("REPORT", "/remote.php/dav/files/{id}/*", svc.Search) // This is a workaround for the go-chi concurrent map read write issue. @@ -129,6 +147,63 @@ func (g Webdav) ServeHTTP(w http.ResponseWriter, r *http.Request) { g.mux.ServeHTTP(w, r) } +func (g Webdav) DavContext() func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + id := chi.URLParam(r, "id") + id, err := url.QueryUnescape(id) + if err == nil && id != "" { + ctx = context.WithValue(ctx, constants.ContextKeyID, id) + } + + filePath := r.URL.Path + if id != "" { + filePath = strings.TrimPrefix(filePath, path.Join("/remote.php/dav/spaces", id)+"/") + filePath = strings.TrimPrefix(filePath, path.Join("/dav/spaces", id)+"/") + + filePath = strings.TrimPrefix(filePath, path.Join("/remote.php/dav/files", id)+"/") + filePath = strings.TrimPrefix(filePath, path.Join("/dav/files", id)+"/") + } + + // token for public links + token := chi.URLParam(r, "token") + + if token != "" { + filePath = strings.TrimPrefix(filePath, path.Join("/remote.php/dav/public-files", token)+"/") + filePath = strings.TrimPrefix(filePath, path.Join("/dav/public-files", token)+"/") + } + ctx = context.WithValue(ctx, constants.ContextKeyPath, filePath) + + next.ServeHTTP(w, r.WithContext(ctx)) + + }) + } +} + +func (g Webdav) WebdavContext() func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + u, ok := revactx.ContextGetUser(r.Context()) + if ok { + if u.Id == nil || u.Id.OpaqueId != "" { + ctx = context.WithValue(ctx, constants.ContextKeyID, u.Id.OpaqueId) + } + } + + filePath := r.URL.Path + filePath = strings.TrimPrefix(filePath, "/remote.php/webdav/") + filePath = strings.TrimPrefix(filePath, "/webdav/") + ctx = context.WithValue(ctx, constants.ContextKeyPath, filePath) + + next.ServeHTTP(w, r.WithContext(ctx)) + }) + } +} + // SpacesThumbnail is the endpoint for retrieving thumbnails inside of spaces. func (g Webdav) SpacesThumbnail(w http.ResponseWriter, r *http.Request) { tr, err := requests.ParseThumbnailRequest(r)