github.com/clly/consul@v1.4.5/agent/consul/filter.go (about) 1 package consul 2 3 import ( 4 "github.com/hashicorp/consul/acl" 5 "github.com/hashicorp/consul/agent/structs" 6 ) 7 8 type dirEntFilter struct { 9 authorizer acl.Authorizer 10 ent structs.DirEntries 11 } 12 13 func (d *dirEntFilter) Len() int { 14 return len(d.ent) 15 } 16 func (d *dirEntFilter) Filter(i int) bool { 17 return !d.authorizer.KeyRead(d.ent[i].Key) 18 } 19 func (d *dirEntFilter) Move(dst, src, span int) { 20 copy(d.ent[dst:dst+span], d.ent[src:src+span]) 21 } 22 23 // FilterDirEnt is used to filter a list of directory entries 24 // by applying an ACL policy 25 func FilterDirEnt(authorizer acl.Authorizer, ent structs.DirEntries) structs.DirEntries { 26 df := dirEntFilter{authorizer: authorizer, ent: ent} 27 return ent[:FilterEntries(&df)] 28 } 29 30 type keyFilter struct { 31 authorizer acl.Authorizer 32 keys []string 33 } 34 35 func (k *keyFilter) Len() int { 36 return len(k.keys) 37 } 38 func (k *keyFilter) Filter(i int) bool { 39 return !k.authorizer.KeyRead(k.keys[i]) 40 } 41 42 func (k *keyFilter) Move(dst, src, span int) { 43 copy(k.keys[dst:dst+span], k.keys[src:src+span]) 44 } 45 46 // FilterKeys is used to filter a list of keys by 47 // applying an ACL policy 48 func FilterKeys(authorizer acl.Authorizer, keys []string) []string { 49 kf := keyFilter{authorizer: authorizer, keys: keys} 50 return keys[:FilterEntries(&kf)] 51 } 52 53 type txnResultsFilter struct { 54 authorizer acl.Authorizer 55 results structs.TxnResults 56 } 57 58 func (t *txnResultsFilter) Len() int { 59 return len(t.results) 60 } 61 62 func (t *txnResultsFilter) Filter(i int) bool { 63 result := t.results[i] 64 switch { 65 case result.KV != nil: 66 return !t.authorizer.KeyRead(result.KV.Key) 67 case result.Node != nil: 68 return !t.authorizer.NodeRead(result.Node.Node) 69 case result.Service != nil: 70 return !t.authorizer.ServiceRead(result.Service.Service) 71 case result.Check != nil: 72 if result.Check.ServiceName != "" { 73 return !t.authorizer.ServiceRead(result.Check.ServiceName) 74 } 75 return !t.authorizer.NodeRead(result.Check.Node) 76 } 77 return false 78 } 79 80 func (t *txnResultsFilter) Move(dst, src, span int) { 81 copy(t.results[dst:dst+span], t.results[src:src+span]) 82 } 83 84 // FilterTxnResults is used to filter a list of transaction results by 85 // applying an ACL policy. 86 func FilterTxnResults(authorizer acl.Authorizer, results structs.TxnResults) structs.TxnResults { 87 rf := txnResultsFilter{authorizer: authorizer, results: results} 88 return results[:FilterEntries(&rf)] 89 } 90 91 // Filter interface is used with FilterEntries to do an 92 // in-place filter of a slice. 93 type Filter interface { 94 Len() int 95 Filter(int) bool 96 Move(dst, src, span int) 97 } 98 99 // FilterEntries is used to do an inplace filter of 100 // a slice. This has cost proportional to the list length. 101 func FilterEntries(f Filter) int { 102 // Compact the list 103 dst := 0 104 src := 0 105 n := f.Len() 106 for dst < n { 107 for src < n && f.Filter(src) { 108 src++ 109 } 110 if src == n { 111 break 112 } 113 end := src + 1 114 for end < n && !f.Filter(end) { 115 end++ 116 } 117 span := end - src 118 if span > 0 { 119 f.Move(dst, src, span) 120 dst += span 121 src += span 122 } 123 } 124 125 // Return the size of the slice 126 return dst 127 }