Skip to content

Commit

Permalink
feat: changes on captcha behavior
Browse files Browse the repository at this point in the history
captchaToken is now optionnal in GraphQL send request
captcha verify url is now configurable
captcha min score is now configurable
add errors to log context when logging errors
using context when requesting captcha verification
  • Loading branch information
ingvaar committed May 18, 2022
1 parent b5fed62 commit e66f92b
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 35 deletions.
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"os"
"strings"

"okp4/cosmos-faucet/pkg"

Expand Down Expand Up @@ -71,6 +72,7 @@ func ReadPersistentFlags(cmd *cobra.Command) error {
}
v.SetEnvPrefix(envPrefix)
v.AutomaticEnv()
v.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))

cmd.Flags().VisitAll(func(f *pflag.Flag) {
if !f.Changed && v.IsSet(f.Name) {
Expand Down
20 changes: 16 additions & 4 deletions cmd/start.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package cmd

import (
"os"

"okp4/cosmos-faucet/internal/server"
"okp4/cosmos-faucet/pkg/client"

Expand All @@ -15,6 +13,8 @@ const (
FlagMetrics = "metrics"
FlagHealth = "health"
FlagCaptchaSecret = "captcha-secret"
FlagCaptchaURL = "captcha-verify-url"
FlagCaptchaScore = "captcha-min-score"
)

var serverConfig server.Config
Expand Down Expand Up @@ -48,8 +48,20 @@ func NewStartCommand() *cobra.Command {
startCmd.Flags().StringVar(
&serverConfig.CaptchaSecret,
FlagCaptchaSecret,
os.Getenv("CAPTCHA_SECRET"),
"set Captcha secret (default from env: CAPTCHA_SECRET)",
"",
"set Captcha secret",
)
startCmd.Flags().StringVar(
&serverConfig.CaptchaVerifyURL,
FlagCaptchaURL,
"https://www.google.com/recaptcha/api/siteverify",
"set Captcha verify URL",
)
startCmd.Flags().Float64Var(
&serverConfig.CaptchaMinScore,
FlagCaptchaScore,
0.5,
"set Captcha min score",
)

return startCmd
Expand Down
4 changes: 2 additions & 2 deletions graph/generated/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion graph/model/models_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion graph/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ scalar UInt64
"""All inputs needed to send token to a given address"""
input SendInput {
"""Captcha token"""
captchaToken: String!
captchaToken: String
"""Address where to send token(s)"""
toAddress: Address!
}
Expand Down
9 changes: 7 additions & 2 deletions graph/schema.resolvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package graph

import (
"context"
"errors"
"okp4/cosmos-faucet/graph/generated"
"okp4/cosmos-faucet/graph/model"

Expand All @@ -13,8 +14,12 @@ import (
)

func (r *mutationResolver) Send(ctx context.Context, input model.SendInput) (*model.TxResponse, error) {
if err := r.CaptchaResolver.CheckRecaptcha(input.CaptchaToken); err != nil {
return nil, err
if input.CaptchaToken != nil {
if err := r.CaptchaResolver.CheckRecaptcha(ctx, *input.CaptchaToken); err != nil {
return nil, err
}
} else {
return nil, errors.New("captcha token not specified")
}

resp, err := r.Faucet.SendTxMsg(ctx, input.ToAddress)
Expand Down
2 changes: 1 addition & 1 deletion graph/schema.resolvers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func newMockCaptchaResolver() captcha.Resolver {
return mockCaptchaResolver{}
}

func (r mockCaptchaResolver) CheckRecaptcha(_ string) error {
func (r mockCaptchaResolver) CheckRecaptcha(_ context.Context, _ string) error {
return nil
}

Expand Down
20 changes: 11 additions & 9 deletions internal/captcha/captcha.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package captcha

import "github.com/rs/zerolog/log"
import (
"context"

type Resolver interface {
CheckRecaptcha(string) error
}
"github.com/rs/zerolog/log"
)

type resolver struct {
secret string
type Resolver interface {
CheckRecaptcha(context.Context, string) error
}

func NewCaptchaResolver(secret string) Resolver {
func NewCaptchaResolver(secret, verifyURL string, minScore float64) Resolver {
if secret == "" {
log.Fatal().Msg("Required Captcha secret not set")
log.Error().Msg("Required Captcha secret not set")
}
return resolver{
secret: secret,
secret: secret,
siteVerifyURL: verifyURL,
minScore: minScore,
}
}
23 changes: 14 additions & 9 deletions internal/captcha/verify.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package captcha

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand All @@ -10,8 +11,6 @@ import (
"github.com/rs/zerolog/log"
)

const siteVerifyURL = "https://www.google.com/recaptcha/api/siteverify"

type siteVerifyResponse struct {
Success bool `json:"success"`
Score float64 `json:"score"`
Expand All @@ -21,10 +20,16 @@ type siteVerifyResponse struct {
ErrorCodes []string `json:"error-codes"`
}

func (c resolver) CheckRecaptcha(response string) error {
req, err := http.NewRequest(http.MethodPost, siteVerifyURL, nil)
type resolver struct {
secret string
siteVerifyURL string
minScore float64
}

func (c resolver) CheckRecaptcha(ctx context.Context, response string) error {
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.siteVerifyURL, nil)
if err != nil {
log.Error().Msgf("Error while creating Captcha verification request: %s", err.Error())
log.Error().Err(err).Msgf("Error while creating Captcha verification request: %s", err.Error())
return fmt.Errorf("error while creating Captcha verification request: %w", err)
}

Expand All @@ -35,14 +40,14 @@ func (c resolver) CheckRecaptcha(response string) error {

resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Error().Msgf("Error while requesting Captcha verification: %s", err.Error())
log.Error().Err(err).Msgf("Error while requesting Captcha verification: %s", err.Error())
return fmt.Errorf("error while requesting Captcha verification: %w", err)
}
defer resp.Body.Close()

var body siteVerifyResponse
if err = json.NewDecoder(resp.Body).Decode(&body); err != nil {
log.Error().Msgf("Error while decoding Captcha verification response: %s", err.Error())
log.Error().Err(err).Msgf("Error while decoding Captcha verification response: %s", err.Error())
return fmt.Errorf("error while decoding Captcha verification response: %w", err)
}

Expand All @@ -53,8 +58,8 @@ func (c resolver) CheckRecaptcha(response string) error {
}

// If score is too low, verification KO.
if body.Score > 0.5 {
log.Debug().Msg("Captcha verification failed: score is too low")
if body.Score < c.minScore {
log.Debug().Float64("score", body.Score).Msg("Captcha verification failed: score is too low")
return errors.New("captcha verification failed: score is too low")
}

Expand Down
8 changes: 6 additions & 2 deletions internal/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ func (s *httpServer) createRoutes(config Config) {
graphql.NewDefaultServer(
generated.NewExecutableSchema(generated.Config{
Resolvers: &graph.Resolver{
Faucet: config.Faucet,
CaptchaResolver: captcha.NewCaptchaResolver(config.CaptchaSecret),
Faucet: config.Faucet,
CaptchaResolver: captcha.NewCaptchaResolver(
config.CaptchaSecret,
config.CaptchaVerifyURL,
config.CaptchaMinScore,
),
},
}),
),
Expand Down
10 changes: 6 additions & 4 deletions internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import (

// Config holds config of the http server.
type Config struct {
EnableMetrics bool `mapstructure:"metrics"`
EnableHealth bool `mapstructure:"health"`
Faucet client.Faucet
CaptchaSecret string `mapstructure:"captcha-secret"`
EnableMetrics bool `mapstructure:"metrics"`
EnableHealth bool `mapstructure:"health"`
Faucet client.Faucet
CaptchaSecret string `mapstructure:"captcha-secret"`
CaptchaVerifyURL string `mapstructure:"captcha-verify-url"`
CaptchaMinScore float64 `mapstructure:"captcha-min-score"`
}

// HTTPServer exposes server methods.
Expand Down

0 comments on commit e66f92b

Please sign in to comment.