Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

return share-types in ocs propfind responses #1329

Merged
merged 2 commits into from
Dec 9, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog/unreleased/ocis-ocs-share-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: include share types in ocs propfind responses

Added the share types to the ocs propfind response when a resource has been shared.

https://github.com/owncloud/ocis/issues/929
https://github.com/cs3org/reva/pull/1329
5 changes: 3 additions & 2 deletions internal/grpc/services/gateway/storageprovider.go
Original file line number Diff line number Diff line change
@@ -1249,13 +1249,14 @@ func (s *svc) ListContainerStream(_ *provider.ListContainerStreamRequest, _ gate
return errtypes.NotSupported("Unimplemented")
}

func (s *svc) listHome(ctx context.Context) (*provider.ListContainerResponse, error) {
func (s *svc) listHome(ctx context.Context, req *provider.ListContainerRequest) (*provider.ListContainerResponse, error) {
lcr, err := s.listContainer(ctx, &provider.ListContainerRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{
Path: s.getHome(ctx),
},
},
ArbitraryMetadataKeys: req.ArbitraryMetadataKeys,
})
if err != nil {
return &provider.ListContainerResponse{
@@ -1361,7 +1362,7 @@ func (s *svc) ListContainer(ctx context.Context, req *provider.ListContainerRequ
}

if path.Clean(p) == s.getHome(ctx) {
return s.listHome(ctx)
return s.listHome(ctx, req)
}

if s.isSharedFolder(ctx, p) {
21 changes: 15 additions & 6 deletions internal/http/services/owncloud/ocdav/propfind.go
Original file line number Diff line number Diff line change
@@ -108,6 +108,9 @@ func (s *svc) handlePropfind(w http.ResponseWriter, r *http.Request, ns string)
if info.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER && depth == "1" {
req := &provider.ListContainerRequest{
Ref: ref,
ArbitraryMetadataKeys: []string{
"http://owncloud.org/ns/share-types",
},
}
res, err := client.ListContainer(ctx, req)
if err != nil {
@@ -143,6 +146,9 @@ func (s *svc) handlePropfind(w http.ResponseWriter, r *http.Request, ns string)
}
req := &provider.ListContainerRequest{
Ref: ref,
ArbitraryMetadataKeys: []string{
"http://owncloud.org/ns/share-types",
},
}
res, err := client.ListContainer(ctx, req)
if err != nil {
@@ -284,7 +290,6 @@ func (s *svc) newProp(key, val string) *propertyXML {
// ns is the CS3 namespace that needs to be removed from the CS3 path before
// prefixing it with the baseURI
func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provider.ResourceInfo, ns string) (*responseXML, error) {

md.Path = strings.TrimPrefix(md.Path, ns)

baseURI := ctx.Value(ctxKeyBaseURI).(string)
@@ -442,6 +447,15 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide
} else {
propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:checksums", ""))
}
case "share-types": // desktop
k := md.GetArbitraryMetadata()
amd := k.GetMetadata()
if amdv, ok := amd[fmt.Sprintf("%s/%s", pf.Prop[i].Space, pf.Prop[i].Local)]; ok {
st := fmt.Sprintf("<oc:share-type>%s</oc:share-type>", amdv)
propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:share-types", st))
} else {
propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:"+pf.Prop[i].Local, ""))
}
case "owner-display-name": // phoenix only
// TODO(jfd): lookup displayname? or let clients do that? They should cache that IMO
fallthrough
@@ -459,11 +473,6 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide
// see https://doc.owncloud.com/server/admin_manual/configuration/server/occ_command.html#maintenance-commands
// TODO(jfd): double check the client behavior with reva on backup restore
fallthrough
case "share-types": // desktop
// <oc:share-types>
// <oc:share-type>1</oc:share-type>
// </oc:share-types>
fallthrough
default:
propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:"+pf.Prop[i].Local, ""))
}
4 changes: 2 additions & 2 deletions pkg/storage/fs/ocis/grants.go
Original file line number Diff line number Diff line change
@@ -124,9 +124,9 @@ func (fs *ocisfs) RemoveGrant(ctx context.Context, ref *provider.Reference, g *p

var attr string
if g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
attr = grantPrefix + "g:" + g.Grantee.Id.OpaqueId
attr = grantPrefix + _groupAcePrefix + g.Grantee.Id.OpaqueId
} else {
attr = grantPrefix + "u:" + g.Grantee.Id.OpaqueId
attr = grantPrefix + _userAcePrefix + g.Grantee.Id.OpaqueId
}

np := fs.lu.toInternalPath(node.ID)
29 changes: 28 additions & 1 deletion pkg/storage/fs/ocis/node.go
Original file line number Diff line number Diff line change
@@ -34,12 +34,18 @@ import (
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/mime"
"github.com/cs3org/reva/pkg/sdk/common"
"github.com/cs3org/reva/pkg/storage/utils/ace"
"github.com/pkg/errors"
"github.com/pkg/xattr"
"github.com/rs/zerolog/log"
)

const (
_shareTypesKey = "http://owncloud.org/ns/share-types"
_userShareType = "0"
)

// Node represents a node in the tree and provides methods to get a Parent or Child instance
type Node struct {
lu *Lookup
@@ -291,7 +297,7 @@ func (n *Node) Owner() (id string, idp string, err error) {
}

// AsResourceInfo return the node as CS3 ResourceInfo
func (n *Node) AsResourceInfo(ctx context.Context) (ri *provider.ResourceInfo, err error) {
func (n *Node) AsResourceInfo(ctx context.Context, mdKeys []string) (ri *provider.ResourceInfo, err error) {
log := appctx.GetLogger(ctx)

var fn string
@@ -399,6 +405,12 @@ func (n *Node) AsResourceInfo(ctx context.Context) (ri *provider.ResourceInfo, e
log.Error().Err(err).Interface("node", n).Msg("could not list attributes")
}

if common.FindString(mdKeys, _shareTypesKey) != -1 {
if n.hasUserShares(ctx) {
ri.ArbitraryMetadata.Metadata[_shareTypesKey] = _userShareType
}
}

log.Debug().
Interface("ri", ri).
Msg("AsResourceInfo")
@@ -469,3 +481,18 @@ func (n *Node) ReadGrant(ctx context.Context, grantee string) (g *provider.Grant
}
return e.Grant(), nil
}

func (n *Node) hasUserShares(ctx context.Context) bool {
g, err := n.ListGrantees(ctx)
if err != nil {
appctx.GetLogger(ctx).Error().Err(err).Msg("hasUserShares: listGrantees")
return false
}

for i := range g {
if strings.Contains(g[i], grantPrefix+_userAcePrefix) {
return true
}
}
return false
}
4 changes: 2 additions & 2 deletions pkg/storage/fs/ocis/ocis.go
Original file line number Diff line number Diff line change
@@ -371,7 +371,7 @@ func (fs *ocisfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []s
return nil, errtypes.PermissionDenied(node.ID)
}

return node.AsResourceInfo(ctx)
return node.AsResourceInfo(ctx, mdKeys)
}

func (fs *ocisfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKeys []string) (finfos []*provider.ResourceInfo, err error) {
@@ -402,7 +402,7 @@ func (fs *ocisfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKey
}

for i := range children {
if ri, err := children[i].AsResourceInfo(ctx); err == nil {
if ri, err := children[i].AsResourceInfo(ctx, mdKeys); err == nil {
finfos = append(finfos, ri)
}
}
11 changes: 8 additions & 3 deletions pkg/storage/fs/ocis/permissions.go
Original file line number Diff line number Diff line change
@@ -31,6 +31,11 @@ import (
"github.com/pkg/xattr"
)

const (
_userAcePrefix = "u:"
_groupAcePrefix = "g:"
)

var defaultPermissions *provider.ResourcePermissions = &provider.ResourcePermissions{
// no permissions
}
@@ -100,15 +105,15 @@ func (p *Permissions) HasPermission(ctx context.Context, n *Node, check func(*pr
return false, err
}

userace := grantPrefix + "u:" + u.Id.OpaqueId
userace := grantPrefix + _userAcePrefix + u.Id.OpaqueId
userFound := false
for i := range grantees {
// we only need the find the user once per node
switch {
case !userFound && grantees[i] == userace:
g, err = cn.ReadGrant(ctx, grantees[i])
case strings.HasPrefix(grantees[i], grantPrefix+"g:"):
gr := strings.TrimPrefix(grantees[i], grantPrefix+"g:")
case strings.HasPrefix(grantees[i], grantPrefix+_groupAcePrefix):
gr := strings.TrimPrefix(grantees[i], grantPrefix+_groupAcePrefix)
if groupsMap[gr] {
g, err = cn.ReadGrant(ctx, grantees[i])
} else {