all repos — captcha @ c179a205da7d0e66a572f0798b189398bf492658

Go package captcha implements generation and verification of image and audio CAPTCHAs.

captcha.go (view raw)

 1package captcha
 2
 3import (
 4	"bytes"
 5	"crypto/rand"
 6	"github.com/dchest/uniuri"
 7	"io"
 8	"os"
 9)
10
11// Standard number of digits in captcha.
12const StdLength = 6
13
14var globalStore = newStore()
15
16// randomDigits return a byte slice of the given length containing random
17// digits in range 0-9.
18func randomDigits(length int) []byte {
19	d := make([]byte, length)
20	if _, err := io.ReadFull(rand.Reader, d); err != nil {
21		panic(err)
22	}
23	for i := range d {
24		d[i] %= 10
25	}
26	return d
27}
28
29// New creates a new captcha of the given length, saves it in the internal
30// storage, and returns its id.
31func New(length int) (id string) {
32	id = uniuri.New()
33	globalStore.saveCaptcha(id, randomDigits(length))
34	return
35}
36
37// Reload generates and remembers new digits for the given captcha id.  This
38// function returns false if there is no captcha with the given id.
39//
40// After calling this function, the image or audio presented to a user must be
41// refreshed to show the new captcha representation (WriteImage and WriteAudio
42// will write the new one).
43func Reload(id string) bool {
44	old := globalStore.getDigits(id)
45	if old == nil {
46		return false
47	}
48	globalStore.saveCaptcha(id, randomDigits(len(old)))
49	return true
50}
51
52// WriteImage writes PNG-encoded image representation of the captcha with the
53// given id. The image will have the given width and height.
54func WriteImage(w io.Writer, id string, width, height int) os.Error {
55	d := globalStore.getDigits(id)
56	if d == nil {
57		return os.NewError("captcha id not found")
58	}
59	_, err := NewImage(d, width, height).WriteTo(w)
60	return err
61}
62
63// WriteAudio writes WAV-encoded audio representation of the captcha with the
64// given id.
65func WriteAudio(w io.Writer, id string) os.Error {
66	d := globalStore.getDigits(id)
67	if d == nil {
68		return os.NewError("captcha id not found")
69	}
70	_, err := NewAudio(d).WriteTo(w)
71	return err
72}
73
74// Verify returns true if the given digits are the ones that were used to
75// create the given captcha id.
76// 
77// The function deletes the captcha with the given id from the internal
78// storage, so that the same captcha can't be verified anymore.
79func Verify(id string, digits []byte) bool {
80	reald := globalStore.getDigitsClear(id)
81	if reald == nil {
82		return false
83	}
84	return bytes.Equal(digits, reald)
85}
86
87// Collect deletes expired and used captchas from the internal
88// storage. It is called automatically by New function every CollectNum
89// generated captchas, but still exported to enable freeing memory manually if
90// needed.
91//
92// Collection is launched in a new goroutine, so this function returns
93// immediately.
94func Collect() {
95	go globalStore.collect()
96}