Skip to content

Commit 47ebffb

Browse files
committed
feat(faucet): gno address and email/token mapping
Closes #148 - Register in redis the gno address as key and email/token as values - Add a pseudo endpoint to retrieve email and token from gno adresses
1 parent 09b3ba8 commit 47ebffb

2 files changed

Lines changed: 83 additions & 11 deletions

File tree

faucet/main.go

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@ import (
2121
tm2Client "github.com/gnolang/faucet/client/http"
2222
"github.com/gnolang/faucet/config"
2323
"github.com/gnolang/faucet/estimate/static"
24-
"github.com/gnolang/gno/tm2/pkg/crypto"
25-
"github.com/gnolang/gno/tm2/pkg/std"
2624
"github.com/peterbourgon/ff/v3"
2725
"github.com/peterbourgon/ff/v3/fftoml"
2826
"github.com/redis/go-redis/v9"
2927
"go.uber.org/zap"
3028
"golang.org/x/sync/errgroup"
3129

30+
"github.com/gnolang/gno/tm2/pkg/crypto"
31+
"github.com/gnolang/gno/tm2/pkg/std"
32+
3233
"github.com/peterbourgon/ff/v3/ffcli"
3334
)
3435

@@ -175,7 +176,7 @@ func registerFlags(fs *flag.FlagSet, c *rootCfg) {
175176
fs.StringVar(
176177
&c.redisURL,
177178
"redis-url",
178-
"redis://user:pass@127.0.0.1:6379",
179+
"redis://127.0.0.1:6379",
179180
"redis connection string",
180181
)
181182

@@ -221,12 +222,10 @@ func execMain(cfg *rootCfg) error {
221222
cli := tm2Client.NewClient(cfg.remote)
222223

223224
// Prepare the middlewares
224-
middlewares := []faucet.Middleware{
225-
prepareFundMiddleware(cli, fundLimit),
226-
}
225+
var middlewares []faucet.Middleware
227226

228-
// TODO temporary
229227
if len(cfg.allowedTokens) != 0 {
228+
// TODO temporary for testing purpose without redis
230229
middlewares = append(middlewares, prepareTokenListMiddleware(cfg.allowedTokens))
231230
} else {
232231
redisOpts, err := redis.ParseURL(cfg.redisURL)
@@ -235,8 +234,21 @@ func execMain(cfg *rootCfg) error {
235234
}
236235
redisClient := redis.NewClient(redisOpts)
237236

237+
// Add /?addr={gnoAddr} endpoint as a middleware in first position.
238+
// If the request contains an `addr` field in the query string, it will fetch
239+
// the email from redis and returns it, without calling the other handlers
240+
// or middlewares behind it.
241+
//
242+
// Why not a faucet.Handler option instead of a middleware ?
243+
// This is not achievable with a real handler passed in the faucet options
244+
// because it inherits the other middlewares which requires a
245+
// faucet.Request or else fails with Bad Request.
246+
middlewares = append(middlewares, getEmail(redisClient))
247+
238248
middlewares = append(middlewares, prepareTokenMiddleware(redisClient))
239249
}
250+
// Call prepareFundMiddleware last to avoid funding users with invalid tokens
251+
middlewares = append(middlewares, prepareFundMiddleware(cli, fundLimit))
240252

241253
// Create a new faucet with
242254
// static gas estimation
@@ -464,14 +476,74 @@ func prepareTokenMiddleware(redisClient *redis.Client) faucet.Middleware {
464476
return
465477
}
466478

467-
// Continue with serving the faucet request
468-
next.ServeHTTP(w, r)
469-
470479
_, err = redisClient.HSet(r.Context(), "TOKEN:"+token, "used", "true").Result()
471480
if err != nil {
472481
http.Error(w, "Unable to lock token", http.StatusInternalServerError)
473482
return
474483
}
484+
485+
// Parse the request to extract the address
486+
// XXX copied from prepareFundMiddleware, don't have time to refactor without unit tests!
487+
var request faucet.Request
488+
body, err := io.ReadAll(r.Body)
489+
if err != nil {
490+
http.Error(w, "Error reading request body", http.StatusInternalServerError)
491+
return
492+
}
493+
// Close the original body
494+
if err := r.Body.Close(); err != nil {
495+
http.Error(w, "Error closing request body", http.StatusInternalServerError)
496+
return
497+
}
498+
// Create a new ReadCloser from the read bytes
499+
// so that future middleware will be able to read
500+
r.Body = io.NopCloser(bytes.NewReader(body))
501+
// Decode the original request
502+
if err := json.NewDecoder(bytes.NewBuffer(body)).Decode(&request); err != nil {
503+
http.Error(w, "Invalid request", http.StatusBadRequest)
504+
return
505+
}
506+
507+
// Read email
508+
email, err := redisClient.HGet(r.Context(), "TOKEN:"+token, "email").Result()
509+
if err != nil {
510+
http.Error(w, "Unable to read token email", http.StatusInternalServerError)
511+
return
512+
}
513+
// Store gno adress, email and token, so they are retrievable via the
514+
// getEmail middleware.
515+
err = redisClient.HSet(r.Context(), "GNO:"+request.To, "email", email, "token", token).Err()
516+
if err != nil {
517+
http.Error(w, "Unable to set gno address and email", http.StatusInternalServerError)
518+
return
519+
}
520+
521+
// Continue with serving the faucet request
522+
next.ServeHTTP(w, r)
523+
})
524+
}
525+
}
526+
527+
// getEmail detects the presence of `addr` form value, if present returns the
528+
// corresponding hashset from redis and stops the request.
529+
func getEmail(redisClient *redis.Client) faucet.Middleware {
530+
return func(next http.Handler) http.Handler {
531+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
532+
addr := r.FormValue("addr")
533+
if addr != "" {
534+
res := redisClient.HGetAll(r.Context(), "GNO:"+addr)
535+
if res.Err() != nil {
536+
http.Error(w, "Unable to get gno address", http.StatusInternalServerError)
537+
return
538+
}
539+
err := json.NewEncoder(w).Encode(res.Val())
540+
if err != nil {
541+
http.Error(w, "Unable to encode gno address values", http.StatusInternalServerError)
542+
return
543+
}
544+
return
545+
}
546+
next.ServeHTTP(w, r)
475547
})
476548
}
477549
}

web/assets/js/components/gameoptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ const Gameoptions = class extends Component {
358358
isTokenError = true;
359359
this.DOM.el.querySelector('#id-gameoptions-token').value = '';
360360
this.DOM.ctrl1.innerHTML = 'Connection';
361-
this.call('appear', ['Invalid token', 'error'], 'toast');
361+
this.call('appear', [e, 'error'], 'toast');
362362
}
363363
}
364364
this.disabled = false;

0 commit comments

Comments
 (0)