2014-08-13 17:42:10 +00:00
|
|
|
package consul
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/hashicorp/consul/acl"
|
|
|
|
"github.com/hashicorp/consul/consul/structs"
|
|
|
|
)
|
|
|
|
|
2014-08-13 18:31:23 +00:00
|
|
|
type dirEntFilter struct {
|
|
|
|
acl acl.ACL
|
|
|
|
ent structs.DirEntries
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *dirEntFilter) Len() int {
|
|
|
|
return len(d.ent)
|
|
|
|
}
|
|
|
|
func (d *dirEntFilter) Filter(i int) bool {
|
|
|
|
return !d.acl.KeyRead(d.ent[i].Key)
|
|
|
|
}
|
|
|
|
func (d *dirEntFilter) Move(dst, src, span int) {
|
|
|
|
copy(d.ent[dst:dst+span], d.ent[src:src+span])
|
|
|
|
}
|
|
|
|
|
|
|
|
// FilterDirEnt is used to filter a list of directory entries
|
|
|
|
// by applying an ACL policy
|
2014-08-13 17:42:10 +00:00
|
|
|
func FilterDirEnt(acl acl.ACL, ent structs.DirEntries) structs.DirEntries {
|
2014-08-13 18:31:23 +00:00
|
|
|
df := dirEntFilter{acl: acl, ent: ent}
|
|
|
|
return ent[:FilterEntries(&df)]
|
|
|
|
}
|
|
|
|
|
|
|
|
type keyFilter struct {
|
|
|
|
acl acl.ACL
|
|
|
|
keys []string
|
|
|
|
}
|
2014-08-13 17:42:10 +00:00
|
|
|
|
2014-08-13 18:31:23 +00:00
|
|
|
func (k *keyFilter) Len() int {
|
|
|
|
return len(k.keys)
|
|
|
|
}
|
|
|
|
func (k *keyFilter) Filter(i int) bool {
|
|
|
|
return !k.acl.KeyRead(k.keys[i])
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k *keyFilter) Move(dst, src, span int) {
|
|
|
|
copy(k.keys[dst:dst+span], k.keys[src:src+span])
|
|
|
|
}
|
|
|
|
|
|
|
|
// FilterKeys is used to filter a list of keys by
|
|
|
|
// applying an ACL policy
|
|
|
|
func FilterKeys(acl acl.ACL, keys []string) []string {
|
|
|
|
kf := keyFilter{acl: acl, keys: keys}
|
|
|
|
return keys[:FilterEntries(&kf)]
|
|
|
|
}
|
|
|
|
|
2016-05-13 22:58:55 +00:00
|
|
|
type txnResultsFilter struct {
|
|
|
|
acl acl.ACL
|
|
|
|
results structs.TxnResults
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *txnResultsFilter) Len() int {
|
|
|
|
return len(t.results)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *txnResultsFilter) Filter(i int) bool {
|
|
|
|
result := t.results[i]
|
|
|
|
if result.KV != nil {
|
|
|
|
return !t.acl.KeyRead(result.KV.Key)
|
|
|
|
} else {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *txnResultsFilter) Move(dst, src, span int) {
|
|
|
|
copy(t.results[dst:dst+span], t.results[src:src+span])
|
|
|
|
}
|
|
|
|
|
|
|
|
// FilterTxnResults is used to filter a list of transaction results by
|
|
|
|
// applying an ACL policy.
|
|
|
|
func FilterTxnResults(acl acl.ACL, results structs.TxnResults) structs.TxnResults {
|
|
|
|
rf := txnResultsFilter{acl: acl, results: results}
|
|
|
|
return results[:FilterEntries(&rf)]
|
|
|
|
}
|
|
|
|
|
2015-09-15 12:22:08 +00:00
|
|
|
// Filter interface is used with FilterEntries to do an
|
2014-08-13 18:31:23 +00:00
|
|
|
// in-place filter of a slice.
|
|
|
|
type Filter interface {
|
|
|
|
Len() int
|
|
|
|
Filter(int) bool
|
|
|
|
Move(dst, src, span int)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FilterEntries is used to do an inplace filter of
|
|
|
|
// a slice. This has cost proportional to the list length.
|
|
|
|
func FilterEntries(f Filter) int {
|
2014-08-13 17:42:10 +00:00
|
|
|
// Compact the list
|
|
|
|
dst := 0
|
|
|
|
src := 0
|
2014-08-13 18:31:23 +00:00
|
|
|
n := f.Len()
|
2014-08-13 17:42:10 +00:00
|
|
|
for dst < n {
|
2014-08-13 18:31:23 +00:00
|
|
|
for src < n && f.Filter(src) {
|
2014-08-13 17:42:10 +00:00
|
|
|
src++
|
|
|
|
}
|
2014-08-13 18:31:23 +00:00
|
|
|
if src == n {
|
|
|
|
break
|
|
|
|
}
|
2014-08-13 17:42:10 +00:00
|
|
|
end := src + 1
|
2014-08-13 18:31:23 +00:00
|
|
|
for end < n && !f.Filter(end) {
|
2014-08-13 17:42:10 +00:00
|
|
|
end++
|
|
|
|
}
|
|
|
|
span := end - src
|
2014-08-13 18:31:23 +00:00
|
|
|
if span > 0 {
|
|
|
|
f.Move(dst, src, span)
|
|
|
|
dst += span
|
|
|
|
src += span
|
|
|
|
}
|
2014-08-13 17:42:10 +00:00
|
|
|
}
|
|
|
|
|
2014-08-13 18:31:23 +00:00
|
|
|
// Return the size of the slice
|
|
|
|
return dst
|
2014-08-13 17:42:10 +00:00
|
|
|
}
|