add readme for captcha, and enhanced performance
Showing
5 changed files
with
339 additions
and
17 deletions
utils/captcha/README.md
0 → 100644
| 1 | # Captcha | ||
| 2 | |||
| 3 | an example for use captcha | ||
| 4 | |||
| 5 | ``` | ||
| 6 | package controllers | ||
| 7 | |||
| 8 | import ( | ||
| 9 | "github.com/astaxie/beego" | ||
| 10 | "github.com/astaxie/beego/cache" | ||
| 11 | "github.com/astaxie/beego/utils/captcha" | ||
| 12 | ) | ||
| 13 | |||
| 14 | var cpt *captcha.Captcha | ||
| 15 | |||
| 16 | func init() { | ||
| 17 | // use beego cache system store the captcha data | ||
| 18 | store := cache.NewMemoryCache() | ||
| 19 | cpt = captcha.NewWithFilter("/captcha/", store) | ||
| 20 | } | ||
| 21 | |||
| 22 | type MainController struct { | ||
| 23 | beego.Controller | ||
| 24 | } | ||
| 25 | |||
| 26 | func (this *MainController) Get() { | ||
| 27 | this.TplNames = "index.tpl" | ||
| 28 | } | ||
| 29 | |||
| 30 | func (this *MainController) Post() { | ||
| 31 | this.TplNames = "index.tpl" | ||
| 32 | |||
| 33 | this.Data["Success"] = cpt.VerifyReq(this.Ctx.Request) | ||
| 34 | } | ||
| 35 | ``` | ||
| 36 | |||
| 37 | template usage | ||
| 38 | |||
| 39 | ``` | ||
| 40 | {{.Success}} | ||
| 41 | <form action="/" method="post"> | ||
| 42 | {{create_captcha}} | ||
| 43 | <input name="captcha" type="text"> | ||
| 44 | </form> | ||
| 45 | ``` |
| ... | @@ -12,6 +12,7 @@ | ... | @@ -12,6 +12,7 @@ |
| 12 | // var cpt *captcha.Captcha | 12 | // var cpt *captcha.Captcha |
| 13 | // | 13 | // |
| 14 | // func init() { | 14 | // func init() { |
| 15 | // // use beego cache system store the captcha data | ||
| 15 | // store := cache.NewMemoryCache() | 16 | // store := cache.NewMemoryCache() |
| 16 | // cpt = captcha.NewWithFilter("/captcha/", store) | 17 | // cpt = captcha.NewWithFilter("/captcha/", store) |
| 17 | // } | 18 | // } | ... | ... |
| ... | @@ -8,8 +8,6 @@ import ( | ... | @@ -8,8 +8,6 @@ import ( |
| 8 | "image/png" | 8 | "image/png" |
| 9 | "io" | 9 | "io" |
| 10 | "math" | 10 | "math" |
| 11 | "math/rand" | ||
| 12 | "time" | ||
| 13 | ) | 11 | ) |
| 14 | 12 | ||
| 15 | const ( | 13 | const ( |
| ... | @@ -236,26 +234,21 @@ type Image struct { | ... | @@ -236,26 +234,21 @@ type Image struct { |
| 236 | dotSize int | 234 | dotSize int |
| 237 | } | 235 | } |
| 238 | 236 | ||
| 239 | func getrand() *rand.Rand { | 237 | var prng = &siprng{} |
| 240 | return rand.New(rand.NewSource(time.Now().UnixNano())) | ||
| 241 | } | ||
| 242 | 238 | ||
| 243 | func randIntn(max int) int { | 239 | // randIntn returns a pseudorandom non-negative int in range [0, n). |
| 244 | if max <= 0 { | 240 | func randIntn(n int) int { |
| 245 | return 0 | 241 | return prng.Intn(n) |
| 246 | } | ||
| 247 | return getrand().Intn(max) | ||
| 248 | } | 242 | } |
| 249 | 243 | ||
| 250 | func randInt(min, max int) int { | 244 | // randInt returns a pseudorandom int in range [from, to]. |
| 251 | if max-min <= 0 { | 245 | func randInt(from, to int) int { |
| 252 | return 0 | 246 | return prng.Intn(to+1-from) + from |
| 253 | } | ||
| 254 | return getrand().Intn(max-min) + min | ||
| 255 | } | 247 | } |
| 256 | 248 | ||
| 257 | func randFloat(min, max float64) float64 { | 249 | // randFloat returns a pseudorandom float64 in range [from, to]. |
| 258 | return (max-min)*getrand().Float64() + min | 250 | func randFloat(from, to float64) float64 { |
| 251 | return (to-from)*prng.Float64() + from | ||
| 259 | } | 252 | } |
| 260 | 253 | ||
| 261 | func randomPalette() color.Palette { | 254 | func randomPalette() color.Palette { | ... | ... |
utils/captcha/siprng.go
0 → 100644
| 1 | // modifiy and integrated to Beego from https://github.com/dchest/captcha | ||
| 2 | package captcha | ||
| 3 | |||
| 4 | import ( | ||
| 5 | "crypto/rand" | ||
| 6 | "encoding/binary" | ||
| 7 | "io" | ||
| 8 | "sync" | ||
| 9 | ) | ||
| 10 | |||
| 11 | // siprng is PRNG based on SipHash-2-4. | ||
| 12 | type siprng struct { | ||
| 13 | mu sync.Mutex | ||
| 14 | k0, k1, ctr uint64 | ||
| 15 | } | ||
| 16 | |||
| 17 | // siphash implements SipHash-2-4, accepting a uint64 as a message. | ||
| 18 | func siphash(k0, k1, m uint64) uint64 { | ||
| 19 | // Initialization. | ||
| 20 | v0 := k0 ^ 0x736f6d6570736575 | ||
| 21 | v1 := k1 ^ 0x646f72616e646f6d | ||
| 22 | v2 := k0 ^ 0x6c7967656e657261 | ||
| 23 | v3 := k1 ^ 0x7465646279746573 | ||
| 24 | t := uint64(8) << 56 | ||
| 25 | |||
| 26 | // Compression. | ||
| 27 | v3 ^= m | ||
| 28 | |||
| 29 | // Round 1. | ||
| 30 | v0 += v1 | ||
| 31 | v1 = v1<<13 | v1>>(64-13) | ||
| 32 | v1 ^= v0 | ||
| 33 | v0 = v0<<32 | v0>>(64-32) | ||
| 34 | |||
| 35 | v2 += v3 | ||
| 36 | v3 = v3<<16 | v3>>(64-16) | ||
| 37 | v3 ^= v2 | ||
| 38 | |||
| 39 | v0 += v3 | ||
| 40 | v3 = v3<<21 | v3>>(64-21) | ||
| 41 | v3 ^= v0 | ||
| 42 | |||
| 43 | v2 += v1 | ||
| 44 | v1 = v1<<17 | v1>>(64-17) | ||
| 45 | v1 ^= v2 | ||
| 46 | v2 = v2<<32 | v2>>(64-32) | ||
| 47 | |||
| 48 | // Round 2. | ||
| 49 | v0 += v1 | ||
| 50 | v1 = v1<<13 | v1>>(64-13) | ||
| 51 | v1 ^= v0 | ||
| 52 | v0 = v0<<32 | v0>>(64-32) | ||
| 53 | |||
| 54 | v2 += v3 | ||
| 55 | v3 = v3<<16 | v3>>(64-16) | ||
| 56 | v3 ^= v2 | ||
| 57 | |||
| 58 | v0 += v3 | ||
| 59 | v3 = v3<<21 | v3>>(64-21) | ||
| 60 | v3 ^= v0 | ||
| 61 | |||
| 62 | v2 += v1 | ||
| 63 | v1 = v1<<17 | v1>>(64-17) | ||
| 64 | v1 ^= v2 | ||
| 65 | v2 = v2<<32 | v2>>(64-32) | ||
| 66 | |||
| 67 | v0 ^= m | ||
| 68 | |||
| 69 | // Compress last block. | ||
| 70 | v3 ^= t | ||
| 71 | |||
| 72 | // Round 1. | ||
| 73 | v0 += v1 | ||
| 74 | v1 = v1<<13 | v1>>(64-13) | ||
| 75 | v1 ^= v0 | ||
| 76 | v0 = v0<<32 | v0>>(64-32) | ||
| 77 | |||
| 78 | v2 += v3 | ||
| 79 | v3 = v3<<16 | v3>>(64-16) | ||
| 80 | v3 ^= v2 | ||
| 81 | |||
| 82 | v0 += v3 | ||
| 83 | v3 = v3<<21 | v3>>(64-21) | ||
| 84 | v3 ^= v0 | ||
| 85 | |||
| 86 | v2 += v1 | ||
| 87 | v1 = v1<<17 | v1>>(64-17) | ||
| 88 | v1 ^= v2 | ||
| 89 | v2 = v2<<32 | v2>>(64-32) | ||
| 90 | |||
| 91 | // Round 2. | ||
| 92 | v0 += v1 | ||
| 93 | v1 = v1<<13 | v1>>(64-13) | ||
| 94 | v1 ^= v0 | ||
| 95 | v0 = v0<<32 | v0>>(64-32) | ||
| 96 | |||
| 97 | v2 += v3 | ||
| 98 | v3 = v3<<16 | v3>>(64-16) | ||
| 99 | v3 ^= v2 | ||
| 100 | |||
| 101 | v0 += v3 | ||
| 102 | v3 = v3<<21 | v3>>(64-21) | ||
| 103 | v3 ^= v0 | ||
| 104 | |||
| 105 | v2 += v1 | ||
| 106 | v1 = v1<<17 | v1>>(64-17) | ||
| 107 | v1 ^= v2 | ||
| 108 | v2 = v2<<32 | v2>>(64-32) | ||
| 109 | |||
| 110 | v0 ^= t | ||
| 111 | |||
| 112 | // Finalization. | ||
| 113 | v2 ^= 0xff | ||
| 114 | |||
| 115 | // Round 1. | ||
| 116 | v0 += v1 | ||
| 117 | v1 = v1<<13 | v1>>(64-13) | ||
| 118 | v1 ^= v0 | ||
| 119 | v0 = v0<<32 | v0>>(64-32) | ||
| 120 | |||
| 121 | v2 += v3 | ||
| 122 | v3 = v3<<16 | v3>>(64-16) | ||
| 123 | v3 ^= v2 | ||
| 124 | |||
| 125 | v0 += v3 | ||
| 126 | v3 = v3<<21 | v3>>(64-21) | ||
| 127 | v3 ^= v0 | ||
| 128 | |||
| 129 | v2 += v1 | ||
| 130 | v1 = v1<<17 | v1>>(64-17) | ||
| 131 | v1 ^= v2 | ||
| 132 | v2 = v2<<32 | v2>>(64-32) | ||
| 133 | |||
| 134 | // Round 2. | ||
| 135 | v0 += v1 | ||
| 136 | v1 = v1<<13 | v1>>(64-13) | ||
| 137 | v1 ^= v0 | ||
| 138 | v0 = v0<<32 | v0>>(64-32) | ||
| 139 | |||
| 140 | v2 += v3 | ||
| 141 | v3 = v3<<16 | v3>>(64-16) | ||
| 142 | v3 ^= v2 | ||
| 143 | |||
| 144 | v0 += v3 | ||
| 145 | v3 = v3<<21 | v3>>(64-21) | ||
| 146 | v3 ^= v0 | ||
| 147 | |||
| 148 | v2 += v1 | ||
| 149 | v1 = v1<<17 | v1>>(64-17) | ||
| 150 | v1 ^= v2 | ||
| 151 | v2 = v2<<32 | v2>>(64-32) | ||
| 152 | |||
| 153 | // Round 3. | ||
| 154 | v0 += v1 | ||
| 155 | v1 = v1<<13 | v1>>(64-13) | ||
| 156 | v1 ^= v0 | ||
| 157 | v0 = v0<<32 | v0>>(64-32) | ||
| 158 | |||
| 159 | v2 += v3 | ||
| 160 | v3 = v3<<16 | v3>>(64-16) | ||
| 161 | v3 ^= v2 | ||
| 162 | |||
| 163 | v0 += v3 | ||
| 164 | v3 = v3<<21 | v3>>(64-21) | ||
| 165 | v3 ^= v0 | ||
| 166 | |||
| 167 | v2 += v1 | ||
| 168 | v1 = v1<<17 | v1>>(64-17) | ||
| 169 | v1 ^= v2 | ||
| 170 | v2 = v2<<32 | v2>>(64-32) | ||
| 171 | |||
| 172 | // Round 4. | ||
| 173 | v0 += v1 | ||
| 174 | v1 = v1<<13 | v1>>(64-13) | ||
| 175 | v1 ^= v0 | ||
| 176 | v0 = v0<<32 | v0>>(64-32) | ||
| 177 | |||
| 178 | v2 += v3 | ||
| 179 | v3 = v3<<16 | v3>>(64-16) | ||
| 180 | v3 ^= v2 | ||
| 181 | |||
| 182 | v0 += v3 | ||
| 183 | v3 = v3<<21 | v3>>(64-21) | ||
| 184 | v3 ^= v0 | ||
| 185 | |||
| 186 | v2 += v1 | ||
| 187 | v1 = v1<<17 | v1>>(64-17) | ||
| 188 | v1 ^= v2 | ||
| 189 | v2 = v2<<32 | v2>>(64-32) | ||
| 190 | |||
| 191 | return v0 ^ v1 ^ v2 ^ v3 | ||
| 192 | } | ||
| 193 | |||
| 194 | // rekey sets a new PRNG key, which is read from crypto/rand. | ||
| 195 | func (p *siprng) rekey() { | ||
| 196 | var k [16]byte | ||
| 197 | if _, err := io.ReadFull(rand.Reader, k[:]); err != nil { | ||
| 198 | panic(err.Error()) | ||
| 199 | } | ||
| 200 | p.k0 = binary.LittleEndian.Uint64(k[0:8]) | ||
| 201 | p.k1 = binary.LittleEndian.Uint64(k[8:16]) | ||
| 202 | p.ctr = 1 | ||
| 203 | } | ||
| 204 | |||
| 205 | // Uint64 returns a new pseudorandom uint64. | ||
| 206 | // It rekeys PRNG on the first call and every 64 MB of generated data. | ||
| 207 | func (p *siprng) Uint64() uint64 { | ||
| 208 | p.mu.Lock() | ||
| 209 | if p.ctr == 0 || p.ctr > 8*1024*1024 { | ||
| 210 | p.rekey() | ||
| 211 | } | ||
| 212 | v := siphash(p.k0, p.k1, p.ctr) | ||
| 213 | p.ctr++ | ||
| 214 | p.mu.Unlock() | ||
| 215 | return v | ||
| 216 | } | ||
| 217 | |||
| 218 | func (p *siprng) Int63() int64 { | ||
| 219 | return int64(p.Uint64() & 0x7fffffffffffffff) | ||
| 220 | } | ||
| 221 | |||
| 222 | func (p *siprng) Uint32() uint32 { | ||
| 223 | return uint32(p.Uint64()) | ||
| 224 | } | ||
| 225 | |||
| 226 | func (p *siprng) Int31() int32 { | ||
| 227 | return int32(p.Uint32() & 0x7fffffff) | ||
| 228 | } | ||
| 229 | |||
| 230 | func (p *siprng) Intn(n int) int { | ||
| 231 | if n <= 0 { | ||
| 232 | panic("invalid argument to Intn") | ||
| 233 | } | ||
| 234 | if n <= 1<<31-1 { | ||
| 235 | return int(p.Int31n(int32(n))) | ||
| 236 | } | ||
| 237 | return int(p.Int63n(int64(n))) | ||
| 238 | } | ||
| 239 | |||
| 240 | func (p *siprng) Int63n(n int64) int64 { | ||
| 241 | if n <= 0 { | ||
| 242 | panic("invalid argument to Int63n") | ||
| 243 | } | ||
| 244 | max := int64((1 << 63) - 1 - (1<<63)%uint64(n)) | ||
| 245 | v := p.Int63() | ||
| 246 | for v > max { | ||
| 247 | v = p.Int63() | ||
| 248 | } | ||
| 249 | return v % n | ||
| 250 | } | ||
| 251 | |||
| 252 | func (p *siprng) Int31n(n int32) int32 { | ||
| 253 | if n <= 0 { | ||
| 254 | panic("invalid argument to Int31n") | ||
| 255 | } | ||
| 256 | max := int32((1 << 31) - 1 - (1<<31)%uint32(n)) | ||
| 257 | v := p.Int31() | ||
| 258 | for v > max { | ||
| 259 | v = p.Int31() | ||
| 260 | } | ||
| 261 | return v % n | ||
| 262 | } | ||
| 263 | |||
| 264 | func (p *siprng) Float64() float64 { return float64(p.Int63()) / (1 << 63) } |
utils/captcha/siprng_test.go
0 → 100644
| 1 | package captcha | ||
| 2 | |||
| 3 | import "testing" | ||
| 4 | |||
| 5 | func TestSiphash(t *testing.T) { | ||
| 6 | good := uint64(0xe849e8bb6ffe2567) | ||
| 7 | cur := siphash(0, 0, 0) | ||
| 8 | if cur != good { | ||
| 9 | t.Fatalf("siphash: expected %x, got %x", good, cur) | ||
| 10 | } | ||
| 11 | } | ||
| 12 | |||
| 13 | func BenchmarkSiprng(b *testing.B) { | ||
| 14 | b.SetBytes(8) | ||
| 15 | p := &siprng{} | ||
| 16 | for i := 0; i < b.N; i++ { | ||
| 17 | p.Uint64() | ||
| 18 | } | ||
| 19 | } |
-
Please register or sign in to post a comment