diff options
Diffstat (limited to 'vendor/github.com/authzed/spicedb/pkg/tuple/v1.go')
| -rw-r--r-- | vendor/github.com/authzed/spicedb/pkg/tuple/v1.go | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/vendor/github.com/authzed/spicedb/pkg/tuple/v1.go b/vendor/github.com/authzed/spicedb/pkg/tuple/v1.go new file mode 100644 index 0000000..5a3705f --- /dev/null +++ b/vendor/github.com/authzed/spicedb/pkg/tuple/v1.go @@ -0,0 +1,340 @@ +package tuple + +import ( + "fmt" + "time" + + v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" + "github.com/jzelinskie/stringz" + "google.golang.org/protobuf/types/known/timestamppb" + + core "github.com/authzed/spicedb/pkg/proto/core/v1" + "github.com/authzed/spicedb/pkg/spiceerrors" +) + +// ParseV1Rel parses a string representation of a relationship into a v1.Relationship object. +func ParseV1Rel(relString string) (*v1.Relationship, error) { + parsed, err := Parse(relString) + if err != nil { + return nil, err + } + + return ToV1Relationship(parsed), nil +} + +// Same as above, but panics if it cannot be parsed. Should only be used in tests. +func MustParseV1Rel(relString string) *v1.Relationship { + parsed, err := Parse(relString) + if err != nil { + panic(fmt.Sprintf("could not parse relationship string: %s %s", relString, err)) + } + + return ToV1Relationship(parsed) +} + +// MustV1RelString converts a relationship into a string. Will panic if +// the Relationship does not validate. +func MustV1RelString(rel *v1.Relationship) string { + if err := rel.Validate(); err != nil { + panic(fmt.Sprintf("invalid relationship: %#v %s", rel, err)) + } + return MustV1StringRelationship(rel) +} + +// StringObjectRef marshals a *v1.ObjectReference into a string. +// +// This function assumes that the provided values have already been validated. +func V1StringObjectRef(ref *v1.ObjectReference) string { + return JoinObjectRef(ref.ObjectType, ref.ObjectId) +} + +// StringSubjectRef marshals a *v1.SubjectReference into a string. +// +// This function assumes that the provided values have already been validated. +func V1StringSubjectRef(ref *v1.SubjectReference) string { + if ref.OptionalRelation == "" { + return V1StringObjectRef(ref.Object) + } + return JoinRelRef(V1StringObjectRef(ref.Object), ref.OptionalRelation) +} + +// MustV1StringRelationship converts a v1.Relationship to a string. +func MustV1StringRelationship(rel *v1.Relationship) string { + relString, err := V1StringRelationship(rel) + if err != nil { + panic(err) + } + return relString +} + +// V1StringRelationship converts a v1.Relationship to a string. +func V1StringRelationship(rel *v1.Relationship) (string, error) { + if rel == nil || rel.Resource == nil || rel.Subject == nil { + return "", nil + } + + caveatString, err := V1StringCaveatRef(rel.OptionalCaveat) + if err != nil { + return "", err + } + + expirationString, err := V1StringExpiration(rel.OptionalExpiresAt) + if err != nil { + return "", err + } + + return V1StringRelationshipWithoutCaveatOrExpiration(rel) + caveatString + expirationString, nil +} + +func V1StringExpiration(expiration *timestamppb.Timestamp) (string, error) { + if expiration == nil { + return "", nil + } + + return "[expiration:" + expiration.AsTime().Format(expirationFormat) + "]", nil +} + +// V1StringRelationshipWithoutCaveatOrExpiration converts a v1.Relationship to a string, excluding any caveat. +func V1StringRelationshipWithoutCaveatOrExpiration(rel *v1.Relationship) string { + if rel == nil || rel.Resource == nil || rel.Subject == nil { + return "" + } + + return V1StringObjectRef(rel.Resource) + "#" + rel.Relation + "@" + V1StringSubjectRef(rel.Subject) +} + +// V1StringCaveatRef converts a v1.ContextualizedCaveat to a string. +func V1StringCaveatRef(caveat *v1.ContextualizedCaveat) (string, error) { + if caveat == nil || caveat.CaveatName == "" { + return "", nil + } + + contextString, err := StringCaveatContext(caveat.Context) + if err != nil { + return "", err + } + + if len(contextString) > 0 { + contextString = ":" + contextString + } + + return "[" + caveat.CaveatName + contextString + "]", nil +} + +// UpdateToV1RelationshipUpdate converts a RelationshipUpdate into a +// v1.RelationshipUpdate. +func UpdateToV1RelationshipUpdate(update RelationshipUpdate) (*v1.RelationshipUpdate, error) { + var op v1.RelationshipUpdate_Operation + switch update.Operation { + case UpdateOperationCreate: + op = v1.RelationshipUpdate_OPERATION_CREATE + case UpdateOperationDelete: + op = v1.RelationshipUpdate_OPERATION_DELETE + case UpdateOperationTouch: + op = v1.RelationshipUpdate_OPERATION_TOUCH + default: + return nil, spiceerrors.MustBugf("unknown update operation: %v", update.Operation) + } + + return &v1.RelationshipUpdate{ + Operation: op, + Relationship: ToV1Relationship(update.Relationship), + }, nil +} + +// MustUpdateToV1RelationshipUpdate converts a RelationshipUpdate into a +// v1.RelationshipUpdate. Panics on error. +func MustUpdateToV1RelationshipUpdate(update RelationshipUpdate) *v1.RelationshipUpdate { + v1rel, err := UpdateToV1RelationshipUpdate(update) + if err != nil { + panic(err) + } + + return v1rel +} + +// UpdateFromV1RelationshipUpdate converts a RelationshipUpdate into a +// RelationTupleUpdate. +func UpdateFromV1RelationshipUpdate(update *v1.RelationshipUpdate) (RelationshipUpdate, error) { + var op UpdateOperation + switch update.Operation { + case v1.RelationshipUpdate_OPERATION_CREATE: + op = UpdateOperationCreate + case v1.RelationshipUpdate_OPERATION_DELETE: + op = UpdateOperationDelete + case v1.RelationshipUpdate_OPERATION_TOUCH: + op = UpdateOperationTouch + default: + return RelationshipUpdate{}, spiceerrors.MustBugf("unknown update operation: %v", update.Operation) + } + + return RelationshipUpdate{ + Operation: op, + Relationship: FromV1Relationship(update.Relationship), + }, nil +} + +// FromV1Relationship converts a v1.Relationship into a Relationship. +func FromV1Relationship(rel *v1.Relationship) Relationship { + var caveat *core.ContextualizedCaveat + if rel.OptionalCaveat != nil { + caveat = &core.ContextualizedCaveat{ + CaveatName: rel.OptionalCaveat.CaveatName, + Context: rel.OptionalCaveat.Context, + } + } + + var expiration *time.Time + if rel.OptionalExpiresAt != nil { + t := rel.OptionalExpiresAt.AsTime() + expiration = &t + } + + return Relationship{ + RelationshipReference: RelationshipReference{ + Resource: ObjectAndRelation{ + ObjectID: rel.Resource.ObjectId, + ObjectType: rel.Resource.ObjectType, + Relation: rel.Relation, + }, + Subject: ObjectAndRelation{ + ObjectID: rel.Subject.Object.ObjectId, + ObjectType: rel.Subject.Object.ObjectType, + Relation: stringz.Default(rel.Subject.OptionalRelation, Ellipsis, ""), + }, + }, + OptionalCaveat: caveat, + OptionalExpiration: expiration, + } +} + +// ToV1Relationship converts a Relationship into a v1.Relationship. +func ToV1Relationship(rel Relationship) *v1.Relationship { + var caveat *v1.ContextualizedCaveat + if rel.OptionalCaveat != nil { + caveat = &v1.ContextualizedCaveat{ + CaveatName: rel.OptionalCaveat.CaveatName, + Context: rel.OptionalCaveat.Context, + } + } + + var expiration *timestamppb.Timestamp + if rel.OptionalExpiration != nil { + expiration = timestamppb.New(*rel.OptionalExpiration) + } + + return &v1.Relationship{ + Resource: &v1.ObjectReference{ + ObjectType: rel.Resource.ObjectType, + ObjectId: rel.Resource.ObjectID, + }, + Relation: rel.Resource.Relation, + Subject: &v1.SubjectReference{ + Object: &v1.ObjectReference{ + ObjectType: rel.Subject.ObjectType, + ObjectId: rel.Subject.ObjectID, + }, + OptionalRelation: stringz.Default(rel.Subject.Relation, "", Ellipsis), + }, + OptionalCaveat: caveat, + OptionalExpiresAt: expiration, + } +} + +// CopyToV1Relationship copies a Relationship into a v1.Relationship. +func CopyToV1Relationship(rel Relationship, v1rel *v1.Relationship) { + v1rel.Resource.ObjectType = rel.Resource.ObjectType + v1rel.Resource.ObjectId = rel.Resource.ObjectID + v1rel.Relation = rel.Resource.Relation + v1rel.Subject.Object.ObjectType = rel.Subject.ObjectType + v1rel.Subject.Object.ObjectId = rel.Subject.ObjectID + v1rel.Subject.OptionalRelation = stringz.Default(rel.Subject.Relation, "", Ellipsis) + + if rel.OptionalCaveat != nil { + if v1rel.OptionalCaveat == nil { + v1rel.OptionalCaveat = &v1.ContextualizedCaveat{} + } + + v1rel.OptionalCaveat.CaveatName = rel.OptionalCaveat.CaveatName + v1rel.OptionalCaveat.Context = rel.OptionalCaveat.Context + } else { + v1rel.OptionalCaveat = nil + } + + if rel.OptionalExpiration != nil { + v1rel.OptionalExpiresAt = timestamppb.New(*rel.OptionalExpiration) + } else { + v1rel.OptionalExpiresAt = nil + } +} + +// UpdatesToV1RelationshipUpdates converts a slice of RelationshipUpdate into a +// slice of v1.RelationshipUpdate. +func UpdatesToV1RelationshipUpdates(updates []RelationshipUpdate) ([]*v1.RelationshipUpdate, error) { + relationshipUpdates := make([]*v1.RelationshipUpdate, 0, len(updates)) + + for _, update := range updates { + converted, err := UpdateToV1RelationshipUpdate(update) + if err != nil { + return nil, err + } + + relationshipUpdates = append(relationshipUpdates, converted) + } + + return relationshipUpdates, nil +} + +// UpdatesFromV1RelationshipUpdates converts a slice of v1.RelationshipUpdate into a +// slice of RelationshipUpdate. +func UpdatesFromV1RelationshipUpdates(updates []*v1.RelationshipUpdate) ([]RelationshipUpdate, error) { + relationshipUpdates := make([]RelationshipUpdate, 0, len(updates)) + + for _, update := range updates { + converted, err := UpdateFromV1RelationshipUpdate(update) + if err != nil { + return nil, err + } + + relationshipUpdates = append(relationshipUpdates, converted) + } + + return relationshipUpdates, nil +} + +// ToV1Filter converts a RelationTuple into a RelationshipFilter. +func ToV1Filter(rel Relationship) *v1.RelationshipFilter { + return &v1.RelationshipFilter{ + ResourceType: rel.Resource.ObjectType, + OptionalResourceId: rel.Resource.ObjectID, + OptionalRelation: rel.Resource.Relation, + OptionalSubjectFilter: SubjectONRToSubjectFilter(rel.Subject), + } +} + +// SubjectONRToSubjectFilter converts a userset to the equivalent exact SubjectFilter. +func SubjectONRToSubjectFilter(subject ObjectAndRelation) *v1.SubjectFilter { + return &v1.SubjectFilter{ + SubjectType: subject.ObjectType, + OptionalSubjectId: subject.ObjectID, + OptionalRelation: &v1.SubjectFilter_RelationFilter{ + Relation: stringz.Default(subject.Relation, "", Ellipsis), + }, + } +} + +// RelToFilter converts a Relationship into a RelationshipFilter. +func RelToFilter(rel *v1.Relationship) *v1.RelationshipFilter { + return &v1.RelationshipFilter{ + ResourceType: rel.Resource.ObjectType, + OptionalResourceId: rel.Resource.ObjectId, + OptionalRelation: rel.Relation, + OptionalSubjectFilter: &v1.SubjectFilter{ + SubjectType: rel.Subject.Object.ObjectType, + OptionalSubjectId: rel.Subject.Object.ObjectId, + OptionalRelation: &v1.SubjectFilter_RelationFilter{ + Relation: rel.Subject.OptionalRelation, + }, + }, + } +} |
