Files
RenewCMS/internal/domain/role/roleDomain.go
T

103 lines
2.8 KiB
Go

package role
import (
"errors"
"strings"
"time"
)
var (
ErrRoleNotFound = errors.New("role not found")
ErrUnknownPermission = errors.New("unknown permission")
ErrRoleConflict = errors.New("role was modified concurrently")
ErrInvalidScope = errors.New("invalid scope for permission")
ErrOwnerOnlyGrant = errors.New("owner-only permission granted to a non-owner role")
ErrDuplicateGrant = errors.New("permission granted more than once")
ErrMissingPermission = errors.New("missing permission")
ErrRoleHasMembers = errors.New("role still has members")
ErrRoleNameTaken = errors.New("role name already used")
ErrRoleLocked = errors.New("role is locked")
ErrBuiltInRole = errors.New("role is built in")
ErrBuiltInName = errors.New("built-in role cannot be renamed")
ErrOwnRole = errors.New("cannot change the role you hold")
ErrInvalidRoleName = errors.New("invalid role name")
ErrUnknownContentType = errors.New("unknown content type")
ErrNotBuiltIn = errors.New("role is not built in")
ErrInvalidReassign = errors.New("invalid reassign target")
ErrEscalation = errors.New("grants more than the caller holds")
ErrUnknownRole = errors.New("unknown role")
)
type Scope string
const (
ScopeNone Scope = "none"
ScopeOwn Scope = "own"
ScopeAll Scope = "all"
)
type Grant struct {
Key string `json:"key"`
Scope Scope `json:"scope"`
}
type Role struct {
ID uint32 `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
BuiltIn bool `json:"built_in"`
Locked bool `json:"locked"`
Version uint32 `json:"version"`
Grants []Grant `json:"grants"`
UpdatedAt time.Time `json:"-"`
UpdatedBy *uint32 `json:"-"`
}
func resolveGrantKey(key string) (Permission, error) {
if strings.Contains(key, typeSeparator) {
base, _, err := ParseTypedKey(key)
if err != nil {
return Permission{}, err
}
return Lookup(base)
}
return Lookup(key)
}
func ValidateGrants(locked bool, grants []Grant) error {
seen := make(map[string]bool, len(grants))
for _, grant := range grants {
permission, err := resolveGrantKey(grant.Key)
if err != nil {
return err
}
if permission.OwnerOnly && !locked {
return ErrOwnerOnlyGrant
}
if !scopeValidFor(permission.Kind, grant.Scope, isTypedKey(grant.Key)) {
return ErrInvalidScope
}
if seen[grant.Key] {
return ErrDuplicateGrant
}
seen[grant.Key] = true
}
return nil
}
func isTypedKey(key string) bool {
return strings.Contains(key, typeSeparator)
}
func scopeValidFor(kind Kind, scope Scope, typed bool) bool {
if typed && scope == ScopeNone {
return true
}
if kind == KindToggle {
return scope == ScopeAll
}
return scope == ScopeOwn || scope == ScopeAll
}