Skip to content

Commit

Permalink
Cleaning api for first release and use time.Duration where relevant (#16
Browse files Browse the repository at this point in the history
)
  • Loading branch information
ezzarghili authored Dec 26, 2018
1 parent 4037443 commit 851b0b5
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 63 deletions.
42 changes: 25 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,22 @@ Google reCAPTCHA v2 & v3 form submittion verification in golang

The API has changed form last version hence the new major version change.
Old API is still available using the package `gopkg.in/ezzarghili/recaptcha-go.v2` although it does not provide all options available in this version
As always install the package in your environment by using a stable API version, see latest version in release page.
As always install the package in your environment by using a stable API version, see latest version in release page.

```bash
go get -u gopkg.in/ezzarghili/recaptcha-go.v3
```
### recaptcha v2 API

### recaptcha v2 API

```go
import "gopkg.in/ezzarghili/recaptcha-go.v3"
func main(){
captcha := recaptcha.NewReCAPTCHA(recaptchaSecret, recaptcha.V2, timeout) // for v2 API get your secret from https://www.google.com/recaptcha/admin
captcha := recaptcha.NewReCAPTCHA(recaptchaSecret, recaptcha.V2, 10*time.Second) // for v2 API get your secret from https://www.google.com/recaptcha/admin
}
```

Now everytime you need to verify a V2 API client with no special options request use
Now everytime you need to verify a V2 API client with no special options request use

```go
err := captcha.Verify(recaptchaResponse)
Expand All @@ -30,15 +32,17 @@ if err != nil {
}
// proceed
```

For specific options use the `VerifyWithOptions` method
Available options for the v2 api are:

```go
Hostname string
ApkPackageName string
ResponseTime float64
RemoteIP string
Hostname string
ApkPackageName string
ResponseTime time.Duration
RemoteIP string
```

Other v3 options are ignored and method will return `nil` when succeeded

```go
Expand All @@ -49,33 +53,36 @@ if err != nil {
// proceed
```

### recaptcha v3 API
### recaptcha v3 API

```go
import "github.com/ezzarghili/recaptcha-go.v3"
func main(){
captcha := recaptcha.NewReCAPTCHA(recaptchaSecret, recaptcha.V3, timeout) // for v3 API use https://g.co/recaptcha/v3 (apperently the same admin UI at the time of writing)
captcha := recaptcha.NewReCAPTCHA(recaptchaSecret, recaptcha.V3, 10*time.Second) // for v3 API use https://g.co/recaptcha/v3 (apperently the same admin UI at the time of writing)
}
```

Now everytime you need to verify a V3 API client with no special options request use
Note that as recaptcha v3 use score for challenge validation, if no treshold option is set the **default** value is `0.5`

```go
err := captcha.Verify(recaptchaResponse)
if err != nil {
// do something with err (log?)
}
// proceed
```

For specific options use the `VerifyWithOptions` method
Availavle options for the v3 api are:

```go
Treshold float32
Action string
Hostname string
ApkPackageName string
ResponseTime float64
RemoteIP string
Treshold float32
Action string
Hostname string
ApkPackageName string
ResponseTime time.Duration
RemoteIP string
```

```go
Expand All @@ -95,10 +102,11 @@ Use the `error` to check for issues with the secret, connection with the server,
This version made timeout explcit to make sure users have the possiblity to set the underling http client timeout suitable for their implemetation.

### Run Tests

Use the standard go means of running test.
You can also check examples of usable in the tests.

```
```bash
go test
```

Expand Down
35 changes: 19 additions & 16 deletions recaptcha.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const (
V2 VERSION = iota
// V3 recaptcha api v3, more details can be found here : https://developers.google.com/recaptcha/docs/v3
V3
DEFAULT_TRESHOLD float32 = 0.5
// DefaultTreshold Default minimin score when using V3 api
DefaultTreshold float32 = 0.5
)

type reCHAPTCHARequest struct {
Expand All @@ -43,6 +44,7 @@ type netClient interface {
PostForm(url string, formValues url.Values) (resp *http.Response, err error)
}

// custom clock so we can mock in tests
type clock interface {
Since(t time.Time) time.Duration
}
Expand All @@ -56,23 +58,23 @@ func (realClock) Since(t time.Time) time.Duration {

// ReCAPTCHA recpatcha holder struct, make adding mocking code simpler
type ReCAPTCHA struct {
Client netClient
client netClient
Secret string
ReCAPTCHALink string
Version VERSION
Timeout uint
Timeout time.Duration
horloge clock
}

// NewReCAPTCHA Create new ReCAPTCHA with the v2 reCAPTCHA secret optained from https://www.google.com/recaptcha/admin
// or https://www.google.com/recaptcha/admin
func NewReCAPTCHA(ReCAPTCHASecret string, version VERSION, timeout uint) (ReCAPTCHA, error) {
// NewReCAPTCHA new ReCAPTCHA instance if version is set to V2 uses recatpcha v2 API, get your secret from https://www.google.com/recaptcha/admin
// if version is set to V2 uses recatpcha v2 API, get your secret from https://g.co/recaptcha/v3
func NewReCAPTCHA(ReCAPTCHASecret string, version VERSION, timeout time.Duration) (ReCAPTCHA, error) {
if ReCAPTCHASecret == "" {
return ReCAPTCHA{}, fmt.Errorf("recaptcha secret cannot be blank")
}
return ReCAPTCHA{
Client: &http.Client{
Timeout: time.Duration(timeout) * time.Second,
client: &http.Client{
Timeout: timeout,
},
horloge: &realClock{},
Secret: ReCAPTCHASecret,
Expand All @@ -82,7 +84,7 @@ func NewReCAPTCHA(ReCAPTCHASecret string, version VERSION, timeout uint) (ReCAPT
}, nil
}

// Verify returns (true, nil) if no error the client answered the challenge correctly and have correct remoteIP
// Verify returns `nil` if no error and the client solved the challenge correctly
func (r *ReCAPTCHA) Verify(challengeResponse string) error {
body := reCHAPTCHARequest{Secret: r.Secret, Response: challengeResponse}
return r.confirm(body, VerifyOption{})
Expand All @@ -94,11 +96,12 @@ type VerifyOption struct {
Action string // ignored in v2 recaptcha
Hostname string
ApkPackageName string
ResponseTime float64
ResponseTime time.Duration
RemoteIP string
}

// VerifyWithOptions returns (true, nil) if no error the client answered the challenge correctly and have correct remoteIP
// VerifyWithOptions returns `nil` if no error and the client solved the challenge correctly and all options are natching
// `Treshold` and `Action` are ignored when using V2 version
func (r *ReCAPTCHA) VerifyWithOptions(challengeResponse string, options VerifyOption) error {
var body reCHAPTCHARequest
if options.RemoteIP == "" {
Expand All @@ -117,7 +120,7 @@ func (r *ReCAPTCHA) confirm(recaptcha reCHAPTCHARequest, options VerifyOption) (
} else {
formValues = url.Values{"secret": {recaptcha.Secret}, "response": {recaptcha.Response}}
}
response, err := r.Client.PostForm(r.ReCAPTCHALink, formValues)
response, err := r.client.PostForm(r.ReCAPTCHALink, formValues)
if err != nil {
Err = fmt.Errorf("error posting to recaptcha endpoint: '%s'", err)
return
Expand Down Expand Up @@ -146,9 +149,9 @@ func (r *ReCAPTCHA) confirm(recaptcha reCHAPTCHARequest, options VerifyOption) (
}

if options.ResponseTime != 0 {
duration := r.horloge.Since(result.ChallengeTS).Seconds()
duration := r.horloge.Since(result.ChallengeTS)
if options.ResponseTime < duration {
Err = fmt.Errorf("time spent in resolving challenge '%f', while expecting maximum '%f'", duration, options.ResponseTime)
Err = fmt.Errorf("time spent in resolving challenge '%fs', while expecting maximum '%fs'", duration.Seconds(), options.ResponseTime.Seconds())
return
}
}
Expand All @@ -161,8 +164,8 @@ func (r *ReCAPTCHA) confirm(recaptcha reCHAPTCHARequest, options VerifyOption) (
Err = fmt.Errorf("received score '%f', while expecting minimum '%f'", result.Score, options.Treshold)
return
}
if options.Treshold == 0 && DEFAULT_TRESHOLD >= result.Score {
Err = fmt.Errorf("received score '%f', while expecting minimum '%f'", result.Score, DEFAULT_TRESHOLD)
if options.Treshold == 0 && DefaultTreshold >= result.Score {
Err = fmt.Errorf("received score '%f', while expecting minimum '%f'", result.Score, DefaultTreshold)
return
}
}
Expand Down
Loading

0 comments on commit 851b0b5

Please sign in to comment.