diff --git a/changelog/unreleased/share-creation-paths.md b/changelog/unreleased/share-creation-paths.md new file mode 100644 index 0000000000..da58064ce5 --- /dev/null +++ b/changelog/unreleased/share-creation-paths.md @@ -0,0 +1,7 @@ +Enhancement: Restrict the paths where share creation is allowed + +This PR limits share creation to certain specified paths. These can be useful +when users have access to global spaces and virtual views but these should not +be sharable. + +https://github.com/cs3org/reva/pull/2267 \ No newline at end of file diff --git a/internal/grpc/services/publicshareprovider/publicshareprovider.go b/internal/grpc/services/publicshareprovider/publicshareprovider.go index f5927f3b62..74fab0d805 100644 --- a/internal/grpc/services/publicshareprovider/publicshareprovider.go +++ b/internal/grpc/services/publicshareprovider/publicshareprovider.go @@ -20,6 +20,7 @@ package publicshareprovider import ( "context" + "regexp" link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" @@ -40,8 +41,9 @@ func init() { } type config struct { - Driver string `mapstructure:"driver"` - Drivers map[string]map[string]interface{} `mapstructure:"drivers"` + Driver string `mapstructure:"driver"` + Drivers map[string]map[string]interface{} `mapstructure:"drivers"` + AllowedPathsForShares []string `mapstructure:"allowed_paths_for_shares"` } func (c *config) init() { @@ -51,8 +53,9 @@ func (c *config) init() { } type service struct { - conf *config - sm publicshare.Manager + conf *config + sm publicshare.Manager + allowedPathsForShares []*regexp.Regexp } func getShareManager(c *config) (publicshare.Manager, error) { @@ -98,18 +101,46 @@ func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) { return nil, err } + allowedPathsForShares := make([]*regexp.Regexp, 0, len(c.AllowedPathsForShares)) + for _, s := range c.AllowedPathsForShares { + regex, err := regexp.Compile(s) + if err != nil { + return nil, err + } + allowedPathsForShares = append(allowedPathsForShares, regex) + } + service := &service{ - conf: c, - sm: sm, + conf: c, + sm: sm, + allowedPathsForShares: allowedPathsForShares, } return service, nil } +func (s *service) isPathAllowed(path string) bool { + if len(s.allowedPathsForShares) == 0 { + return true + } + for _, reg := range s.allowedPathsForShares { + if reg.MatchString(path) { + return true + } + } + return false +} + func (s *service) CreatePublicShare(ctx context.Context, req *link.CreatePublicShareRequest) (*link.CreatePublicShareResponse, error) { log := appctx.GetLogger(ctx) log.Info().Str("publicshareprovider", "create").Msg("create public share") + if !s.isPathAllowed(req.ResourceInfo.Path) { + return &link.CreatePublicShareResponse{ + Status: status.NewInvalidArg(ctx, "share creation is not allowed for the specified path"), + }, nil + } + u, ok := ctxpkg.ContextGetUser(ctx) if !ok { log.Error().Msg("error getting user from context") diff --git a/internal/grpc/services/usershareprovider/usershareprovider.go b/internal/grpc/services/usershareprovider/usershareprovider.go index 9f5b0d1fc8..372020704f 100644 --- a/internal/grpc/services/usershareprovider/usershareprovider.go +++ b/internal/grpc/services/usershareprovider/usershareprovider.go @@ -20,6 +20,7 @@ package usershareprovider import ( "context" + "regexp" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" @@ -41,8 +42,9 @@ func init() { } type config struct { - Driver string `mapstructure:"driver"` - Drivers map[string]map[string]interface{} `mapstructure:"drivers"` + Driver string `mapstructure:"driver"` + Drivers map[string]map[string]interface{} `mapstructure:"drivers"` + AllowedPathsForShares []string `mapstructure:"allowed_paths_for_shares"` } func (c *config) init() { @@ -52,8 +54,9 @@ func (c *config) init() { } type service struct { - conf *config - sm share.Manager + conf *config + sm share.Manager + allowedPathsForShares []*regexp.Regexp } func getShareManager(c *config) (share.Manager, error) { @@ -100,14 +103,36 @@ func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) { return nil, err } + allowedPathsForShares := make([]*regexp.Regexp, 0, len(c.AllowedPathsForShares)) + for _, s := range c.AllowedPathsForShares { + regex, err := regexp.Compile(s) + if err != nil { + return nil, err + } + allowedPathsForShares = append(allowedPathsForShares, regex) + } + service := &service{ - conf: c, - sm: sm, + conf: c, + sm: sm, + allowedPathsForShares: allowedPathsForShares, } return service, nil } +func (s *service) isPathAllowed(path string) bool { + if len(s.allowedPathsForShares) == 0 { + return true + } + for _, reg := range s.allowedPathsForShares { + if reg.MatchString(path) { + return true + } + } + return false +} + func (s *service) CreateShare(ctx context.Context, req *collaboration.CreateShareRequest) (*collaboration.CreateShareResponse, error) { u := ctxpkg.ContextMustGetUser(ctx) if req.Grant.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && req.Grant.Grantee.GetUserId().Idp == "" { @@ -115,6 +140,13 @@ func (s *service) CreateShare(ctx context.Context, req *collaboration.CreateShar g := &userpb.UserId{OpaqueId: req.Grant.Grantee.GetUserId().OpaqueId, Idp: u.Id.Idp, Type: userpb.UserType_USER_TYPE_PRIMARY} req.Grant.Grantee.Id = &provider.Grantee_UserId{UserId: g} } + + if !s.isPathAllowed(req.ResourceInfo.Path) { + return &collaboration.CreateShareResponse{ + Status: status.NewInvalidArg(ctx, "share creation is not allowed for the specified path"), + }, nil + } + share, err := s.sm.Share(ctx, req.ResourceInfo, req.Grant) if err != nil { return &collaboration.CreateShareResponse{ diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index f76c2c14b4..a85e6988ca 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -104,12 +104,7 @@ func ResolvePath(path string) (string, error) { path = filepath.Join(homeDir, path[2:]) } - path, err = filepath.Abs(path) - if err != nil { - return "", err - } - - return path, nil + return filepath.Abs(path) } // RandString is a helper to create tokens.