From b3de3144cc08b60ae19fd9821f98cc8464617a07 Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Fri, 28 Jul 2023 10:04:31 -0600 Subject: [PATCH] Reworked actions to be lists of parts, and added wildcards for both multi-level and single-level --- graph_test.go | 2 +- lockable_test.go | 5 +++-- policy.go | 54 +++++++++++++++++++++++++++++++++--------------- signal.go | 20 +++++++++++++----- 4 files changed, 56 insertions(+), 25 deletions(-) diff --git a/graph_test.go b/graph_test.go index 8adcbe2..4a6a9d9 100644 --- a/graph_test.go +++ b/graph_test.go @@ -84,7 +84,7 @@ func (t * GraphTester) CheckForNone(listener *ListenerExt, str string) { const SimpleListenerNodeType = NodeType("SIMPLE_LISTENER") func NewSimpleListener(ctx *Context, buffer int) (*Node, *ListenerExt) { - policy := NewAllNodesPolicy([]Action{Action("status")}) + policy := NewAllNodesPolicy(Actions{MakeAction("status")}) listener_extension := NewListenerExt(buffer) listener := NewNode(ctx, RandID(), diff --git a/lockable_test.go b/lockable_test.go index 75123a7..aef88c8 100644 --- a/lockable_test.go +++ b/lockable_test.go @@ -16,8 +16,9 @@ func lockableTestContext(t *testing.T, logs []string) *Context { } -var link_policy = NewAllNodesPolicy([]Action{Action(LinkSignalType), Action(StatusSignalType)}) -var lock_policy = NewAllNodesPolicy([]Action{Action(LockSignalType)}) +//TODO: add new finer grained signals, and probably add wildcards to not have to deal with annoying acl policies +var link_policy = NewAllNodesPolicy(Actions{MakeAction(LinkSignalType, "*"), MakeAction(StatusSignalType, "+")}) +var lock_policy = NewAllNodesPolicy(Actions{MakeAction(LockSignalType, "*")}) func TestLink(t *testing.T) { ctx := lockableTestContext(t, []string{"lockable"}) diff --git a/policy.go b/policy.go index da1eb53..821464a 100644 --- a/policy.go +++ b/policy.go @@ -22,7 +22,6 @@ type Policy interface { Merge(Policy) Policy } -//TODO: Update with change from principal *Node to principal_id so sane policies can still be made func (policy *AllNodesPolicy) Allows(principal_id NodeID, action Action, node *Node) error { return policy.Actions.Allows(action) } @@ -32,11 +31,7 @@ func (policy *PerNodePolicy) Allows(principal_id NodeID, action Action, node *No if id != principal_id { continue } - for _, a := range(actions) { - if a == action { - return nil - } - } + return actions.Allows(action) } return fmt.Errorf("%s is not in per node policy of %s", principal_id, node.ID) } @@ -72,15 +67,7 @@ func NewRequirementOfPolicy(actions Actions) RequirementOfPolicy { func MergeActions(first Actions, second Actions) Actions { ret := second for _, action := range(first) { - found := false - for _, a := range(second) { - if a == action { - break - } - } - if found == false { - ret = append(ret, action) - } + ret = append(ret, action) } return ret } @@ -114,12 +101,45 @@ func (policy *RequirementOfPolicy) Merge(p Policy) Policy { return policy } -type Action string +type Action []string + +func MakeAction(parts ...interface{}) Action { + action := make(Action, len(parts)) + for i, part := range(parts) { + stringer, ok := part.(fmt.Stringer) + if ok == false { + switch p := part.(type) { + case string: + action[i] = p + default: + panic("%s can not be part of an action") + } + } else { + action[i] = stringer.String() + } + } + return action +} + +func (action Action) Allows(test Action) bool { + for i, part := range(test) { + if action[i] == part || action[i] == "*" { + continue + } else if action[i] == "+" { + break + } else { + return false + } + } + + return true +} + type Actions []Action func (actions Actions) Allows(action Action) error { for _, a := range(actions) { - if a == action { + if a.Allows(action) == true { return nil } } diff --git a/signal.go b/signal.go index 2e9d399..54fb462 100644 --- a/signal.go +++ b/signal.go @@ -4,6 +4,13 @@ import ( "encoding/json" ) +const ( + StopSignalType = SignalType("STOP") + StatusSignalType = SignalType("STATUS") + LinkSignalType = SignalType("LINK") + LockSignalType = SignalType("LOCK") +) + type SignalDirection int const ( Up SignalDirection = iota @@ -12,6 +19,9 @@ const ( ) type SignalType string +func (signal_type SignalType) String() string { + return string(signal_type) +} type Signal interface { Serializable[SignalType] @@ -29,7 +39,7 @@ func (signal BaseSignal) Type() SignalType { } func (signal BaseSignal) Permission() Action { - return Action(signal.Type()) + return MakeAction(signal.Type()) } func (signal BaseSignal) Direction() SignalDirection { @@ -60,7 +70,6 @@ func NewDirectSignal(signal_type SignalType) BaseSignal { return NewBaseSignal(signal_type, Direct) } -const StopSignalType = SignalType("STOP") var StopSignal = NewDownSignal(StopSignalType) type IDSignal struct { @@ -96,7 +105,6 @@ func (signal StatusSignal) String() string { return string(ser) } -const StatusSignalType = SignalType("STATUS") func NewStatusSignal(status string, source NodeID) StatusSignal { return StatusSignal{ IDSignal: NewIDSignal(StatusSignalType, Up, source), @@ -104,8 +112,6 @@ func NewStatusSignal(status string, source NodeID) StatusSignal { } } -const LinkSignalType = SignalType("LINK") -const LockSignalType = SignalType("LOCK") type StateSignal struct { BaseSignal State string `json:"state"` @@ -134,6 +140,10 @@ func NewLockSignal(state string) StateSignal { } } +func (signal StateSignal) Permission() Action { + return MakeAction(signal.Type(), signal.State) +} + type StartChildSignal struct { IDSignal Action string `json:"action"`