Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sharing ng preparation and bugfix #4335

Merged
merged 3 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog/unreleased/fix-shares-cleanup-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Bugfix: Fix public shares cleanup config

The public shares cleanup for expired shares was not configurable via ocis.

https://github.com/cs3org/reva/pull/4335/
6 changes: 6 additions & 0 deletions changelog/unreleased/new-permission-helper-function.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Add sufficient permissions check function

We added a helper function to check for sufficient CS3 resource permissions.

https://github.com/cs3org/reva/pull/4335/
https://github.com/owncloud/ocis/issues/6993
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/conversions"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/publicshare"
Expand All @@ -44,6 +45,7 @@ type config struct {
Driver string `mapstructure:"driver"`
Drivers map[string]map[string]interface{} `mapstructure:"drivers"`
AllowedPathsForShares []string `mapstructure:"allowed_paths_for_shares"`
EnableExpiredSharesCleanup bool `mapstructure:"enable_expired_shares_cleanup"`
WriteableShareMustHavePassword bool `mapstructure:"writeable_share_must_have_password"`
}

Expand Down Expand Up @@ -136,6 +138,12 @@ func (s *service) CreatePublicShare(ctx context.Context, req *link.CreatePublicS
log := appctx.GetLogger(ctx)
log.Info().Str("publicshareprovider", "create").Msg("create public share")

if !conversions.SufficientCS3Permissions(req.GetResourceInfo().GetPermissionSet(), req.GetGrant().GetPermissions().GetPermissions()) {
return &link.CreatePublicShareResponse{
Status: status.NewInvalid(ctx, "insufficient permissions to create that kind of share"),
}, nil
}

if !s.isPathAllowed(req.ResourceInfo.Path) {
return &link.CreatePublicShareResponse{
Status: status.NewInvalid(ctx, "share creation is not allowed for the specified path"),
Expand Down
31 changes: 31 additions & 0 deletions pkg/conversions/role.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package conversions

import (
"fmt"
"reflect"
"strings"

provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
Expand Down Expand Up @@ -508,3 +509,33 @@ func RoleFromResourcePermissions(rp *provider.ResourcePermissions, islink bool)
// TODO what about even more granular cs3 permissions?, eg. only stat
return r
}

// SufficientCS3Permissions returns true if the `existing` permissions contain the `requested` permissions
func SufficientCS3Permissions(existing, requested *provider.ResourcePermissions) bool {
if existing == nil || requested == nil {
return false
}
// empty permissions represent a denial
micbar marked this conversation as resolved.
Show resolved Hide resolved
if grants.PermissionsEqual(requested, &provider.ResourcePermissions{}) {
return existing.DenyGrant
}
requestedPermissionsType := reflect.TypeOf(provider.ResourcePermissions{})
numFields := requestedPermissionsType.NumField()
requestedPermissionsValues := reflect.ValueOf(requested)
existingPermissionsValues := reflect.ValueOf(existing)

for i := 0; i < numFields; i++ {
permissionName := requestedPermissionsType.Field(i).Name
// filter out irrelevant fields
if strings.Contains(permissionName, "XXX") {
continue
}
existingPermission := reflect.Indirect(existingPermissionsValues).FieldByName(permissionName).Bool()
requestedPermission := requestedPermissionsValues.Elem().Field(i).Bool()
// every requested permission needs to exist for the creator
if requestedPermission && !existingPermission {
return false
}
}
return true
}
107 changes: 107 additions & 0 deletions pkg/conversions/role_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package conversions

import (
"testing"

providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/stretchr/testify/assert"
)

func TestSufficientPermissions(t *testing.T) {
type testData struct {
Existing *providerv1beta1.ResourcePermissions
Requested *providerv1beta1.ResourcePermissions
Sufficient bool
}
table := []testData{
micbar marked this conversation as resolved.
Show resolved Hide resolved
{
Existing: nil,
Requested: nil,
Sufficient: false,
},
{
Existing: RoleFromName("editor", true).CS3ResourcePermissions(),
Requested: nil,
Sufficient: false,
},
{
Existing: nil,
Requested: RoleFromName("viewer", true).CS3ResourcePermissions(),
Sufficient: false,
},
{
Existing: RoleFromName("editor", true).CS3ResourcePermissions(),
Requested: RoleFromName("viewer", true).CS3ResourcePermissions(),
Sufficient: true,
},
{
Existing: RoleFromName("viewer", true).CS3ResourcePermissions(),
Requested: RoleFromName("editor", true).CS3ResourcePermissions(),
Sufficient: false,
},
{
Existing: RoleFromName("spaceviewer", true).CS3ResourcePermissions(),
Requested: RoleFromName("spaceeditor", true).CS3ResourcePermissions(),
Sufficient: false,
},
{
Existing: RoleFromName("manager", true).CS3ResourcePermissions(),
Requested: RoleFromName("spaceeditor", true).CS3ResourcePermissions(),
Sufficient: true,
},
{
Existing: RoleFromName("manager", true).CS3ResourcePermissions(),
Requested: RoleFromName("spaceviewer", true).CS3ResourcePermissions(),
Sufficient: true,
},
{
Existing: RoleFromName("manager", true).CS3ResourcePermissions(),
Requested: RoleFromName("manager", true).CS3ResourcePermissions(),
Sufficient: true,
},
{
Existing: RoleFromName("manager", true).CS3ResourcePermissions(),
Requested: RoleFromName("denied", true).CS3ResourcePermissions(),
Sufficient: true,
},
{
Existing: RoleFromName("spaceeditor", true).CS3ResourcePermissions(),
Requested: RoleFromName("denied", true).CS3ResourcePermissions(),
Sufficient: false,
},
{
Existing: RoleFromName("editor", true).CS3ResourcePermissions(),
Requested: RoleFromName("denied", true).CS3ResourcePermissions(),
Sufficient: false,
},
{
Existing: &providerv1beta1.ResourcePermissions{
// all permissions, used for personal space owners
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,
},
Requested: RoleFromName("denied", true).CS3ResourcePermissions(),
Sufficient: true,
},
}
for _, test := range table {
assert.Equal(t, test.Sufficient, SufficientCS3Permissions(test.Existing, test.Requested))
}
}