Remove dependency on uniuri. Add random.go. Captcha ids are now 20 characters long.
Dmitry Chestnykh dmitry@codingrobots.com
Thu, 28 Apr 2011 23:12:29 +0200
8 files changed,
74 insertions(+),
49 deletions(-)
M
README.md
→
README.md
@@ -109,8 +109,9 @@ ### func RandomDigits
func RandomDigits(length int) []byte -RandomDigits returns a byte slice of the given length containing random -digits in range 0-9. +RandomDigits returns a byte slice of the given length containing pseudorandom +numbers in range 0-9. The slice can be used as a captcha solution. + ### func Reload
M
audio.go
→
audio.go
@@ -2,7 +2,6 @@ package captcha
import ( "bytes" - crand "crypto/rand" "encoding/binary" "math" "os"@@ -154,11 +153,6 @@ }
return b } -// rndf returns a random float64 number in range [from, to]. -func rndf(from, to float64) float64 { - return (to-from)*rand.Float64() + from -} - func randomSpeed(a []byte) []byte { pitch := rndf(0.9, 1.2) return changeSpeed(a, pitch)@@ -173,10 +167,7 @@ return b
} func makeWhiteNoise(length int, level uint8) []byte { - noise := make([]byte, length) - if _, err := io.ReadFull(crand.Reader, noise); err != nil { - panic("error reading from random source: " + err.String()) - } + noise := randomBytes(length) adj := 128 - level/2 for i, v := range noise { v %= level
M
captcha.go
→
captcha.go
@@ -43,8 +43,6 @@ package captcha
import ( "bytes" - "crypto/rand" - "github.com/dchest/uniuri" "io" "os" )@@ -57,13 +55,13 @@ // by default store.
CollectNum = 100 // Expiration time of captchas used by default store. Expiration = 10 * 60 // 10 minutes - ) -var ErrNotFound = os.NewError("captcha with the given id not found") - -// globalStore is a shared storage for captchas, generated by New function. -var globalStore = NewMemoryStore(CollectNum, Expiration) +var ( + ErrNotFound = os.NewError("captcha with the given id not found") + // globalStore is a shared storage for captchas, generated by New function. + globalStore = NewMemoryStore(CollectNum, Expiration) +) // SetCustomStore sets custom storage for captchas, replacing the default // memory store. This function must be called before generating any captchas.@@ -71,19 +69,6 @@ func SetCustomStore(s Store) {
globalStore = s } -// RandomDigits returns a byte slice of the given length containing random -// digits in range 0-9. -func RandomDigits(length int) []byte { - d := make([]byte, length) - if _, err := io.ReadFull(rand.Reader, d); err != nil { - panic("error reading random source: " + err.String()) - } - for i := range d { - d[i] %= 10 - } - return d -} - // New creates a new captcha with the standard length, saves it in the internal // storage and returns its id. func New() string {@@ -93,7 +78,7 @@
// NewLen is just like New, but accepts length of a captcha solution as the // argument. func NewLen(length int) (id string) { - id = uniuri.New() + id = randomId() globalStore.Set(id, RandomDigits(length)) return }
M
image.go
→
image.go
@@ -7,7 +7,6 @@ "io"
"math" "os" "rand" - "time" ) const (@@ -25,10 +24,6 @@ *image.Paletted
numWidth int numHeight int dotSize int -} - -func init() { - rand.Seed(time.Seconds()) } func randomPalette() image.PalettedColorModel {@@ -261,8 +256,3 @@ o = z
} return } - -// rnd returns a random number in range [from, to]. -func rnd(from, to int) int { - return rand.Intn(to+1-from) + from -}
A
random.go
@@ -0,0 +1,58 @@
+package captcha + +import ( + crand "crypto/rand" + "io" + "rand" + "time" +) + +// idLen is a length of captcha id string. +const idLen = 20 + +// idChars are characters allowed in captcha id. +var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") + +func init() { + rand.Seed(time.Seconds()) +} + +// RandomDigits returns a byte slice of the given length containing +// pseudorandom numbers in range 0-9. The slice can be used as a captcha +// solution. +func RandomDigits(length int) (b []byte) { + b = randomBytes(length) + for i := range b { + b[i] %= 10 + } + return +} + +// randomBytes returns a byte slice of the given length read from CSPRNG. +func randomBytes(length int) (b []byte) { + b = make([]byte, length) + if _, err := io.ReadFull(crand.Reader, b); err != nil { + panic("error reading random source: " + err.String()) + } + return +} + +// randomId returns a new random id string. +func randomId() string { + b := randomBytes(idLen) + alen := byte(len(idChars)) + for i, c := range b { + b[i] = idChars[c%alen] + } + return string(b) +} + +// rnd returns a non-crypto pseudorandom int in range [from, to]. +func rnd(from, to int) int { + return rand.Intn(to+1-from) + from +} + +// rndf returns a non-crypto pseudorandom float64 in range [from, to]. +func rndf(from, to float64) float64 { + return (to-from)*rand.Float64() + from +}
M
server.go
→
server.go
@@ -18,13 +18,13 @@ // arguments. The server decides which captcha to serve based on the last URL
// path component: file name part must contain a captcha id, file extension — // its format (PNG or WAV). // -// For example, for file name "B9QTvDV1RXbVJ3Ac.png" it serves an image captcha -// with id "B9QTvDV1RXbVJ3Ac", and for "B9QTvDV1RXbVJ3Ac.wav" it serves the +// For example, for file name "LBm5vMjHDtdUfaWYXiQX.png" it serves an image captcha +// with id "LBm5vMjHDtdUfaWYXiQX", and for "LBm5vMjHDtdUfaWYXiQX.wav" it serves the // same captcha in audio format. // // To serve a captcha as a downloadable file, the URL must be constructed in // such a way as if the file to serve is in the "download" subdirectory: -// "/download/B9QTvDV1RXbVJ3Ac.wav". +// "/download/LBm5vMjHDtdUfaWYXiQX.wav". // // To reload captcha (get a different solution for the same captcha id), append // "?reload=x" to URL, where x may be anything (for example, current time or a
M
store_test.go
→
store_test.go
@@ -2,7 +2,6 @@ package captcha
import ( "bytes" - "github.com/dchest/uniuri" "testing" )@@ -40,7 +39,7 @@ // create 10 ids
ids := make([]string, 10) d := RandomDigits(10) for i := range ids { - ids[i] = uniuri.New() + ids[i] = randomId() s.Set(ids[i], d) } s.(*memoryStore).collect()@@ -65,7 +64,7 @@ d := RandomDigits(10)
s := NewMemoryStore(9999, -1) ids := make([]string, 1000) for i := range ids { - ids[i] = uniuri.New() + ids[i] = randomId() } b.StartTimer() for i := 0; i < b.N; i++ {