2022-06-24 23:09:46 +04:00
|
|
|
package captcha
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/rand"
|
|
|
|
"image"
|
|
|
|
"math/big"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2022-08-17 21:46:10 +04:00
|
|
|
maxIntAnswer = 999999
|
2022-06-24 23:09:46 +04:00
|
|
|
)
|
|
|
|
|
|
|
|
type Answer string
|
|
|
|
|
2022-08-17 21:46:10 +04:00
|
|
|
func NewIntAnswer() Answer {
|
|
|
|
ans, _ := rand.Int(rand.Reader, big.NewInt(maxIntAnswer))
|
|
|
|
return (Answer(ans.String()))
|
|
|
|
}
|
|
|
|
|
2022-08-29 00:02:58 +04:00
|
|
|
// Captcha interface that should be implemented by a CAPTCHA.
|
2022-07-30 15:37:05 +04:00
|
|
|
type Captcha interface {
|
2022-08-29 00:02:58 +04:00
|
|
|
// Image generates and returns a pointer to an image of CAPTCHA.
|
2022-08-17 21:47:27 +04:00
|
|
|
Image(style string) *image.Image
|
2022-08-29 00:02:58 +04:00
|
|
|
// Answer returns a pregenerated answer.
|
2022-08-19 02:24:00 +04:00
|
|
|
Answer() Answer
|
2022-06-27 00:43:12 +04:00
|
|
|
// Solve compares a stored answer with a passed one.
|
2022-06-24 23:09:46 +04:00
|
|
|
Solve(answer Answer) bool
|
2022-08-29 00:02:58 +04:00
|
|
|
// IsSolved returns if a CAPTCHA is solved or not.
|
2022-06-24 23:09:46 +04:00
|
|
|
IsSolved() bool
|
2022-08-29 00:02:58 +04:00
|
|
|
// Expiry returns a date after what CAPTCHA will expire.
|
2022-06-26 20:47:25 +04:00
|
|
|
Expiry() time.Time
|
2022-06-24 23:09:46 +04:00
|
|
|
}
|
|
|
|
|
2022-07-30 15:37:05 +04:00
|
|
|
// BaseCaptcha is a base implementation of a CAPTCHA.
|
2022-06-27 00:43:12 +04:00
|
|
|
//
|
2022-08-29 00:02:58 +04:00
|
|
|
// All derivatives that embed this struct only need to implement
|
|
|
|
// an Image() method.
|
2022-07-30 15:37:05 +04:00
|
|
|
type BaseCaptcha struct {
|
2022-08-19 02:21:57 +04:00
|
|
|
answer Answer
|
|
|
|
solved bool
|
|
|
|
expireIn time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewBaseCaptcha(expiry time.Duration) *BaseCaptcha {
|
|
|
|
return &BaseCaptcha{
|
|
|
|
expireIn: ExpiryDate(expiry),
|
|
|
|
}
|
2022-06-24 23:09:46 +04:00
|
|
|
}
|
|
|
|
|
2022-07-30 15:37:05 +04:00
|
|
|
func (c *BaseCaptcha) Image(style string) *image.Image {
|
2022-06-26 23:53:52 +04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-08-29 00:02:58 +04:00
|
|
|
// Answer generates an integer answer for a CAPTCHA or just returns
|
|
|
|
// an existing one.
|
2022-08-19 02:24:00 +04:00
|
|
|
func (c *BaseCaptcha) Answer() Answer {
|
2022-08-19 02:21:57 +04:00
|
|
|
if c.answer == "" {
|
|
|
|
c.answer = NewIntAnswer()
|
2022-06-27 00:44:11 +04:00
|
|
|
}
|
2022-08-19 02:21:57 +04:00
|
|
|
return c.answer
|
2022-06-26 22:02:38 +04:00
|
|
|
}
|
|
|
|
|
2022-08-29 00:02:58 +04:00
|
|
|
// Solve sets solved field to true if given answer is right and returns a result
|
|
|
|
// of a check.
|
2022-08-19 02:11:06 +04:00
|
|
|
func (c *BaseCaptcha) Solve(answer Answer) bool {
|
2022-08-19 02:21:57 +04:00
|
|
|
c.solved = c.answer == answer
|
|
|
|
return c.solved
|
2022-08-19 02:11:06 +04:00
|
|
|
}
|
|
|
|
|
2022-07-30 15:37:05 +04:00
|
|
|
func (c *BaseCaptcha) IsSolved() bool {
|
2022-08-19 02:21:57 +04:00
|
|
|
return c.solved
|
2022-06-26 22:02:38 +04:00
|
|
|
}
|
|
|
|
|
2022-07-30 15:37:05 +04:00
|
|
|
func (c *BaseCaptcha) Expiry() time.Time {
|
2022-08-19 02:21:57 +04:00
|
|
|
return c.expireIn
|
2022-06-26 22:02:38 +04:00
|
|
|
}
|
|
|
|
|
2022-08-29 00:02:58 +04:00
|
|
|
// ExpiryDate returns a date when CAPTCHA expires. It adds a passed
|
|
|
|
// expiry duration to a current time.
|
2022-06-26 20:47:25 +04:00
|
|
|
func ExpiryDate(expiry time.Duration) time.Time {
|
|
|
|
return time.Now().Add(expiry)
|
2022-06-24 23:09:46 +04:00
|
|
|
}
|