Last active
January 27, 2025 09:58
-
-
Save ribtoks/1c0c0f70c89cdda7de656df01d5d19c8 to your computer and use it in GitHub Desktop.
Private Captcha Local e2e tutorial
This file contains hidden or 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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<title>Private Captcha Example</title> | |
<style> | |
body { | |
display:flex; | |
flex-direction: column; | |
min-height: 100vh; | |
} | |
form { | |
max-width: 32rem; | |
margin: auto; | |
display: flex; | |
flex-direction: column; | |
gap: 20px; | |
border: 1px #ccc solid; | |
padding: 20px; | |
} | |
</style> | |
<script defer src="https://cdn.privatecaptcha.com/widget/js/privatecaptcha.js"></script> | |
<script type="text/javascript"> | |
function onCaptchaSolved() { | |
const submitButton = document.querySelector('#formSubmit'); | |
submitButton.disabled = false; | |
} | |
</script> | |
</head> | |
<body> | |
<div style="display: flex; flex: 1 1 0%"> | |
<form action='/submit' method="POST"> | |
<label> Email: </label> | |
<input type="email" name="email" placeholder="Email address" required /> | |
<div class="private-captcha" data-sitekey="9f08508c99674b1daf5008b3c64403ed" | |
data-finished-callback="onCaptchaSolved"></div> | |
<button id="formSubmit" type="submit" disabled> Submit </button> | |
</form> | |
</div> | |
</body> | |
</html> |
This file contains hidden or 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
package main | |
import ( | |
"encoding/json" | |
"errors" | |
"fmt" | |
"io" | |
"log" | |
"net/http" | |
"strings" | |
) | |
func checkSolution(solution, apiKey string) error { | |
req, err := http.NewRequest("POST", "https://api.privatecaptcha.com/siteverify", strings.NewReader(solution)) | |
if err != nil { | |
return err | |
} | |
req.Header.Set("X-Api-Key", apiKey) | |
resp, err := http.DefaultClient.Do(req) | |
if err != nil { | |
return err | |
} | |
defer resp.Body.Close() | |
response := struct { | |
Success bool `json:"success"` | |
// NOTE: other fields omitted for brevity | |
}{} | |
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { | |
return err | |
} | |
if !response.Success { | |
return errors.New("solution is not correct") | |
} | |
return nil | |
} | |
func main() { | |
const page = `<!DOCTYPE html><html><body style="background-color: %s;"></body></html>` | |
http.HandleFunc("POST /submit", func(w http.ResponseWriter, r *http.Request) { | |
captchaSolution := r.FormValue("private-captcha-solution") | |
if err := checkSolution(captchaSolution, "pc_1c582dd06cde41b48e86f5cac278abb8"); err != nil { | |
fmt.Fprintf(w, page, "red") | |
return | |
} | |
fmt.Fprintf(w, page, "green") | |
}) | |
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { | |
if r.URL.Path == "/" { | |
http.ServeFile(w, r, "index.html") | |
return | |
} | |
// Return 404 for any other paths | |
http.NotFound(w, r) | |
}) | |
if err := http.ListenAndServe(":8081", nil); err != nil { | |
log.Fatal(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment