| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- // Copyright 2011 Dmitry Chestnykh. All rights reserved.
- // Use of this source code is governed by a MIT-style
- // license that can be found in the LICENSE file.
- package captcha
- import (
- crand "crypto/rand"
- "io"
- "math/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.Now().UnixNano())
- }
- // 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) []byte {
- return randomBytesMod(length, 10)
- }
- // 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("captcha: error reading random source: " + err.Error())
- }
- return
- }
- // randomBytesMod returns a byte slice of the given length, where each byte is
- // a random number modulo mod.
- func randomBytesMod(length int, mod byte) (b []byte) {
- b = make([]byte, length)
- maxrb := byte(256 - (256 % int(mod)))
- i := 0
- for {
- r := randomBytes(length + (length / 4))
- for _, c := range r {
- if c >= maxrb {
- // Skip this number to avoid modulo bias.
- continue
- }
- b[i] = c % mod
- i++
- if i == length {
- return
- }
- }
- }
- panic("unreachable")
- }
- // randomId returns a new random id string.
- func randomId() string {
- b := randomBytesMod(idLen, byte(len(idChars)))
- for i, c := range b {
- b[i] = idChars[c]
- }
- 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
- }
|