github.com/cs3org/reva/v2@v2.27.7/pkg/conversions/role.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 conversions sits between CS3 type definitions and OCS API Responses
    20  package conversions
    21  
    22  import (
    23  	"fmt"
    24  	"strings"
    25  
    26  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    27  	"github.com/cs3org/reva/v2/pkg/storage/utils/grants"
    28  )
    29  
    30  // Role is a set of ocs permissions and cs3 resource permissions under a common name.
    31  type Role struct {
    32  	Name                   string
    33  	cS3ResourcePermissions *provider.ResourcePermissions
    34  	ocsPermissions         Permissions
    35  }
    36  
    37  const (
    38  	// RoleViewer grants non-editor role on a resource.
    39  	RoleViewer = "viewer"
    40  	// RoleViewerListGrants grants non-editor role on a resource.
    41  	RoleViewerListGrants = "viewer-list-grants"
    42  	// RoleSpaceViewer grants non-editor role on a space.
    43  	RoleSpaceViewer = "spaceviewer"
    44  	// RoleEditor grants editor permission on a resource, including folders.
    45  	RoleEditor = "editor"
    46  	// RoleEditorListGrants grants editor permission on a resource, including folders.
    47  	RoleEditorListGrants = "editor-list-grants"
    48  	// RoleEditorListGrantsWithVersions grants editor permission on a resource, including folders.
    49  	RoleEditorListGrantsWithVersions = "editor-list-grants-with-versions"
    50  	// RoleSpaceEditor grants editor permission on a space.
    51  	RoleSpaceEditor = "spaceeditor"
    52  	// RoleSpaceEditorWithoutVersions grants editor permission without list/restore versions on a space.
    53  	RoleSpaceEditorWithoutVersions = "spaceeditor-without-versions"
    54  	// RoleFileEditor grants editor permission on a single file.
    55  	RoleFileEditor = "file-editor"
    56  	// RoleFileEditorListGrants grants editor permission on a single file.
    57  	RoleFileEditorListGrants = "file-editor-list-grants"
    58  	// RoleFileEditorListGrantsWithVersions grants editor permission on a single file.
    59  	RoleFileEditorListGrantsWithVersions = "file-editor-list-grants-with-versions"
    60  	// RoleCoowner grants co-owner permissions on a resource.
    61  	RoleCoowner = "coowner"
    62  	// RoleEditorLite grants permission to upload and download to a resource.
    63  	RoleEditorLite = "editor-lite"
    64  	// RoleUploader grants uploader permission to upload onto a resource (no download).
    65  	RoleUploader = "uploader"
    66  	// RoleManager grants manager permissions on a resource. Semantically equivalent to co-owner.
    67  	RoleManager = "manager"
    68  	// RoleSecureViewer grants secure view permissions on a resource or space.
    69  	RoleSecureViewer = "secure-viewer"
    70  
    71  	// RoleUnknown is used for unknown roles.
    72  	RoleUnknown = "unknown"
    73  	// RoleLegacy provides backwards compatibility.
    74  	RoleLegacy = "legacy"
    75  	// RoleDenied grants no permission at all on a resource
    76  	RoleDenied = "denied"
    77  )
    78  
    79  // CS3ResourcePermissions for the role
    80  func (r *Role) CS3ResourcePermissions() *provider.ResourcePermissions {
    81  	return r.cS3ResourcePermissions
    82  }
    83  
    84  // OCSPermissions for the role
    85  func (r *Role) OCSPermissions() Permissions {
    86  	return r.ocsPermissions
    87  }
    88  
    89  // WebDAVPermissions returns the webdav permissions used in propfinds, eg. "WCKDNVR"
    90  /*
    91  	from https://github.com/owncloud/core/blob/10715e2b1c85fc3855a38d2b1fe4426b5e3efbad/apps/dav/lib/Files/PublicFiles/SharedNodeTrait.php#L196-L215
    92  
    93  		$p = '';
    94  		if ($node->isDeletable() && $this->checkSharePermissions(Constants::PERMISSION_DELETE)) {
    95  			$p .= 'D';
    96  		}
    97  		if ($node->isUpdateable() && $this->checkSharePermissions(Constants::PERMISSION_UPDATE)) {
    98  			$p .= 'NV'; // Renameable, Moveable
    99  		}
   100  		if ($node->getType() === \OCP\Files\FileInfo::TYPE_FILE) {
   101  			if ($node->isUpdateable() && $this->checkSharePermissions(Constants::PERMISSION_UPDATE)) {
   102  				$p .= 'W';
   103  			}
   104  		} else {
   105  			if ($node->isCreatable() && $this->checkSharePermissions(Constants::PERMISSION_CREATE)) {
   106  				$p .= 'CK';
   107  			}
   108  		}
   109  
   110  */
   111  // D = delete
   112  // NV = update (renameable moveable)
   113  // W = update (files only)
   114  // CK = create (folders only)
   115  // S = Shared
   116  // R = Shareable
   117  // M = Mounted
   118  // Z = Deniable (NEW)
   119  // P = Purge from trashbin
   120  // X = SecureViewable
   121  func (r *Role) WebDAVPermissions(isDir, isShared, isMountpoint, isPublic bool) string {
   122  	var b strings.Builder
   123  	if !isPublic && isShared {
   124  		fmt.Fprintf(&b, "S")
   125  	}
   126  	if r.ocsPermissions.Contain(PermissionShare) {
   127  		fmt.Fprintf(&b, "R")
   128  	}
   129  	if !isPublic && isMountpoint {
   130  		fmt.Fprintf(&b, "M")
   131  	}
   132  	if r.ocsPermissions.Contain(PermissionDelete) {
   133  		fmt.Fprintf(&b, "D") // TODO oc10 shows received shares as deletable
   134  	}
   135  	if r.ocsPermissions.Contain(PermissionWrite) {
   136  		// Single file public link shares cannot be renamed
   137  		if !isPublic || (isPublic && r.cS3ResourcePermissions != nil && r.cS3ResourcePermissions.Move) {
   138  			fmt.Fprintf(&b, "NV")
   139  		}
   140  		if !isDir {
   141  			fmt.Fprintf(&b, "W")
   142  		}
   143  	}
   144  	if isDir && r.ocsPermissions.Contain(PermissionCreate) {
   145  		fmt.Fprintf(&b, "CK")
   146  	}
   147  
   148  	if r.CS3ResourcePermissions().DenyGrant {
   149  		fmt.Fprintf(&b, "Z")
   150  	}
   151  
   152  	if r.CS3ResourcePermissions().PurgeRecycle {
   153  		fmt.Fprintf(&b, "P")
   154  	}
   155  
   156  	if r.Name == RoleSecureViewer {
   157  		fmt.Fprintf(&b, "X")
   158  	}
   159  
   160  	return b.String()
   161  }
   162  
   163  // RoleFromName creates a role from the name
   164  func RoleFromName(name string) *Role {
   165  	switch name {
   166  	case RoleDenied:
   167  		return NewDeniedRole()
   168  	case RoleViewer:
   169  		return NewViewerRole()
   170  	case RoleViewerListGrants:
   171  		return NewViewerListGrantsRole()
   172  	case RoleSpaceViewer:
   173  		return NewSpaceViewerRole()
   174  	case RoleEditor:
   175  		return NewEditorRole()
   176  	case RoleEditorListGrants:
   177  		return NewEditorListGrantsRole()
   178  	case RoleEditorListGrantsWithVersions:
   179  		return NewEditorListGrantsWithVersionsRole()
   180  	case RoleSpaceEditor:
   181  		return NewSpaceEditorRole()
   182  	case RoleFileEditor:
   183  		return NewFileEditorRole()
   184  	case RoleFileEditorListGrants:
   185  		return NewFileEditorListGrantsRole()
   186  	case RoleFileEditorListGrantsWithVersions:
   187  		return NewFileEditorListGrantsWithVersionsRole()
   188  	case RoleUploader:
   189  		return NewUploaderRole()
   190  	case RoleManager:
   191  		return NewManagerRole()
   192  	case RoleSecureViewer:
   193  		return NewSecureViewerRole()
   194  	default:
   195  		return NewUnknownRole()
   196  	}
   197  }
   198  
   199  // NewUnknownRole creates an unknown role. An Unknown role has no permissions over a cs3 resource nor any ocs endpoint.
   200  func NewUnknownRole() *Role {
   201  	return &Role{
   202  		Name:                   RoleUnknown,
   203  		cS3ResourcePermissions: &provider.ResourcePermissions{},
   204  		ocsPermissions:         PermissionInvalid,
   205  	}
   206  }
   207  
   208  // NewDeniedRole creates a fully denied role
   209  func NewDeniedRole() *Role {
   210  	return &Role{
   211  		Name:                   RoleDenied,
   212  		cS3ResourcePermissions: &provider.ResourcePermissions{},
   213  		ocsPermissions:         PermissionsNone,
   214  	}
   215  }
   216  
   217  // NewViewerRole creates a viewer role. `sharing` indicates if sharing permission should be added
   218  func NewViewerRole() *Role {
   219  	p := PermissionRead
   220  	return &Role{
   221  		Name: RoleViewer,
   222  		cS3ResourcePermissions: &provider.ResourcePermissions{
   223  			GetPath:              true,
   224  			GetQuota:             true,
   225  			InitiateFileDownload: true,
   226  			ListContainer:        true,
   227  			ListRecycle:          true,
   228  			Stat:                 true,
   229  		},
   230  		ocsPermissions: p,
   231  	}
   232  }
   233  
   234  // NewViewerListGrantsRole creates a viewer role. `sharing` indicates if sharing permission should be added
   235  func NewViewerListGrantsRole() *Role {
   236  	role := NewViewerRole()
   237  	role.cS3ResourcePermissions.ListGrants = true
   238  	return role
   239  }
   240  
   241  // NewSpaceViewerRole creates a spaceviewer role
   242  func NewSpaceViewerRole() *Role {
   243  	return &Role{
   244  		Name: RoleSpaceViewer,
   245  		cS3ResourcePermissions: &provider.ResourcePermissions{
   246  			GetPath:              true,
   247  			GetQuota:             true,
   248  			InitiateFileDownload: true,
   249  			ListContainer:        true,
   250  			ListGrants:           true,
   251  			ListRecycle:          true,
   252  			Stat:                 true,
   253  		},
   254  		ocsPermissions: PermissionRead,
   255  	}
   256  }
   257  
   258  // NewEditorRole creates an editor role. `sharing` indicates if sharing permission should be added
   259  func NewEditorRole() *Role {
   260  	p := PermissionRead | PermissionCreate | PermissionWrite | PermissionDelete
   261  	return &Role{
   262  		Name: RoleEditor,
   263  		cS3ResourcePermissions: &provider.ResourcePermissions{
   264  			CreateContainer:      true,
   265  			Delete:               true,
   266  			GetPath:              true,
   267  			GetQuota:             true,
   268  			InitiateFileDownload: true,
   269  			InitiateFileUpload:   true,
   270  			ListContainer:        true,
   271  			ListRecycle:          true,
   272  			Move:                 true,
   273  			RestoreRecycleItem:   true,
   274  			Stat:                 true,
   275  		},
   276  		ocsPermissions: p,
   277  	}
   278  }
   279  
   280  // NewEditorListGrantsRole creates an editor role. `sharing` indicates if sharing permission should be added
   281  func NewEditorListGrantsRole() *Role {
   282  	role := NewEditorRole()
   283  	role.cS3ResourcePermissions.ListGrants = true
   284  	return role
   285  }
   286  
   287  // NewEditorListGrantsWithVersionsRole creates an editor role. `sharing` indicates if sharing permission should be added
   288  func NewEditorListGrantsWithVersionsRole() *Role {
   289  	role := NewEditorListGrantsRole()
   290  	role.cS3ResourcePermissions.ListFileVersions = true
   291  	return role
   292  }
   293  
   294  // NewSpaceEditorRole creates an editor role
   295  func NewSpaceEditorRole() *Role {
   296  	return &Role{
   297  		Name: RoleSpaceEditor,
   298  		cS3ResourcePermissions: &provider.ResourcePermissions{
   299  			CreateContainer:      true,
   300  			Delete:               true,
   301  			GetPath:              true,
   302  			GetQuota:             true,
   303  			InitiateFileDownload: true,
   304  			InitiateFileUpload:   true,
   305  			ListContainer:        true,
   306  			ListFileVersions:     true,
   307  			ListGrants:           true,
   308  			ListRecycle:          true,
   309  			Move:                 true,
   310  			RestoreFileVersion:   true,
   311  			RestoreRecycleItem:   true,
   312  			Stat:                 true,
   313  		},
   314  		ocsPermissions: PermissionRead | PermissionCreate | PermissionWrite | PermissionDelete,
   315  	}
   316  }
   317  
   318  // NewSpaceEditorWithoutVersionsRole creates an editor without list/restore versions role
   319  func NewSpaceEditorWithoutVersionsRole() *Role {
   320  	return &Role{
   321  		Name: RoleSpaceEditorWithoutVersions,
   322  		cS3ResourcePermissions: &provider.ResourcePermissions{
   323  			CreateContainer:      true,
   324  			Delete:               true,
   325  			GetPath:              true,
   326  			GetQuota:             true,
   327  			InitiateFileDownload: true,
   328  			InitiateFileUpload:   true,
   329  			ListContainer:        true,
   330  			ListGrants:           true,
   331  			ListRecycle:          true,
   332  			Move:                 true,
   333  			RestoreRecycleItem:   true,
   334  			Stat:                 true,
   335  		},
   336  		ocsPermissions: PermissionRead | PermissionCreate | PermissionWrite | PermissionDelete,
   337  	}
   338  }
   339  
   340  // NewFileEditorRole creates a file-editor role
   341  func NewFileEditorRole() *Role {
   342  	p := PermissionRead | PermissionWrite
   343  	return &Role{
   344  		Name: RoleEditor,
   345  		cS3ResourcePermissions: &provider.ResourcePermissions{
   346  			GetPath:              true,
   347  			GetQuota:             true,
   348  			InitiateFileDownload: true,
   349  			ListContainer:        true,
   350  			ListRecycle:          true,
   351  			Stat:                 true,
   352  			InitiateFileUpload:   true,
   353  			RestoreRecycleItem:   true,
   354  		},
   355  		ocsPermissions: p,
   356  	}
   357  }
   358  
   359  // NewFileEditorListGrantsRole creates a file-editor role
   360  func NewFileEditorListGrantsRole() *Role {
   361  	role := NewFileEditorRole()
   362  	role.cS3ResourcePermissions.ListGrants = true
   363  	return role
   364  }
   365  
   366  // NewFileEditorListGrantsWithVersionsRole creates a file-editor role
   367  func NewFileEditorListGrantsWithVersionsRole() *Role {
   368  	role := NewFileEditorListGrantsRole()
   369  	role.cS3ResourcePermissions.ListFileVersions = true
   370  	return role
   371  }
   372  
   373  // NewCoownerRole creates a coowner role.
   374  func NewCoownerRole() *Role {
   375  	return &Role{
   376  		Name: RoleCoowner,
   377  		cS3ResourcePermissions: &provider.ResourcePermissions{
   378  			GetPath:              true,
   379  			GetQuota:             true,
   380  			InitiateFileDownload: true,
   381  			ListGrants:           true,
   382  			ListContainer:        true,
   383  			ListFileVersions:     true,
   384  			ListRecycle:          true,
   385  			Stat:                 true,
   386  			InitiateFileUpload:   true,
   387  			RestoreFileVersion:   true,
   388  			RestoreRecycleItem:   true,
   389  			CreateContainer:      true,
   390  			Delete:               true,
   391  			Move:                 true,
   392  			PurgeRecycle:         true,
   393  			AddGrant:             true,
   394  			UpdateGrant:          true,
   395  			RemoveGrant:          true,
   396  		},
   397  		ocsPermissions: PermissionAll,
   398  	}
   399  }
   400  
   401  // NewEditorLiteRole creates an editor-lite role
   402  func NewEditorLiteRole() *Role {
   403  	return &Role{
   404  		Name: RoleEditorLite,
   405  		cS3ResourcePermissions: &provider.ResourcePermissions{
   406  			Stat:                 true,
   407  			GetPath:              true,
   408  			CreateContainer:      true,
   409  			InitiateFileUpload:   true,
   410  			InitiateFileDownload: true,
   411  			ListContainer:        true,
   412  			Move:                 true,
   413  		},
   414  		ocsPermissions: PermissionCreate,
   415  	}
   416  }
   417  
   418  // NewUploaderRole creates an uploader role with no download permissions
   419  func NewUploaderRole() *Role {
   420  	return &Role{
   421  		Name: RoleUploader,
   422  		cS3ResourcePermissions: &provider.ResourcePermissions{
   423  			Stat:               true,
   424  			GetPath:            true,
   425  			CreateContainer:    true,
   426  			InitiateFileUpload: true,
   427  		},
   428  		ocsPermissions: PermissionCreate,
   429  	}
   430  }
   431  
   432  // NewNoneRole creates a role with no permissions
   433  func NewNoneRole() *Role {
   434  	return &Role{
   435  		Name:                   "none",
   436  		cS3ResourcePermissions: &provider.ResourcePermissions{},
   437  		ocsPermissions:         PermissionInvalid,
   438  	}
   439  }
   440  
   441  // NewManagerRole creates an manager role
   442  func NewManagerRole() *Role {
   443  	return &Role{
   444  		Name: RoleManager,
   445  		cS3ResourcePermissions: &provider.ResourcePermissions{
   446  			GetPath:              true,
   447  			GetQuota:             true,
   448  			InitiateFileDownload: true,
   449  			ListGrants:           true,
   450  			ListContainer:        true,
   451  			ListFileVersions:     true,
   452  			ListRecycle:          true,
   453  			Stat:                 true,
   454  			InitiateFileUpload:   true,
   455  			RestoreFileVersion:   true,
   456  			RestoreRecycleItem:   true,
   457  			Move:                 true,
   458  			CreateContainer:      true,
   459  			Delete:               true,
   460  			PurgeRecycle:         true,
   461  
   462  			// these permissions only make sense to enforce them in the root of the storage space.
   463  			AddGrant:    true, // managers can add users to the space
   464  			RemoveGrant: true, // managers can remove users from the space
   465  			UpdateGrant: true,
   466  			DenyGrant:   true, // managers can deny access to sub folders
   467  		},
   468  		ocsPermissions: PermissionAll,
   469  	}
   470  }
   471  
   472  // NewSecureViewerRole creates a secure viewer role
   473  func NewSecureViewerRole() *Role {
   474  	return &Role{
   475  		Name: RoleSecureViewer,
   476  		cS3ResourcePermissions: &provider.ResourcePermissions{
   477  			GetPath:       true,
   478  			ListContainer: true,
   479  			Stat:          true,
   480  		},
   481  	}
   482  }
   483  
   484  // RoleFromOCSPermissions tries to map ocs permissions to a role
   485  // TODO: rethink using this. ocs permissions cannot be assigned 1:1 to roles
   486  func RoleFromOCSPermissions(p Permissions, ri *provider.ResourceInfo) *Role {
   487  	switch {
   488  	// Invalid
   489  	case p == PermissionInvalid:
   490  		return NewNoneRole()
   491  	// Uploader
   492  	case p == PermissionCreate:
   493  		return NewUploaderRole()
   494  	// Viewer/SpaceViewer
   495  	case p == PermissionRead:
   496  		if isSpaceRoot(ri) {
   497  			return NewSpaceViewerRole()
   498  		}
   499  		return NewViewerRole()
   500  	// Editor/SpaceEditor
   501  	case p.Contain(PermissionRead) && p.Contain(PermissionWrite) && p.Contain(PermissionCreate) && p.Contain(PermissionDelete) && !p.Contain(PermissionShare):
   502  		if isSpaceRoot(ri) {
   503  			return NewSpaceEditorRole()
   504  		}
   505  
   506  		return NewEditorRole()
   507  	// Custom
   508  	default:
   509  		return NewLegacyRoleFromOCSPermissions(p)
   510  	}
   511  }
   512  
   513  func isSpaceRoot(ri *provider.ResourceInfo) bool {
   514  	if ri == nil {
   515  		return false
   516  	}
   517  	if ri.Type != provider.ResourceType_RESOURCE_TYPE_CONTAINER {
   518  		return false
   519  	}
   520  
   521  	if ri.GetId().GetOpaqueId() != ri.GetSpace().GetRoot().GetOpaqueId() ||
   522  		ri.GetId().GetSpaceId() != ri.GetSpace().GetRoot().GetSpaceId() ||
   523  		ri.GetId().GetStorageId() != ri.GetSpace().GetRoot().GetStorageId() {
   524  		return false
   525  	}
   526  	return true
   527  }
   528  
   529  // NewLegacyRoleFromOCSPermissions tries to map a legacy combination of ocs permissions to cs3 resource permissions as a legacy role
   530  func NewLegacyRoleFromOCSPermissions(p Permissions) *Role {
   531  	r := &Role{
   532  		Name:                   RoleLegacy, // TODO custom role?
   533  		ocsPermissions:         p,
   534  		cS3ResourcePermissions: &provider.ResourcePermissions{},
   535  	}
   536  	if p.Contain(PermissionRead) {
   537  		r.cS3ResourcePermissions.ListContainer = true
   538  		// r.cS3ResourcePermissions.ListGrants = true
   539  		r.cS3ResourcePermissions.ListRecycle = true
   540  		r.cS3ResourcePermissions.Stat = true
   541  		r.cS3ResourcePermissions.GetPath = true
   542  		r.cS3ResourcePermissions.GetQuota = true
   543  		r.cS3ResourcePermissions.InitiateFileDownload = true
   544  	}
   545  	if p.Contain(PermissionWrite) {
   546  		r.cS3ResourcePermissions.InitiateFileUpload = true
   547  		r.cS3ResourcePermissions.RestoreRecycleItem = true
   548  	}
   549  	if p.Contain(PermissionCreate) {
   550  		r.cS3ResourcePermissions.Stat = true
   551  		r.cS3ResourcePermissions.CreateContainer = true
   552  		// FIXME permissions mismatch: double check ocs create vs update file
   553  		// - if the file exists the ocs api needs to check update permission,
   554  		// - if the file does not exist  the ocs api needs to check update permission
   555  		r.cS3ResourcePermissions.InitiateFileUpload = true
   556  		if p.Contain(PermissionWrite) {
   557  			r.cS3ResourcePermissions.Move = true // TODO move only when create and write?
   558  		}
   559  	}
   560  	if p.Contain(PermissionDelete) {
   561  		r.cS3ResourcePermissions.Delete = true
   562  	}
   563  	if p.Contain(PermissionShare) {
   564  		r.cS3ResourcePermissions.AddGrant = true
   565  		// r.cS3ResourcePermissions.RemoveGrant = true // TODO when are you able to unshare / delete
   566  		// r.cS3ResourcePermissions.UpdateGrant = true
   567  	}
   568  	return r
   569  }
   570  
   571  // RoleFromResourcePermissions tries to map cs3 resource permissions to a role
   572  // It needs to know whether this is a link or not, because empty permissions on links mean "INTERNAL LINK"
   573  // while empty permissions on other resources mean "DENIAL". Obviously this is not optimal.
   574  func RoleFromResourcePermissions(rp *provider.ResourcePermissions, islink bool) *Role {
   575  	r := &Role{
   576  		Name:                   RoleUnknown,
   577  		ocsPermissions:         PermissionInvalid,
   578  		cS3ResourcePermissions: rp,
   579  	}
   580  	if rp == nil {
   581  		return r
   582  	}
   583  	if grants.PermissionsEqual(rp, &provider.ResourcePermissions{}) {
   584  		if !islink {
   585  			r.ocsPermissions = PermissionsNone
   586  			r.Name = RoleDenied
   587  		}
   588  		return r
   589  	}
   590  	if rp.ListContainer &&
   591  		rp.ListRecycle &&
   592  		rp.Stat &&
   593  		rp.GetPath &&
   594  		rp.GetQuota &&
   595  		rp.InitiateFileDownload {
   596  		r.ocsPermissions |= PermissionRead
   597  	}
   598  	if rp.InitiateFileUpload &&
   599  		rp.RestoreRecycleItem {
   600  		r.ocsPermissions |= PermissionWrite
   601  	}
   602  	if rp.Stat &&
   603  		rp.CreateContainer &&
   604  		rp.InitiateFileUpload {
   605  		r.ocsPermissions |= PermissionCreate
   606  	}
   607  	if rp.Delete {
   608  		r.ocsPermissions |= PermissionDelete
   609  	}
   610  	if rp.AddGrant {
   611  		r.ocsPermissions |= PermissionShare
   612  	}
   613  
   614  	if r.ocsPermissions.Contain(PermissionRead) {
   615  		if r.ocsPermissions.Contain(PermissionWrite) && r.ocsPermissions.Contain(PermissionCreate) && r.ocsPermissions.Contain(PermissionDelete) && r.ocsPermissions.Contain(PermissionShare) {
   616  			r.Name = RoleEditor
   617  			if rp.ListGrants {
   618  				r.Name = RoleEditorListGrants
   619  			}
   620  			if rp.ListGrants && rp.ListFileVersions {
   621  				r.Name = RoleEditorListGrantsWithVersions
   622  			}
   623  			if rp.RemoveGrant {
   624  				r.Name = RoleManager
   625  			}
   626  			return r // editor or manager
   627  		}
   628  		if r.ocsPermissions == PermissionRead|PermissionShare {
   629  			r.Name = RoleViewer
   630  			if rp.ListGrants {
   631  				r.Name = RoleViewerListGrants
   632  			}
   633  			return r
   634  		}
   635  	} else if rp.Stat && rp.GetPath && rp.ListContainer && !rp.InitiateFileUpload && !rp.Delete && !rp.AddGrant {
   636  		r.Name = RoleSecureViewer
   637  		return r
   638  	}
   639  	if r.ocsPermissions == PermissionCreate {
   640  		if rp.GetPath && rp.InitiateFileDownload && rp.ListContainer && rp.Move {
   641  			r.Name = RoleEditorLite
   642  			return r
   643  		}
   644  		r.Name = RoleUploader
   645  		return r
   646  	}
   647  	r.Name = RoleLegacy
   648  	// at this point other ocs permissions may have been mapped.
   649  	// TODO what about even more granular cs3 permissions?, eg. only stat
   650  	return r
   651  }
   652  
   653  // SufficientCS3Permissions returns true if the `existing` permissions contain the `requested` permissions
   654  func SufficientCS3Permissions(existing, requested *provider.ResourcePermissions) bool {
   655  	if existing == nil || requested == nil {
   656  		return false
   657  	}
   658  	// empty permissions represent a denial
   659  	if grants.PermissionsEqual(requested, &provider.ResourcePermissions{}) {
   660  		return existing.DenyGrant
   661  	}
   662  
   663  	numFields := existing.ProtoReflect().Descriptor().Fields().Len()
   664  	for i := 0; i < numFields; i++ {
   665  		field := existing.ProtoReflect().Descriptor().Fields().Get(i)
   666  		existingPermission := existing.ProtoReflect().Get(field).Bool()
   667  		requestedPermission := requested.ProtoReflect().Get(field).Bool()
   668  		// every requested permission needs to exist for the creator
   669  		if requestedPermission && !existingPermission {
   670  			return false
   671  		}
   672  	}
   673  	return true
   674  }