From c6961000b5368e3f2e1518e0ec660b5f390b4c4b Mon Sep 17 00:00:00 2001 From: jkoberg Date: Tue, 5 Apr 2022 16:12:00 +0200 Subject: [PATCH 1/4] quicklink functionality Signed-off-by: jkoberg --- .../handlers/apps/sharing/shares/public.go | 64 ++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go index 2f4da7830f..6adc38a08f 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go @@ -37,6 +37,10 @@ import ( "github.com/pkg/errors" ) +// QuicklinkName is the reserved name for a quicklink. +// Creating (or updating) a link with (to) the same name will be blocked by the server +var QuicklinkName = "Quicklink" + func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, statInfo *provider.ResourceInfo) (*link.PublicShare, *ocsError) { ctx := r.Context() log := appctx.GetLogger(ctx) @@ -59,6 +63,54 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, } } + // check reserved names + linkname := r.FormValue("name") + quick, _ := strconv.ParseBool(r.FormValue("quicklink")) // no need to check the error - defaults to zero value! + if !quick && linkname == QuicklinkName { + return nil, &ocsError{ + Code: response.MetaBadRequest.StatusCode, + Message: fmt.Sprintf("not allowed to use `%s` as name", linkname), + } + + } + + // check if a quicklink should be created + if quick { + _, f, err := h.addFilters(w, r, &provider.Reference{ResourceId: statInfo.Id}) + if err != nil { + log.Error().Err(err).Msg("could not add filters") + return nil, &ocsError{ + Code: response.MetaServerError.StatusCode, + Message: "could not add filters", + Error: err, + } + } + + req := link.ListPublicSharesRequest{Filters: f} + res, err := c.ListPublicShares(ctx, &req) + if err != nil { + return nil, &ocsError{ + Code: response.MetaServerError.StatusCode, + Message: "could not list public links", + Error: err, + } + } + if res.Status.Code != rpc.Code_CODE_OK { + return nil, &ocsError{ + Code: int(res.Status.GetCode()), + Message: "could not list public links", + } + } + + for _, l := range res.GetShare() { + if l.DisplayName == QuicklinkName { + return l, nil + } + } + + linkname = QuicklinkName + } + newPermissions, err := permissionFromRequest(r, h) if err != nil { return nil, &ocsError{ @@ -120,7 +172,7 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, // set displayname and password protected as arbitrary metadata req.ResourceInfo.ArbitraryMetadata = &provider.ArbitraryMetadata{ Metadata: map[string]string{ - "name": r.FormValue("name"), + "name": linkname, // "password": r.FormValue("password"), }, } @@ -262,7 +314,15 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar newName, ok := r.Form["name"] if ok { updatesFound = true - if newName[0] != before.Share.DisplayName { + if n := newName[0]; n != before.Share.DisplayName { + if n == QuicklinkName { + response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, fmt.Sprintf("not allowed to rename a link to '%s'", n), nil) + return + } + if before.Share.DisplayName == QuicklinkName { + response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "not allowed to rename a quicklink", nil) + return + } updates = append(updates, &link.UpdatePublicShareRequest_Update{ Type: link.UpdatePublicShareRequest_Update_TYPE_DISPLAYNAME, DisplayName: newName[0], From 99c0c11b3b53854407183f4d07088905c8494f17 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Tue, 5 Apr 2022 16:15:58 +0200 Subject: [PATCH 2/4] changelog Signed-off-by: jkoberg --- changelog/unreleased/quicklinks.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 changelog/unreleased/quicklinks.md diff --git a/changelog/unreleased/quicklinks.md b/changelog/unreleased/quicklinks.md new file mode 100644 index 0000000000..f37df39d4b --- /dev/null +++ b/changelog/unreleased/quicklinks.md @@ -0,0 +1,9 @@ +Enhancement: introduced quicklinks + +We now support Quicklinks. When creating a link with flag "quicklink=true", no new link will be created when a link +already exists. + +Downside: since we can't update cs3api at the moment, we reserve the name `Quicklink` for the quicklink. Trying to create +a link named `Quicklink` without the "quicklink=true" flag will result in a `Bad Request` + +https://github.com/cs3org/reva/pull/2715 From 7657f63d1f14885d21c3cbf5b2ffed4360f60420 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Wed, 6 Apr 2022 09:59:05 +0200 Subject: [PATCH 3/4] avoid extra stat call and const Signed-off-by: jkoberg --- .../ocs/handlers/apps/sharing/shares/public.go | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go index 6adc38a08f..455d09c47b 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go @@ -33,13 +33,14 @@ import ( "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/conversions" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/response" "github.com/cs3org/reva/v2/pkg/appctx" + "github.com/cs3org/reva/v2/pkg/publicshare" "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" "github.com/pkg/errors" ) // QuicklinkName is the reserved name for a quicklink. // Creating (or updating) a link with (to) the same name will be blocked by the server -var QuicklinkName = "Quicklink" +const QuicklinkName = "Quicklink" func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, statInfo *provider.ResourceInfo) (*link.PublicShare, *ocsError) { ctx := r.Context() @@ -76,16 +77,7 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, // check if a quicklink should be created if quick { - _, f, err := h.addFilters(w, r, &provider.Reference{ResourceId: statInfo.Id}) - if err != nil { - log.Error().Err(err).Msg("could not add filters") - return nil, &ocsError{ - Code: response.MetaServerError.StatusCode, - Message: "could not add filters", - Error: err, - } - } - + f := []*link.ListPublicSharesRequest_Filter{publicshare.ResourceIDFilter(statInfo.Id)} req := link.ListPublicSharesRequest{Filters: f} res, err := c.ListPublicShares(ctx, &req) if err != nil { From 52d89535ce5a1eee8605b76c821d50291d6f9bbc Mon Sep 17 00:00:00 2001 From: jkoberg Date: Wed, 6 Apr 2022 16:17:10 +0200 Subject: [PATCH 4/4] use forked cs3api to get access to quicklink field Signed-off-by: jkoberg --- changelog/unreleased/quicklinks.md | 3 -- cmd/reva/preferences.go | 4 +-- go.mod | 1 + go.sum | 6 ++-- .../grpc/services/preferences/preferences.go | 6 ++-- .../services/owncloud/ocs/conversions/main.go | 3 ++ .../handlers/apps/sharing/shares/public.go | 33 +++---------------- pkg/publicshare/manager/cs3/cs3.go | 6 +++- pkg/publicshare/manager/json/json.go | 4 +++ 9 files changed, 25 insertions(+), 41 deletions(-) diff --git a/changelog/unreleased/quicklinks.md b/changelog/unreleased/quicklinks.md index f37df39d4b..1995715526 100644 --- a/changelog/unreleased/quicklinks.md +++ b/changelog/unreleased/quicklinks.md @@ -3,7 +3,4 @@ Enhancement: introduced quicklinks We now support Quicklinks. When creating a link with flag "quicklink=true", no new link will be created when a link already exists. -Downside: since we can't update cs3api at the moment, we reserve the name `Quicklink` for the quicklink. Trying to create -a link named `Quicklink` without the "quicklink=true" flag will result in a `Bad Request` - https://github.com/cs3org/reva/pull/2715 diff --git a/cmd/reva/preferences.go b/cmd/reva/preferences.go index 8a5f86e0a7..dff5e475d1 100644 --- a/cmd/reva/preferences.go +++ b/cmd/reva/preferences.go @@ -55,7 +55,7 @@ var preferencesCommand = func() *command { } value := cmd.Args()[2] req := &preferences.SetKeyRequest{ - Key: key, + Key: &preferences.PreferenceKey{Key: key}, Val: value, } @@ -70,7 +70,7 @@ var preferencesCommand = func() *command { case "get": req := &preferences.GetKeyRequest{ - Key: key, + Key: &preferences.PreferenceKey{Key: key}, } res, err := client.GetKey(ctx, req) diff --git a/go.mod b/go.mod index 90cdb170ee..09f7b789b4 100644 --- a/go.mod +++ b/go.mod @@ -93,6 +93,7 @@ require ( go 1.16 replace ( + github.com/cs3org/go-cs3apis => github.com/kobergj/go-cs3apis v0.0.0-20220406134716-65f04386eb09 // temporary fork github.com/eventials/go-tus => github.com/andrewmostello/go-tus v0.0.0-20200314041820-904a9904af9a github.com/oleiade/reflections => github.com/oleiade/reflections v1.0.1 google.golang.org/grpc => google.golang.org/grpc v1.26.0 // temporary downgrade diff --git a/go.sum b/go.sum index 5d9dd61366..f3583e6b34 100644 --- a/go.sum +++ b/go.sum @@ -207,10 +207,6 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e h1:tqSPWQeueWTKnJVMJffz4pz0o1WuQxJ28+5x5JgaHD8= github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4= -github.com/cs3org/go-cs3apis v0.0.0-20220126114148-64c025ccdd19 h1:1jqPH58jCxvbaJ9WLIJ7W2/m622bWS6ChptzljSG6IQ= -github.com/cs3org/go-cs3apis v0.0.0-20220126114148-64c025ccdd19/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= -github.com/cs3org/go-cs3apis v0.0.0-20220328105952-297bef33e13f h1:emnlOWc1s2gx77MViLnZH9yh5TRHKsykRu6rJjx3lkM= -github.com/cs3org/go-cs3apis v0.0.0-20220328105952-297bef33e13f/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= @@ -639,6 +635,8 @@ github.com/klauspost/compress v1.14.3/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= +github.com/kobergj/go-cs3apis v0.0.0-20220406134716-65f04386eb09 h1:i1caLRatgEscEdtcplmwjxHSVve13rQTuRDxo42FZI8= +github.com/kobergj/go-cs3apis v0.0.0-20220406134716-65f04386eb09/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= diff --git a/internal/grpc/services/preferences/preferences.go b/internal/grpc/services/preferences/preferences.go index 2241a2a8cf..26ed1aceb0 100644 --- a/internal/grpc/services/preferences/preferences.go +++ b/internal/grpc/services/preferences/preferences.go @@ -92,10 +92,10 @@ func (s *service) SetKey(ctx context.Context, req *preferences.SetKeyRequest) (* mutex.Lock() defer mutex.Unlock() if len(m[name]) == 0 { - m[name] = map[string]string{key: value} + m[name] = map[string]string{key.Key: value} } else { usersettings := m[name] - usersettings[key] = value + usersettings[key.Key] = value } return &preferences.SetKeyResponse{ @@ -118,7 +118,7 @@ func (s *service) GetKey(ctx context.Context, req *preferences.GetKeyRequest) (* mutex.Lock() defer mutex.Unlock() if len(m[name]) != 0 { - if value, ok := m[name][key]; ok { + if value, ok := m[name][key.Key]; ok { return &preferences.GetKeyResponse{ Status: status.NewOK(ctx), Val: value, diff --git a/internal/http/services/owncloud/ocs/conversions/main.go b/internal/http/services/owncloud/ocs/conversions/main.go index 553433417a..9abf695cec 100644 --- a/internal/http/services/owncloud/ocs/conversions/main.go +++ b/internal/http/services/owncloud/ocs/conversions/main.go @@ -142,6 +142,8 @@ type ShareData struct { URL string `json:"url,omitempty" xml:"url,omitempty"` // Attributes associated Attributes string `json:"attributes,omitempty" xml:"attributes,omitempty"` + // Quicklink indicates if the link is the quicklink + Quicklink bool `json:"quicklink,omitempty" xml:"quicklink,omitempty"` // PasswordProtected represents a public share is password protected // PasswordProtected bool `json:"password_protected,omitempty" xml:"password_protected,omitempty"` } @@ -233,6 +235,7 @@ func PublicShare2ShareData(share *link.PublicShare, r *http.Request, publicURL s URL: publicURL + path.Join("/", "s/"+share.Token), UIDOwner: LocalUserIDToString(share.Creator), UIDFileOwner: LocalUserIDToString(share.Owner), + Quicklink: share.Quicklink, } if share.Id != nil { sd.ID = share.Id.OpaqueId diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go index 455d09c47b..a56444daaa 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go @@ -38,10 +38,6 @@ import ( "github.com/pkg/errors" ) -// QuicklinkName is the reserved name for a quicklink. -// Creating (or updating) a link with (to) the same name will be blocked by the server -const QuicklinkName = "Quicklink" - func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, statInfo *provider.ResourceInfo) (*link.PublicShare, *ocsError) { ctx := r.Context() log := appctx.GetLogger(ctx) @@ -64,18 +60,8 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, } } - // check reserved names - linkname := r.FormValue("name") - quick, _ := strconv.ParseBool(r.FormValue("quicklink")) // no need to check the error - defaults to zero value! - if !quick && linkname == QuicklinkName { - return nil, &ocsError{ - Code: response.MetaBadRequest.StatusCode, - Message: fmt.Sprintf("not allowed to use `%s` as name", linkname), - } - - } - // check if a quicklink should be created + quick, _ := strconv.ParseBool(r.FormValue("quicklink")) // no need to check the error - defaults to zero value! if quick { f := []*link.ListPublicSharesRequest_Filter{publicshare.ResourceIDFilter(statInfo.Id)} req := link.ListPublicSharesRequest{Filters: f} @@ -95,12 +81,10 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, } for _, l := range res.GetShare() { - if l.DisplayName == QuicklinkName { + if l.Quicklink { return l, nil } } - - linkname = QuicklinkName } newPermissions, err := permissionFromRequest(r, h) @@ -164,7 +148,8 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, // set displayname and password protected as arbitrary metadata req.ResourceInfo.ArbitraryMetadata = &provider.ArbitraryMetadata{ Metadata: map[string]string{ - "name": linkname, + "name": r.FormValue("name"), + "quicklink": r.FormValue("quicklink"), // "password": r.FormValue("password"), }, } @@ -306,15 +291,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar newName, ok := r.Form["name"] if ok { updatesFound = true - if n := newName[0]; n != before.Share.DisplayName { - if n == QuicklinkName { - response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, fmt.Sprintf("not allowed to rename a link to '%s'", n), nil) - return - } - if before.Share.DisplayName == QuicklinkName { - response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "not allowed to rename a quicklink", nil) - return - } + if newName[0] != before.Share.DisplayName { updates = append(updates, &link.UpdatePublicShareRequest_Update{ Type: link.UpdatePublicShareRequest_Update_TYPE_DISPLAYNAME, DisplayName: newName[0], diff --git a/pkg/publicshare/manager/cs3/cs3.go b/pkg/publicshare/manager/cs3/cs3.go index bddbac9528..aff9466449 100644 --- a/pkg/publicshare/manager/cs3/cs3.go +++ b/pkg/publicshare/manager/cs3/cs3.go @@ -24,6 +24,7 @@ import ( "fmt" "net/url" "path" + "strconv" "strings" "sync" "time" @@ -173,12 +174,14 @@ func (m *Manager) CreatePublicShare(ctx context.Context, u *user.User, ri *provi tkn := utils.RandString(15) now := time.Now().UnixNano() - displayName := tkn + displayName, quicklink := tkn, false if ri.ArbitraryMetadata != nil { metadataName, ok := ri.ArbitraryMetadata.Metadata["name"] if ok { displayName = metadataName } + + quicklink, _ = strconv.ParseBool(ri.ArbitraryMetadata.Metadata["quicklink"]) } var passwordProtected bool @@ -210,6 +213,7 @@ func (m *Manager) CreatePublicShare(ctx context.Context, u *user.User, ri *provi PasswordProtected: passwordProtected, Expiration: g.Expiration, DisplayName: displayName, + Quicklink: quicklink, }, HashedPassword: password, } diff --git a/pkg/publicshare/manager/json/json.go b/pkg/publicshare/manager/json/json.go index 7d72cb00b4..311a3ff781 100644 --- a/pkg/publicshare/manager/json/json.go +++ b/pkg/publicshare/manager/json/json.go @@ -26,6 +26,7 @@ import ( "os" "os/signal" "path/filepath" + "strconv" "strings" "sync" "syscall" @@ -159,6 +160,8 @@ func (m *manager) CreatePublicShare(ctx context.Context, u *user.User, rInfo *pr displayName = tkn } + quicklink, _ := strconv.ParseBool(rInfo.ArbitraryMetadata.Metadata["quicklink"]) + var passwordProtected bool password := g.Password if len(password) > 0 { @@ -187,6 +190,7 @@ func (m *manager) CreatePublicShare(ctx context.Context, u *user.User, rInfo *pr PasswordProtected: passwordProtected, Expiration: g.Expiration, DisplayName: displayName, + Quicklink: quicklink, } ps := &publicShare{