diff --git a/consul/filter.go b/consul/filter.go new file mode 100644 index 0000000000..9ccefc0797 --- /dev/null +++ b/consul/filter.go @@ -0,0 +1,39 @@ +package consul + +import ( + "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/consul/structs" +) + +func FilterDirEnt(acl acl.ACL, ent structs.DirEntries) structs.DirEntries { + // Remove any keys blocked by ACLs + removed := 0 + for i := 0; i < len(ent); i++ { + if !acl.KeyRead(ent[i].Key) { + ent[i] = nil + removed++ + } + } + + // Compact the list + dst := 0 + src := 0 + n := len(ent) - removed + for dst < n { + for ent[src] == nil && src < n { + src++ + } + end := src + 1 + for ent[end] != nil && end < n { + end++ + } + span := end - src + copy(ent[dst:dst+span], ent[src:src+span]) + dst += span + src += span + } + + // Trim the entries + ent = ent[:n] + return ent +} diff --git a/consul/filter_test.go b/consul/filter_test.go new file mode 100644 index 0000000000..99c0398a62 --- /dev/null +++ b/consul/filter_test.go @@ -0,0 +1,65 @@ +package consul + +import ( + "reflect" + "testing" + + "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/consul/structs" +) + +func TestFilterDirEnt(t *testing.T) { + policy, _ := acl.Parse(testFilterRules) + aclR, _ := acl.New(acl.DenyAll(), policy) + + type tcase struct { + in []string + out []string + } + cases := []tcase{ + tcase{ + in: []string{"foo/test", "foo/priv/nope", "foo/other", "zoo"}, + out: []string{"foo/test", "foo/other"}, + }, + tcase{ + in: []string{"abe", "lincoln"}, + out: nil, + }, + tcase{ + in: []string{"abe", "foo/1", "foo/2", "foo/3", "nope"}, + out: []string{"foo/1", "foo/2", "foo/3"}, + }, + } + + for _, tc := range cases { + ents := structs.DirEntries{} + for _, in := range tc.in { + ents = append(ents, &structs.DirEntry{Key: in}) + } + + ents = FilterDirEnt(aclR, ents) + var outL []string + for _, e := range ents { + outL = append(outL, e.Key) + } + + if !reflect.DeepEqual(outL, tc.out) { + t.Fatalf("bad: %#v %#v", outL, tc.out) + } + } +} + +var testFilterRules = ` +key "" { + policy = "deny" +} +key "foo/" { + policy = "read" +} +key "foo/priv/" { + policy = "deny" +} +key "zip/" { + policy = "read" +} +`