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
|
package namespace
import (
"sort"
"github.com/authzed/spicedb/pkg/schema"
)
// computePermissionAliases computes a map of aliases between the various permissions in a
// namespace. A permission is considered an alias if it *directly* refers to another permission
// or relation without any other form of expression.
func computePermissionAliases(typeDefinition *schema.ValidatedDefinition) (map[string]string, error) {
aliases := map[string]string{}
done := map[string]struct{}{}
unresolvedAliases := map[string]string{}
for _, rel := range typeDefinition.Namespace().Relation {
// Ensure the relation has a rewrite...
if rel.GetUsersetRewrite() == nil {
done[rel.Name] = struct{}{}
continue
}
// ... with a union ...
union := rel.GetUsersetRewrite().GetUnion()
if union == nil {
done[rel.Name] = struct{}{}
continue
}
// ... with a single child ...
if len(union.Child) != 1 {
done[rel.Name] = struct{}{}
continue
}
// ... that is a computed userset.
computedUserset := union.Child[0].GetComputedUserset()
if computedUserset == nil {
done[rel.Name] = struct{}{}
continue
}
// If the aliased item is a relation, then we've found the alias target.
aliasedPermOrRel := computedUserset.GetRelation()
if !typeDefinition.IsPermission(aliasedPermOrRel) {
done[rel.Name] = struct{}{}
aliases[rel.Name] = aliasedPermOrRel
continue
}
// Otherwise, add the permission to the working set.
unresolvedAliases[rel.Name] = aliasedPermOrRel
}
for len(unresolvedAliases) > 0 {
startingCount := len(unresolvedAliases)
for relName, aliasedPermission := range unresolvedAliases {
if _, ok := done[aliasedPermission]; ok {
done[relName] = struct{}{}
if alias, ok := aliases[aliasedPermission]; ok {
aliases[relName] = alias
} else {
aliases[relName] = aliasedPermission
}
delete(unresolvedAliases, relName)
continue
}
}
if len(unresolvedAliases) == startingCount {
keys := make([]string, 0, len(unresolvedAliases))
for key := range unresolvedAliases {
keys = append(keys, key)
}
sort.Strings(keys)
return nil, NewPermissionsCycleErr(typeDefinition.Namespace().Name, keys)
}
}
return aliases, nil
}
|