package captcha import ( "crypto/rand" "errors" "image" "math/big" "time" ) const ( maxAnswer = 999999 ) var errorNotFound = errors.New("captcha not found") type Answer string // ICaptcha interface that should be implemented by captcha. type ICaptcha interface { // generateImage is used to create a captcha image. generateImage(style string) *image.Image // GetImage() returns an image of captcha. Calls // generateImage() method if image doesn't exist. GetImage(style string) *image.Image // GetAnswer returns a pregenerated answer. GetAnswer() Answer // Solve compares a stored answer with a passed one. // Sets field Solved to true if they are equal. Solve(answer Answer) bool // IsSolved returns field IsSolved. IsSolved() bool // Expiry returns a date after what captcha will expire. Expiry() time.Time } // Captcha is a base implementation of a CAPTCHA. // // All derivatives that embed this struct only need to // implement GetImage() and generateImage() methods. // And GetImage() could simply be copied. // // You need to do that because in Go there is no inheritance, // and if you won't do that, calling a base GetImage // method will call an empty base generateImage() method. type Captcha struct { Image image.Image Answer Answer Solved bool ExpireIn time.Time } func (c *Captcha) generateImage(style string) *image.Image { return nil } func (c *Captcha) GetImage(style string) *image.Image { if c.Image == nil { return c.generateImage(style) } return &c.Image } func (c *Captcha) Solve(answer Answer) bool { c.Solved = c.Answer == answer return c.Solved } func (c *Captcha) GetAnswer() Answer { if c.Answer == "" { c.Answer = generateAnswer() } return c.Answer } func (c *Captcha) IsSolved() bool { return c.Solved } func (c *Captcha) Expiry() time.Time { return c.ExpireIn } func generateAnswer() Answer { ans, _ := rand.Int(rand.Reader, big.NewInt(maxAnswer)) return (Answer(ans.String())) } func ExpiryDate(expiry time.Duration) time.Time { return time.Now().Add(expiry) }