sipd-auth/controller/captcha.go
2025-09-16 08:32:11 +07:00

144 lines
3.8 KiB
Go

package controller
import (
"bytes"
"encoding/base64"
models "kemendagri/sipd/services/sipd_auth/model"
"kemendagri/sipd/services/sipd_auth/utils"
"kemendagri/sipd/services/sipd_auth/utils/captcha_store"
"log"
"net/http"
"time"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
"github.com/dchest/captcha"
)
type CaptchaController struct {
captchaStore *captcha_store.PostgreSQLStore
contextTimeout time.Duration
validate *validator.Validate
}
// https://www.machinet.net/tutorial-eng/implement-go-based-captcha-generator-validator
func NewCaptchaController(store *captcha_store.PostgreSQLStore, timeout time.Duration, vld *validator.Validate) *CaptchaController {
return &CaptchaController{
captchaStore: store,
contextTimeout: timeout,
validate: vld,
}
}
func (c *CaptchaController) New() (string, string, string, error) {
var err error
var captchaId, captchaBase64, audioBase64 string
captcha.SetCustomStore(c.captchaStore)
captchaId = uuid.New().String()
//captchaId = captcha.New()
c.captchaStore.Set(captchaId, captcha.RandomDigits(captcha.DefaultLen))
//c.captchaStore.Set(captchaId, captcha.RandomDigits(captcha.DefaultLen))
//c.captchaStore.Set(captchaId, []byte("123456"))
var captchaImage bytes.Buffer
err = captcha.WriteImage(&captchaImage, captchaId, captcha.StdWidth, captcha.StdHeight)
if err != nil {
err = utils.RequestError{
Code: http.StatusInternalServerError,
Message: "failed to generate image. - " + err.Error(),
}
return captchaId, captchaBase64, audioBase64, err
}
captchaBase64 = base64.StdEncoding.EncodeToString(captchaImage.Bytes())
var captchaAudio bytes.Buffer
err = captcha.WriteAudio(&captchaAudio, captchaId, "id")
if err != nil {
err = utils.RequestError{
Code: http.StatusInternalServerError,
Message: "failed to generate audio. - " + err.Error(),
}
return captchaId, captchaBase64, audioBase64, err
}
// Encode the audio to Base64
audioBase64 = base64.StdEncoding.EncodeToString(captchaAudio.Bytes())
/*log.Println("captchaId: ", captchaId)
log.Println("captchaBase64: ", captchaBase64)*/
return captchaId, captchaBase64, audioBase64, err
}
func (c *CaptchaController) Reload(captchaId string) (string, string, error) {
var err error
var captchaBase64, audioBase64 string
captcha.SetCustomStore(c.captchaStore)
if !captcha.Reload(captchaId) {
err = utils.RequestError{
Code: http.StatusBadRequest,
Message: "captcha reload failed, invalid captcha ID.",
}
return captchaBase64, audioBase64, err
}
var captchaImage bytes.Buffer
err = captcha.WriteImage(&captchaImage, captchaId, captcha.StdWidth, captcha.StdHeight)
if err != nil {
err = utils.RequestError{
Code: http.StatusInternalServerError,
Message: "failed to reload captcha. - " + err.Error(),
}
return captchaBase64, audioBase64, err
}
captchaBase64 = base64.StdEncoding.EncodeToString(captchaImage.Bytes())
var captchaAudio bytes.Buffer
err = captcha.WriteAudio(&captchaAudio, captchaId, "id")
if err != nil {
err = utils.RequestError{
Code: http.StatusInternalServerError,
Message: "failed to generate audio. - " + err.Error(),
}
return captchaBase64, audioBase64, err
}
// Encode the audio to Base64
audioBase64 = base64.StdEncoding.EncodeToString(captchaAudio.Bytes())
/*log.Println("captchaId: ", captchaId)
log.Println("captchaBase64: ", captchaBase64)*/
return captchaBase64, audioBase64, nil
}
func (c *CaptchaController) Validate(pl models.ValidateCaptcha) error {
var err error
err = c.validate.Struct(pl)
if err != nil {
return err
}
captcha.SetCustomStore(c.captchaStore)
log.Printf("%+v\n", pl)
if !captcha.VerifyString(pl.Id, pl.Solution) {
err = utils.RequestError{
Code: http.StatusUnprocessableEntity,
Message: "invalid captcha",
}
return err
}
return err
}