From 9c6ce5297ec0014a80160c368cde390174b3cc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=BCller?= Date: Thu, 21 Sep 2017 22:59:23 +0200 Subject: [PATCH] recaptcha implemented --- Makefile | 2 +- assets/public/style.css | 4 ++++ assets/templates/form.html | 19 ++++++++++++------- render.go | 1 + server.go | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index bc1266f..81164a9 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ run: - go run *.go + SKIP_CAPTCHA=1 go run *.go test: jasmine-node . diff --git a/assets/public/style.css b/assets/public/style.css index 701e1d9..1fc9bed 100644 --- a/assets/public/style.css +++ b/assets/public/style.css @@ -264,3 +264,7 @@ form { flex: 1 0; flex-direction: column; } + +#captcha { + display: none; +} diff --git a/assets/templates/form.html b/assets/templates/form.html index a44de7d..90efeef 100644 --- a/assets/templates/form.html +++ b/assets/templates/form.html @@ -3,22 +3,24 @@ NoteHub — {{if .ID}}Edit{{else}}Add{{end}} note - - + + - + +
- + - +
+
diff --git a/render.go b/render.go index 0ca3ccd..3b34410 100644 --- a/render.go +++ b/render.go @@ -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", diff --git a/server.go b/server.go index e2d0ccb..90b7151 100644 --- a/server.go +++ b/server.go @@ -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() { } defer db.Close() + skipCaptcha := os.Getenv("SKIP_CAPTCHA") != "" + var ads []byte adsFName := os.Getenv("ADS") if adsFName != "" { @@ -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 { 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 + +}