Files
godoxy-yusing/internal/net/gphttp/middleware/captcha/middleware.go

64 lines
1.5 KiB
Go

package captcha
import (
"net/http"
"text/template"
"github.com/rs/zerolog/log"
"github.com/yusing/godoxy/internal/auth"
httputils "github.com/yusing/goutils/http"
_ "embed"
)
const cookieName = "godoxy_captcha_session"
//go:embed captcha.html
var captchaPageHTML string
var captchaPage = template.Must(template.New("captcha").Parse(captchaPageHTML))
func PreRequest(p Provider, w http.ResponseWriter, r *http.Request) (proceed bool) {
// check session
sessionID, err := r.Cookie(cookieName)
if err == nil {
session, ok := CaptchaSessions.Load(sessionID.Value)
if ok {
if session.expired() {
CaptchaSessions.Delete(sessionID.Value)
} else {
return true
}
}
}
if !httputils.GetAccept(r.Header).AcceptHTML() {
http.Error(w, "Captcha is required", http.StatusForbidden)
return false
}
if r.Method == http.MethodPost {
err := p.Verify(r)
if err == nil {
session := newCaptchaSession(p)
CaptchaSessions.Store(session.ID, session)
auth.SetTokenCookie(w, r, cookieName, session.ID, p.SessionExpiry())
http.Redirect(w, r, r.URL.Path, http.StatusFound)
return false
}
log.Warn().Err(err).Str("url", r.URL.String()).Str("remote_addr", r.RemoteAddr).Msg("failed to verify captcha")
http.Error(w, "Failed to verify captcha", http.StatusUnauthorized)
return false
}
// captcha challenge
err = captchaPage.Execute(w, map[string]any{
"ScriptHTML": p.ScriptHTML(),
"FormHTML": p.FormHTML(),
})
if err != nil {
log.Error().Err(err).Msg("failed to execute captcha page")
}
return false
}