github.com/cs3org/reva/v2@v2.27.7/pkg/storage/utils/decomposedfs/permissions/spacepermissions.go (about) 1 package permissions 2 3 import ( 4 "context" 5 6 userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 7 cs3permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1" 8 v1beta11 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" 9 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 10 ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" 11 "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" 12 "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node" 13 "github.com/cs3org/reva/v2/pkg/utils" 14 "go.opentelemetry.io/otel" 15 "go.opentelemetry.io/otel/trace" 16 "google.golang.org/grpc" 17 ) 18 19 var ( 20 tracer trace.Tracer 21 ) 22 23 func init() { 24 tracer = otel.Tracer("github.com/cs3org/reva/pkg/storage/utils/decomposedfs/permissions") 25 } 26 27 const ( 28 _spaceTypePersonal = "personal" 29 _spaceTypeProject = "project" 30 ) 31 32 // PermissionsChecker defines an interface for checking permissions on a Node 33 type PermissionsChecker interface { 34 AssemblePermissions(ctx context.Context, n *node.Node) (ap *provider.ResourcePermissions, err error) 35 AssembleTrashPermissions(ctx context.Context, n *node.Node) (ap *provider.ResourcePermissions, err error) 36 } 37 38 // CS3PermissionsClient defines an interface for checking permissions against the CS3 permissions service 39 type CS3PermissionsClient interface { 40 CheckPermission(ctx context.Context, in *cs3permissions.CheckPermissionRequest, opts ...grpc.CallOption) (*cs3permissions.CheckPermissionResponse, error) 41 } 42 43 // Permissions manages permissions 44 type Permissions struct { 45 item PermissionsChecker // handles item permissions 46 permissionsSelector pool.Selectable[cs3permissions.PermissionsAPIClient] // handlers space permissions 47 } 48 49 // NewPermissions returns a new Permissions instance 50 func NewPermissions(item PermissionsChecker, permissionsSelector pool.Selectable[cs3permissions.PermissionsAPIClient]) Permissions { 51 return Permissions{item: item, permissionsSelector: permissionsSelector} 52 } 53 54 // AssemblePermissions is used to assemble file permissions 55 func (p Permissions) AssemblePermissions(ctx context.Context, n *node.Node) (*provider.ResourcePermissions, error) { 56 ctx, span := tracer.Start(ctx, "AssemblePermissions") 57 defer span.End() 58 return p.item.AssemblePermissions(ctx, n) 59 } 60 61 // AssembleTrashPermissions is used to assemble file permissions 62 func (p Permissions) AssembleTrashPermissions(ctx context.Context, n *node.Node) (*provider.ResourcePermissions, error) { 63 _, span := tracer.Start(ctx, "AssembleTrashPermissions") 64 defer span.End() 65 return p.item.AssembleTrashPermissions(ctx, n) 66 } 67 68 // CreateSpace returns true when the user is allowed to create the space 69 func (p Permissions) CreateSpace(ctx context.Context, spaceid string) bool { 70 return p.checkPermission(ctx, "Drives.Create", spaceRef(spaceid)) 71 } 72 73 // SetSpaceQuota returns true when the user is allowed to change the spaces quota 74 func (p Permissions) SetSpaceQuota(ctx context.Context, spaceid string, spaceType string) bool { 75 switch spaceType { 76 default: 77 return false // only quotas of personal and project space may be changed 78 case _spaceTypePersonal: 79 return p.checkPermission(ctx, "Drives.ReadWritePersonalQuota", spaceRef(spaceid)) 80 case _spaceTypeProject: 81 return p.checkPermission(ctx, "Drives.ReadWriteProjectQuota", spaceRef(spaceid)) 82 } 83 } 84 85 // ManageSpaceProperties returns true when the user is allowed to change space properties (name/subtitle) 86 func (p Permissions) ManageSpaceProperties(ctx context.Context, spaceid string) bool { 87 return p.checkPermission(ctx, "Drives.ReadWrite", spaceRef(spaceid)) 88 } 89 90 // SpaceAbility returns true when the user is allowed to enable/disable the space 91 func (p Permissions) SpaceAbility(ctx context.Context, spaceid string) bool { 92 return p.checkPermission(ctx, "Drives.ReadWriteEnabled", spaceRef(spaceid)) 93 } 94 95 // ListAllSpaces returns true when the user is allowed to list all spaces 96 func (p Permissions) ListAllSpaces(ctx context.Context) bool { 97 return p.checkPermission(ctx, "Drives.List", nil) 98 } 99 100 // ListSpacesOfUser returns true when the user is allowed to list the spaces of the given user 101 func (p Permissions) ListSpacesOfUser(ctx context.Context, userid *userv1beta1.UserId) bool { 102 switch { 103 case userid == nil: 104 // there is no filter 105 return true // TODO: is `true` actually correct here? Shouldn't we check for ListAllSpaces too? 106 case utils.UserIDEqual(ctxpkg.ContextMustGetUser(ctx).GetId(), userid): 107 return true 108 default: 109 return p.ListAllSpaces(ctx) 110 } 111 } 112 113 // DeleteAllSpaces returns true when the user is allowed to delete all spaces 114 func (p Permissions) DeleteAllSpaces(ctx context.Context) bool { 115 return p.checkPermission(ctx, "Drives.DeleteProject", nil) 116 } 117 118 // DeleteAllHomeSpaces returns true when the user is allowed to delete all home spaces 119 func (p Permissions) DeleteAllHomeSpaces(ctx context.Context) bool { 120 return p.checkPermission(ctx, "Drives.DeletePersonal", nil) 121 } 122 123 // checkPermission is used to check a users space permissions 124 func (p Permissions) checkPermission(ctx context.Context, perm string, ref *provider.Reference) bool { 125 permissionsClient, err := p.permissionsSelector.Next() 126 if err != nil { 127 return false 128 } 129 130 user := ctxpkg.ContextMustGetUser(ctx) 131 checkRes, err := permissionsClient.CheckPermission(ctx, &cs3permissions.CheckPermissionRequest{ 132 Permission: perm, 133 SubjectRef: &cs3permissions.SubjectReference{ 134 Spec: &cs3permissions.SubjectReference_UserId{ 135 UserId: user.Id, 136 }, 137 }, 138 Ref: ref, 139 }) 140 if err != nil { 141 return false 142 } 143 144 return checkRes.Status.Code == v1beta11.Code_CODE_OK 145 } 146 147 // IsManager returns true if the given resource permissions evaluate the user as "manager" 148 func IsManager(rp *provider.ResourcePermissions) bool { 149 return rp.RemoveGrant 150 } 151 152 // IsEditor returns true if the given resource permissions evaluate the user as "editor" 153 func IsEditor(rp *provider.ResourcePermissions) bool { 154 return rp.InitiateFileUpload 155 } 156 157 // IsViewer returns true if the given resource permissions evaluate the user as "viewer" 158 func IsViewer(rp *provider.ResourcePermissions) bool { 159 return rp.Stat 160 } 161 162 func spaceRef(spaceid string) *provider.Reference { 163 return &provider.Reference{ 164 ResourceId: &provider.ResourceId{ 165 StorageId: spaceid, 166 // OpaqueId is the same, no need to transfer it 167 }, 168 } 169 }