diff --git a/changelog/unreleased/spaces-grants.md b/changelog/unreleased/spaces-grants.md new file mode 100644 index 0000000000..3013ebc8ae --- /dev/null +++ b/changelog/unreleased/spaces-grants.md @@ -0,0 +1,5 @@ +Enhancement: Include grants in list storage spaces response + +Added the grants to the response of list storage spaces. This allows service clients to show who has access to a space. + +https://github.com/cs3org/reva/pull/2498 diff --git a/pkg/storage/utils/decomposedfs/node/node.go b/pkg/storage/utils/decomposedfs/node/node.go index 273fac5ed4..9be1a2d09f 100644 --- a/pkg/storage/utils/decomposedfs/node/node.go +++ b/pkg/storage/utils/decomposedfs/node/node.go @@ -879,7 +879,7 @@ func (n *Node) ReadUserPermissions(ctx context.Context, u *userpb.User) (ap prov func (n *Node) ListGrantees(ctx context.Context) (grantees []string, err error) { var attrs []string if attrs, err = xattr.List(n.InternalPath()); err != nil { - appctx.GetLogger(ctx).Error().Err(err).Interface("node", n).Msg("error listing attributes") + appctx.GetLogger(ctx).Error().Err(err).Str("node", n.ID).Msg("error listing attributes") return nil, err } for i := range attrs { @@ -903,6 +903,30 @@ func (n *Node) ReadGrant(ctx context.Context, grantee string) (g *provider.Grant return e.Grant(), nil } +// ListGrants lists all grants of the current node. +func (n *Node) ListGrants(ctx context.Context) ([]*provider.Grant, error) { + grantees, err := n.ListGrantees(ctx) + if err != nil { + return nil, err + } + + grants := make([]*provider.Grant, 0, len(grantees)) + for _, g := range grantees { + grant, err := n.ReadGrant(ctx, g) + if err != nil { + appctx.GetLogger(ctx). + Error(). + Err(err). + Str("node", n.ID). + Str("grantee", g). + Msg("error reading grant") + continue + } + grants = append(grants, grant) + } + return grants, nil +} + // ReadBlobSizeAttr reads the blobsize from the xattrs func ReadBlobSizeAttr(path string) (int64, error) { attrBytes, err := xattr.Get(path, xattrs.BlobsizeAttr) diff --git a/pkg/storage/utils/decomposedfs/spaces.go b/pkg/storage/utils/decomposedfs/spaces.go index 877718b239..a380eedc6e 100644 --- a/pkg/storage/utils/decomposedfs/spaces.go +++ b/pkg/storage/utils/decomposedfs/spaces.go @@ -20,6 +20,7 @@ package decomposedfs import ( "context" + "encoding/json" "fmt" "math" "os" @@ -478,6 +479,19 @@ func (fs *Decomposedfs) createStorageSpace(ctx context.Context, spaceType, space } func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, n *node.Node, spaceType, nodePath string, canListAllSpaces bool) (*provider.StorageSpace, error) { + user := ctxpkg.ContextMustGetUser(ctx) + if !canListAllSpaces { + ok, err := node.NewPermissions(fs.lu).HasPermission(ctx, n, func(p *provider.ResourcePermissions) bool { + return p.Stat + }) + if err != nil || !ok { + return nil, errtypes.PermissionDenied(fmt.Sprintf("user %s is not allowed to Stat the space %s", user.Username, n.SpaceRoot.ID)) + } + if n.SpaceRoot != nil && strings.Contains(n.SpaceRoot.ID, node.TrashIDDelimiter) { + return nil, errtypes.PermissionDenied(fmt.Sprintf("user %s is not allowed to list deleted spaces %s", user.Username, n.SpaceRoot.ID)) + } + } + owner, err := n.Owner() if err != nil { return nil, err @@ -506,7 +520,39 @@ func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, n *node.Node, spaceType = filepath.Base(filepath.Dir(matches[0])) + grants, err := n.ListGrants(ctx) + if err != nil { + return nil, err + } + + m := make(map[string]*provider.ResourcePermissions, len(grants)) + for _, g := range grants { + var id string + switch g.Grantee.Type { + case provider.GranteeType_GRANTEE_TYPE_GROUP: + id = g.Grantee.GetGroupId().OpaqueId + case provider.GranteeType_GRANTEE_TYPE_USER: + id = g.Grantee.GetUserId().OpaqueId + default: + continue + } + + m[id] = g.Permissions + } + marshalled, err := json.Marshal(m) + if err != nil { + return nil, err + } + space := &provider.StorageSpace{ + Opaque: &types.Opaque{ + Map: map[string]*types.OpaqueEntry{ + "grants": { + Decoder: "json", + Value: marshalled, + }, + }, + }, Id: &provider.StorageSpaceId{OpaqueId: n.SpaceRoot.ID}, Root: &provider.ResourceId{ StorageId: n.SpaceRoot.ID, @@ -517,19 +563,6 @@ func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, n *node.Node, // Mtime is set either as node.tmtime or as fi.mtime below } - user := ctxpkg.ContextMustGetUser(ctx) - if !canListAllSpaces { - ok, err := node.NewPermissions(fs.lu).HasPermission(ctx, n, func(p *provider.ResourcePermissions) bool { - return p.Stat - }) - if err != nil || !ok { - return nil, errtypes.PermissionDenied(fmt.Sprintf("user %s is not allowed to Stat the space %+v", user.Username, space)) - } - if strings.Contains(space.Root.OpaqueId, node.TrashIDDelimiter) { - return nil, errtypes.PermissionDenied(fmt.Sprintf("user %s is not allowed to list deleted spaces %+v", user.Username, space)) - } - } - space.Owner = &userv1beta1.User{ // FIXME only return a UserID, not a full blown user object Id: owner, }