package captcha import ( "crypto/rand" "image" "math/big" "time" ) const ( maxAnswer = 999999 ) type Answer string // Captcha interface that should be implemented by captcha. type Captcha interface { // Image generates and returns an image of captcha. Image(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 } // BaseCaptcha 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 BaseCaptcha struct { Answer Answer Solved bool ExpireIn time.Time } func (c *BaseCaptcha) Image(style string) *image.Image { return nil } func (c *BaseCaptcha) Solve(answer Answer) bool { c.Solved = c.Answer == answer return c.Solved } func (c *BaseCaptcha) GetAnswer() Answer { if c.Answer == "" { c.Answer = generateAnswer() } return c.Answer } func (c *BaseCaptcha) IsSolved() bool { return c.Solved } func (c *BaseCaptcha) 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) }