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 }