Skip to content

Commit

Permalink
First release
Browse files Browse the repository at this point in the history
  • Loading branch information
ezzarghili committed Dec 23, 2017
1 parent 8208ee4 commit db66e0b
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 1 deletion.
56 changes: 55 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,56 @@
# recaptcha-go
Google recaptcha implementation in golang

Google reCAPTCHA v2 form submittion in golang

## Usage

Install the package in your environment

```bash
go get github.com/ezzarghili/recaptcha-go
```

To use it within your own code

```go
import "github.com/ezzarghili/recaptcha-go"
func main(){
recaptcha.Init (recaptchaSecret) // get your secret from https://www.google.com/recaptcha/admin
}
```

Now everytime you need to verify a client request use

```go
success, err :=recaptcha.Verify(recaptchaResponse, ClientRemoteIP)
if err !=nil {
// do something with err (log?)
}
// proceed with success (true|false)
```

or

```go
recaptcha.VerifyNoRemoteIP(recaptchaResponse)
if err !=nil {
// do something with err (log?)
}
// proceed with success (true|false)
```

while `recaptchaResponse` is the form value with name `g-recaptcha-response` sent back by recaptcha server and set for in the form when user answers the challenge

Both `recaptcha.Verify` and `recaptcha.VerifyNoRemoteIP` return a `bool` and `error` values `(bool, error)`

Use the `error` to check for issues with the secret and connection in the server, and use the `bool` value to verify if the client answered the challenge correctly

### Issues with this library

If you have some problems with using this library, bug reports or enhancement please open an issue in the issues tracker.

### License

Let's go with somehting permitive should we ?

[MIT](https://choosealicense.com/licenses/mit/)
79 changes: 79 additions & 0 deletions recaptcha.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package recaptcha

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
)

var recaptchaSecret string

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

type reCHAPTCHRequest struct {
Secret string `json:"secret"`
Response string `json:"response"`
RemoteIP string `json:"remoteip,omitempty"`
}

type reCHAPTCHResponse struct {
Success bool `json:"success"`
ChallengeTS time.Time `json:"challenge_ts"`
Hostname string `json:"hostname"`
ErrorCodes []string `json:"error-codes,omitempty"`
}

// Init initialize with the reCAPTCHA secret optained from https://www.google.com/recaptcha/admin
func Init(ReCAPTCHASecret string) {
recaptchaSecret = ReCAPTCHASecret
}

// Verify returns true if the client answered the challenge correctly and have correct remoteIP
func Verify(challenResponse string, remoteIP string) (bool, error) {
body := reCHAPTCHRequest{Secret: recaptchaSecret, Response: challenResponse, RemoteIP: remoteIP}
return confirm(body)
}

// VerifyNoRemoteIP returns true if the client answered the challenge correctly
func VerifyNoRemoteIP(challenResponse string) (bool, error) {
body := reCHAPTCHRequest{Secret: recaptchaSecret, Response: challenResponse}
return confirm(body)
}

func confirm(recaptach reCHAPTCHRequest) (Ok bool, Err error) {
if recaptach.Secret == "" {
Err = fmt.Errorf("recaptcha secret has not been set, please set recaptcha.Init(secret) before calling verification functions")
return false, Err
}
// Go http client does not set a default timeout for request, so we need
// to set one for worse cases when the server hang, we need to make this available in the API
// to make it possible this library's users to change it, for now a 10s timeout seems resonable
netClient := &http.Client{
Timeout: 10 * time.Second,
}
jsonValue, _ := json.Marshal(recaptach)
response, err := netClient.Post(
reCAPTCHALink, "application/json",
bytes.NewBuffer(jsonValue),
)
if err != nil {
Err = fmt.Errorf("error posting to recaptcha endpoint: %s", err)
return false, Err
}
defer response.Body.Close()
resultBody, err := ioutil.ReadAll(response.Body)
if err != nil {
Err = fmt.Errorf("couldn't read response body: %s", err)
return false, Err
}
var result reCHAPTCHResponse
err = json.Unmarshal(resultBody, &result)
if err != nil {
Err = fmt.Errorf("invalid response body json: %s", err)
return false, Err
}
return result.Success, nil
}

0 comments on commit db66e0b

Please sign in to comment.