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  }