package captcha import ( "crypto/rand" "crypto/sha256" "encoding/base64" "errors" "image" "strconv" "time" ) var ErrorNotFound = errors.New("captcha not found") const DefaultExpiredScanInterval = 60 * time.Second // ID is a CAPTCHA identifier. type ID string // NewID generates an ID as a sha256 hash of additionalData (usually IP-address), // current time, answer and more, it adds a set of random bytes and encodes all // of it with base64 in raw URL variant. func NewID(additionalData string, answer Answer) ID { idHash := sha256.New() idHash.Write([]byte(additionalData)) idHash.Write([]byte(strconv.FormatInt(time.Now().UnixMicro(), 16))) idHash.Write([]byte(answer)) randData := make([]byte, 32) rand.Read(randData) idHash.Write(randData) return ID(base64.RawURLEncoding.EncodeToString(idHash.Sum(nil))) } // CaptchaDB interface with all necessary methods. type CaptchaDB interface { New(data string, captcha Captcha) (Captcha, ID) GetExpiry() time.Duration SetExpiry(expiry time.Duration) Image(id ID, style string) (*image.Image, error) Solve(id ID, answer Answer) (bool, error) IsSolved(id ID) (bool, error) Remove(id ID) error }