-
Notifications
You must be signed in to change notification settings - Fork 243
/
foundsubject.go
142 lines (115 loc) · 4.44 KB
/
foundsubject.go
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
134
135
136
137
138
139
140
141
142
package membership
import (
"fmt"
"sort"
"strings"
v0 "github.com/authzed/authzed-go/proto/authzed/api/v0"
"github.com/authzed/spicedb/pkg/tuple"
)
// NewFoundSubject creates a new FoundSubject for a subject and a set of its resources.
func NewFoundSubject(subject *v0.ObjectAndRelation, resources ...*v0.ObjectAndRelation) FoundSubject {
return FoundSubject{subject, tuple.NewONRSet(), tuple.NewONRSet(resources...)}
}
// FoundSubject contains a single found subject and all the relationships in which that subject
// is a member which were found via the ONRs expansion.
type FoundSubject struct {
// subject is the subject found.
subject *v0.ObjectAndRelation
// excludedSubjects are any subjects excluded. Only should be set if subject is a wildcard.
excludedSubjects *tuple.ONRSet
// relations are the relations under which the subject lives that informed the locating
// of this subject for the root ONR.
relationships *tuple.ONRSet
}
// Subject returns the Subject of the FoundSubject.
func (fs FoundSubject) Subject() *v0.ObjectAndRelation {
return fs.subject
}
// WildcardType returns the object type for the wildcard subject, if this is a wildcard subject.
func (fs FoundSubject) WildcardType() (string, bool) {
if fs.subject.ObjectId == tuple.PublicWildcard {
return fs.subject.Namespace, true
}
return "", false
}
// ExcludedSubjectsFromWildcard returns those subjects excluded from the wildcard subject.
// If not a wildcard subject, returns false.
func (fs FoundSubject) ExcludedSubjectsFromWildcard() ([]*v0.ObjectAndRelation, bool) {
if fs.subject.ObjectId == tuple.PublicWildcard {
return fs.excludedSubjects.AsSlice(), true
}
return []*v0.ObjectAndRelation{}, false
}
// Relationships returns all the relationships in which the subject was found as per the expand.
func (fs FoundSubject) Relationships() []*v0.ObjectAndRelation {
return fs.relationships.AsSlice()
}
// ToValidationString returns the FoundSubject in a format that is consumable by the validationfile
// package.
func (fs FoundSubject) ToValidationString() string {
onrString := tuple.StringONR(fs.Subject())
excluded, isWildcard := fs.ExcludedSubjectsFromWildcard()
if isWildcard && len(excluded) > 0 {
excludedONRStrings := make([]string, 0, len(excluded))
for _, excludedONR := range excluded {
excludedONRStrings = append(excludedONRStrings, tuple.StringONR(excludedONR))
}
sort.Strings(excludedONRStrings)
return fmt.Sprintf("%s - {%s}", onrString, strings.Join(excludedONRStrings, ", "))
}
return onrString
}
// union performs merging of two FoundSubject's with the same subject.
func (fs FoundSubject) union(other FoundSubject) FoundSubject {
if toKey(fs.subject) != toKey(other.subject) {
panic("Got wrong found subject to union")
}
relationships := fs.relationships.Union(other.relationships)
var excludedSubjects *tuple.ONRSet
// If a wildcard, then union together excluded subjects.
_, isWildcard := fs.WildcardType()
if isWildcard {
excludedSubjects = fs.excludedSubjects.Union(other.excludedSubjects)
}
return FoundSubject{
subject: fs.subject,
excludedSubjects: excludedSubjects,
relationships: relationships,
}
}
// intersect performs intersection between two FoundSubject's with the same subject.
func (fs FoundSubject) intersect(other FoundSubject) FoundSubject {
if toKey(fs.subject) != toKey(other.subject) {
panic("Got wrong found subject to intersect")
}
relationships := fs.relationships.Union(other.relationships)
var excludedSubjects *tuple.ONRSet
// If a wildcard, then union together excluded subjects.
_, isWildcard := fs.WildcardType()
if isWildcard {
excludedSubjects = fs.excludedSubjects.Union(other.excludedSubjects)
}
return FoundSubject{
subject: fs.subject,
excludedSubjects: excludedSubjects,
relationships: relationships,
}
}
// FoundSubjects contains the subjects found for a specific ONR.
type FoundSubjects struct {
// subjects is a map from the Subject ONR (as a string) to the FoundSubject information.
subjects map[string]FoundSubject
}
// ListFound returns a slice of all the FoundSubject's.
func (fs FoundSubjects) ListFound() []FoundSubject {
found := []FoundSubject{}
for _, sub := range fs.subjects {
found = append(found, sub)
}
return found
}
// LookupSubject returns the FoundSubject for a matching subject, if any.
func (fs FoundSubjects) LookupSubject(subject *v0.ObjectAndRelation) (FoundSubject, bool) {
found, ok := fs.subjects[toKey(subject)]
return found, ok
}