Browse Source

recaptcha implemented

master
Christian Müller 8 years ago
parent
commit
9c6ce5297e
  1. 2
      Makefile
  2. 4
      assets/public/style.css
  3. 19
      assets/templates/form.html
  4. 1
      render.go
  5. 37
      server.go

2
Makefile

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
run:
go run *.go
SKIP_CAPTCHA=1 go run *.go
test:
jasmine-node .

4
assets/public/style.css

@ -264,3 +264,7 @@ form { @@ -264,3 +264,7 @@ form {
flex: 1 0;
flex-direction: column;
}
#captcha {
display: none;
}

19
assets/templates/form.html

@ -3,22 +3,24 @@ @@ -3,22 +3,24 @@
<html>
<head>
<title>NoteHub &mdash; {{if .ID}}Edit{{else}}Add{{end}} note</title>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta charset="UTF-8" />
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
<link href="/style.css" rel="stylesheet" type="text/css" />
<base target="_blank">
<base target="_blank" />
<script src='https://www.google.com/recaptcha/api.js'></script>
</head>
<body>
<form action="/note" autocomplete="off" method="POST" target="_self">
<textarea autofocus name="text">{{.Text}}</textarea>
<fieldset>
<input id="id" name="id" value="{{.ID}}" type="hidden" />
<input class="ui-elem" id="password" name="password" placeholder="Password for editing" type="text" autocomplete="off">
<input class="ui-elem" name="password" placeholder="Password for editing" type="text" autocomplete="off" />
<label style="margin-right: 1em">
<input id="tos" name="tos" type="checkbox" onClick="toggleButton()">
<input id="tos" name="tos" type="checkbox" onClick="toggleButton()" />
Accept <a href="/TOS.md">Terms of Service</a>
</label>
<input class="button ui-elem" disabled id="publish-button" name="button" type="submit" value="Publish">
<div id="captcha" class="g-recaptcha" data-sitekey="6LemnDEUAAAAAC6A4VNRefz0BSLiC343W4sXQd6I"></div>
<input class="button ui-elem" disabled id="publish-button" name="button" type="submit" value="Publish" />
</fieldset>
</form>
<footer>
@ -28,7 +30,10 @@ @@ -28,7 +30,10 @@
</footer>
<script>
function $(id) { return document.getElementById(id) }
function toggleButton() { $('publish-button').disabled = !$('tos').checked }
function toggleButton() {
$('publish-button').disabled = !$('tos').checked;
$('captcha').style.display = $('tos').checked ? 'block' : 'none';
}
</script>
</body>
</html>

1
render.go

@ -17,6 +17,7 @@ var ( @@ -17,6 +17,7 @@ var (
statuses = map[int]string{
400: "Bad request",
401: "Unauthorized",
403: "Forbidden",
404: "Not found",
412: "Precondition failed",
429: "Too many requests",

37
server.go

@ -2,11 +2,13 @@ package main @@ -2,11 +2,13 @@ package main
import (
"bytes"
"encoding/json"
"html/template"
"io"
"io/ioutil"
"math"
"net/http"
"net/url"
"os"
"time"
@ -36,6 +38,8 @@ func main() { @@ -36,6 +38,8 @@ func main() {
}
defer db.Close()
skipCaptcha := os.Getenv("SKIP_CAPTCHA") != ""
var ads []byte
adsFName := os.Getenv("ADS")
if adsFName != "" {
@ -102,6 +106,11 @@ func main() { @@ -102,6 +106,11 @@ func main() {
e.POST("/note", func(c echo.Context) error {
c.Logger().Debug("POST /note requested")
if !skipCaptcha && !checkRecaptcha(c, c.FormValue("g-recaptcha-response")) {
c.Logger().Warnf("captcha validation failed for %s", c.Request().RemoteAddr)
code := http.StatusForbidden
return c.Render(code, "Note", responsePage(code))
}
if !legitAccess(c) {
code := http.StatusTooManyRequests
c.Logger().Errorf("rate limit exceeded for %s", c.Request().RemoteAddr)
@ -169,3 +178,31 @@ func fraudelent(n *Note) bool { @@ -169,3 +178,31 @@ func fraudelent(n *Note) bool {
return n.Views > 100 &&
int(math.Ceil(100*float64(l1-l2)/float64(l1))) > fraudThreshold
}
func checkRecaptcha(c echo.Context, captchaResp string) bool {
resp, err := http.PostForm("https://www.google.com/recaptcha/api/siteverify", url.Values{
"secret": []string{os.Getenv("RECAPTCHA_SECRET")},
"response": []string{captchaResp},
"remoteip": []string{c.Request().RemoteAddr},
})
if err != nil {
c.Logger().Errorf("captcha response verification failed: %v", err)
return false
}
defer resp.Body.Close()
respJson := &struct {
Success bool `json:"success"`
ErrorCodes []string `json:"error-codes"`
}{}
s, err := ioutil.ReadAll(resp.Body)
err = json.Unmarshal(s, respJson)
if err != nil {
c.Logger().Errorf("captcha response parse recaptcha response: %v", err)
return false
}
if !respJson.Success {
c.Logger().Errorf("captcha response validation failed: %v", respJson.ErrorCodes)
}
return respJson.Success
}

Loading…
Cancel
Save