mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-02-28 09:29:41 -06:00
listing drives sould use the user filter (#6103)
* listing drives shsould use the user filter Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> * fix status code Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> * check correct error Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> * Adapt expected failures * Bump reva --------- Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> Co-authored-by: André Duffeck <andre.duffeck@firondu.de>
This commit is contained in:
committed by
GitHub
parent
f0cd81f4e1
commit
3489de1c42
2
go.mod
2
go.mod
@@ -13,7 +13,7 @@ require (
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/coreos/go-oidc/v3 v3.4.0
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20221012090518-ef2996678965
|
||||
github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1
|
||||
github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
||||
github.com/egirna/icap-client v0.1.1
|
||||
|
||||
4
go.sum
4
go.sum
@@ -627,8 +627,8 @@ github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo
|
||||
github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
|
||||
github.com/crewjam/saml v0.4.13 h1:TYHggH/hwP7eArqiXSJUvtOPNzQDyQ7vwmwEqlFWhMc=
|
||||
github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA=
|
||||
github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1 h1:p563+4bqdVSYPtDeo6ikOEbciU/mjbYhrei2zCjzxkw=
|
||||
github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1/go.mod h1:VxBmpOvIKlgKLPOsHun+fABopzX+3ZELPAp3N5bQMsM=
|
||||
github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5 h1:wloX5LiqRxwh2ID9O+em8O5VU1h2ZN5u6tPceAdLNDI=
|
||||
github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5/go.mod h1:VxBmpOvIKlgKLPOsHun+fABopzX+3ZELPAp3N5bQMsM=
|
||||
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=
|
||||
|
||||
@@ -91,6 +91,20 @@ func (g Graph) getDrives(w http.ResponseWriter, r *http.Request, unrestricted bo
|
||||
errorcode.NotSupported.Render(w, r, http.StatusNotImplemented, err.Error())
|
||||
return
|
||||
}
|
||||
if !unrestricted {
|
||||
user, ok := revactx.ContextGetUser(r.Context())
|
||||
if !ok {
|
||||
logger.Debug().Msg("could not create drive: invalid user")
|
||||
errorcode.NotAllowed.Render(w, r, http.StatusUnauthorized, "invalid user")
|
||||
return
|
||||
}
|
||||
filters = append(filters, &storageprovider.ListStorageSpacesRequest_Filter{
|
||||
Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_USER,
|
||||
Term: &storageprovider.ListStorageSpacesRequest_Filter_User{
|
||||
User: user.GetId(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
logger.Debug().
|
||||
Interface("filters", filters).
|
||||
@@ -240,7 +254,7 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
if !canCreateSpace {
|
||||
logger.Debug().Bool("cancreatespace", canCreateSpace).Msg("could not create drive: insufficient permissions")
|
||||
// if the permission is not existing for the user in context we can assume we don't have it. Return 401.
|
||||
errorcode.NotAllowed.Render(w, r, http.StatusUnauthorized, "insufficient permissions to create a space.")
|
||||
errorcode.NotAllowed.Render(w, r, http.StatusForbidden, "insufficient permissions to create a space.")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ var _ = Describe("Graph", func() {
|
||||
}, nil)
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetDrives(rr, r)
|
||||
Expect(rr.Code).To(Equal(http.StatusOK))
|
||||
@@ -102,6 +103,7 @@ var _ = Describe("Graph", func() {
|
||||
}, nil)
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/drives", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetAllDrives(rr, r)
|
||||
Expect(rr.Code).To(Equal(http.StatusOK))
|
||||
@@ -131,6 +133,7 @@ var _ = Describe("Graph", func() {
|
||||
}, nil)
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetDrives(rr, r)
|
||||
|
||||
@@ -201,6 +204,7 @@ var _ = Describe("Graph", func() {
|
||||
}, nil)
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives?$orderby=name%20asc", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetDrives(rr, r)
|
||||
|
||||
@@ -281,6 +285,7 @@ var _ = Describe("Graph", func() {
|
||||
}, nil)
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetDrives(rr, r)
|
||||
|
||||
@@ -320,6 +325,7 @@ var _ = Describe("Graph", func() {
|
||||
}, nil)
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives?$orderby=owner%20asc", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetDrives(rr, r)
|
||||
Expect(rr.Code).To(Equal(http.StatusBadRequest))
|
||||
@@ -361,6 +367,7 @@ var _ = Describe("Graph", func() {
|
||||
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(nil, errors.New("transport error"))
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives)", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetDrives(rr, r)
|
||||
Expect(rr.Code).To(Equal(http.StatusInternalServerError))
|
||||
@@ -378,6 +385,7 @@ var _ = Describe("Graph", func() {
|
||||
StorageSpaces: []*provider.StorageSpace{}}, nil)
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives)", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetDrives(rr, r)
|
||||
Expect(rr.Code).To(Equal(http.StatusInternalServerError))
|
||||
@@ -395,6 +403,7 @@ var _ = Describe("Graph", func() {
|
||||
StorageSpaces: []*provider.StorageSpace{}}, nil)
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives)", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetDrives(rr, r)
|
||||
Expect(rr.Code).To(Equal(http.StatusOK))
|
||||
@@ -430,6 +439,7 @@ var _ = Describe("Graph", func() {
|
||||
}, nil)
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetDrives(rr, r)
|
||||
|
||||
@@ -469,7 +479,7 @@ var _ = Describe("Graph", func() {
|
||||
r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/drives", bytes.NewBuffer(jsonBody)).WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.CreateDrive(rr, r)
|
||||
Expect(rr.Code).To(Equal(http.StatusUnauthorized))
|
||||
Expect(rr.Code).To(Equal(http.StatusForbidden))
|
||||
|
||||
body, _ := io.ReadAll(rr.Body)
|
||||
var libreError libregraph.OdataError
|
||||
|
||||
@@ -146,8 +146,6 @@ The expected failures in this file are from features in the owncloud/ocis repo.
|
||||
- [apiGraph/removeUserFromGroup.feature:192](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/removeUserFromGroup.feature#L192)
|
||||
- [apiGraph/removeUserFromGroup.feature:193](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/removeUserFromGroup.feature#L193)
|
||||
- [apiGraph/removeUserFromGroup.feature:194](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/removeUserFromGroup.feature#L194)
|
||||
- [apiSpaces/createSpace.feature:18](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpaces/createSpace.feature#L18)
|
||||
- [apiSpaces/createSpace.feature:19](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpaces/createSpace.feature#L19)
|
||||
|
||||
#### [API requests for a non-existent resources should return 404](https://github.com/owncloud/ocis/issues/5939)
|
||||
- [apiGraph/addUserToGroup.feature:202](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/addUserToGroup.feature#L202)
|
||||
|
||||
4
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/decomposedfs.go
generated
vendored
4
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/decomposedfs.go
generated
vendored
@@ -57,6 +57,7 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/templates"
|
||||
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"github.com/jellydator/ttlcache/v2"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
@@ -95,6 +96,8 @@ type Decomposedfs struct {
|
||||
chunkHandler *chunking.ChunkHandler
|
||||
stream events.Stream
|
||||
cache cache.StatCache
|
||||
|
||||
UserCache *ttlcache.Cache
|
||||
}
|
||||
|
||||
// NewDefault returns an instance with default components
|
||||
@@ -160,6 +163,7 @@ func New(o *options.Options, lu *lookup.Lookup, p Permissions, tp Tree, es event
|
||||
chunkHandler: chunking.NewChunkHandler(filepath.Join(o.Root, "uploads")),
|
||||
stream: es,
|
||||
cache: cache.GetStatCache(o.StatCache.Store, o.StatCache.Nodes, o.StatCache.Database, "stat", time.Duration(o.StatCache.TTL)*time.Second, o.StatCache.Size),
|
||||
UserCache: ttlcache.NewCache(),
|
||||
}
|
||||
|
||||
if o.AsyncFileUploads {
|
||||
|
||||
32
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/grants.go
generated
vendored
32
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/grants.go
generated
vendored
@@ -201,8 +201,6 @@ func (fs *Decomposedfs) RemoveGrant(ctx context.Context, ref *provider.Reference
|
||||
return err
|
||||
}
|
||||
|
||||
spaceGrant := ctx.Value(utils.SpaceGrant)
|
||||
|
||||
var attr string
|
||||
if g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
|
||||
attr = prefixes.GrantGroupAcePrefix + g.Grantee.GetGroupId().OpaqueId
|
||||
@@ -214,18 +212,34 @@ func (fs *Decomposedfs) RemoveGrant(ctx context.Context, ref *provider.Reference
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO we need an index for groups
|
||||
if spaceGrant != nil && g.Grantee.Type != provider.GranteeType_GRANTEE_TYPE_GROUP {
|
||||
// remove from user index
|
||||
userIDPath := filepath.Join(fs.o.Root, "indexes", "by-user-id", g.Grantee.GetUserId().OpaqueId, grantNode.SpaceID)
|
||||
if err := os.Remove(userIDPath); err != nil {
|
||||
return err
|
||||
if isShareGrant(ctx) {
|
||||
// do not invalidate by user or group indexes
|
||||
// FIXME we should invalidate the by-type index, but that requires reference counting
|
||||
} else {
|
||||
// invalidate space grant
|
||||
switch {
|
||||
case g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER:
|
||||
// remove from user index
|
||||
userIDPath := filepath.Join(fs.o.Root, "indexes", "by-user-id", g.Grantee.GetUserId().GetOpaqueId(), grantNode.SpaceID)
|
||||
if err := os.Remove(userIDPath); err != nil {
|
||||
return err
|
||||
}
|
||||
case g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP:
|
||||
// remove from group index
|
||||
userIDPath := filepath.Join(fs.o.Root, "indexes", "by-group-id", g.Grantee.GetGroupId().GetOpaqueId(), grantNode.SpaceID)
|
||||
if err := os.Remove(userIDPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fs.tp.Propagate(ctx, grantNode, 0)
|
||||
}
|
||||
|
||||
func isShareGrant(ctx context.Context) bool {
|
||||
return ctx.Value(utils.SpaceGrant) == nil
|
||||
}
|
||||
|
||||
// UpdateGrant updates a grant on a resource
|
||||
// TODO remove AddGrant or UpdateGrant grant from CS3 api, redundant? tracked in https://github.com/cs3org/cs3apis/issues/92
|
||||
func (fs *Decomposedfs) UpdateGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error {
|
||||
@@ -319,7 +333,7 @@ func (fs *Decomposedfs) storeGrant(ctx context.Context, n *node.Node, g *provide
|
||||
}
|
||||
|
||||
// update the indexes only after successfully setting the grant
|
||||
err := fs.updateIndexes(ctx, g.GetGrantee().GetUserId().GetOpaqueId(), spaceType, n.ID)
|
||||
err := fs.updateIndexes(ctx, g.GetGrantee(), spaceType, n.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
47
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node/node.go
generated
vendored
47
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node/node.go
generated
vendored
@@ -1046,19 +1046,46 @@ func (n *Node) ReadUserPermissions(ctx context.Context, u *userpb.User) (ap prov
|
||||
|
||||
// IsDenied checks if the node was denied to that user
|
||||
func (n *Node) IsDenied(ctx context.Context) bool {
|
||||
u := ctxpkg.ContextMustGetUser(ctx)
|
||||
userace := prefixes.GrantUserAcePrefix + u.Id.OpaqueId
|
||||
g, err := n.ReadGrant(ctx, userace)
|
||||
switch {
|
||||
case err == nil:
|
||||
// If all permissions are set to false we have a deny grant
|
||||
return grants.PermissionsEqual(g.Permissions, &provider.ResourcePermissions{})
|
||||
case metadata.IsAttrUnset(err):
|
||||
return false
|
||||
default:
|
||||
gs, err := n.ListGrants(ctx)
|
||||
if err != nil {
|
||||
// be paranoid, resource is denied
|
||||
return true
|
||||
}
|
||||
|
||||
u := ctxpkg.ContextMustGetUser(ctx)
|
||||
isExecutant := func(g *provider.Grantee) bool {
|
||||
switch g.GetType() {
|
||||
case provider.GranteeType_GRANTEE_TYPE_USER:
|
||||
return g.GetUserId().GetOpaqueId() == u.GetId().GetOpaqueId()
|
||||
case provider.GranteeType_GRANTEE_TYPE_GROUP:
|
||||
// check gid
|
||||
gid := g.GetGroupId().GetOpaqueId()
|
||||
for _, group := range u.Groups {
|
||||
if gid == group {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
return false
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for _, g := range gs {
|
||||
if !isExecutant(g.Grantee) {
|
||||
continue
|
||||
}
|
||||
|
||||
if grants.PermissionsEqual(g.Permissions, &provider.ResourcePermissions{}) {
|
||||
// resource is denied
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// no deny grants
|
||||
return false
|
||||
}
|
||||
|
||||
// ListGrantees lists the grantees of the current node
|
||||
|
||||
5
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/options/options.go
generated
vendored
5
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/options/options.go
generated
vendored
@@ -35,6 +35,9 @@ type Option func(o *Options)
|
||||
// Options defines the available options for this package.
|
||||
type Options struct {
|
||||
|
||||
// the gateway address
|
||||
GatewayAddr string `mapstructure:"gateway_addr"`
|
||||
|
||||
// the metadata backend to use, currently supports `xattr` or `ini`
|
||||
MetadataBackend string `mapstructure:"metadata_backend"`
|
||||
|
||||
@@ -99,6 +102,8 @@ func New(m map[string]interface{}) (*Options, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
o.GatewayAddr = sharedconf.GetGatewaySVC(o.GatewayAddr)
|
||||
|
||||
if o.MetadataBackend == "" {
|
||||
o.MetadataBackend = "xattrs"
|
||||
}
|
||||
|
||||
10
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spacepermissions.go
generated
vendored
10
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spacepermissions.go
generated
vendored
@@ -3,11 +3,13 @@ package decomposedfs
|
||||
import (
|
||||
"context"
|
||||
|
||||
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
cs3permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
|
||||
v1beta11 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
@@ -70,12 +72,12 @@ func (p Permissions) ListAllSpaces(ctx context.Context) bool {
|
||||
}
|
||||
|
||||
// ListSpacesOfUser returns true when the user is allowed to list the spaces of the given user
|
||||
func (p Permissions) ListSpacesOfUser(ctx context.Context, userid string) bool {
|
||||
switch userid {
|
||||
case userIDAny:
|
||||
func (p Permissions) ListSpacesOfUser(ctx context.Context, userid *userv1beta1.UserId) bool {
|
||||
switch {
|
||||
case userid == nil:
|
||||
// there is no filter
|
||||
return true // TODO: is `true` actually correct here? Shouldn't we check for ListAllSpaces too?
|
||||
case ctxpkg.ContextMustGetUser(ctx).GetId().GetOpaqueId():
|
||||
case utils.UserIDEqual(ctxpkg.ContextMustGetUser(ctx).GetId(), userid):
|
||||
return true
|
||||
default:
|
||||
return p.ListAllSpaces(ctx)
|
||||
|
||||
113
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spaces.go
generated
vendored
113
vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spaces.go
generated
vendored
@@ -37,6 +37,7 @@ import (
|
||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/lookup"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata/prefixes"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
|
||||
@@ -54,13 +55,13 @@ const (
|
||||
spaceTypeShare = "share"
|
||||
spaceTypeAny = "*"
|
||||
spaceIDAny = "*"
|
||||
userIDAny = "*"
|
||||
|
||||
quotaUnrestricted = 0
|
||||
)
|
||||
|
||||
// CreateStorageSpace creates a storage space
|
||||
func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.CreateStorageSpaceRequest) (*provider.CreateStorageSpaceResponse, error) {
|
||||
ctx = context.WithValue(ctx, utils.SpaceGrant, struct{}{})
|
||||
|
||||
// "everything is a resource" this is the unique ID for the Space resource.
|
||||
spaceID := uuid.New().String()
|
||||
@@ -147,7 +148,10 @@ func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.Cr
|
||||
}
|
||||
|
||||
// Write index
|
||||
err = fs.updateIndexes(ctx, req.GetOwner().GetId().GetOpaqueId(), req.Type, root.ID)
|
||||
err = fs.updateIndexes(ctx, &provider.Grantee{
|
||||
Type: provider.GranteeType_GRANTEE_TYPE_USER,
|
||||
Id: &provider.Grantee_UserId{UserId: req.GetOwner().GetId()},
|
||||
}, req.Type, root.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -218,7 +222,7 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
|
||||
var (
|
||||
spaceID = spaceIDAny
|
||||
nodeID = spaceIDAny
|
||||
requestedUserID = userIDAny
|
||||
requestedUserID *userv1beta1.UserId
|
||||
)
|
||||
|
||||
spaceTypes := map[string]struct{}{}
|
||||
@@ -241,10 +245,10 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
|
||||
}
|
||||
case provider.ListStorageSpacesRequest_Filter_TYPE_USER:
|
||||
// TODO: refactor this to GetUserId() in cs3
|
||||
requestedUserID = filter[i].GetUser().GetOpaqueId()
|
||||
requestedUserID = filter[i].GetUser()
|
||||
case provider.ListStorageSpacesRequest_Filter_TYPE_OWNER:
|
||||
// TODO: improve further by not evaluating shares
|
||||
requestedUserID = filter[i].GetOwner().GetOpaqueId()
|
||||
requestedUserID = filter[i].GetOwner()
|
||||
}
|
||||
}
|
||||
if len(spaceTypes) == 0 {
|
||||
@@ -292,8 +296,8 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
|
||||
|
||||
matches := map[string]struct{}{}
|
||||
|
||||
if requestedUserID != userIDAny {
|
||||
path := filepath.Join(fs.o.Root, "indexes", "by-user-id", requestedUserID, nodeID)
|
||||
if requestedUserID != nil {
|
||||
path := filepath.Join(fs.o.Root, "indexes", "by-user-id", requestedUserID.GetOpaqueId(), nodeID)
|
||||
m, err := filepath.Glob(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -305,9 +309,35 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
|
||||
}
|
||||
matches[link] = struct{}{}
|
||||
}
|
||||
|
||||
// get Groups for userid
|
||||
user := ctxpkg.ContextMustGetUser(ctx)
|
||||
// TODO the user from context may not have groups populated
|
||||
if !utils.UserIDEqual(user.GetId(), requestedUserID) {
|
||||
user, err = fs.UserIDToUserAndGroups(ctx, requestedUserID)
|
||||
if err != nil {
|
||||
return nil, err // TODO log and continue?
|
||||
}
|
||||
}
|
||||
|
||||
for _, group := range user.Groups {
|
||||
path := filepath.Join(fs.o.Root, "indexes", "by-group-id", group, nodeID)
|
||||
m, err := filepath.Glob(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, match := range m {
|
||||
link, err := os.Readlink(match)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
matches[link] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if requestedUserID == userIDAny {
|
||||
if requestedUserID == nil {
|
||||
for spaceType := range spaceTypes {
|
||||
path := filepath.Join(fs.o.Root, "indexes", "by-type", spaceType, nodeID)
|
||||
m, err := filepath.Glob(path)
|
||||
@@ -412,6 +442,31 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
|
||||
|
||||
}
|
||||
|
||||
// UserIDToUserAndGroups converts a user ID to a user with groups
|
||||
func (fs *Decomposedfs) UserIDToUserAndGroups(ctx context.Context, userid *userv1beta1.UserId) (*userv1beta1.User, error) {
|
||||
user, err := fs.UserCache.Get(userid.GetOpaqueId())
|
||||
if err == nil {
|
||||
return user.(*userv1beta1.User), nil
|
||||
}
|
||||
|
||||
gwConn, err := pool.GetGatewayServiceClient(fs.o.GatewayAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
getUserResponse, err := gwConn.GetUser(ctx, &userv1beta1.GetUserRequest{
|
||||
UserId: userid,
|
||||
SkipFetchingUserGroups: false,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if getUserResponse.Status.Code != v1beta11.Code_CODE_OK {
|
||||
return nil, status.NewErrorFromCode(getUserResponse.Status.Code, "gateway")
|
||||
}
|
||||
_ = fs.UserCache.Set(userid.GetOpaqueId(), getUserResponse.GetUser())
|
||||
return getUserResponse.GetUser(), nil
|
||||
}
|
||||
|
||||
// MustCheckNodePermissions checks if permission checks are needed to be performed when user requests spaces
|
||||
func (fs *Decomposedfs) MustCheckNodePermissions(ctx context.Context, unrestricted bool) bool {
|
||||
// canListAllSpaces indicates if the user has the permission from the global user role
|
||||
@@ -649,12 +704,26 @@ func (fs *Decomposedfs) DeleteStorageSpace(ctx context.Context, req *provider.De
|
||||
return n.SetDTime(&dtime)
|
||||
}
|
||||
|
||||
func (fs *Decomposedfs) updateIndexes(ctx context.Context, userID, spaceType, spaceID string) error {
|
||||
func (fs *Decomposedfs) updateIndexes(ctx context.Context, grantee *provider.Grantee, spaceType, spaceID string) error {
|
||||
err := fs.linkStorageSpaceType(ctx, spaceType, spaceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fs.linkSpaceByUser(ctx, userID, spaceID)
|
||||
if isShareGrant(ctx) {
|
||||
// FIXME we should count the references for the by-type index currently removing the second share from the same
|
||||
// space cannot determine if the by-type should be deletet, which is why we never delete them ...
|
||||
return nil
|
||||
}
|
||||
|
||||
// create space grant index
|
||||
switch {
|
||||
case grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER:
|
||||
return fs.linkSpaceByUser(ctx, grantee.GetUserId().GetOpaqueId(), spaceID)
|
||||
case grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP:
|
||||
return fs.linkSpaceByGroup(ctx, grantee.GetGroupId().GetOpaqueId(), spaceID)
|
||||
default:
|
||||
return errtypes.BadRequest("invalid grantee type: " + grantee.GetType().String())
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *Decomposedfs) linkSpaceByUser(ctx context.Context, userID, spaceID string) error {
|
||||
@@ -681,6 +750,30 @@ func (fs *Decomposedfs) linkSpaceByUser(ctx context.Context, userID, spaceID str
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *Decomposedfs) linkSpaceByGroup(ctx context.Context, groupID, spaceID string) error {
|
||||
if groupID == "" {
|
||||
return nil
|
||||
}
|
||||
// create group index dir
|
||||
// TODO: pathify groupid
|
||||
if err := os.MkdirAll(filepath.Join(fs.o.Root, "indexes", "by-group-id", groupID), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := os.Symlink("../../../spaces/"+lookup.Pathify(spaceID, 1, 2)+"/nodes/"+lookup.Pathify(spaceID, 4, 2), filepath.Join(fs.o.Root, "indexes/by-group-id", groupID, spaceID))
|
||||
if err != nil {
|
||||
if isAlreadyExists(err) {
|
||||
appctx.GetLogger(ctx).Debug().Err(err).Str("space", spaceID).Str("group-id", groupID).Msg("symlink already exists")
|
||||
// FIXME: is it ok to wipe this err if the symlink already exists?
|
||||
err = nil //nolint
|
||||
} else {
|
||||
// TODO how should we handle error cases here?
|
||||
appctx.GetLogger(ctx).Error().Err(err).Str("space", spaceID).Str("group-id", groupID).Msg("could not create symlink")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: implement linkSpaceByGroup
|
||||
|
||||
func (fs *Decomposedfs) linkStorageSpaceType(ctx context.Context, spaceType string, spaceID string) error {
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -349,7 +349,7 @@ github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/tx/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/types/v1beta1
|
||||
# github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1
|
||||
# github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5
|
||||
## explicit; go 1.19
|
||||
github.com/cs3org/reva/v2/cmd/revad/internal/grace
|
||||
github.com/cs3org/reva/v2/cmd/revad/runtime
|
||||
|
||||
Reference in New Issue
Block a user