Skip to content

Commit

Permalink
Filter directory in list Container if the path is the root dir
Browse files Browse the repository at this point in the history
  • Loading branch information
gmgigi96 committed Nov 1, 2021
1 parent 5d1650e commit 11fa21f
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 91 deletions.
56 changes: 56 additions & 0 deletions internal/grpc/interceptors/useragent/useragent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2018-2021 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

package useragent

import (
"context"

ctxpkg "github.com/cs3org/reva/pkg/ctx"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)

// NewUnary returns a new unary interceptor that adds
// the useragent to the context.
func NewUnary() grpc.UnaryServerInterceptor {
interceptor := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
if md, ok := metadata.FromIncomingContext(ctx); ok {
if lst, ok := md[ctxpkg.UserAgentHeader]; ok && len(lst) != 0 {
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.UserAgentHeader, lst[0])
}
}
return handler(ctx, req)
}
return interceptor
}

// NewStream returns a new server stream interceptor
// that adds the user agent to the context.
func NewStream() grpc.StreamServerInterceptor {
interceptor := func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
ctx := ss.Context()
if md, ok := metadata.FromIncomingContext(ctx); ok {
if lst, ok := md[ctxpkg.UserAgentHeader]; ok && len(lst) != 0 {
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.UserAgentHeader, lst[0])
}
}
return handler(srv, ss)
}
return interceptor
}
30 changes: 22 additions & 8 deletions internal/grpc/services/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type config struct {
HomeMapping string `mapstructure:"home_mapping"`
TokenManagers map[string]map[string]interface{} `mapstructure:"token_managers"`
EtagCacheTTL int `mapstructure:"etag_cache_ttl"`
HiddenRootFolders map[string][]string `mapstructure:"hidden_root_folders"`
}

// sets defaults
Expand Down Expand Up @@ -116,10 +117,11 @@ func (c *config) init() {
}

type svc struct {
c *config
dataGatewayURL url.URL
tokenmgr token.Manager
etagCache *ttlcache.Cache `mapstructure:"etag_cache"`
c *config
dataGatewayURL url.URL
tokenmgr token.Manager
etagCache *ttlcache.Cache `mapstructure:"etag_cache"`
hiddenRootFolders map[string]map[string]struct{}
}

