diff --git a/changelog/unreleased/uniform-ocs-roles.md b/changelog/unreleased/uniform-ocs-roles.md new file mode 100644 index 0000000000..9c953ecb13 --- /dev/null +++ b/changelog/unreleased/uniform-ocs-roles.md @@ -0,0 +1,3 @@ +Enhancement: Reuse ocs role objects in other drivers + +https://github.com/cs3org/reva/pull/2514 \ No newline at end of file diff --git a/cmd/reva/ocm-share-create.go b/cmd/reva/ocm-share-create.go index 06ce7c9105..10eb2d1691 100644 --- a/cmd/reva/ocm-share-create.go +++ b/cmd/reva/ocm-share-create.go @@ -31,6 +31,7 @@ import ( ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" + "github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions" "github.com/cs3org/reva/pkg/utils" "github.com/jedib0t/go-pretty/table" "github.com/pkg/errors" @@ -165,28 +166,11 @@ func ocmShareCreateCommand() *command { func getOCMSharePerm(p string) (*ocm.SharePermissions, int, error) { if p == viewerPermission { return &ocm.SharePermissions{ - Permissions: &provider.ResourcePermissions{ - GetPath: true, - InitiateFileDownload: true, - ListFileVersions: true, - ListContainer: true, - Stat: true, - }, + Permissions: conversions.NewViewerRole().CS3ResourcePermissions(), }, 1, nil } else if p == editorPermission { return &ocm.SharePermissions{ - Permissions: &provider.ResourcePermissions{ - GetPath: true, - InitiateFileDownload: true, - ListFileVersions: true, - ListContainer: true, - Stat: true, - CreateContainer: true, - Delete: true, - InitiateFileUpload: true, - RestoreFileVersion: true, - Move: true, - }, + Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), }, 15, nil } return nil, 0, errors.New("invalid rol: " + p) diff --git a/internal/grpc/interceptors/auth/scope.go b/internal/grpc/interceptors/auth/scope.go index 5f1c96cb91..df425f6dbc 100644 --- a/internal/grpc/interceptors/auth/scope.go +++ b/internal/grpc/interceptors/auth/scope.go @@ -57,15 +57,7 @@ func expandAndVerifyScope(ctx context.Context, req interface{}, tokenScope map[s return err } - hasEditorRole := false - for _, v := range tokenScope { - if v.Role == authpb.Role_ROLE_OWNER || v.Role == authpb.Role_ROLE_EDITOR { - hasEditorRole = true - break - } - } - - if ref, ok := extractRef(req, hasEditorRole); ok { + if ref, ok := extractRef(req, tokenScope); ok { // The request is for a storage reference. This can be the case for multiple scenarios: // - If the path is not empty, the request might be coming from a share where the accessor is // trying to impersonate the owner, since the share manager doesn't know the @@ -240,7 +232,7 @@ func checkIfNestedResource(ctx context.Context, ref *provider.Reference, parent } -func extractRef(req interface{}, hasEditorRole bool) (*provider.Reference, bool) { +func extractRefForReaderRole(req interface{}) (*provider.Reference, bool) { switch v := req.(type) { // Read requests case *registry.GetStorageProvidersRequest: @@ -256,33 +248,84 @@ func extractRef(req interface{}, hasEditorRole bool) (*provider.Reference, bool) case *gateway.OpenInAppRequest: return v.GetRef(), true - // App provider requests + // App provider requests case *appregistry.GetAppProvidersRequest: return &provider.Reference{ResourceId: v.ResourceInfo.Id}, true } - if !hasEditorRole { - return nil, false - } + return nil, false + +} +func extractRefForUploaderRole(req interface{}) (*provider.Reference, bool) { switch v := req.(type) { // Write Requests + case *registry.GetStorageProvidersRequest: + return v.GetRef(), true + case *provider.StatRequest: + return v.GetRef(), true case *provider.CreateContainerRequest: return v.GetRef(), true case *provider.TouchFileRequest: return v.GetRef(), true + case *provider.InitiateFileUploadRequest: + return v.GetRef(), true + } + + return nil, false + +} + +func extractRefForEditorRole(req interface{}) (*provider.Reference, bool) { + switch v := req.(type) { + // Remaining edit Requests case *provider.DeleteRequest: return v.GetRef(), true case *provider.MoveRequest: return v.GetSource(), true - case *provider.InitiateFileUploadRequest: - return v.GetRef(), true case *provider.SetArbitraryMetadataRequest: return v.GetRef(), true case *provider.UnsetArbitraryMetadataRequest: return v.GetRef(), true + } + + return nil, false +} + +func extractRef(req interface{}, tokenScope map[string]*authpb.Scope) (*provider.Reference, bool) { + var readPerm, uploadPerm, editPerm bool + for _, v := range tokenScope { + if v.Role == authpb.Role_ROLE_OWNER || v.Role == authpb.Role_ROLE_EDITOR || v.Role == authpb.Role_ROLE_VIEWER { + readPerm = true + } + if v.Role == authpb.Role_ROLE_OWNER || v.Role == authpb.Role_ROLE_EDITOR || v.Role == authpb.Role_ROLE_UPLOADER { + uploadPerm = true + } + if v.Role == authpb.Role_ROLE_OWNER || v.Role == authpb.Role_ROLE_EDITOR { + editPerm = true + } + } + + if readPerm { + ref, ok := extractRefForReaderRole(req) + if ok { + return ref, true + } } + if uploadPerm { + ref, ok := extractRefForUploaderRole(req) + if ok { + return ref, true + } + } + if editPerm { + ref, ok := extractRefForEditorRole(req) + if ok { + return ref, true + } + } + return nil, false } diff --git a/internal/grpc/services/gateway/storageprovider.go b/internal/grpc/services/gateway/storageprovider.go index 54c0230f9b..912fc72d1b 100644 --- a/internal/grpc/services/gateway/storageprovider.go +++ b/internal/grpc/services/gateway/storageprovider.go @@ -37,8 +37,6 @@ 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" - ua "github.com/mileusna/useragent" "github.com/cs3org/reva/pkg/appctx" "github.com/cs3org/reva/pkg/errtypes" @@ -1778,30 +1776,36 @@ func (s *svc) listSharesFolder(ctx context.Context) (*provider.ListContainerResp return lcr, nil } -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 { diff --git a/internal/http/interceptors/auth/auth.go b/internal/http/interceptors/auth/auth.go index c73b8afacb..cb4c55c6a0 100644 --- a/internal/http/interceptors/auth/auth.go +++ b/internal/http/interceptors/auth/auth.go @@ -173,7 +173,7 @@ func New(m map[string]interface{}, unprotected []string) (global.Middleware, err isUnprotectedEndpoint = true } - ctx, err := authenticateUser(w, r, conf, unprotected, tokenStrategy, tokenManager, tokenWriter, credChain, isUnprotectedEndpoint) + ctx, err := authenticateUser(w, r, conf, tokenStrategy, tokenManager, tokenWriter, credChain, isUnprotectedEndpoint) if err != nil { if !isUnprotectedEndpoint { return @@ -187,7 +187,7 @@ func New(m map[string]interface{}, unprotected []string) (global.Middleware, err return chain, nil } -func authenticateUser(w http.ResponseWriter, r *http.Request, conf *config, unprotected []string, tokenStrategy auth.TokenStrategy, tokenManager token.Manager, tokenWriter auth.TokenWriter, credChain map[string]auth.CredentialStrategy, isUnprotectedEndpoint bool) (context.Context, error) { +func authenticateUser(w http.ResponseWriter, r *http.Request, conf *config, tokenStrategy auth.TokenStrategy, tokenManager token.Manager, tokenWriter auth.TokenWriter, credChain map[string]auth.CredentialStrategy, isUnprotectedEndpoint bool) (context.Context, error) { ctx := r.Context() log := appctx.GetLogger(ctx) diff --git a/internal/http/services/owncloud/ocs/conversions/role.go b/internal/http/services/owncloud/ocs/conversions/role.go index f04bd7cabd..3ede7b81df 100644 --- a/internal/http/services/owncloud/ocs/conversions/role.go +++ b/internal/http/services/owncloud/ocs/conversions/role.go @@ -242,7 +242,7 @@ func NewCoownerRole() *Role { // NewUploaderRole creates an uploader role func NewUploaderRole() *Role { return &Role{ - Name: RoleViewer, + Name: RoleUploader, cS3ResourcePermissions: &provider.ResourcePermissions{ Stat: true, ListContainer: true, diff --git a/pkg/auth/manager/publicshares/publicshares.go b/pkg/auth/manager/publicshares/publicshares.go index 0dc4de28be..bbbc30a25a 100644 --- a/pkg/auth/manager/publicshares/publicshares.go +++ b/pkg/auth/manager/publicshares/publicshares.go @@ -137,10 +137,14 @@ func (m *manager) Authenticate(ctx context.Context, token, secret string) (*user share := publicShareResponse.GetShare() role := authpb.Role_ROLE_VIEWER roleStr := "viewer" - if share.Permissions.Permissions.InitiateFileUpload { + if share.Permissions.Permissions.InitiateFileUpload && !share.Permissions.Permissions.InitiateFileDownload { + role = authpb.Role_ROLE_UPLOADER + roleStr = "uploader" + } else if share.Permissions.Permissions.InitiateFileUpload { role = authpb.Role_ROLE_EDITOR roleStr = "editor" } + scope, err := scope.AddPublicShareScope(share, role, nil) if err != nil { return nil, nil, err diff --git a/pkg/auth/scope/scope.go b/pkg/auth/scope/scope.go index 4c4ddc2c67..c040854e80 100644 --- a/pkg/auth/scope/scope.go +++ b/pkg/auth/scope/scope.go @@ -56,5 +56,5 @@ func VerifyScope(ctx context.Context, scopeMap map[string]*authpb.Scope, resourc } func hasRoleEditor(scope authpb.Scope) bool { - return scope.Role == authpb.Role_ROLE_EDITOR + return scope.Role == authpb.Role_ROLE_OWNER || scope.Role == authpb.Role_ROLE_EDITOR || scope.Role == authpb.Role_ROLE_UPLOADER } diff --git a/pkg/cbox/storage/eoshomewrapper/eoshomewrapper.go b/pkg/cbox/storage/eoshomewrapper/eoshomewrapper.go index 7160967ff8..39a021d92b 100644 --- a/pkg/cbox/storage/eoshomewrapper/eoshomewrapper.go +++ b/pkg/cbox/storage/eoshomewrapper/eoshomewrapper.go @@ -26,6 +26,7 @@ import ( "github.com/Masterminds/sprig" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" ctxpkg "github.com/cs3org/reva/pkg/ctx" + "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/storage" "github.com/cs3org/reva/pkg/storage/fs/registry" "github.com/cs3org/reva/pkg/storage/utils/eosfs" @@ -112,6 +113,10 @@ func (w *wrapper) ListFolder(ctx context.Context, ref *provider.Reference, mdKey return res, nil } +func (w *wrapper) DenyGrant(ctx context.Context, ref *provider.Reference, g *provider.Grantee) error { + return errtypes.NotSupported("eos: deny grant is only enabled for project spaces") +} + func (w *wrapper) getMountID(ctx context.Context, r *provider.ResourceInfo) string { u := ctxpkg.ContextMustGetUser(ctx) b := bytes.Buffer{} diff --git a/pkg/cbox/storage/eoswrapper/eoswrapper.go b/pkg/cbox/storage/eoswrapper/eoswrapper.go index 5cbfc0feed..4ec0413cf0 100644 --- a/pkg/cbox/storage/eoswrapper/eoswrapper.go +++ b/pkg/cbox/storage/eoswrapper/eoswrapper.go @@ -162,6 +162,18 @@ func (w *wrapper) RestoreRevision(ctx context.Context, ref *provider.Reference, return w.FS.RestoreRevision(ctx, ref, revisionKey) } +func (w *wrapper) DenyGrant(ctx context.Context, ref *provider.Reference, g *provider.Grantee) error { + // This is only allowed for project space admins + if strings.HasPrefix(w.conf.Namespace, eosProjectsNamespace) { + if err := w.userIsProjectAdmin(ctx, ref); err != nil { + return err + } + return w.FS.DenyGrant(ctx, ref, g) + } + + return errtypes.NotSupported("eos: deny grant is only enabled for project spaces") +} + func (w *wrapper) getMountID(ctx context.Context, r *provider.ResourceInfo) string { if r == nil { return "" @@ -194,6 +206,7 @@ func (w *wrapper) setProjectSharingPermissions(ctx context.Context, r *provider. r.PermissionSet.UpdateGrant = true r.PermissionSet.ListGrants = true r.PermissionSet.GetQuota = true + r.PermissionSet.DenyGrant = true return nil } } diff --git a/pkg/cbox/utils/conversions.go b/pkg/cbox/utils/conversions.go index 271f8d5cb1..41b8e78a44 100644 --- a/pkg/cbox/utils/conversions.go +++ b/pkg/cbox/utils/conversions.go @@ -28,6 +28,7 @@ import ( link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" + "github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions" ) // DBShare stores information about user and public shares. @@ -129,46 +130,14 @@ func SharePermToInt(p *provider.ResourcePermissions) int { func IntTosharePerm(p int, itemType string) *provider.ResourcePermissions { switch p { case 1: - return &provider.ResourcePermissions{ - ListContainer: true, - ListGrants: true, - ListFileVersions: true, - ListRecycle: true, - Stat: true, - GetPath: true, - GetQuota: true, - InitiateFileDownload: true, - } + return conversions.NewViewerRole().CS3ResourcePermissions() case 15: - perm := &provider.ResourcePermissions{ - ListContainer: true, - ListGrants: true, - ListFileVersions: true, - ListRecycle: true, - Stat: true, - GetPath: true, - GetQuota: true, - InitiateFileDownload: true, - - InitiateFileUpload: true, - RestoreFileVersion: true, - RestoreRecycleItem: true, - } if itemType == "folder" { - perm.CreateContainer = true - perm.Delete = true - perm.Move = true - perm.PurgeRecycle = true + return conversions.NewEditorRole().CS3ResourcePermissions() } - return perm + return conversions.NewFileEditorRole().CS3ResourcePermissions() case 4: - return &provider.ResourcePermissions{ - Stat: true, - ListContainer: true, - GetPath: true, - CreateContainer: true, - InitiateFileUpload: true, - } + return conversions.NewUploaderRole().CS3ResourcePermissions() default: // TODO we may have other options, for now this is a denial return &provider.ResourcePermissions{} diff --git a/pkg/ctx/agentctx.go b/pkg/ctx/agentctx.go index 74eda0b563..1d96f355af 100644 --- a/pkg/ctx/agentctx.go +++ b/pkg/ctx/agentctx.go @@ -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 @@ -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") +} diff --git a/pkg/useragent/useragent_test.go b/pkg/ctx/agentctx_test.go similarity index 50% rename from pkg/useragent/useragent_test.go rename to pkg/ctx/agentctx_test.go index c37ae97508..8cfd6b0e6a 100644 --- a/pkg/useragent/useragent_test.go +++ b/pkg/ctx/agentctx_test.go @@ -16,12 +16,13 @@ // 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) { @@ -29,92 +30,48 @@ 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) } }) diff --git a/pkg/storage/utils/eosfs/eosfs.go b/pkg/storage/utils/eosfs/eosfs.go index c8c44b7c56..4e6bbab6e0 100644 --- a/pkg/storage/utils/eosfs/eosfs.go +++ b/pkg/storage/utils/eosfs/eosfs.go @@ -38,6 +38,7 @@ import ( rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" + "github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions" "github.com/cs3org/reva/pkg/appctx" ctxpkg "github.com/cs3org/reva/pkg/ctx" "github.com/cs3org/reva/pkg/eosclient" @@ -1677,59 +1678,17 @@ func (fs *eosfs) permissionSet(ctx context.Context, eosFileInfo *eosclient.FileI if u.Opaque != nil { if publicShare, ok := u.Opaque.Map["public-share-role"]; ok { if string(publicShare.Value) == "editor" { - return &provider.ResourcePermissions{ - CreateContainer: true, - Delete: true, - GetPath: true, - GetQuota: true, - InitiateFileDownload: true, - InitiateFileUpload: true, - ListContainer: true, - ListFileVersions: true, - ListGrants: true, - ListRecycle: true, - Move: true, - PurgeRecycle: true, - RestoreFileVersion: true, - RestoreRecycleItem: true, - Stat: true, - } - } - return &provider.ResourcePermissions{ - GetPath: true, - GetQuota: true, - InitiateFileDownload: true, - ListContainer: true, - ListFileVersions: true, - ListRecycle: true, - ListGrants: true, - Stat: true, + return conversions.NewEditorRole().CS3ResourcePermissions() + } else if string(publicShare.Value) == "uploader" { + return conversions.NewUploaderRole().CS3ResourcePermissions() } + // Default to viewer role + return conversions.NewViewerRole().CS3ResourcePermissions() } } - return &provider.ResourcePermissions{ - // owner has all permissions - AddGrant: true, - CreateContainer: true, - Delete: true, - GetPath: true, - GetQuota: true, - InitiateFileDownload: true, - InitiateFileUpload: true, - ListContainer: true, - ListFileVersions: true, - ListGrants: true, - ListRecycle: true, - Move: true, - PurgeRecycle: true, - RemoveGrant: true, - RestoreFileVersion: true, - RestoreRecycleItem: true, - Stat: true, - UpdateGrant: true, - DenyGrant: true, - } + // owner has all permissions + return conversions.NewManagerRole().CS3ResourcePermissions() } auth, err := fs.getUserAuth(ctx, u, eosFileInfo.File) diff --git a/pkg/useragent/useragent.go b/pkg/useragent/useragent.go deleted file mode 100644 index 53d766ed26..0000000000 --- a/pkg/useragent/useragent.go +++ /dev/null @@ -1,77 +0,0 @@ -// 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 ( - "strings" - - ua "github.com/mileusna/useragent" -) - -// isWeb returns true if the useragent is generated by the web -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") -} - -// getCategory returns the category of the user agent -// (i.e. if it is a web, mobile, desktop or grpc user agent) -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 "" - } -} - -// IsUserAgentAllowed return true if the user agent corresponds -// to one in the allowed user agents list -func IsUserAgentAllowed(ua *ua.UserAgent, allowedUserAgents []string) bool { - cat := getCategory(ua) - for _, userAgent := range allowedUserAgents { - if userAgent == cat { - return true - } - } - return false -}