justcaptcha/internal/http/handlers.go

79 lines
2.0 KiB
Go

package http
import (
"fmt"
"image/jpeg"
"net/http"
"time"
"git.arav.top/Arav/justcaptcha/pkg/captcha"
"git.arav.top/Arav/justcaptcha/pkg/captcha/inmemdb"
"git.arav.top/Arav/justcaptcha/pkg/dwcaptcha"
)
const errMsgWrongAnswer = "An answer provided was wrong"
const errMsgImageNotFound = "cannot get an image for a non-existing CAPTCHA"
type CaptchaHandlers struct {
expiry time.Duration
}
func NewCaptchaHandlers(expiry time.Duration) *CaptchaHandlers {
inmemdb.SetExpiry(expiry)
return &CaptchaHandlers{expiry: expiry}
}
func (h *CaptchaHandlers) New(w http.ResponseWriter, r *http.Request) {
dc := dwcaptcha.NewDwellingCaptcha(h.expiry)
_, id := inmemdb.New(r.RemoteAddr, dc)
w.WriteHeader(http.StatusCreated)
fmt.Fprint(w, id)
}
func (h *CaptchaHandlers) Image(w http.ResponseWriter, r *http.Request) {
captchaID := captcha.ID(getURLParam(r, "captcha"))
captchaStyle := r.URL.Query().Get("style")
captchaImage := inmemdb.Image(captchaID, captchaStyle)
if captchaImage == nil {
http.Error(w, errMsgImageNotFound, http.StatusNotFound)
return
}
w.Header().Add("Content-Disposition", "inline; filename=\""+string(captchaID)+"\"")
jpeg.Encode(w, *captchaImage, &jpeg.Options{Quality: 20})
}
func (h *CaptchaHandlers) Solve(w http.ResponseWriter, r *http.Request) {
captchaID := captcha.ID(getURLParam(r, "captcha"))
r.ParseForm()
answer := captcha.Answer(r.FormValue("answer"))
if ok := inmemdb.Solve(captchaID, answer); !ok {
http.Error(w, errMsgWrongAnswer, http.StatusForbidden)
return
}
w.WriteHeader(http.StatusAccepted)
}
func (h *CaptchaHandlers) IsSolved(w http.ResponseWriter, r *http.Request) {
captchaID := captcha.ID(getURLParam(r, "captcha"))
isJustRemove := r.URL.Query().Has("remove")
if isJustRemove {
inmemdb.Remove(captchaID)
w.WriteHeader(http.StatusNoContent)
return
}
if solved := inmemdb.IsSolved(captchaID); !solved {
http.Error(w, errMsgWrongAnswer, http.StatusForbidden)
return
}
w.WriteHeader(http.StatusNoContent)
}