Skip to content

Commit

Permalink
refactor permission mapping to a role struct
Browse files Browse the repository at this point in the history
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
  • Loading branch information
butonic committed Dec 10, 2020
1 parent 761ca60 commit 9637661
Show file tree
Hide file tree
Showing 9 changed files with 452 additions and 391 deletions.
21 changes: 8 additions & 13 deletions internal/http/services/ocmd/shares.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
ocmcore "github.com/cs3org/go-cs3apis/cs3/ocm/core/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
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"
Expand Down Expand Up @@ -87,7 +86,7 @@ func (h *sharesHandler) createShare(w http.ResponseWriter, r *http.Request) {
providerInfo := ocmprovider.ProviderInfo{
Domain: meshProvider,
Services: []*ocmprovider.Service{
&ocmprovider.Service{
{
Host: clientIP,
},
},
Expand Down Expand Up @@ -124,7 +123,7 @@ func (h *sharesHandler) createShare(w http.ResponseWriter, r *http.Request) {
}

var permissions conversions.Permissions
var role, token string
var token string
options, ok := protocolDecoded["options"].(map[string]interface{})
if !ok {
WriteError(w, r, APIErrorInvalidParameter, "protocol: webdav token not provided", nil)
Expand All @@ -137,24 +136,20 @@ func (h *sharesHandler) createShare(w http.ResponseWriter, r *http.Request) {
return
}

var role *conversions.Role
pval, ok := options["permissions"].(int)
if !ok {
role = conversions.RoleViewer
role = conversions.NewViewerRole()
} else {
permissions, err = conversions.NewPermissions(pval)
if err != nil {
WriteError(w, r, APIErrorInvalidParameter, err.Error(), nil)
return
}
role = conversions.Permissions2Role(permissions)
role = conversions.RoleFromOCSPermissions(permissions)
}

var resourcePermissions *provider.ResourcePermissions
resourcePermissions, err = conversions.Role2CS3Permissions(role)
if err != nil {
WriteError(w, r, APIErrorInvalidParameter, "unknown role", err)
}
val, err := json.Marshal(resourcePermissions)
val, err := json.Marshal(role.CS3ResourcePermissions())
if err != nil {
WriteError(w, r, APIErrorServerError, "could not encode role", nil)
return
Expand All @@ -173,11 +168,11 @@ func (h *sharesHandler) createShare(w http.ResponseWriter, r *http.Request) {
Name: protocolDecoded["name"].(string),
Opaque: &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"permissions": &types.OpaqueEntry{
"permissions": {
Decoder: "json",
Value: val,
},
"token": &types.OpaqueEntry{
"token": {
Decoder: "plain",
Value: []byte(token),
},
Expand Down
116 changes: 0 additions & 116 deletions internal/http/services/owncloud/ocs/conversions/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,111 +168,6 @@ type MatchValueData struct {
ShareWith string `json:"shareWith" xml:"shareWith"`
}

// Role2CS3Permissions converts string roles (from the request body) into cs3 permissions
// TODO(refs) consider using a mask instead of booleans here, might reduce all this boilerplate
func Role2CS3Permissions(r string) (*provider.ResourcePermissions, error) {
switch r {
case RoleViewer:
return &provider.ResourcePermissions{
ListContainer: true,
ListGrants: true,
ListFileVersions: true,
ListRecycle: true,
Stat: true,
GetPath: true,
GetQuota: true,
InitiateFileDownload: true,
}, nil
case RoleEditor:
return &provider.ResourcePermissions{
ListContainer: true,
ListGrants: true,
ListFileVersions: true,
ListRecycle: true,
Stat: true,
GetPath: true,
GetQuota: true,
InitiateFileDownload: true,

Move: true,
InitiateFileUpload: true,
RestoreFileVersion: true,
RestoreRecycleItem: true,
CreateContainer: true,
Delete: true,
PurgeRecycle: true,
}, nil
case RoleCoowner:
return &provider.ResourcePermissions{
ListContainer: true,
ListGrants: true,
ListFileVersions: true,
ListRecycle: true,
Stat: true,
GetPath: true,
GetQuota: true,
InitiateFileDownload: true,

Move: true,
InitiateFileUpload: true,
RestoreFileVersion: true,
RestoreRecycleItem: true,
CreateContainer: true,
Delete: true,
PurgeRecycle: true,

AddGrant: true,
RemoveGrant: true, // TODO when are you able to unshare / delete
UpdateGrant: true,
}, nil
default:
return nil, fmt.Errorf("unknown role: %s", r)
}
}

// AsCS3Permissions returns permission values as cs3api permissions
// TODO sort out mapping, this is just a first guess
// TODO use roles to make this configurable
func AsCS3Permissions(p int, rp *provider.ResourcePermissions) *provider.ResourcePermissions {
if rp == nil {
rp = &provider.ResourcePermissions{}
}

if p&int(PermissionRead) != 0 {
rp.ListContainer = true
rp.ListGrants = true
rp.ListFileVersions = true
rp.ListRecycle = true
rp.Stat = true
rp.GetPath = true
rp.GetQuota = true
rp.InitiateFileDownload = true
}
if p&int(PermissionWrite) != 0 {
rp.InitiateFileUpload = true
rp.RestoreFileVersion = true
rp.RestoreRecycleItem = true
}
if p&int(PermissionCreate) != 0 {
rp.CreateContainer = true
// FIXME permissions mismatch: double check create vs write file
rp.InitiateFileUpload = true
if p&int(PermissionWrite) != 0 {
rp.Move = true // TODO move only when create and write?
}
}
if p&int(PermissionDelete) != 0 {
rp.Delete = true
rp.PurgeRecycle = true
}
if p&int(PermissionShare) != 0 {
rp.AddGrant = true
rp.RemoveGrant = true // TODO when are you able to unshare / delete
rp.UpdateGrant = true
}
return rp
}

// UserShare2ShareData converts a cs3api user share into shareData data model
// TODO(jfd) merge userShare2ShareData with publicShare2ShareData
func UserShare2ShareData(ctx context.Context, share *collaboration.Share) (*ShareData, error) {
Expand Down Expand Up @@ -415,14 +310,3 @@ func Permissions2OCSPermissions(p *provider.ResourcePermissions) Permissions {
func timestampToExpiration(t *types.Timestamp) string {
return time.Unix(int64(t.Seconds), int64(t.Nanos)).UTC().Format("2006-01-02 15:05:05")
}

const (
// RoleLegacy provides backwards compatibility
RoleLegacy string = "legacy"
// RoleViewer grants non-editor role on a resource
RoleViewer string = "viewer"
// RoleEditor grants editor permission on a resource
RoleEditor string = "editor"
// RoleCoowner grants owner permissions on a resource
RoleCoowner string = "coowner"
)
64 changes: 0 additions & 64 deletions internal/http/services/owncloud/ocs/conversions/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ package conversions

import (
"fmt"

provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
)

// Permissions reflects the CRUD permissions used in the OCS sharing API
Expand Down Expand Up @@ -64,65 +62,3 @@ func NewPermissions(val int) (Permissions, error) {
func (p Permissions) Contain(other Permissions) bool {
return p&other != 0
}

// Permissions2Role performs permission conversions for user and federated shares
func Permissions2Role(p Permissions) string {
role := RoleLegacy
if p.Contain(PermissionRead) {
role = RoleViewer
if p.Contain(PermissionWrite) && p.Contain(PermissionCreate) && p.Contain(PermissionDelete) {
role = RoleEditor
if p.Contain(PermissionShare) {
role = RoleCoowner
}
}
}
return role
}

// Role2Permissions converts string roles into ocs permissions
func Role2Permissions(r string) (Permissions, error) {
switch r {
case RoleViewer:
return PermissionRead, nil
case RoleEditor:
return PermissionRead & PermissionWrite & PermissionCreate & PermissionDelete, nil
case RoleCoowner:
return PermissionAll, nil
case RoleLegacy:
return PermissionInvalid, nil // FIXME
default:
return PermissionInvalid, fmt.Errorf("unknown role: %s", r)
}
}

// ResourcePermissions2Permissions converts CS3 storage resource permissions into ocs permissions
func ResourcePermissions2Permissions(rp *provider.ResourcePermissions) Permissions {
// TODO what about trash? and versions?
p := PermissionInvalid
if rp.ListContainer == true &&
//rp.ListGrants == true &&
//rp.ListFileVersions == true &&
//rp.ListRecycle == true &&
//rp.Stat == true &&
//rp.GetPath == true &&
//rp.GetQuota == true &&
rp.InitiateFileDownload == true {
p = p | PermissionRead
}
if rp.InitiateFileUpload == true {
p = p | PermissionWrite
}
if rp.CreateContainer == true {
p = p | PermissionCreate
}
if rp.Delete == true {
p = p | PermissionDelete
}
if rp.AddGrant == true &&
rp.RemoveGrant == true &&
rp.UpdateGrant == true {
p = p | PermissionShare
}
return p
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,16 @@ func TestPermissions2Role(t *testing.T) {
}

table := map[Permissions]string{
PermissionRead: RoleViewer,
PermissionWrite: RoleEditor,
PermissionShare: RoleCoowner,
PermissionRead: RoleViewer,
PermissionRead | PermissionWrite | PermissionCreate | PermissionDelete: RoleEditor,
PermissionAll: RoleCoowner,
PermissionRead | PermissionWrite: RoleEditor,
PermissionWrite | PermissionShare: RoleCoowner,
PermissionWrite: RoleLegacy,
PermissionShare: RoleLegacy,
PermissionWrite | PermissionShare: RoleLegacy,
}

for permissions, role := range table {
actual := Permissions2Role(permissions)
actual := RoleFromOCSPermissions(permissions).Name
checkRole(role, actual)
}
}
Loading

0 comments on commit 9637661

Please sign in to comment.