upd(messaging): messaging repository/permissions to service/rules

This commit is contained in:
Mitja Zivkovic
2019-02-14 16:44:02 +01:00
parent f155f48bdf
commit ea71c581f3
6 changed files with 174 additions and 147 deletions
+15
View File
@@ -0,0 +1,15 @@
package organization
import (
"context"
"github.com/crusttech/crust/system/types"
)
func GetFromContext(ctx context.Context) types.Organisation {
if orgID, ok := ctx.Value("organizationID").(uint64); ok {
return types.Organisation{ID: orgID}
} else {
return types.Organisation{ID: 1}
}
}
-140
View File
@@ -1,140 +0,0 @@
package repository
import (
"context"
"github.com/titpetric/factory"
"github.com/crusttech/crust/internal/rules"
"github.com/crusttech/crust/messaging/types"
systemTypes "github.com/crusttech/crust/system/types"
)
type PermissionsRepository interface {
With(context.Context, *factory.DB) PermissionsRepository
// Applies mostly to admin panel
isAdmin(org *types.Organisation) bool
// Individual rules for administration
canManageOrganisation(org *types.Organisation) bool
canManageRoles(org *types.Organisation) bool
canManageChannels(org *types.Organisation) bool
// types.Team derived from identity uses a wildcard match
canManageWebhooks(org *types.Organisation, ch *types.Channel) bool
// Messaging rules
canSendMessages(org *types.Organisation, ch *types.Channel) bool
canEmbedLinks(org *types.Organisation, ch *types.Channel) bool
canAttachFiles(org *types.Organisation, ch *types.Channel) bool
canEditOwnMessages(org *types.Organisation, ch *types.Channel) bool
canEditMessages(org *types.Organisation, ch *types.Channel) bool
canReact(org *types.Organisation, ch *types.Channel) bool
}
type permissions struct {
*repository
// identity is passed with context
resources rules.ResourcesInterface
team *systemTypes.Team
}
func Permissions(ctx context.Context, db *factory.DB) PermissionsRepository {
return (&permissions{
team: &systemTypes.Team{},
}).With(ctx, db)
}
func (r *permissions) With(ctx context.Context, db *factory.DB) PermissionsRepository {
return &permissions{
team: r.team,
resources: rules.NewResources(ctx, db),
repository: r.repository.With(ctx, db),
}
}
var (
ErrPermissionsNotLoggedIn = repositoryError("PermissionsNotLoggedIn")
)
// @todo: honor defaults from (org/team/channel).Permissions()
func (r *permissions) isAdmin(org *types.Organisation) bool {
op := "admin"
return r.hasAccess(op, org.PermissionDefault(op), org.Resource().String())
}
func (r *permissions) canManageOrganisation(org *types.Organisation) bool {
op := "manage.organisation"
return r.hasAccess(op, org.PermissionDefault(op), org.Resource().String())
}
func (r *permissions) canManageRoles(org *types.Organisation) bool {
op := "manage.roles"
return r.hasAccess(op, org.PermissionDefault(op), org.Resource().String())
}
func (r *permissions) canManageChannels(org *types.Organisation) bool {
op := "manage.channels"
return r.hasAccess(op, org.PermissionDefault(op), org.Resource().String())
}
func (r *permissions) canManageWebhooks(org *types.Organisation, ch *types.Channel) bool {
op := "manage.webhooks"
return r.hasAccess(op, org.PermissionDefault(op), org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *permissions) canSendMessages(org *types.Organisation, ch *types.Channel) bool {
op := "text.send"
return r.hasAccess(op, org.PermissionDefault(op), org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *permissions) canEmbedLinks(org *types.Organisation, ch *types.Channel) bool {
op := "text.embed"
return r.hasAccess(op, org.PermissionDefault(op), org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *permissions) canAttachFiles(org *types.Organisation, ch *types.Channel) bool {
op := "text.attach"
return r.hasAccess(op, org.PermissionDefault(op), org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *permissions) canEditOwnMessages(org *types.Organisation, ch *types.Channel) bool {
op := "text.edit_own"
return r.hasAccess(op, org.PermissionDefault(op), org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *permissions) canEditMessages(org *types.Organisation, ch *types.Channel) bool {
op := "text.edit_all"
return r.hasAccess(op, org.PermissionDefault(op), org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *permissions) canReact(org *types.Organisation, ch *types.Channel) bool {
op := "text.react"
return r.hasAccess(op, org.PermissionDefault(op), org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *permissions) hasAccess(operation string, value rules.Access, scopes ...string) bool {
// reverse scopes from to order it from most-least significant
// aka: [0]channel [1]teams [2]org
last := len(scopes) - 1
for i := 0; i < len(scopes)/2; i++ {
scopes[i], scopes[last-i] = scopes[last-i], scopes[i]
}
for _, scope := range scopes {
if scope == "" {
continue
}
switch r.resources.IsAllowed(scope, operation) {
case rules.Allow:
return true
case rules.Deny:
return false
default: // inherit
}
}
return false
}
+8
View File
@@ -6,6 +6,8 @@ import (
"github.com/titpetric/factory"
"github.com/crusttech/crust/internal/auth"
"github.com/crusttech/crust/internal/organization"
"github.com/crusttech/crust/messaging/types"
)
type (
@@ -24,6 +26,12 @@ func Identity(ctx context.Context) uint64 {
return auth.GetIdentityFromContext(ctx).Identity()
}
func Organization(ctx context.Context) *types.Organisation {
return &types.Organisation{
organization.GetFromContext(ctx),
}
}
func (r *repository) With(ctx context.Context, db *factory.DB) *repository {
return &repository{
ctx: ctx,
+5 -5
View File
@@ -5,7 +5,7 @@ import (
"github.com/pkg/errors"
"github.com/crusttech/crust/internal/rules"
internalRules "github.com/crusttech/crust/internal/rules"
"github.com/crusttech/crust/messaging/repository"
)
@@ -14,7 +14,7 @@ type (
db db
ctx context.Context
scopes rules.ScopeInterface
scopes internalRules.ScopeInterface
}
PermissionsService interface {
@@ -22,11 +22,11 @@ type (
List() (interface{}, error)
Get(teamID uint64, scope string, resource string) (interface{}, error)
Set(teamID uint64, rules []rules.Rules) (interface{}, error)
Set(teamID uint64, rules []internalRules.Rules) (interface{}, error)
}
)
func Permissions(scopes rules.ScopeInterface) PermissionsService {
func Permissions(scopes internalRules.ScopeInterface) PermissionsService {
return (&permissions{
scopes: scopes,
}).With(context.Background())
@@ -49,6 +49,6 @@ func (p *permissions) Get(teamID uint64, scope string, resource string) (interfa
return nil, errors.New("service.permissions.get: not implemented")
}
func (p *permissions) Set(teamID uint64, rules []rules.Rules) (interface{}, error) {
func (p *permissions) Set(teamID uint64, rules []internalRules.Rules) (interface{}, error) {
return nil, errors.New("service.permissions.set: not implemented")
}
+144
View File
@@ -0,0 +1,144 @@
package service
import (
"context"
internalRules "github.com/crusttech/crust/internal/rules"
"github.com/crusttech/crust/messaging/repository"
"github.com/crusttech/crust/messaging/types"
systemTypes "github.com/crusttech/crust/system/types"
)
type (
rules struct {
db db
ctx context.Context
// identity is passed with context
resources internalRules.ResourcesInterface
team *systemTypes.Team
org *types.Organisation
}
RulesService interface {
With(context.Context) RulesService
// Applies mostly to admin panel
isAdmin() bool
// Individual rules for administration
canManageOrganisation() bool
canManageRoles() bool
canManageChannels() bool
// types.Team derived from identity uses a wildcard match
canManageWebhooks(ch *types.Channel) bool
// Messaging rules
canSendMessages(ch *types.Channel) bool
canEmbedLinks(ch *types.Channel) bool
canAttachFiles(ch *types.Channel) bool
canUpdateOwnMessages(ch *types.Channel) bool
canUpdateMessages(ch *types.Channel) bool
canReact(ch *types.Channel) bool
}
)
func Rules() RulesService {
return (&rules{
team: &systemTypes.Team{},
}).With(context.Background())
}
func (r *rules) With(ctx context.Context) RulesService {
db := repository.DB(ctx)
org := repository.Organization(ctx)
return &rules{
db: db,
ctx: ctx,
org: org,
team: r.team,
resources: internalRules.NewResources(ctx, db),
}
}
// @todo: honor defaults from (org/team/channel).Permissions()
func (r *rules) isAdmin() bool {
op := "admin"
return r.hasAccess(op, r.org.PermissionDefault(op), r.org.Resource().String())
}
func (r *rules) canManageOrganisation() bool {
op := "manage.organisation"
return r.hasAccess(op, r.org.PermissionDefault(op), r.org.Resource().String())
}
func (r *rules) canManageRoles() bool {
op := "manage.roles"
return r.hasAccess(op, r.org.PermissionDefault(op), r.org.Resource().String())
}
func (r *rules) canManageChannels() bool {
op := "manage.channels"
return r.hasAccess(op, r.org.PermissionDefault(op), r.org.Resource().String())
}
func (r *rules) canManageWebhooks(ch *types.Channel) bool {
op := "manage.webhooks"
return r.hasAccess(op, r.org.PermissionDefault(op), r.org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *rules) canSendMessages(ch *types.Channel) bool {
op := "message.send"
return r.hasAccess(op, r.org.PermissionDefault(op), r.org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *rules) canEmbedLinks(ch *types.Channel) bool {
op := "message.embed"
return r.hasAccess(op, r.org.PermissionDefault(op), r.org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *rules) canAttachFiles(ch *types.Channel) bool {
op := "message.attach"
return r.hasAccess(op, r.org.PermissionDefault(op), r.org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *rules) canUpdateOwnMessages(ch *types.Channel) bool {
op := "message.update_own"
return r.hasAccess(op, r.org.PermissionDefault(op), r.org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *rules) canUpdateMessages(ch *types.Channel) bool {
op := "message.update_all"
return r.hasAccess(op, r.org.PermissionDefault(op), r.org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *rules) canReact(ch *types.Channel) bool {
op := "message.react"
return r.hasAccess(op, r.org.PermissionDefault(op), r.org.Resource().String(), r.team.Resource().All(), ch.Resource().String())
}
func (r *rules) hasAccess(operation string, value internalRules.Access, scopes ...string) bool {
// reverse scopes from to order it from most-least significant
// aka: [0]channel [1]teams [2]org
last := len(scopes) - 1
for i := 0; i < len(scopes)/2; i++ {
scopes[i], scopes[last-i] = scopes[last-i], scopes[i]
}
for _, scope := range scopes {
if scope == "" {
continue
}
switch r.resources.IsAllowed(scope, operation) {
case internalRules.Allow:
return true
case internalRules.Deny:
return false
default: // inherit
}
}
return false
}
+2 -2
View File
@@ -5,7 +5,7 @@ import (
"sync"
"time"
"github.com/crusttech/crust/internal/rules"
internalRules "github.com/crusttech/crust/internal/rules"
"github.com/crusttech/crust/internal/store"
"github.com/crusttech/crust/messaging/types"
@@ -34,7 +34,7 @@ func Init() {
log.Fatalf("Failed to initialize stor: %v", err)
}
scopes := rules.NewScope()
scopes := internalRules.NewScope()
scopes.Add(&types.Organisation{})
scopes.Add(&types.Team{})
scopes.Add(&types.Channel{})