Skip to content
This repository has been archived by the owner on Jan 31, 2024. It is now read-only.

Commit

Permalink
[cbox-commit-19] Refactor ctx user agent interceptor and add desktop …
Browse files Browse the repository at this point in the history
…client ns
  • Loading branch information
ishank011 committed Feb 25, 2022
1 parent 5a4160c commit 800ce3e
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 149 deletions.
30 changes: 17 additions & 13 deletions internal/grpc/services/gateway/storageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ import (
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/useragent"
"github.com/cs3org/reva/pkg/utils"
ua "github.com/mileusna/useragent"

"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
Expand Down Expand Up @@ -1602,30 +1600,36 @@ func (s *svc) ListContainerStream(_ *provider.ListContainerStreamRequest, _ gate
return errtypes.NotSupported("Unimplemented")
}

func (s *svc) isPathAllowed(ua *ua.UserAgent, path string) bool {
uaLst, ok := s.c.AllowedUserAgents[path]
if !ok {
// if no user agent is defined for a path, all user agents are allowed
return true
}
return useragent.IsUserAgentAllowed(ua, uaLst)
}

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

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

func (s *svc) isPathAllowed(cat string, path string) bool {
allowedUserAgents, ok := s.c.AllowedUserAgents[path]
if !ok {
// if no user agent is defined for a path, all user agents are allowed
return true
}

for _, userAgent := range allowedUserAgents {
if userAgent == cat {
return true
}
}
return false
}

func (s *svc) listContainer(ctx context.Context, req *provider.ListContainerRequest) (*provider.ListContainerResponse, error) {
providers, err := s.findProviders(ctx, req.Ref)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions internal/http/services/owncloud/ocdav/ocdav.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ type Config struct {
PublicURL string `mapstructure:"public_url"`
FavoriteStorageDriver string `mapstructure:"favorite_storage_driver"`
FavoriteStorageDrivers map[string]map[string]interface{} `mapstructure:"favorite_storage_drivers"`
DesktopClientNamespace string `mapstructure:"desktop_client_namespace"`
}

func (c *Config) init() {
Expand Down
3 changes: 3 additions & 0 deletions internal/http/services/owncloud/ocdav/propfind.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,9 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide
md.Path = strings.TrimPrefix(md.Path, ns)

baseURI := ctx.Value(ctxKeyBaseURI).(string)
if userAgent, ok := ctxpkg.ContextGetUserAgentCategory(ctx); ok && userAgent == ctxpkg.DesktopUserAgent {
baseURI = path.Join(s.c.DesktopClientNamespace, baseURI)
}

ref := path.Join(baseURI, md.Path)
if md.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER {
Expand Down
53 changes: 52 additions & 1 deletion pkg/ctx/agentctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,21 @@ package ctx

import (
"context"
"strings"

ua "github.com/mileusna/useragent"
"google.golang.org/grpc/metadata"
)

// UserAgentHeader is the header used for the user agent
const UserAgentHeader = "x-user-agent"
const (
UserAgentHeader = "x-user-agent"

WebUserAgent = "web"
GrpcUserAgent = "grpc"
MobileUserAgent = "mobile"
DesktopUserAgent = "desktop"
)

// ContextGetUserAgent returns the user agent if set in the given context.
// see https://github.com/grpc/grpc-go/issues/1100
Expand Down Expand Up @@ -56,3 +64,46 @@ func ContextGetUserAgentString(ctx context.Context) (string, bool) {
}
return userAgentLst[0], true
}

// ContextGetUserAgentCategory returns the category of the user agent
// (i.e. if it is a web, mobile, desktop or grpc user agent)
func ContextGetUserAgentCategory(ctx context.Context) (string, bool) {
agent, ok := ContextGetUserAgent(ctx)
if !ok {
return "", false
}
switch {
case isWeb(agent):
return WebUserAgent, true
case isMobile(agent):
return MobileUserAgent, true
case isDesktop(agent):
return DesktopUserAgent, true
case isGRPC(agent):
return GrpcUserAgent, true
default:
return "", false
}
}

func isWeb(ua *ua.UserAgent) bool {
return ua.IsChrome() || ua.IsEdge() || ua.IsFirefox() || ua.IsSafari() ||
ua.IsInternetExplorer() || ua.IsOpera() || ua.IsOperaMini()
}

// isMobile returns true if the useragent is generated by the mobile
func isMobile(ua *ua.UserAgent) bool {
// workaround as the library does not recognise iOS string inside the user agent
isIOS := ua.IsIOS() || strings.Contains(ua.String, "iOS")
return !isWeb(ua) && (ua.IsAndroid() || isIOS)
}

// isDesktop returns true if the useragent is generated by a desktop application
func isDesktop(ua *ua.UserAgent) bool {
return ua.Desktop && !isWeb(ua)
}

// isGRPC returns true if the useragent is generated by a grpc client
func isGRPC(ua *ua.UserAgent) bool {
return strings.HasPrefix(ua.Name, "grpc")
}
73 changes: 15 additions & 58 deletions pkg/useragent/useragent_test.go → pkg/ctx/agentctx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,105 +16,62 @@
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

package useragent
package ctx

import (
"context"
"testing"

ua "github.com/mileusna/useragent"
"google.golang.org/grpc/metadata"
)

func TestUserAgentIsAllowed(t *testing.T) {

tests := []struct {
description string
userAgent string
userAgents []string
expected bool
expected string
}{
{
description: "grpc-go",
userAgent: "grpc-go",
userAgents: []string{"grpc"},
expected: true,
},
{
description: "grpc-go",
userAgent: "grpc-go",
userAgents: []string{"desktop", "mobile", "web"},
expected: false,
expected: "grpc",
},
{
description: "web-firefox",
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15",
userAgents: []string{"web"},
expected: true,
},
{
description: "web-firefox",
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15",
userAgents: []string{"desktop", "mobile", "grpc"},
expected: false,
},
{
description: "desktop-mirall",
userAgent: "Mozilla/5.0 (Linux) mirall/2.7.1 (build 2596) (cernboxcmd, centos-3.10.0-1160.36.2.el7.x86_64 ClientArchitecture: x86_64 OsArchitecture: x86_64)",
userAgents: []string{"desktop"},
expected: true,
expected: "web",
},
{
description: "desktop-mirall",
userAgent: "Mozilla/5.0 (Linux) mirall/2.7.1 (build 2596) (cernboxcmd, centos-3.10.0-1160.36.2.el7.x86_64 ClientArchitecture: x86_64 OsArchitecture: x86_64)",
userAgents: []string{"web", "mobile", "grpc"},
expected: false,
},
{
description: "mobile-android",
userAgent: "Mozilla/5.0 (Android) ownCloud-android/2.13.1 cernbox/Android",
userAgents: []string{"mobile"},
expected: true,
},
{
description: "mobile-ios",
userAgent: "Mozilla/5.0 (iOS) ownCloud-iOS/3.8.0 cernbox/iOS",
userAgents: []string{"mobile"},
expected: true,
expected: "desktop",
},
{
description: "mobile-android",
userAgent: "Mozilla/5.0 (Android) ownCloud-android/2.13.1 cernbox/Android",
userAgents: []string{"web", "desktop", "grpc"},
expected: false,
expected: "mobile",
},
{
description: "mobile-ios",
userAgent: "Mozilla/5.0 (iOS) ownCloud-iOS/3.8.0 cernbox/iOS",
userAgents: []string{"web", "desktop", "grpc"},
expected: false,
expected: "mobile",
},
{
description: "mobile-web",
userAgent: "Mozilla/5.0 (Android 11; Mobile; rv:86.0) Gecko/86.0 Firefox/86.0",
userAgents: []string{"web"},
expected: true,
},
{
description: "mobile-web",
userAgent: "Mozilla/5.0 (Android 11; Mobile; rv:86.0) Gecko/86.0 Firefox/86.0",
userAgents: []string{"desktop", "grpc", "mobile"},
expected: false,
expected: "web",
},
}

ctx := context.Background()
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
ctx = metadata.NewIncomingContext(ctx, metadata.New(map[string]string{UserAgentHeader: tt.userAgent}))
cat, _ := ContextGetUserAgentCategory(ctx)

ua := ua.Parse(tt.userAgent)

res := IsUserAgentAllowed(&ua, tt.userAgents)

if res != tt.expected {
t.Fatalf("result does not match with expected. got=%+v expected=%+v", res, tt.expected)
if cat != tt.expected {
t.Fatalf("result does not match with expected. got=%+v expected=%+v", cat, tt.expected)
}

})
Expand Down
77 changes: 0 additions & 77 deletions pkg/useragent/useragent.go

This file was deleted.

0 comments on commit 800ce3e

Please sign in to comment.