github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/services/v1/hash.go (about) 1 package v1 2 3 import ( 4 "strconv" 5 6 v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" 7 "google.golang.org/protobuf/types/known/structpb" 8 9 "github.com/authzed/spicedb/pkg/caveats" 10 "github.com/authzed/spicedb/pkg/spiceerrors" 11 "github.com/authzed/spicedb/pkg/tuple" 12 ) 13 14 func computeCheckBulkPermissionsItemHashWithoutResourceID(req *v1.CheckBulkPermissionsRequestItem) (string, error) { 15 return computeCallHash("v1.checkbulkpermissionsrequestitem", nil, map[string]any{ 16 "resource-type": req.Resource.ObjectType, 17 "permission": req.Permission, 18 "subject-type": req.Subject.Object.ObjectType, 19 "subject-id": req.Subject.Object.ObjectId, 20 "subject-relation": req.Subject.OptionalRelation, 21 "context": req.Context, 22 }) 23 } 24 25 func computeCheckBulkPermissionsItemHash(req *v1.CheckBulkPermissionsRequestItem) (string, error) { 26 return computeCallHash("v1.checkbulkpermissionsrequestitem", nil, map[string]any{ 27 "resource-type": req.Resource.ObjectType, 28 "resource-id": req.Resource.ObjectId, 29 "permission": req.Permission, 30 "subject-type": req.Subject.Object.ObjectType, 31 "subject-id": req.Subject.Object.ObjectId, 32 "subject-relation": req.Subject.OptionalRelation, 33 "context": req.Context, 34 }) 35 } 36 37 func computeReadRelationshipsRequestHash(req *v1.ReadRelationshipsRequest) (string, error) { 38 osf := req.RelationshipFilter.OptionalSubjectFilter 39 if osf == nil { 40 osf = &v1.SubjectFilter{} 41 } 42 43 srf := "(none)" 44 if osf.OptionalRelation != nil { 45 srf = osf.OptionalRelation.Relation 46 } 47 48 return computeCallHash("v1.readrelationships", req.Consistency, map[string]any{ 49 "filter-resource-type": req.RelationshipFilter.ResourceType, 50 "filter-relation": req.RelationshipFilter.OptionalRelation, 51 "filter-resource-id": req.RelationshipFilter.OptionalResourceId, 52 "subject-type": osf.SubjectType, 53 "subject-relation": srf, 54 "subject-resource-id": osf.OptionalSubjectId, 55 "limit": req.OptionalLimit, 56 }) 57 } 58 59 func computeLRRequestHash(req *v1.LookupResourcesRequest) (string, error) { 60 return computeCallHash("v1.lookupresources", req.Consistency, map[string]any{ 61 "resource-type": req.ResourceObjectType, 62 "permission": req.Permission, 63 "subject": tuple.StringSubjectRef(req.Subject), 64 "limit": req.OptionalLimit, 65 "context": req.Context, 66 }) 67 } 68 69 func computeLSRequestHash(req *v1.LookupSubjectsRequest) (string, error) { 70 return computeCallHash("v1.lookupsubjects", req.Consistency, map[string]any{ 71 "subject-type": req.SubjectObjectType, 72 "permission": req.Permission, 73 "resource": tuple.StringObjectRef(req.Resource), 74 "limit": req.OptionalConcreteLimit, 75 "context": req.Context, 76 "wildcard-option": int(req.WildcardOption), 77 }) 78 } 79 80 func computeCallHash(apiName string, consistency *v1.Consistency, arguments map[string]any) (string, error) { 81 stringArguments := make(map[string]string, len(arguments)+1) 82 83 if consistency == nil { 84 consistency = &v1.Consistency{ 85 Requirement: &v1.Consistency_MinimizeLatency{ 86 MinimizeLatency: true, 87 }, 88 } 89 } 90 91 consistencyBytes, err := consistency.MarshalVT() 92 if err != nil { 93 return "", err 94 } 95 96 stringArguments["consistency"] = string(consistencyBytes) 97 98 for argName, argValue := range arguments { 99 if argName == "consistency" { 100 return "", spiceerrors.MustBugf("cannot specify consistency in the arguments") 101 } 102 103 switch v := argValue.(type) { 104 case string: 105 stringArguments[argName] = v 106 107 case int: 108 stringArguments[argName] = strconv.Itoa(v) 109 110 case uint32: 111 stringArguments[argName] = strconv.Itoa(int(v)) 112 113 case *structpb.Struct: 114 stringArguments[argName] = caveats.StableContextStringForHashing(v) 115 116 default: 117 return "", spiceerrors.MustBugf("unknown argument type in compute call hash") 118 } 119 } 120 return computeAPICallHash(apiName, stringArguments) 121 }