@@ -11,7 +11,6 @@ import (
1111 "github.com/DIMO-Network/fetch-api/pkg/eventrepo"
1212 "github.com/DIMO-Network/fetch-api/pkg/grpc"
1313 "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims"
14- "github.com/ethereum/go-ethereum/common"
1514)
1615
1716// This file will not be regenerated automatically.
@@ -24,69 +23,65 @@ type ClaimsContextKey struct{}
2423type Resolver struct {
2524 EventService * eventrepo.Service
2625 Buckets []string
27- VehicleAddr common.Address
28- ChainID uint64
2926 IdentityClient identity.Client
3027}
3128
32- // CheckVehicleRawDataByDID returns an error if the context does not have claims or the token
33- // does not have GetRawData permission for the given vehicle DID, or if the DID is invalid.
34- func CheckVehicleRawDataByDID (ctx context.Context , did string ) error {
35- if _ , err := cloudevent .DecodeERC721DID (did ); err != nil {
36- return fmt .Errorf ("invalid DID: %w" , err )
29+ const (
30+ errNoTokenClaims = "unauthorized: no token claims"
31+ errNoPermission = "unauthorized: token does not have required permission for this operation"
32+ errNoAccessToSubject = "unauthorized: token does not have access to this subject"
33+ )
34+
35+ // requireSubjectOptsByDID validates raw-data access and returns search options for the DID.
36+ // requestedDID: the DID from the client (e.g. cloudEvents(did: "...")).
37+ // tokenSubjectDID: the DID the JWT grants access to (tok.Asset).
38+ func (r * queryResolver ) requireSubjectOptsByDID (ctx context.Context , requestedDID string , filter * model.CloudEventFilter ) (* grpc.SearchOptions , error ) {
39+ token , err := requireRawDataToken (ctx )
40+ if err != nil {
41+ return nil , err
42+ }
43+ tokenSubjectDID := token .Asset // DID the JWT permits access to
44+ searchSubject , err := r .ensureRequestedDIDLinkedToPermissionedSubject (ctx , requestedDID , tokenSubjectDID )
45+ if err != nil {
46+ return nil , err
3747 }
38- return checkRawDataPermissionsForVehicle ( ctx , did )
48+ return filterToSearchOptions ( filter , searchSubject ), nil
3949}
4050
41- // checkRawDataPermissionsForVehicle verifies the context token has access for vehicleDID.
42- // vehicleDID must already be validated.
43- // Allowed: GetRawData, or both GetLocationHistory (all-time location) and GetNonLocationHistory.
44- func checkRawDataPermissionsForVehicle (ctx context.Context , vehicleDID string ) error {
51+ // requireRawDataToken returns the token if the context has claims and the token has raw-data permission.
52+ // Call this first so unauthenticated or insufficient-permission requests get a clear error before any DID resolution.
53+ func requireRawDataToken (ctx context.Context ) (* tokenclaims.Token , error ) {
4554 tok , _ := ctx .Value (ClaimsContextKey {}).(* tokenclaims.Token )
4655 if tok == nil {
47- return fmt .Errorf ("unauthorized: no token claims" )
48- }
49- if tok .Asset != vehicleDID {
50- return fmt .Errorf ("unauthorized: token does not have access to this vehicle" )
56+ return nil , fmt .Errorf ("%s" , errNoTokenClaims )
5157 }
5258 hasGetRawData := slices .Contains (tok .Permissions , tokenclaims .PermissionGetRawData )
5359 hasLocationHistory := slices .Contains (tok .Permissions , tokenclaims .PermissionGetLocationHistory )
5460 hasNonLocationHistory := slices .Contains (tok .Permissions , tokenclaims .PermissionGetNonLocationHistory )
5561 hasAllTimeData := hasLocationHistory && hasNonLocationHistory
5662 if ! hasGetRawData && ! hasAllTimeData {
57- return fmt .Errorf ("unauthorized: token does not have required permission for this vehicle operation" )
63+ return nil , fmt .Errorf ("%s" , errNoPermission )
5864 }
59- return nil
65+ return tok , nil
6066}
6167
62- // requireVehicleOptsByDID validates raw-data access and returns search options for the DID.
63- //
64- // If did belongs to the vehicle NFT contract (r.VehicleAddr), the token asset must match that
65- // vehicle DID directly. Otherwise the DID is treated as a device DID: identity-api is called
66- // to resolve the paired vehicle, and the token must have access to that vehicle. Either way,
67- // the search subject is always the originally requested DID.
68- func (r * queryResolver ) requireVehicleOptsByDID (ctx context.Context , did string , filter * model.CloudEventFilter ) (* grpc.SearchOptions , error ) {
69- decoded , err := cloudevent .DecodeERC721DID (did )
68+ // ensureRequestedDIDLinkedToPermissionedSubject verifies the client-requested DID is allowed by the token.
69+ // requestedDID: the DID from the query (e.g. cloudEvents(did: "...")).
70+ // tokenSubjectDID: the DID the JWT grants access to (tok.Asset).
71+ func (r * queryResolver ) ensureRequestedDIDLinkedToPermissionedSubject (ctx context.Context , requestedDID string , tokenSubjectDID string ) (cloudevent.ERC721DID , error ) {
72+ requestedDIDParsed , err := cloudevent .DecodeERC721DID (requestedDID )
7073 if err != nil {
71- return nil , fmt .Errorf ("invalid DID: %w " , err )
74+ return cloudevent. ERC721DID {} , fmt .Errorf ("%s " , errNoAccessToSubject )
7275 }
73-
74- var vehicleDID string
75- if decoded .ContractAddress == r .VehicleAddr {
76- vehicleDID = did
77- } else {
78- if r .IdentityClient == nil {
79- return nil , fmt .Errorf ("device DID lookup not configured: no identity client" )
80- }
81- vehicleDID , err = r .IdentityClient .GetVehicleDIDForDevice (ctx , did )
82- if err != nil {
83- return nil , fmt .Errorf ("failed to resolve vehicle for device DID: %w" , err )
84- }
76+ if requestedDID == tokenSubjectDID {
77+ return requestedDIDParsed , nil
8578 }
86-
87- if err := checkRawDataPermissionsForVehicle (ctx , vehicleDID ); err != nil {
88- return nil , err
79+ if r .IdentityClient == nil {
80+ return cloudevent.ERC721DID {}, fmt .Errorf ("%s" , errNoAccessToSubject )
8981 }
90-
91- return filterToSearchOptions (filter , decoded ), nil
82+ linkedDID , err := r .IdentityClient .GetLinkedDIDForDevice (ctx , requestedDIDParsed .String ())
83+ if err != nil || linkedDID != tokenSubjectDID {
84+ return cloudevent.ERC721DID {}, fmt .Errorf ("%s" , errNoAccessToSubject )
85+ }
86+ return requestedDIDParsed , nil
9287}
0 commit comments