justcaptcha/pkg/captcha/captcha.go

78 lines
1.7 KiB
Go

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)
}