// New creates a new gateway svc that acts as a proxy for any grpc operation.
Expand Down Expand Up @@ -148,11 +150,23 @@ func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) {
_ = etagCache.SetTTL(time.Duration(c.EtagCacheTTL) * time.Second)
etagCache.SkipTTLExtensionOnHit(true)

// create set of hidden root folders
hiddenRootFolders := make(map[string]map[string]struct{})
for agent, folders := range c.HiddenRootFolders {
if _, ok := hiddenRootFolders[agent]; !ok {
hiddenRootFolders[agent] = make(map[string]struct{})
}
for _, f := range folders {
hiddenRootFolders[agent][f] = struct{}{}
}
}

s := &svc{
c: c,
dataGatewayURL: *u,
tokenmgr: tokenManager,
etagCache: etagCache,
c: c,
dataGatewayURL: *u,
tokenmgr: tokenManager,
etagCache: etagCache,
hiddenRootFolders: hiddenRootFolders,
}

return s, nil
Expand Down
39 changes: 39 additions & 0 deletions internal/grpc/services/gateway/storageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ import (
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
ctxpkg "github.com/cs3org/reva/pkg/ctx"
rtrace "github.com/cs3org/reva/pkg/trace"

"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/rgrpc/status"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/storage/utils/etag"
"github.com/cs3org/reva/pkg/useragent"
"github.com/cs3org/reva/pkg/utils"
"github.com/golang-jwt/jwt"
"github.com/google/uuid"
Expand Down Expand Up @@ -1648,6 +1650,31 @@ func (s *svc) listSharesFolder(ctx context.Context) (*provider.ListContainerResp
return lcr, nil
}

func (s *svc) isFolderHidden(ua, path string) bool {
uaSet, ok := s.hiddenRootFolders[ua]
if !ok {
return false
}
_, ok = uaSet[path]
return ok
}

func (s *svc) filterProvidersByUserAgent(ctx context.Context, providers []*registry.ProviderInfo) []*registry.ProviderInfo {
ua, ok := ctxpkg.ContextGetUserAgent(ctx)
if !ok {
return providers
}
cat := useragent.GetCategory(ua)

filters := []*registry.ProviderInfo{}
for _, p := range providers {
if !s.isFolderHidden(cat, p.ProviderPath) {
filters = append(filters, p)
}
}
return filters
}

func (s *svc) listContainer(ctx context.Context, req *provider.ListContainerRequest) (*provider.ListContainerResponse, error) {
providers, err := s.findProviders(ctx, req.Ref)
if err != nil {
Expand All @@ -1672,6 +1699,18 @@ func (s *svc) listContainer(ctx context.Context, req *provider.ListContainerRequ
return rsp, nil
}

p, st := s.getPath(ctx, req.Ref, req.ArbitraryMetadataKeys...)
if st.Code != rpc.Code_CODE_OK {
return &provider.ListContainerResponse{
Status: st,
}, nil
}

// check if the path is the root folder
if path.Clean(p) == "/" {
providers = s.filterProvidersByUserAgent(ctx, providers)
}

return s.listContainerAcrossProviders(ctx, req, providers)
}

Expand Down
2 changes: 2 additions & 0 deletions internal/http/interceptors/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ func New(m map[string]interface{}, unprotected []string) (global.Middleware, err
ctx = ctxpkg.ContextSetToken(ctx, tkn)
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, tkn) // TODO(jfd): hardcoded metadata key. use PerRPCCredentials?

ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.UserAgentHeader, r.UserAgent())

r = r.WithContext(ctx)
h.ServeHTTP(w, r)
})
Expand Down
2 changes: 1 addition & 1 deletion internal/http/services/owncloud/ocdav/propfind.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ func (s *svc) getResourceInfos(ctx context.Context, w http.ResponseWriter, r *ht
if depth == "" {
depth = "1"
}
log.Error().Msgf("***** getResourceInfos depth=%s *****", depth)
// see https://tools.ietf.org/html/rfc4918#section-9.1
if depth != "0" && depth != "1" && depth != "infinity" {
log.Debug().Str("depth", depth).Msgf("invalid Depth header value")
Expand Down Expand Up @@ -261,7 +262,6 @@ func (s *svc) getResourceInfos(ctx context.Context, w http.ResponseWriter, r *ht
}
res, err := client.ListContainer(ctx, req)
if err != nil {
log.Error().Err(err).Msg("error sending list container grpc request")
w.WriteHeader(http.StatusInternalServerError)
return nil, nil, false
}
Expand Down
9 changes: 7 additions & 2 deletions pkg/ctx/agentctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,21 @@ import (
"google.golang.org/grpc/metadata"
)

const UserAgentHeader = "x-user-agent"

// ContextGetUserAgent returns the user agent if set in the given context.
// see https://github.com/grpc/grpc-go/issues/1100
func ContextGetUserAgent(ctx context.Context) (*ua.UserAgent, bool) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, false
}
userAgentLst, ok := md["user-agent"]
userAgentLst, ok := md[UserAgentHeader]
if !ok {
return nil, false
userAgentLst, ok = md["user-agent"]
if !ok {
return nil, false
}
}
if len(userAgentLst) == 0 {
return nil, false
Expand Down
3 changes: 3 additions & 0 deletions pkg/rgrpc/rgrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/cs3org/reva/internal/grpc/interceptors/log"
"github.com/cs3org/reva/internal/grpc/interceptors/recovery"
"github.com/cs3org/reva/internal/grpc/interceptors/token"
"github.com/cs3org/reva/internal/grpc/interceptors/useragent"
"github.com/cs3org/reva/pkg/sharedconf"
rtrace "github.com/cs3org/reva/pkg/trace"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
Expand Down Expand Up @@ -292,6 +293,7 @@ func (s *Server) getInterceptors(unprotected []string) ([]grpc.ServerOption, err
token.NewUnary(),
log.NewUnary(),
recovery.NewUnary(),
useragent.NewUnary(),
}, unaryInterceptors...)
unaryChain := grpc_middleware.ChainUnaryServer(unaryInterceptors...)

Expand Down Expand Up @@ -333,6 +335,7 @@ func (s *Server) getInterceptors(unprotected []string) ([]grpc.ServerOption, err
token.NewStream(),
log.NewStream(),
recovery.NewStream(),
useragent.NewStream(),
}, streamInterceptors...)
streamChain := grpc_middleware.ChainStreamServer(streamInterceptors...)

