81 lines
1.7 KiB
Go
81 lines
1.7 KiB
Go
package captcha
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"image"
|
|
"math/big"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
maxIntAnswer = 999999
|
|
)
|
|
|
|
type Answer string
|
|
|
|
func NewIntAnswer() Answer {
|
|
ans, _ := rand.Int(rand.Reader, big.NewInt(maxIntAnswer))
|
|
return (Answer(ans.String()))
|
|
}
|
|
|
|
// Captcha interface that should be implemented by a CAPTCHA.
|
|
type Captcha interface {
|
|
// Image generates an image of a CAPTCHA according to a passed style
|
|
// and returns a pointer to it.
|
|
Image(style string) *image.Image
|
|
// Answer returns a pregenerated answer.
|
|
Answer() Answer
|
|
// Solve compares a stored answer with a passed one.
|
|
Solve(answer Answer) bool
|
|
// IsSolved returns if a CAPTCHA is solved or not.
|
|
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
|
|
// an Image() method.
|
|
type BaseCaptcha struct {
|
|
answer Answer
|
|
solved bool
|
|
expiry time.Time
|
|
}
|
|
|
|
func NewBaseCaptcha(expiry time.Duration) *BaseCaptcha {
|
|
return &BaseCaptcha{
|
|
expiry: ExpiryDate(expiry),
|
|
}
|
|
}
|
|
|
|
func (c *BaseCaptcha) Image(style string) *image.Image {
|
|
return nil
|
|
}
|
|
|
|
func (c *BaseCaptcha) Answer() Answer {
|
|
if c.answer == "" {
|
|
c.answer = NewIntAnswer()
|
|
}
|
|
return c.answer
|
|
}
|
|
|
|
func (c *BaseCaptcha) Solve(answer Answer) bool {
|
|
c.solved = c.answer == answer
|
|
return c.solved
|
|
}
|
|
|
|
func (c *BaseCaptcha) IsSolved() bool {
|
|
return c.solved
|
|
}
|
|
|
|
func (c *BaseCaptcha) Expiry() time.Time {
|
|
return c.expiry
|
|
}
|
|
|
|
// ExpiryDate returns a date when CAPTCHA expires. It adds a passed
|
|
// expiry duration to a current time.
|
|
func ExpiryDate(expiry time.Duration) time.Time {
|
|
return time.Now().Add(expiry)
|
|
}
|