summaryrefslogtreecommitdiff
path: root/vendor/github.com/authzed/spicedb/internal/developmentmembership/foundsubject.go
blob: bf93d562938b2d463ede014a2846f3fe76e9a27f (plain)
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
package developmentmembership

import (
	"sort"
	"strings"

	core "github.com/authzed/spicedb/pkg/proto/core/v1"

	"github.com/authzed/spicedb/pkg/tuple"
)

// NewFoundSubject creates a new FoundSubject for a subject and a set of its resources.
func NewFoundSubject(subject *core.DirectSubject, resources ...tuple.ObjectAndRelation) FoundSubject {
	return FoundSubject{tuple.FromCoreObjectAndRelation(subject.Subject), nil, subject.CaveatExpression, 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 tuple.ObjectAndRelation

	// excludedSubjects are any subjects excluded. Only should be set if subject is a wildcard.
	excludedSubjects []FoundSubject

	// caveatExpression is the conditional expression on the found subject.
	caveatExpression *core.CaveatExpression

	// resources are the resources under which the subject lives that informed the locating
	// of this subject for the root ONR.
	resources ONRSet
}

// GetSubjectId is named to match the Subject interface for the BaseSubjectSet.
//
//nolint:all
func (fs FoundSubject) GetSubjectId() string {
	return fs.subject.ObjectID
}

func (fs FoundSubject) GetCaveatExpression() *core.CaveatExpression {
	return fs.caveatExpression
}

func (fs FoundSubject) GetExcludedSubjects() []FoundSubject {
	return fs.excludedSubjects
}

// Subject returns the Subject of the FoundSubject.
func (fs FoundSubject) Subject() tuple.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.ObjectType, true
	}

	return "", false
}

// ExcludedSubjectsFromWildcard returns those subjects excluded from the wildcard subject.
// If not a wildcard subject, returns false.
func (fs FoundSubject) ExcludedSubjectsFromWildcard() ([]FoundSubject, bool) {
	if fs.subject.ObjectID == tuple.PublicWildcard {
		return fs.excludedSubjects, true
	}

	return nil, false
}

func (fs FoundSubject) excludedSubjectStrings() []string {
	excludedStrings := make([]string, 0, len(fs.excludedSubjects))
	for _, excludedSubject := range fs.excludedSubjects {
		excludedSubjectString := tuple.StringONR(excludedSubject.subject)
		if excludedSubject.GetCaveatExpression() != nil {
			excludedSubjectString += "[...]"
		}
		excludedStrings = append(excludedStrings, excludedSubjectString)
	}

	sort.Strings(excludedStrings)
	return excludedStrings
}

// ToValidationString returns the FoundSubject in a format that is consumable by the validationfile
// package.
func (fs FoundSubject) ToValidationString() string {
	onrString := tuple.StringONR(fs.Subject())
	validationString := onrString
	if fs.caveatExpression != nil {
		validationString = validationString + "[...]"
	}

	excluded, isWildcard := fs.ExcludedSubjectsFromWildcard()
	if isWildcard && len(excluded) > 0 {
		validationString = validationString + " - {" + strings.Join(fs.excludedSubjectStrings(), ", ") + "}"
	}

	return validationString
}

func (fs FoundSubject) String() string {
	return fs.ToValidationString()
}

// ParentResources returns all the resources in which the subject was found as per the expand.
func (fs FoundSubject) ParentResources() []tuple.ObjectAndRelation {
	return fs.resources.AsSlice()
}

// 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 *TrackingSubjectSet
}

// ListFound returns a slice of all the FoundSubject's.
func (fs FoundSubjects) ListFound() []FoundSubject {
	return fs.subjects.ToSlice()
}

// LookupSubject returns the FoundSubject for a matching subject, if any.
func (fs FoundSubjects) LookupSubject(subject tuple.ObjectAndRelation) (FoundSubject, bool) {
	return fs.subjects.Get(subject)
}