Expand Down
32 changes: 6 additions & 26 deletions pkg/storage/registry/static/static.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (
"github.com/cs3org/reva/pkg/storage"
"github.com/cs3org/reva/pkg/storage/registry/registry"
"github.com/cs3org/reva/pkg/storage/utils/templates"
"github.com/cs3org/reva/pkg/useragent"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
)
Expand All @@ -44,10 +43,9 @@ func init() {
var bracketRegex = regexp.MustCompile(`\[(.*?)\]`)

type rule struct {
Mapping string `mapstructure:"mapping"`
Address string `mapstructure:"address"`
Aliases map[string]string `mapstructure:"aliases"`
AllowedUserAgents []string `mapstructure:"allowed_user_agents"`
Mapping string `mapstructure:"mapping"`
Address string `mapstructure:"address"`
Aliases map[string]string `mapstructure:"aliases"`
}

type config struct {
Expand Down Expand Up @@ -112,7 +110,7 @@ func getProviderAddr(ctx context.Context, r rule) string {

func (b *reg) ListProviders(ctx context.Context) ([]*registrypb.ProviderInfo, error) {
providers := []*registrypb.ProviderInfo{}
for k, v := range rulesFilteredByUserAgent(ctx, b.c.Rules) {
for k, v := range b.c.Rules {
if addr := getProviderAddr(ctx, v); addr != "" {
combs := generateRegexCombinations(k)
for _, c := range combs {
Expand Down Expand Up @@ -140,24 +138,6 @@ func (b *reg) GetHome(ctx context.Context) (*registrypb.ProviderInfo, error) {
return nil, errors.New("static: home not found")
}

func rulesFilteredByUserAgent(ctx context.Context, rules map[string]rule) map[string]rule {
filtered := make(map[string]rule)
for prefix, rule := range rules {
// check if the provider is allowed to be shown according to the
// user agent that made the request
// if the list of AllowedUserAgents is empty, this means that
// every agents that made the request could see the provider

if len(rule.AllowedUserAgents) != 0 {
if ua, ok := ctxpkg.ContextGetUserAgent(ctx); !ok || !useragent.IsAllowed(ua, rule.AllowedUserAgents) {
continue
}
}
filtered[prefix] = rule
}
return filtered
}

func (b *reg) FindProviders(ctx context.Context, ref *provider.Reference) ([]*registrypb.ProviderInfo, error) {
// find longest match
var match *registrypb.ProviderInfo
Expand All @@ -166,7 +146,7 @@ func (b *reg) FindProviders(ctx context.Context, ref *provider.Reference) ([]*re
// If the reference has a resource id set, use it to route
if ref.ResourceId != nil {
if ref.ResourceId.StorageId != "" {
for prefix, rule := range rulesFilteredByUserAgent(ctx, b.c.Rules) {
for prefix, rule := range b.c.Rules {
addr := getProviderAddr(ctx, rule)
r, err := regexp.Compile("^" + prefix + "$")
if err != nil {
Expand All @@ -192,7 +172,7 @@ func (b *reg) FindProviders(ctx context.Context, ref *provider.Reference) ([]*re
// TODO this needs to be reevaluated once all clients query the storage registry for a list of storage providers
fn := path.Clean(ref.GetPath())
if fn != "" {
for prefix, rule := range rulesFilteredByUserAgent(ctx, b.c.Rules) {
for prefix, rule := range b.c.Rules {

addr := getProviderAddr(ctx, rule)
r, err := regexp.Compile("^" + prefix)
Expand Down
39 changes: 12 additions & 27 deletions pkg/useragent/useragent.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,32 +47,17 @@ func isGRPC(ua *ua.UserAgent) bool {
return strings.HasPrefix(ua.Name, "grpc")
}

// IsAllowed returns true if the user agent category is one in the user agents list
func IsAllowed(ua *ua.UserAgent, userAgents []string) bool {
isWeb := isWeb(ua)
isMobile := isMobile(ua)
isDesktop := isDesktop(ua)
isGRPC := isGRPC(ua)

for _, userAgent := range userAgents {
switch userAgent {
case "web":
if isWeb {
return true
}
case "mobile":
if isMobile {
return true
}
case "desktop":
if isDesktop {
return true
}
case "grpc":
if isGRPC {
return true
}
}
func GetCategory(ua *ua.UserAgent) string {
switch {
case isWeb(ua):
return "web"
case isMobile(ua):
return "mobile"
case isDesktop(ua):
return "desktop"
case isGRPC(ua):
return "grpc"
default:
return ""
}
return false
}
Loading

0 comments on commit 11fa21f

Please sign in to comment.