Skip to content
This repository was archived by the owner on Jan 13, 2023. It is now read-only.

Commit b1bd735

Browse files
authored
Merge pull request #50 from itzmeanjan/graphql-fix
Imposing rate limiting in `/v1/graphql` endpoint
2 parents f296956 + ec88f3d commit b1bd735

File tree

3 files changed

+154
-48
lines changed

3 files changed

+154
-48
lines changed

app/rest/graph/data.go

Lines changed: 105 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package graph
22

33
import (
4+
"context"
45
"encoding/hex"
56
"errors"
67
"fmt"
8+
"log"
79
"strconv"
810
"strings"
911

1012
"github.com/ethereum/go-ethereum/common"
13+
"github.com/gin-gonic/gin"
1114
"github.com/itzmeanjan/ette/app/data"
15+
_db "github.com/itzmeanjan/ette/app/db"
1216
"github.com/itzmeanjan/ette/app/rest/graph/model"
1317
"github.com/lib/pq"
1418
"gorm.io/gorm"
@@ -22,12 +26,75 @@ func GetDatabaseConnection(conn *gorm.DB) {
2226
db = conn
2327
}
2428

29+
// Attempting to recover router context i.e. which holds client `APIKey` in request header,
30+
// in graphql handler context, so that we can do some accounting job
31+
func routerContextFromGraphQLContext(ctx context.Context) (*gin.Context, error) {
32+
33+
ginContext := ctx.Value("RouterContextInGraphQL")
34+
if ginContext == nil {
35+
return nil, errors.New("Failed to retrieve router context")
36+
}
37+
38+
gc, ok := ginContext.(*gin.Context)
39+
if !ok {
40+
return nil, errors.New("Type assert of router context failed")
41+
}
42+
43+
return gc, nil
44+
45+
}
46+
47+
// Attempts to extract out `APIKey` used passed along
48+
// with request, in graphql handler function, to be used for
49+
// doing some book keeping work
50+
func getAPIKey(ctx context.Context) string {
51+
52+
routerCtx, err := routerContextFromGraphQLContext(ctx)
53+
if err != nil {
54+
55+
log.Printf("[!] Failed to get `APIKey` : %s\n", err.Error())
56+
return ""
57+
58+
}
59+
60+
return routerCtx.GetHeader("APIKey")
61+
62+
}
63+
64+
// Attempts to recover `APIKey` from router context, which is
65+
// then used for looking up user, so that data delivery information can
66+
// be persisted into DB
67+
func doBookKeeping(ctx context.Context, _data []byte) error {
68+
69+
if _data == nil {
70+
return errors.New("JSON marshalling failed")
71+
}
72+
73+
user := _db.GetUserFromAPIKey(db, getAPIKey(ctx))
74+
if user == nil {
75+
return errors.New("Failed to get user from `APIKey`")
76+
}
77+
78+
_db.PutDataDeliveryInfo(db, user.Address, "/v1/graphql", uint64(len(_data)))
79+
return nil
80+
81+
}
82+
2583
// Converting block data to graphQL compatible data structure
26-
func getGraphQLCompatibleBlock(block *data.Block) (*model.Block, error) {
84+
func getGraphQLCompatibleBlock(ctx context.Context, block *data.Block, bookKeeping bool) (*model.Block, error) {
85+
2786
if block == nil {
2887
return nil, errors.New("Found nothing")
2988
}
3089

90+
// to be `false` when calling from `getGraphQLCompatibleBlocks(...)`
91+
// because that function will then take care of it's own book keeping logic
92+
if bookKeeping {
93+
if err := doBookKeeping(ctx, block.ToJSON()); err != nil {
94+
return nil, errors.New("Book keeping failed")
95+
}
96+
}
97+
3198
return &model.Block{
3299
Hash: block.Hash,
33100
Number: fmt.Sprintf("%d", block.Number),
@@ -42,10 +109,11 @@ func getGraphQLCompatibleBlock(block *data.Block) (*model.Block, error) {
42109
TxRootHash: block.TransactionRootHash,
43110
ReceiptRootHash: block.ReceiptRootHash,
44111
}, nil
112+
45113
}
46114

47115
// Converting block array to graphQL compatible data structure
48-
func getGraphQLCompatibleBlocks(blocks *data.Blocks) ([]*model.Block, error) {
116+
func getGraphQLCompatibleBlocks(ctx context.Context, blocks *data.Blocks) ([]*model.Block, error) {
49117
if blocks == nil {
50118
return nil, errors.New("Found nothing")
51119
}
@@ -54,18 +122,22 @@ func getGraphQLCompatibleBlocks(blocks *data.Blocks) ([]*model.Block, error) {
54122
return nil, errors.New("Found nothing")
55123
}
56124

125+
if err := doBookKeeping(ctx, blocks.ToJSON()); err != nil {
126+
return nil, errors.New("Book keeping failed")
127+
}
128+
57129
_blocks := make([]*model.Block, len(blocks.Blocks))
58130

59131
for k, v := range blocks.Blocks {
60-
_v, _ := getGraphQLCompatibleBlock(v)
132+
_v, _ := getGraphQLCompatibleBlock(ctx, v, false)
61133
_blocks[k] = _v
62134
}
63135

64136
return _blocks, nil
65137
}
66138

67139
// Converting transaction data to graphQL compatible data structure
68-
func getGraphQLCompatibleTransaction(tx *data.Transaction) (*model.Transaction, error) {
140+
func getGraphQLCompatibleTransaction(ctx context.Context, tx *data.Transaction, bookKeeping bool) (*model.Transaction, error) {
69141
if tx == nil {
70142
return nil, errors.New("Found nothing")
71143
}
@@ -75,6 +147,14 @@ func getGraphQLCompatibleTransaction(tx *data.Transaction) (*model.Transaction,
75147
data = fmt.Sprintf("0x%s", _h)
76148
}
77149

150+
// to be `false` when calling from `getGraphQLCompatibleTransactions(...)`
151+
// because that function will then take care of it's own book keeping logic
152+
if bookKeeping {
153+
if err := doBookKeeping(ctx, tx.ToJSON()); err != nil {
154+
return nil, errors.New("Book keeping failed")
155+
}
156+
}
157+
78158
if !strings.HasPrefix(tx.Contract, "0x") {
79159
return &model.Transaction{
80160
Hash: tx.Hash,
@@ -109,7 +189,7 @@ func getGraphQLCompatibleTransaction(tx *data.Transaction) (*model.Transaction,
109189
}
110190

111191
// Converting transaction array to graphQL compatible data structure
112-
func getGraphQLCompatibleTransactions(tx *data.Transactions) ([]*model.Transaction, error) {
192+
func getGraphQLCompatibleTransactions(ctx context.Context, tx *data.Transactions) ([]*model.Transaction, error) {
113193
if tx == nil {
114194
return nil, errors.New("Found nothing")
115195
}
@@ -118,18 +198,22 @@ func getGraphQLCompatibleTransactions(tx *data.Transactions) ([]*model.Transacti
118198
return nil, errors.New("Found nothing")
119199
}
120200

201+
if err := doBookKeeping(ctx, tx.ToJSON()); err != nil {
202+
return nil, errors.New("Book keeping failed")
203+
}
204+
121205
_tx := make([]*model.Transaction, len(tx.Transactions))
122206

123207
for k, v := range tx.Transactions {
124-
_v, _ := getGraphQLCompatibleTransaction(v)
208+
_v, _ := getGraphQLCompatibleTransaction(ctx, v, false)
125209
_tx[k] = _v
126210
}
127211

128212
return _tx, nil
129213
}
130214

131215
// Converting event data to graphQL compatible data structure
132-
func getGraphQLCompatibleEvent(event *data.Event) (*model.Event, error) {
216+
func getGraphQLCompatibleEvent(ctx context.Context, event *data.Event, bookKeeping bool) (*model.Event, error) {
133217
if event == nil {
134218
return nil, errors.New("Found nothing")
135219
}
@@ -139,6 +223,14 @@ func getGraphQLCompatibleEvent(event *data.Event) (*model.Event, error) {
139223
data = fmt.Sprintf("0x%s", _h)
140224
}
141225

226+
// to be `false` when calling from `getGraphQLCompatibleEvents(...)`
227+
// because that function will then take care of it's own book keeping logic
228+
if bookKeeping {
229+
if err := doBookKeeping(ctx, event.ToJSON()); err != nil {
230+
return nil, errors.New("Book keeping failed")
231+
}
232+
}
233+
142234
return &model.Event{
143235
Origin: event.Origin,
144236
Index: fmt.Sprintf("%d", event.Index),
@@ -150,7 +242,7 @@ func getGraphQLCompatibleEvent(event *data.Event) (*model.Event, error) {
150242
}
151243

152244
// Converting event array to graphQL compatible data structure
153-
func getGraphQLCompatibleEvents(events *data.Events) ([]*model.Event, error) {
245+
func getGraphQLCompatibleEvents(ctx context.Context, events *data.Events) ([]*model.Event, error) {
154246
if events == nil {
155247
return nil, errors.New("Found nothing")
156248
}
@@ -159,10 +251,14 @@ func getGraphQLCompatibleEvents(events *data.Events) ([]*model.Event, error) {
159251
return nil, errors.New("Found nothing")
160252
}
161253

254+
if err := doBookKeeping(ctx, events.ToJSON()); err != nil {
255+
return nil, errors.New("Book keeping failed")
256+
}
257+
162258
_events := make([]*model.Event, len(events.Events))
163259

164260
for k, v := range events.Events {
165-
_v, _ := getGraphQLCompatibleEvent(v)
261+
_v, _ := getGraphQLCompatibleEvent(ctx, v, false)
166262
_events[k] = _v
167263
}
168264

0 commit comments

Comments
 (0)