mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-07 15:43:11 -04:00
reva-bump-2.42.2
This commit is contained in:
committed by
Ralf Haferkamp
parent
f21207ed96
commit
2bf70a6f70
145
vendor/github.com/opencloud-eu/reva/v2/internal/grpc/interceptors/auth/scope.go
generated
vendored
145
vendor/github.com/opencloud-eu/reva/v2/internal/grpc/interceptors/auth/scope.go
generated
vendored
@@ -75,11 +75,6 @@ func expandAndVerifyScope(ctx context.Context, req interface{}, tokenScope map[s
|
||||
return nil
|
||||
}
|
||||
|
||||
case strings.HasPrefix(k, "share"):
|
||||
if err = resolveUserShare(ctx, ref, tokenScope[k], client, mgr); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
case strings.HasPrefix(k, "lightweight"):
|
||||
if err = resolveLightweightScope(ctx, ref, tokenScope[k], user, client, mgr); err == nil {
|
||||
return nil
|
||||
@@ -130,8 +125,13 @@ func expandAndVerifyScope(ctx context.Context, req interface{}, tokenScope map[s
|
||||
}
|
||||
|
||||
func resolveLightweightScope(ctx context.Context, ref *provider.Reference, scope *authpb.Scope, user *userpb.User, client gateway.GatewayAPIClient, mgr token.Manager) error {
|
||||
refString, err := storagespace.FormatReference(ref)
|
||||
if err != nil {
|
||||
// cannot format reference, so cannot be valid
|
||||
return errtypes.PermissionDenied("invalid reference")
|
||||
}
|
||||
// Check if this ref is cached
|
||||
key := "lw:" + user.Id.OpaqueId + scopeDelimiter + getRefKey(ref)
|
||||
key := "lw:" + user.Id.OpaqueId + scopeDelimiter + refString
|
||||
if _, err := scopeExpansionCache.Get(key); err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -164,13 +164,7 @@ func resolvePublicShare(ctx context.Context, ref *provider.Reference, scope *aut
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkCacheForNestedResource(ctx, ref, share.ResourceId, client, mgr); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Some services like wopi don't access the shared resource relative to the
|
||||
// share root but instead relative to the shared resources parent.
|
||||
return checkRelativeReference(ctx, ref, share.ResourceId, client)
|
||||
return checkCacheForNestedResource(ctx, ref, share.ResourceId, client, mgr)
|
||||
}
|
||||
|
||||
func resolveOCMShare(ctx context.Context, ref *provider.Reference, scope *authpb.Scope, client gateway.GatewayAPIClient, mgr token.Manager) error {
|
||||
@@ -184,69 +178,18 @@ func resolveOCMShare(ctx context.Context, ref *provider.Reference, scope *authpb
|
||||
ref.ResourceId = share.GetResourceId()
|
||||
}
|
||||
|
||||
if err := checkCacheForNestedResource(ctx, ref, share.ResourceId, client, mgr); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Some services like wopi don't access the shared resource relative to the
|
||||
// share root but instead relative to the shared resources parent.
|
||||
return checkRelativeReference(ctx, ref, share.ResourceId, client)
|
||||
}
|
||||
|
||||
// checkRelativeReference checks if the shared resource is being accessed via a relative reference
|
||||
// e.g.:
|
||||
// storage: abcd, space: efgh
|
||||
// /root (id: efgh)
|
||||
// - New file.txt (id: ijkl) <- shared resource
|
||||
//
|
||||
// If the requested reference looks like this:
|
||||
// Reference{ResourceId: {StorageId: "abcd", SpaceId: "efgh"}, Path: "./New file.txt"}
|
||||
// then the request is considered relative and this function would return true.
|
||||
// Only references which are relative to the immediate parent of a resource are considered valid.
|
||||
func checkRelativeReference(ctx context.Context, requested *provider.Reference, sharedResourceID *provider.ResourceId, client gateway.GatewayAPIClient) error {
|
||||
sRes, err := client.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{ResourceId: sharedResourceID}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sRes.Status.Code != rpc.Code_CODE_OK {
|
||||
return statuspkg.NewErrorFromCode(sRes.Status.Code, "auth interceptor")
|
||||
}
|
||||
|
||||
sharedResource := sRes.Info
|
||||
|
||||
// Is this a shared space
|
||||
if sharedResource.ParentId == nil {
|
||||
// Is the requested resource part of the shared space?
|
||||
if requested.ResourceId.StorageId != sharedResource.Id.StorageId || requested.ResourceId.SpaceId != sharedResource.Id.SpaceId {
|
||||
return errtypes.PermissionDenied("space access forbidden via public link")
|
||||
}
|
||||
} else {
|
||||
parentID := sharedResource.ParentId
|
||||
parentID.StorageId = sharedResource.Id.StorageId
|
||||
|
||||
if !utils.ResourceIDEqual(parentID, requested.ResourceId) && utils.MakeRelativePath(sharedResource.Path) != requested.Path {
|
||||
return errtypes.PermissionDenied("access forbidden via public link")
|
||||
}
|
||||
}
|
||||
|
||||
key := storagespace.FormatResourceID(sharedResourceID) + scopeDelimiter + getRefKey(requested)
|
||||
_ = scopeExpansionCache.SetWithExpire(key, nil, scopeCacheExpiration*time.Second)
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveUserShare(ctx context.Context, ref *provider.Reference, scope *authpb.Scope, client gateway.GatewayAPIClient, mgr token.Manager) error {
|
||||
var share collaboration.Share
|
||||
err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &share)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return checkCacheForNestedResource(ctx, ref, share.ResourceId, client, mgr)
|
||||
}
|
||||
|
||||
func checkCacheForNestedResource(ctx context.Context, ref *provider.Reference, resource *provider.ResourceId, client gateway.GatewayAPIClient, mgr token.Manager) error {
|
||||
refString, err := storagespace.FormatReference(ref)
|
||||
if err != nil {
|
||||
// cannot format reference, so cannot be valid
|
||||
return errtypes.PermissionDenied("invalid reference")
|
||||
}
|
||||
|
||||
// Check if this ref is cached
|
||||
key := storagespace.FormatResourceID(resource) + scopeDelimiter + getRefKey(ref)
|
||||
key := storagespace.FormatResourceID(resource) + scopeDelimiter + refString
|
||||
if _, err := scopeExpansionCache.Get(key); err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -270,40 +213,25 @@ func checkIfNestedResource(ctx context.Context, ref *provider.Reference, parent
|
||||
return false, statuspkg.NewErrorFromCode(statResponse.Status.Code, "auth interceptor")
|
||||
}
|
||||
|
||||
pathResp, err := client.GetPath(ctx, &provider.GetPathRequest{ResourceId: statResponse.GetInfo().GetId()})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if pathResp.Status.Code != rpc.Code_CODE_OK {
|
||||
return false, statuspkg.NewErrorFromCode(pathResp.Status.Code, "auth interceptor")
|
||||
}
|
||||
parentPath := pathResp.Path
|
||||
parentInfo := statResponse.GetInfo()
|
||||
|
||||
childPath := ref.GetPath()
|
||||
if childPath != "" && childPath != "." && strings.HasPrefix(childPath, parentPath) {
|
||||
// if the request is relative from the root, we can return directly
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// The request is not relative to the root. We need to find out if the requested resource is child of the `parent` (coming from token scope)
|
||||
// We need to find out if the requested resource is child of the `parent` (coming from token scope)
|
||||
// We mint a token as the owner of the public share and try to stat the reference
|
||||
// TODO(ishank011): We need to find a better alternative to this
|
||||
// NOTE: did somebody say service accounts? ...
|
||||
|
||||
var user *userpb.User
|
||||
if statResponse.GetInfo().GetOwner().GetType() == userpb.UserType_USER_TYPE_SPACE_OWNER {
|
||||
if parentInfo.GetOwner().GetType() == userpb.UserType_USER_TYPE_SPACE_OWNER {
|
||||
// fake a space owner user
|
||||
user = &userpb.User{
|
||||
Id: statResponse.GetInfo().GetOwner(),
|
||||
Id: parentInfo.GetOwner(),
|
||||
}
|
||||
} else {
|
||||
userResp, err := client.GetUser(ctx, &userpb.GetUserRequest{UserId: statResponse.Info.Owner, SkipFetchingUserGroups: true})
|
||||
userResp, err := client.GetUser(ctx, &userpb.GetUserRequest{UserId: parentInfo.GetOwner(), SkipFetchingUserGroups: true})
|
||||
if err != nil || userResp.Status.Code != rpc.Code_CODE_OK {
|
||||
return false, err
|
||||
}
|
||||
user = userResp.User
|
||||
}
|
||||
|
||||
scope, err := scope.AddOwnerScope(map[string]*authpb.Scope{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -329,6 +257,24 @@ func checkIfNestedResource(ctx context.Context, ref *provider.Reference, parent
|
||||
if childStat.GetStatus().GetCode() != rpc.Code_CODE_OK {
|
||||
return false, statuspkg.NewErrorFromCode(childStat.Status.Code, "auth interceptor")
|
||||
}
|
||||
childInfo := childStat.GetInfo()
|
||||
|
||||
// child can only be a nested resource if it is within the same space as parent
|
||||
if childInfo.GetId().GetStorageId() != parentInfo.GetId().GetStorageId() ||
|
||||
childInfo.GetId().GetSpaceId() != parentInfo.GetId().GetSpaceId() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Both resources are in the same space, now check paths
|
||||
pathResp, err := client.GetPath(ctx, &provider.GetPathRequest{ResourceId: statResponse.GetInfo().GetId()})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if pathResp.Status.Code != rpc.Code_CODE_OK {
|
||||
return false, statuspkg.NewErrorFromCode(pathResp.Status.Code, "auth interceptor")
|
||||
}
|
||||
parentPath := pathResp.Path
|
||||
|
||||
pathResp, err = client.GetPath(ctx, &provider.GetPathRequest{ResourceId: childStat.GetInfo().GetId()})
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -336,10 +282,9 @@ func checkIfNestedResource(ctx context.Context, ref *provider.Reference, parent
|
||||
if pathResp.GetStatus().GetCode() != rpc.Code_CODE_OK {
|
||||
return false, statuspkg.NewErrorFromCode(pathResp.Status.Code, "auth interceptor")
|
||||
}
|
||||
childPath = pathResp.Path
|
||||
childPath := pathResp.Path
|
||||
|
||||
return strings.HasPrefix(childPath, parentPath), nil
|
||||
|
||||
}
|
||||
|
||||
func extractRefFromListProvidersReq(v *registry.ListStorageProvidersRequest) (*provider.Reference, bool) {
|
||||
@@ -513,17 +458,3 @@ func extractShareRef(req interface{}) (*collaboration.ShareReference, bool) {
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func getRefKey(ref *provider.Reference) string {
|
||||
if ref.GetPath() != "" {
|
||||
return ref.Path
|
||||
}
|
||||
|
||||
if ref.GetResourceId() != nil {
|
||||
return storagespace.FormatResourceID(ref.ResourceId)
|
||||
}
|
||||
|
||||
// on malicious request both path and rid could be empty
|
||||
// we still should not panic
|
||||
return ""
|
||||
}
|
||||
|
||||
89
vendor/github.com/opencloud-eu/reva/v2/internal/http/services/owncloud/ocdav/copy.go
generated
vendored
89
vendor/github.com/opencloud-eu/reva/v2/internal/http/services/owncloud/ocdav/copy.go
generated
vendored
@@ -21,6 +21,7 @@ package ocdav
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -274,7 +275,7 @@ func (s *svc) executePathCopy(ctx context.Context, selector pool.Selectable[gate
|
||||
|
||||
var uploadEP, uploadToken string
|
||||
for _, p := range uRes.Protocols {
|
||||
if p.Protocol == "simple" {
|
||||
if p.Protocol == "tus" {
|
||||
uploadEP, uploadToken = p.UploadEndpoint, p.Token
|
||||
}
|
||||
}
|
||||
@@ -303,24 +304,10 @@ func (s *svc) executePathCopy(ctx context.Context, selector pool.Selectable[gate
|
||||
}
|
||||
|
||||
// 4. do upload
|
||||
|
||||
httpUploadReq, err := rhttp.NewRequest(ctx, "PUT", uploadEP, httpDownloadRes.Body)
|
||||
fileid, err = s.tusUpload(ctx, uploadEP, uploadToken, httpDownloadRes.Body, int64(cp.sourceInfo.GetSize()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
httpUploadReq.Header.Set(datagateway.TokenTransportHeader, uploadToken)
|
||||
httpUploadReq.ContentLength = int64(cp.sourceInfo.GetSize())
|
||||
|
||||
httpUploadRes, err := s.client.Do(httpUploadReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer httpUploadRes.Body.Close()
|
||||
if httpUploadRes.StatusCode != http.StatusOK {
|
||||
return err
|
||||
}
|
||||
|
||||
fileid = httpUploadRes.Header.Get(net.HeaderOCFileID)
|
||||
}
|
||||
|
||||
w.Header().Set(net.HeaderOCFileID, fileid)
|
||||
@@ -498,7 +485,7 @@ func (s *svc) executeSpacesCopy(ctx context.Context, w http.ResponseWriter, sele
|
||||
|
||||
var uploadEP, uploadToken string
|
||||
for _, p := range uRes.Protocols {
|
||||
if p.Protocol == "simple" {
|
||||
if p.Protocol == "tus" {
|
||||
uploadEP, uploadToken = p.UploadEndpoint, p.Token
|
||||
}
|
||||
}
|
||||
@@ -530,24 +517,10 @@ func (s *svc) executeSpacesCopy(ctx context.Context, w http.ResponseWriter, sele
|
||||
}
|
||||
|
||||
// 4. do upload
|
||||
|
||||
httpUploadReq, err := rhttp.NewRequest(ctx, http.MethodPut, uploadEP, httpDownloadRes.Body)
|
||||
fileid, err = s.tusUpload(ctx, uploadEP, uploadToken, httpDownloadRes.Body, int64(cp.sourceInfo.GetSize()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
httpUploadReq.Header.Set(datagateway.TokenTransportHeader, uploadToken)
|
||||
httpUploadReq.ContentLength = int64(cp.sourceInfo.GetSize())
|
||||
|
||||
httpUploadRes, err := s.client.Do(httpUploadReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer httpUploadRes.Body.Close()
|
||||
if httpUploadRes.StatusCode != http.StatusOK {
|
||||
return err
|
||||
}
|
||||
|
||||
fileid = httpUploadRes.Header.Get(net.HeaderOCFileID)
|
||||
}
|
||||
|
||||
w.Header().Set(net.HeaderOCFileID, fileid)
|
||||
@@ -756,3 +729,55 @@ func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
|
||||
return ©{source: srcRef, sourceInfo: srcStatRes.Info, depth: depth, successCode: successCode, destination: dstRef}
|
||||
}
|
||||
|
||||
func (s *svc) tusUpload(ctx context.Context, uploadEP, uploadToken string, body io.Reader, size int64) (string, error) {
|
||||
chunkSize := int64(10000000)
|
||||
var offset int64
|
||||
var fileid string
|
||||
|
||||
for offset < size {
|
||||
n := chunkSize
|
||||
if offset+n > size {
|
||||
n = size - offset
|
||||
}
|
||||
|
||||
req, err := rhttp.NewRequest(ctx, http.MethodPatch, uploadEP, io.LimitReader(body, n))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req.Header.Set(datagateway.TokenTransportHeader, uploadToken)
|
||||
req.Header.Set(net.HeaderTusResumable, "1.0.0")
|
||||
req.Header.Set(net.HeaderUploadOffset, strconv.FormatInt(offset, 10))
|
||||
req.Header.Set(net.HeaderContentType, "application/offset+octet-stream")
|
||||
req.ContentLength = n
|
||||
|
||||
res, err := s.client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusNoContent && res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated {
|
||||
res.Body.Close()
|
||||
return "", fmt.Errorf("unexpected status code during TUS upload: %d", res.StatusCode)
|
||||
}
|
||||
|
||||
if id := res.Header.Get(net.HeaderOCFileID); id != "" {
|
||||
fileid = id
|
||||
}
|
||||
|
||||
newOffsetStr := res.Header.Get(net.HeaderUploadOffset)
|
||||
res.Body.Close()
|
||||
|
||||
if newOffsetStr != "" {
|
||||
newOffset, err := strconv.ParseInt(newOffsetStr, 10, 64)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid Upload-Offset header: %v", err)
|
||||
}
|
||||
offset = newOffset
|
||||
} else {
|
||||
offset += n
|
||||
}
|
||||
}
|
||||
return fileid, nil
|
||||
}
|
||||
|
||||
75
vendor/github.com/opencloud-eu/reva/v2/pkg/auth/scope/receivedshare.go
generated
vendored
75
vendor/github.com/opencloud-eu/reva/v2/pkg/auth/scope/receivedshare.go
generated
vendored
@@ -1,75 +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 scope
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
|
||||
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/errtypes"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
func receivedShareScope(_ context.Context, scope *authpb.Scope, resource interface{}, logger *zerolog.Logger) (bool, error) {
|
||||
var share collaboration.ReceivedShare
|
||||
err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &share)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
switch v := resource.(type) {
|
||||
case *collaboration.GetReceivedShareRequest:
|
||||
return checkShareRef(share.Share, v.GetRef()), nil
|
||||
case *collaboration.UpdateReceivedShareRequest:
|
||||
return checkShare(share.Share, v.GetShare().GetShare()), nil
|
||||
case string:
|
||||
return checkSharePath(v) || checkResourcePath(v), nil
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("resource type assertion failed: %+v", resource)
|
||||
logger.Debug().Str("scope", "receivedShareScope").Msg(msg)
|
||||
return false, errtypes.InternalError(msg)
|
||||
}
|
||||
|
||||
// AddReceivedShareScope adds the scope to allow access to a received user/group share and
|
||||
// the shared resource.
|
||||
func AddReceivedShareScope(share *collaboration.ReceivedShare, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
|
||||
// Create a new "scope share" to only expose the required fields to the scope.
|
||||
scopeShare := &collaboration.Share{Id: share.Share.Id, Owner: share.Share.Owner, Creator: share.Share.Creator, ResourceId: share.Share.ResourceId}
|
||||
|
||||
val, err := utils.MarshalProtoV1ToJSON(&collaboration.ReceivedShare{Share: scopeShare})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if scopes == nil {
|
||||
scopes = make(map[string]*authpb.Scope)
|
||||
}
|
||||
scopes["receivedshare:"+share.Share.Id.OpaqueId] = &authpb.Scope{
|
||||
Resource: &types.OpaqueEntry{
|
||||
Decoder: "json",
|
||||
Value: val,
|
||||
},
|
||||
Role: role,
|
||||
}
|
||||
return scopes, nil
|
||||
}
|
||||
12
vendor/github.com/opencloud-eu/reva/v2/pkg/auth/scope/scope.go
generated
vendored
12
vendor/github.com/opencloud-eu/reva/v2/pkg/auth/scope/scope.go
generated
vendored
@@ -31,13 +31,11 @@ import (
|
||||
type Verifier func(context.Context, *authpb.Scope, interface{}, *zerolog.Logger) (bool, error)
|
||||
|
||||
var supportedScopes = map[string]Verifier{
|
||||
"user": userScope,
|
||||
"publicshare": publicshareScope,
|
||||
"resourceinfo": resourceinfoScope,
|
||||
"share": shareScope,
|
||||
"receivedshare": receivedShareScope,
|
||||
"lightweight": lightweightAccountScope,
|
||||
"ocmshare": ocmShareScope,
|
||||
"user": userScope,
|
||||
"publicshare": publicshareScope,
|
||||
"resourceinfo": resourceinfoScope,
|
||||
"lightweight": lightweightAccountScope,
|
||||
"ocmshare": ocmShareScope,
|
||||
}
|
||||
|
||||
// VerifyScope is the function to be called when dismantling tokens to check if
|
||||
|
||||
142
vendor/github.com/opencloud-eu/reva/v2/pkg/auth/scope/share.go
generated
vendored
142
vendor/github.com/opencloud-eu/reva/v2/pkg/auth/scope/share.go
generated
vendored
@@ -1,142 +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 scope
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
|
||||
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
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"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/errtypes"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
func shareScope(_ context.Context, scope *authpb.Scope, resource interface{}, logger *zerolog.Logger) (bool, error) {
|
||||
var share collaboration.Share
|
||||
err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &share)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
switch v := resource.(type) {
|
||||
// Viewer role
|
||||
case *registry.GetStorageProvidersRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.StatRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.ListContainerRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.InitiateFileDownloadRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
|
||||
// Editor role
|
||||
// TODO(ishank011): Add role checks,
|
||||
// need to return appropriate status codes in the ocs/ocdav layers.
|
||||
case *provider.CreateContainerRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.TouchFileRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.DeleteRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.MoveRequest:
|
||||
return checkShareStorageRef(&share, v.GetSource()) && checkShareStorageRef(&share, v.GetDestination()), nil
|
||||
case *provider.InitiateFileUploadRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
|
||||
case *collaboration.ListReceivedSharesRequest:
|
||||
return true, nil
|
||||
case *collaboration.GetReceivedShareRequest:
|
||||
return checkShareRef(&share, v.GetRef()), nil
|
||||
case string:
|
||||
return checkSharePath(v) || checkResourcePath(v), nil
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("resource type assertion failed: %+v", resource)
|
||||
logger.Debug().Str("scope", "shareScope").Msg(msg)
|
||||
return false, errtypes.InternalError(msg)
|
||||
}
|
||||
|
||||
func checkShareStorageRef(s *collaboration.Share, r *provider.Reference) bool {
|
||||
// ref: <id:<storage_id:$storageID opaque_id:$opaqueID > >
|
||||
if r.GetResourceId() != nil && r.Path == "" { // path must be empty
|
||||
return utils.ResourceIDEqual(s.ResourceId, r.GetResourceId())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkShareRef(s *collaboration.Share, ref *collaboration.ShareReference) bool {
|
||||
if ref.GetId() != nil {
|
||||
return ref.GetId().OpaqueId == s.Id.OpaqueId
|
||||
}
|
||||
if key := ref.GetKey(); key != nil {
|
||||
return (utils.UserEqual(key.Owner, s.Owner) || utils.UserEqual(key.Owner, s.Creator)) &&
|
||||
utils.ResourceIDEqual(key.ResourceId, s.ResourceId) && utils.GranteeEqual(key.Grantee, s.Grantee)
|
||||
}
|
||||
return false
|
||||
}
|
||||
func checkShare(s1 *collaboration.Share, s2 *collaboration.Share) bool {
|
||||
if s2.GetId() != nil {
|
||||
return s2.GetId().OpaqueId == s1.Id.OpaqueId
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkSharePath(path string) bool {
|
||||
paths := []string{
|
||||
"/ocs/v2.php/apps/files_sharing/api/v1/shares",
|
||||
"/ocs/v1.php/apps/files_sharing/api/v1/shares",
|
||||
"/remote.php/webdav",
|
||||
"/remote.php/dav/files",
|
||||
}
|
||||
for _, p := range paths {
|
||||
if strings.HasPrefix(path, p) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AddShareScope adds the scope to allow access to a user/group share and
|
||||
// the shared resource.
|
||||
func AddShareScope(share *collaboration.Share, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
|
||||
// Create a new "scope share" to only expose the required fields to the scope.
|
||||
scopeShare := &collaboration.Share{Id: share.Id, Owner: share.Owner, Creator: share.Creator, ResourceId: share.ResourceId}
|
||||
|
||||
val, err := utils.MarshalProtoV1ToJSON(scopeShare)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if scopes == nil {
|
||||
scopes = make(map[string]*authpb.Scope)
|
||||
}
|
||||
scopes["share:"+share.Id.OpaqueId] = &authpb.Scope{
|
||||
Resource: &types.OpaqueEntry{
|
||||
Decoder: "json",
|
||||
Value: val,
|
||||
},
|
||||
Role: role,
|
||||
}
|
||||
return scopes, nil
|
||||
}
|
||||
Reference in New Issue
Block a user