github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/dispatch/keys/keys.go (about) 1 package keys 2 3 import ( 4 "context" 5 6 datastoremw "github.com/authzed/spicedb/internal/middleware/datastore" 7 "github.com/authzed/spicedb/internal/namespace" 8 v1 "github.com/authzed/spicedb/pkg/proto/dispatch/v1" 9 ) 10 11 // Handler is an interface defining how keys are computed for dispatching and caching. 12 type Handler interface { 13 // CheckCacheKey computes the caching key for a Check operation. 14 CheckCacheKey(ctx context.Context, req *v1.DispatchCheckRequest) (DispatchCacheKey, error) 15 16 // LookupResourcesCacheKey computes the caching key for a LookupResources operation. 17 LookupResourcesCacheKey(ctx context.Context, req *v1.DispatchLookupResourcesRequest) (DispatchCacheKey, error) 18 19 // LookupSubjectsCacheKey computes the caching key for a LookupSubjects operation. 20 LookupSubjectsCacheKey(ctx context.Context, req *v1.DispatchLookupSubjectsRequest) (DispatchCacheKey, error) 21 22 // ExpandCacheKey computes the caching key for an Expand operation. 23 ExpandCacheKey(ctx context.Context, req *v1.DispatchExpandRequest) (DispatchCacheKey, error) 24 25 // ReachableResourcesCacheKey computes the caching key for a ReachableResources operation. 26 ReachableResourcesCacheKey(ctx context.Context, req *v1.DispatchReachableResourcesRequest) (DispatchCacheKey, error) 27 28 // CheckDispatchKey computes the dispatch key for a Check operation. 29 CheckDispatchKey(ctx context.Context, req *v1.DispatchCheckRequest) ([]byte, error) 30 31 // LookupResourcesDispatchKey computes the dispatch key for a LookupResources operation. 32 LookupResourcesDispatchKey(ctx context.Context, req *v1.DispatchLookupResourcesRequest) ([]byte, error) 33 34 // LookupSubjectsDispatchKey computes the key for a LookupSubjects operation. 35 LookupSubjectsDispatchKey(ctx context.Context, req *v1.DispatchLookupSubjectsRequest) ([]byte, error) 36 37 // ExpandDispatchKey computes the dispatch key for an Expand operation. 38 ExpandDispatchKey(ctx context.Context, req *v1.DispatchExpandRequest) ([]byte, error) 39 40 // ReachableResourcesDispatchKey computes the key for a ReachableResources operation. 41 ReachableResourcesDispatchKey(ctx context.Context, req *v1.DispatchReachableResourcesRequest) ([]byte, error) 42 } 43 44 type baseKeyHandler struct{} 45 46 func (b baseKeyHandler) LookupResourcesCacheKey(_ context.Context, req *v1.DispatchLookupResourcesRequest) (DispatchCacheKey, error) { 47 return lookupResourcesRequestToKey(req, computeBothHashes), nil 48 } 49 50 func (b baseKeyHandler) LookupSubjectsCacheKey(_ context.Context, req *v1.DispatchLookupSubjectsRequest) (DispatchCacheKey, error) { 51 return lookupSubjectsRequestToKey(req, computeBothHashes), nil 52 } 53 54 func (b baseKeyHandler) ExpandCacheKey(_ context.Context, req *v1.DispatchExpandRequest) (DispatchCacheKey, error) { 55 return expandRequestToKey(req, computeBothHashes), nil 56 } 57 58 func (b baseKeyHandler) ReachableResourcesCacheKey(_ context.Context, req *v1.DispatchReachableResourcesRequest) (DispatchCacheKey, error) { 59 return reachableResourcesRequestToKey(req, computeBothHashes), nil 60 } 61 62 func (b baseKeyHandler) CheckDispatchKey(_ context.Context, req *v1.DispatchCheckRequest) ([]byte, error) { 63 return checkRequestToKey(req, computeOnlyStableHash).StableSumAsBytes(), nil 64 } 65 66 func (b baseKeyHandler) LookupResourcesDispatchKey(_ context.Context, req *v1.DispatchLookupResourcesRequest) ([]byte, error) { 67 return lookupResourcesRequestToKey(req, computeOnlyStableHash).StableSumAsBytes(), nil 68 } 69 70 func (b baseKeyHandler) LookupSubjectsDispatchKey(_ context.Context, req *v1.DispatchLookupSubjectsRequest) ([]byte, error) { 71 return lookupSubjectsRequestToKey(req, computeOnlyStableHash).StableSumAsBytes(), nil 72 } 73 74 func (b baseKeyHandler) ExpandDispatchKey(_ context.Context, req *v1.DispatchExpandRequest) ([]byte, error) { 75 return expandRequestToKey(req, computeOnlyStableHash).StableSumAsBytes(), nil 76 } 77 78 func (b baseKeyHandler) ReachableResourcesDispatchKey(_ context.Context, req *v1.DispatchReachableResourcesRequest) ([]byte, error) { 79 return reachableResourcesRequestToKey(req, computeOnlyStableHash).StableSumAsBytes(), nil 80 } 81 82 // DirectKeyHandler is a key handler that uses the relation name itself as the key. 83 type DirectKeyHandler struct { 84 baseKeyHandler 85 } 86 87 func (d *DirectKeyHandler) CheckCacheKey(_ context.Context, req *v1.DispatchCheckRequest) (DispatchCacheKey, error) { 88 return checkRequestToKey(req, computeBothHashes), nil 89 } 90 91 // CanonicalKeyHandler is a key handler which makes use of the canonical key for relations for 92 // dispatching. 93 type CanonicalKeyHandler struct { 94 baseKeyHandler 95 } 96 97 func (c *CanonicalKeyHandler) CheckCacheKey(ctx context.Context, req *v1.DispatchCheckRequest) (DispatchCacheKey, error) { 98 // NOTE: We do not use the canonicalized cache key when checking within the same namespace, as 99 // we may get different results if the subject being checked matches the resource exactly, e.g. 100 // a check for `somenamespace:someobject#somerel@somenamespace:someobject#somerel`. 101 if req.ResourceRelation.Namespace != req.Subject.Namespace { 102 // Load the relation to get its computed cache key, if any. 103 ds := datastoremw.MustFromContext(ctx) 104 105 revision, err := ds.RevisionFromString(req.Metadata.AtRevision) 106 if err != nil { 107 return emptyDispatchCacheKey, err 108 } 109 r := ds.SnapshotReader(revision) 110 111 _, relation, err := namespace.ReadNamespaceAndRelation( 112 ctx, 113 req.ResourceRelation.Namespace, 114 req.ResourceRelation.Relation, 115 r, 116 ) 117 if err != nil { 118 return emptyDispatchCacheKey, err 119 } 120 121 if relation.CanonicalCacheKey != "" { 122 return checkRequestToKeyWithCanonical(req, relation.CanonicalCacheKey) 123 } 124 } 125 126 return checkRequestToKey(req, computeBothHashes), nil 127 }