102 lines
2.7 KiB
Go
102 lines
2.7 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")
|
|
)
|
|
|
|
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
|
|
}
|