1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
package trustgraph
import (
"strings"
"github.com/containers/libtrust"
)
type grantNode struct {
grants []*Grant
children map[string]*grantNode
}
type memoryGraph struct {
roots map[string]*grantNode
}
func newGrantNode() *grantNode {
return &grantNode{
grants: []*Grant{},
children: map[string]*grantNode{},
}
}
// NewMemoryGraph returns a new in memory trust graph created from
// a static list of grants. This graph is immutable after creation
// and any alterations should create a new instance.
func NewMemoryGraph(grants []*Grant) TrustGraph {
roots := map[string]*grantNode{}
for _, grant := range grants {
parts := strings.Split(grant.Grantee, "/")
nodes := roots
var node *grantNode
var nodeOk bool
for _, part := range parts {
node, nodeOk = nodes[part]
if !nodeOk {
node = newGrantNode()
nodes[part] = node
}
if part != "" {
node.grants = append(node.grants, grant)
}
nodes = node.children
}
}
return &memoryGraph{roots}
}
func (g *memoryGraph) getGrants(name string) []*Grant {
nameParts := strings.Split(name, "/")
nodes := g.roots
var node *grantNode
var nodeOk bool
for _, part := range nameParts {
node, nodeOk = nodes[part]
if !nodeOk {
return nil
}
nodes = node.children
}
return node.grants
}
func isSubName(name, sub string) bool {
if strings.HasPrefix(name, sub) {
if len(name) == len(sub) || name[len(sub)] == '/' {
return true
}
}
return false
}
type walkFunc func(*Grant, []*Grant) bool
func foundWalkFunc(*Grant, []*Grant) bool {
return true
}
func (g *memoryGraph) walkGrants(start, target string, permission uint16, f walkFunc, chain []*Grant, visited map[*Grant]bool, collect bool) bool {
if visited == nil {
visited = map[*Grant]bool{}
}
grants := g.getGrants(start)
subGrants := make([]*Grant, 0, len(grants))
for _, grant := range grants {
if visited[grant] {
continue
}
visited[grant] = true
if grant.Permission&permission == permission {
if isSubName(target, grant.Subject) {
if f(grant, chain) {
return true
}
} else {
subGrants = append(subGrants, grant)
}
}
}
for _, grant := range subGrants {
var chainCopy []*Grant
if collect {
chainCopy = make([]*Grant, len(chain)+1)
copy(chainCopy, chain)
chainCopy[len(chainCopy)-1] = grant
} else {
chainCopy = nil
}
if g.walkGrants(grant.Subject, target, permission, f, chainCopy, visited, collect) {
return true
}
}
return false
}
func (g *memoryGraph) Verify(key libtrust.PublicKey, node string, permission uint16) (bool, error) {
return g.walkGrants(key.KeyID(), node, permission, foundWalkFunc, nil, nil, false), nil
}
func (g *memoryGraph) GetGrants(key libtrust.PublicKey, node string, permission uint16) ([][]*Grant, error) {
grants := [][]*Grant{}
collect := func(grant *Grant, chain []*Grant) bool {
grantChain := make([]*Grant, len(chain)+1)
copy(grantChain, chain)
grantChain[len(grantChain)-1] = grant
grants = append(grants, grantChain)
return false
}
g.walkGrants(key.KeyID(), node, permission, collect, nil, nil, true)
return grants, nil
}
|