github.com/cs3org/reva/v2@v2.27.7/pkg/auth/scope/share.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package scope 20 21 import ( 22 "context" 23 "fmt" 24 "strings" 25 26 authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" 27 collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" 28 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 29 registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1" 30 types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" 31 "github.com/cs3org/reva/v2/pkg/errtypes" 32 "github.com/cs3org/reva/v2/pkg/utils" 33 "github.com/rs/zerolog" 34 ) 35 36 func shareScope(_ context.Context, scope *authpb.Scope, resource interface{}, logger *zerolog.Logger) (bool, error) { 37 var share collaboration.Share 38 err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &share) 39 if err != nil { 40 return false, err 41 } 42 43 switch v := resource.(type) { 44 // Viewer role 45 case *registry.GetStorageProvidersRequest: 46 return checkShareStorageRef(&share, v.GetRef()), nil 47 case *provider.StatRequest: 48 return checkShareStorageRef(&share, v.GetRef()), nil 49 case *provider.ListContainerRequest: 50 return checkShareStorageRef(&share, v.GetRef()), nil 51 case *provider.InitiateFileDownloadRequest: 52 return checkShareStorageRef(&share, v.GetRef()), nil 53 54 // Editor role 55 // TODO(ishank011): Add role checks, 56 // need to return appropriate status codes in the ocs/ocdav layers. 57 case *provider.CreateContainerRequest: 58 return checkShareStorageRef(&share, v.GetRef()), nil 59 case *provider.TouchFileRequest: 60 return checkShareStorageRef(&share, v.GetRef()), nil 61 case *provider.DeleteRequest: 62 return checkShareStorageRef(&share, v.GetRef()), nil 63 case *provider.MoveRequest: 64 return checkShareStorageRef(&share, v.GetSource()) && checkShareStorageRef(&share, v.GetDestination()), nil 65 case *provider.InitiateFileUploadRequest: 66 return checkShareStorageRef(&share, v.GetRef()), nil 67 68 case *collaboration.ListReceivedSharesRequest: 69 return true, nil 70 case *collaboration.GetReceivedShareRequest: 71 return checkShareRef(&share, v.GetRef()), nil 72 case string: 73 return checkSharePath(v) || checkResourcePath(v), nil 74 } 75 76 msg := fmt.Sprintf("resource type assertion failed: %+v", resource) 77 logger.Debug().Str("scope", "shareScope").Msg(msg) 78 return false, errtypes.InternalError(msg) 79 } 80 81 func checkShareStorageRef(s *collaboration.Share, r *provider.Reference) bool { 82 // ref: <id:<storage_id:$storageID opaque_id:$opaqueID > > 83 if r.GetResourceId() != nil && r.Path == "" { // path must be empty 84 return utils.ResourceIDEqual(s.ResourceId, r.GetResourceId()) 85 } 86 return false 87 } 88 89 func checkShareRef(s *collaboration.Share, ref *collaboration.ShareReference) bool { 90 if ref.GetId() != nil { 91 return ref.GetId().OpaqueId == s.Id.OpaqueId 92 } 93 if key := ref.GetKey(); key != nil { 94 return (utils.UserEqual(key.Owner, s.Owner) || utils.UserEqual(key.Owner, s.Creator)) && 95 utils.ResourceIDEqual(key.ResourceId, s.ResourceId) && utils.GranteeEqual(key.Grantee, s.Grantee) 96 } 97 return false 98 } 99 func checkShare(s1 *collaboration.Share, s2 *collaboration.Share) bool { 100 if s2.GetId() != nil { 101 return s2.GetId().OpaqueId == s1.Id.OpaqueId 102 } 103 return false 104 } 105 106 func checkSharePath(path string) bool { 107 paths := []string{ 108 "/ocs/v2.php/apps/files_sharing/api/v1/shares", 109 "/ocs/v1.php/apps/files_sharing/api/v1/shares", 110 "/remote.php/webdav", 111 "/remote.php/dav/files", 112 } 113 for _, p := range paths { 114 if strings.HasPrefix(path, p) { 115 return true 116 } 117 } 118 return false 119 } 120 121 // AddShareScope adds the scope to allow access to a user/group share and 122 // the shared resource. 123 func AddShareScope(share *collaboration.Share, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) { 124 // Create a new "scope share" to only expose the required fields to the scope. 125 scopeShare := &collaboration.Share{Id: share.Id, Owner: share.Owner, Creator: share.Creator, ResourceId: share.ResourceId} 126 127 val, err := utils.MarshalProtoV1ToJSON(scopeShare) 128 if err != nil { 129 return nil, err 130 } 131 if scopes == nil { 132 scopes = make(map[string]*authpb.Scope) 133 } 134 scopes["share:"+share.Id.OpaqueId] = &authpb.Scope{ 135 Resource: &types.OpaqueEntry{ 136 Decoder: "json", 137 Value: val, 138 }, 139 Role: role, 140 } 141 return scopes, nil 142 }