package role type MissingPermissionError struct { Key string } func (e MissingPermissionError) Error() string { return ErrMissingPermission.Error() + ": " + e.Key } func (e MissingPermissionError) Is(target error) bool { return target == ErrMissingPermission } type GrantSet struct { scopes map[string]Scope } func (r Role) GrantSet() GrantSet { scopes := make(map[string]Scope, len(r.Grants)) for _, grant := range r.Grants { permission, err := resolveGrantKey(grant.Key) if err != nil || permission.OwnerOnly && !r.Locked { continue } scope := effectiveScope(permission.Kind, grant.Scope) if held, present := scopes[grant.Key]; present { scope = mostRestrictive(held, scope) } scopes[grant.Key] = scope } return GrantSet{scopes: scopes} } func effectiveScope(kind Kind, scope Scope) Scope { switch { case scope == ScopeAll: return ScopeAll case scope == ScopeOwn && kind == KindScoped: return ScopeOwn default: return ScopeNone } } func scopeRank(scope Scope) int { switch scope { case ScopeAll: return 2 case ScopeOwn: return 1 default: return 0 } } func mostRestrictive(left Scope, right Scope) Scope { if scopeRank(left) <= scopeRank(right) { return left } return right } func (g GrantSet) ScopeFor(key string, typeKey string) Scope { if typeKey == "" { return g.wildcard(key) } composite := key + typeSeparator + typeKey if _, _, err := ParseTypedKey(composite); err != nil { return ScopeNone } if scope, present := g.scopes[composite]; present { return scope } return g.wildcard(key) } func (g GrantSet) wildcard(key string) Scope { if isTypedKey(key) { return ScopeNone } scope, present := g.scopes[key] if !present { return ScopeNone } return scope } func (g GrantSet) Permits(key string, typeKey string, callerID uint32, createdBy uint32) bool { return ScopePermits(g.ScopeFor(key, typeKey), callerID, createdBy) } func ScopePermits(scope Scope, callerID uint32, createdBy uint32) bool { switch scope { case ScopeAll: return true case ScopeOwn: return callerID != 0 && callerID == createdBy default: return false } } func (g GrantSet) HoldsFor(key string, typeKey string) bool { return g.ScopeFor(key, typeKey) != ScopeNone } func (g GrantSet) Holds(key string) bool { return g.HoldsFor(key, "") } func (g GrantSet) HoldsAll(key string) bool { return g.ScopeFor(key, "") == ScopeAll }