-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
200 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,69 @@ | ||
# friendly-captcha-go-sdk | ||
A Go client for the Friendly Captcha verification API | ||
A Go client for the Friendly Captcha verification API. | ||
|
||
## Installation | ||
``` | ||
go get github.com/friendlycaptcha/friendly-captcha-go-sdk | ||
``` | ||
|
||
## Usage | ||
|
||
```go | ||
import "github.com/friendlycaptcha/friendly-captcha-go-sdk" | ||
|
||
frcClient := friendlycaptcha.NewClient(apikey, sitekey) | ||
``` | ||
|
||
|
||
```go | ||
// In your middleware or request handler | ||
solution := r.FormValue(friendlycaptcha.SolutionFormFieldName) | ||
shouldAccept, err := frcClient.CheckCaptchaSolution(r.Context(), solution) | ||
|
||
if err != nil { | ||
if errors.Is(err, friendlycaptcha.ErrVerificationFailedDueToClientError) { | ||
log.Printf("!!!!!\n\nFriendlyCaptcha is misconfigured! Check your Friendly Captcha API key and sitekey: %v\n", err) | ||
// Send yourself an alert - the captcha won't be able to do its job to prevent spam. | ||
} else if (errors.Is(err, friendlycaptcha.ErrVerificationRequest)) { | ||
log.Printf("Could not talk to the Friendly Captcha API: %v\n", err) | ||
// Perhaps the Friendly Captcha API is down? | ||
} | ||
} | ||
|
||
if !shouldAccept { // The captcha was invalid | ||
// Show the user a message that the anti-robot verification failed and that they should try again | ||
return | ||
} | ||
|
||
// The captcha check was succesful, handle the request :) | ||
``` | ||
|
||
Beware that the `CheckCaptchaSolution` function returns two values: | ||
* Whether you should accept the request (`bool`) | ||
* An error (or nil) | ||
|
||
Even if the error is non-nil, the first boolean value may still be true and you should accept the request! | ||
### Advanced, optional strictness setting | ||
As a best practice we accept the captcha solution if we are unable to verify it: if we misconfigure our apikey or Friendly Captcha's API goes down we would rather accept all requests than lock all users out. | ||
|
||
If you want to change this behavior you can set `client.Strict` to true, then the accept value will only be true if we were actually able to verify the captcha solution and it was valid. | ||
|
||
|
||
## Example | ||
|
||
Run the example | ||
```shell | ||
cd examples/form | ||
FRC_SITEKEY=<my sitekey> FRC_APIKEY=<my api key> go run main.go | ||
``` | ||
|
||
Then open your browser and head to [http://localhost:8844](http://localhost:8844) | ||
|
||
> Note: you can create a sitekey and API key in the [Friendly Captcha dashboard](https://app.friendlycaptcha.com/account). | ||
**Example Screenshot** | ||
|
||
![Example screenshot](https://i.imgur.com/bsp7qDA.png) | ||
|
||
## License | ||
[MIT](./LICENSE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | ||
<title>Friendly Captcha Go SDK example</title> | ||
|
||
<script type="module" src="https://cdn.jsdelivr.net/npm/[email protected]/widget.module.min.js" async defer></script> | ||
<script nomodule src="https://cdn.jsdelivr.net/npm/[email protected]/widget.min.js" async defer></script> | ||
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]" /> | ||
|
||
</head> | ||
<body> | ||
<main> | ||
{{if .Submitted}} | ||
<h1>Thanks for your message!</h1> | ||
|
||
{{else}} | ||
<h1>Friendly Captcha Go SDK form</h1> | ||
{{if .Message}} | ||
<p style="color:#ba1f1f">{{.Message}}</p> | ||
{{end}} | ||
<form method="POST"> | ||
<div class="form-group"> | ||
<label>Subject:</label><br /> | ||
<input type="text" name="subject"><br /> | ||
<label>Message:</label><br /> | ||
<textarea name="message"></textarea><br /> | ||
|
||
<div class="frc-captcha" data-sitekey="{{.Sitekey}}"></div> | ||
<input style="margin-top: 1em" type="submit" value="Submit"> | ||
</div> | ||
</form> | ||
{{end}} | ||
</main> | ||
|
||
<script> | ||
// A trick to prevent re-submission on reloading the page. | ||
if (window.history.replaceState) { | ||
window.history.replaceState( null, null, window.location.href ); | ||
} | ||
</script> | ||
</body> | ||
</html> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"html/template" | ||
"log" | ||
"net/http" | ||
"os" | ||
|
||
friendlycaptcha "github.com/friendlycaptcha/friendly-captcha-go" | ||
) | ||
|
||
type FormMessage struct { | ||
Subject string | ||
Message string | ||
} | ||
|
||
type TemplateData struct { | ||
Submitted bool | ||
Message string | ||
Sitekey string | ||
} | ||
|
||
func main() { | ||
sitekey := os.Getenv("FRC_SITEKEY") | ||
apikey := os.Getenv("FRC_APIKEY") | ||
|
||
if sitekey == "" || apikey == "" { | ||
log.Fatalf("Please set the FRC_SITEKEY and FRC_APIKEY environment values before running this example to your Friendly Captcha sitekey and apikey respectively.") | ||
} | ||
|
||
frcClient := friendlycaptcha.NewClient(apikey, sitekey) | ||
tmpl := template.Must(template.ParseFiles("form.html")) | ||
|
||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { | ||
// GET - the user is requesting the form, not submitting it. | ||
if r.Method != http.MethodPost { | ||
tmpl.Execute(w, TemplateData{Submitted: false, Message: "", Sitekey: sitekey}) | ||
return | ||
} | ||
|
||
formMessage := FormMessage{ | ||
Subject: r.FormValue("subject"), | ||
Message: r.FormValue("message"), | ||
} | ||
|
||
solution := r.FormValue(friendlycaptcha.SolutionFormFieldName) | ||
shouldAccept, err := frcClient.CheckCaptchaSolution(r.Context(), solution) | ||
|
||
if err != nil { | ||
// Note that there can be errors but we still want to accept the form. | ||
// The reason is that if Friendly Captcha's API ever goes down, we would rather accept | ||
// also spammy messages than lock everybody out. | ||
|
||
if errors.Is(err, friendlycaptcha.ErrVerificationFailedDueToClientError) { | ||
log.Printf("!!!!!\nFriendlyCaptcha is misconfigured! Check your Friendly Captcha API key and sitekey: %s\n", err.Error()) | ||
// Send yourself an alert - the captcha won't be able to do its job to prevent spam. | ||
} else if (errors.Is(err, friendlycaptcha.ErrVerificationRequest)) { | ||
log.Printf("Could not talk to the Friendly Captcha API: %s\n", err.Error()) | ||
// Maybe also alert yourself, maybe the Friendly Captcha API is down? | ||
} | ||
} | ||
|
||
if !shouldAccept { // The captcha was invalid | ||
tmpl.Execute(w, TemplateData{Submitted: false, Message: "Anti-robot verification failed, please try again.", Sitekey: sitekey}) | ||
return | ||
} | ||
|
||
// do something with the data in the form | ||
_ = formMessage | ||
|
||
tmpl.Execute(w, TemplateData{Submitted: true, Message: "", Sitekey: sitekey}) | ||
}) | ||
log.Printf("Starting server on localhost port 8844 (http://localhost:8844)") | ||
|
||
http.ListenAndServe(":8844", nil) | ||
} |