mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Added all required dependencies
This commit is contained in:
		
							
								
								
									
										191
									
								
								vendor/github.com/go-macaron/captcha/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								vendor/github.com/go-macaron/captcha/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
			
		||||
Apache License
 | 
			
		||||
Version 2.0, January 2004
 | 
			
		||||
http://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
1. Definitions.
 | 
			
		||||
 | 
			
		||||
"License" shall mean the terms and conditions for use, reproduction, and
 | 
			
		||||
distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
 | 
			
		||||
owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
"Legal Entity" shall mean the union of the acting entity and all other entities
 | 
			
		||||
that control, are controlled by, or are under common control with that entity.
 | 
			
		||||
For the purposes of this definition, "control" means (i) the power, direct or
 | 
			
		||||
indirect, to cause the direction or management of such entity, whether by
 | 
			
		||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
 | 
			
		||||
permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
"Source" form shall mean the preferred form for making modifications, including
 | 
			
		||||
but not limited to software source code, documentation source, and configuration
 | 
			
		||||
files.
 | 
			
		||||
 | 
			
		||||
"Object" form shall mean any form resulting from mechanical transformation or
 | 
			
		||||
translation of a Source form, including but not limited to compiled object code,
 | 
			
		||||
generated documentation, and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
 | 
			
		||||
available under the License, as indicated by a copyright notice that is included
 | 
			
		||||
in or attached to the work (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
 | 
			
		||||
is based on (or derived from) the Work and for which the editorial revisions,
 | 
			
		||||
annotations, elaborations, or other modifications represent, as a whole, an
 | 
			
		||||
original work of authorship. For the purposes of this License, Derivative Works
 | 
			
		||||
shall not include works that remain separable from, or merely link (or bind by
 | 
			
		||||
name) to the interfaces of, the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
"Contribution" shall mean any work of authorship, including the original version
 | 
			
		||||
of the Work and any modifications or additions to that Work or Derivative Works
 | 
			
		||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
 | 
			
		||||
by the copyright owner or by an individual or Legal Entity authorized to submit
 | 
			
		||||
on behalf of the copyright owner. For the purposes of this definition,
 | 
			
		||||
"submitted" means any form of electronic, verbal, or written communication sent
 | 
			
		||||
to the Licensor or its representatives, including but not limited to
 | 
			
		||||
communication on electronic mailing lists, source code control systems, and
 | 
			
		||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
 | 
			
		||||
the purpose of discussing and improving the Work, but excluding communication
 | 
			
		||||
that is conspicuously marked or otherwise designated in writing by the copyright
 | 
			
		||||
owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
 | 
			
		||||
of whom a Contribution has been received by Licensor and subsequently
 | 
			
		||||
incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
2. Grant of Copyright License.
 | 
			
		||||
 | 
			
		||||
Subject to the terms and conditions of this License, each Contributor hereby
 | 
			
		||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
 | 
			
		||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
publicly display, publicly perform, sublicense, and distribute the Work and such
 | 
			
		||||
Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
3. Grant of Patent License.
 | 
			
		||||
 | 
			
		||||
Subject to the terms and conditions of this License, each Contributor hereby
 | 
			
		||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
 | 
			
		||||
irrevocable (except as stated in this section) patent license to make, have
 | 
			
		||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
 | 
			
		||||
such license applies only to those patent claims licensable by such Contributor
 | 
			
		||||
that are necessarily infringed by their Contribution(s) alone or by combination
 | 
			
		||||
of their Contribution(s) with the Work to which such Contribution(s) was
 | 
			
		||||
submitted. If You institute patent litigation against any entity (including a
 | 
			
		||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
 | 
			
		||||
Contribution incorporated within the Work constitutes direct or contributory
 | 
			
		||||
patent infringement, then any patent licenses granted to You under this License
 | 
			
		||||
for that Work shall terminate as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
4. Redistribution.
 | 
			
		||||
 | 
			
		||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
 | 
			
		||||
in any medium, with or without modifications, and in Source or Object form,
 | 
			
		||||
provided that You meet the following conditions:
 | 
			
		||||
 | 
			
		||||
You must give any other recipients of the Work or Derivative Works a copy of
 | 
			
		||||
this License; and
 | 
			
		||||
You must cause any modified files to carry prominent notices stating that You
 | 
			
		||||
changed the files; and
 | 
			
		||||
You must retain, in the Source form of any Derivative Works that You distribute,
 | 
			
		||||
all copyright, patent, trademark, and attribution notices from the Source form
 | 
			
		||||
of the Work, excluding those notices that do not pertain to any part of the
 | 
			
		||||
Derivative Works; and
 | 
			
		||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
 | 
			
		||||
Derivative Works that You distribute must include a readable copy of the
 | 
			
		||||
attribution notices contained within such NOTICE file, excluding those notices
 | 
			
		||||
that do not pertain to any part of the Derivative Works, in at least one of the
 | 
			
		||||
following places: within a NOTICE text file distributed as part of the
 | 
			
		||||
Derivative Works; within the Source form or documentation, if provided along
 | 
			
		||||
with the Derivative Works; or, within a display generated by the Derivative
 | 
			
		||||
Works, if and wherever such third-party notices normally appear. The contents of
 | 
			
		||||
the NOTICE file are for informational purposes only and do not modify the
 | 
			
		||||
License. You may add Your own attribution notices within Derivative Works that
 | 
			
		||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
 | 
			
		||||
provided that such additional attribution notices cannot be construed as
 | 
			
		||||
modifying the License.
 | 
			
		||||
You may add Your own copyright statement to Your modifications and may provide
 | 
			
		||||
additional or different license terms and conditions for use, reproduction, or
 | 
			
		||||
distribution of Your modifications, or for any such Derivative Works as a whole,
 | 
			
		||||
provided Your use, reproduction, and distribution of the Work otherwise complies
 | 
			
		||||
with the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
5. Submission of Contributions.
 | 
			
		||||
 | 
			
		||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
 | 
			
		||||
for inclusion in the Work by You to the Licensor shall be under the terms and
 | 
			
		||||
conditions of this License, without any additional terms or conditions.
 | 
			
		||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
 | 
			
		||||
any separate license agreement you may have executed with Licensor regarding
 | 
			
		||||
such Contributions.
 | 
			
		||||
 | 
			
		||||
6. Trademarks.
 | 
			
		||||
 | 
			
		||||
This License does not grant permission to use the trade names, trademarks,
 | 
			
		||||
service marks, or product names of the Licensor, except as required for
 | 
			
		||||
reasonable and customary use in describing the origin of the Work and
 | 
			
		||||
reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
7. Disclaimer of Warranty.
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, Licensor provides the
 | 
			
		||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
 | 
			
		||||
including, without limitation, any warranties or conditions of TITLE,
 | 
			
		||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
 | 
			
		||||
solely responsible for determining the appropriateness of using or
 | 
			
		||||
redistributing the Work and assume any risks associated with Your exercise of
 | 
			
		||||
permissions under this License.
 | 
			
		||||
 | 
			
		||||
8. Limitation of Liability.
 | 
			
		||||
 | 
			
		||||
In no event and under no legal theory, whether in tort (including negligence),
 | 
			
		||||
contract, or otherwise, unless required by applicable law (such as deliberate
 | 
			
		||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
liable to You for damages, including any direct, indirect, special, incidental,
 | 
			
		||||
or consequential damages of any character arising as a result of this License or
 | 
			
		||||
out of the use or inability to use the Work (including but not limited to
 | 
			
		||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
 | 
			
		||||
any and all other commercial damages or losses), even if such Contributor has
 | 
			
		||||
been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
9. Accepting Warranty or Additional Liability.
 | 
			
		||||
 | 
			
		||||
While redistributing the Work or Derivative Works thereof, You may choose to
 | 
			
		||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
 | 
			
		||||
other liability obligations and/or rights consistent with this License. However,
 | 
			
		||||
in accepting such obligations, You may act only on Your own behalf and on Your
 | 
			
		||||
sole responsibility, not on behalf of any other Contributor, and only if You
 | 
			
		||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
 | 
			
		||||
incurred by, or claims asserted against, such Contributor by reason of your
 | 
			
		||||
accepting any such warranty or additional liability.
 | 
			
		||||
 | 
			
		||||
END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
APPENDIX: How to apply the Apache License to your work
 | 
			
		||||
 | 
			
		||||
To apply the Apache License to your work, attach the following boilerplate
 | 
			
		||||
notice, with the fields enclosed by brackets "[]" replaced with your own
 | 
			
		||||
identifying information. (Don't include the brackets!) The text should be
 | 
			
		||||
enclosed in the appropriate comment syntax for the file format. We also
 | 
			
		||||
recommend that a file or class name and description of purpose be included on
 | 
			
		||||
the same "printed page" as the copyright notice for easier identification within
 | 
			
		||||
third-party archives.
 | 
			
		||||
 | 
			
		||||
   Copyright [yyyy] [name of copyright owner]
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/github.com/go-macaron/captcha/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/go-macaron/captcha/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
# captcha [](https://travis-ci.org/go-macaron/captcha)
 | 
			
		||||
 | 
			
		||||
Middleware captcha provides captcha service for [Macaron](https://github.com/go-macaron/macaron).
 | 
			
		||||
 | 
			
		||||
### Installation
 | 
			
		||||
 | 
			
		||||
	go get github.com/go-macaron/captcha
 | 
			
		||||
 | 
			
		||||
## Getting Help
 | 
			
		||||
 | 
			
		||||
- [API Reference](https://gowalker.org/github.com/go-macaron/captcha)
 | 
			
		||||
- [Documentation](http://go-macaron.com/docs/middlewares/captcha)
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text.
 | 
			
		||||
							
								
								
									
										241
									
								
								vendor/github.com/go-macaron/captcha/captcha.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								vendor/github.com/go-macaron/captcha/captcha.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,241 @@
 | 
			
		||||
// Copyright 2013 Beego Authors
 | 
			
		||||
// Copyright 2014 The Macaron Authors
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
 | 
			
		||||
// not use this file except in compliance with the License. You may obtain
 | 
			
		||||
// a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
// License for the specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
 | 
			
		||||
// Package captcha a middleware that provides captcha service for Macaron.
 | 
			
		||||
package captcha
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"html/template"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
	"github.com/go-macaron/cache"
 | 
			
		||||
	"gopkg.in/macaron.v1"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const _VERSION = "0.1.0"
 | 
			
		||||
 | 
			
		||||
func Version() string {
 | 
			
		||||
	return _VERSION
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	defaultChars = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Captcha represents a captcha service.
 | 
			
		||||
type Captcha struct {
 | 
			
		||||
	store            cache.Cache
 | 
			
		||||
	SubURL           string
 | 
			
		||||
	URLPrefix        string
 | 
			
		||||
	FieldIdName      string
 | 
			
		||||
	FieldCaptchaName string
 | 
			
		||||
	StdWidth         int
 | 
			
		||||
	StdHeight        int
 | 
			
		||||
	ChallengeNums    int
 | 
			
		||||
	Expiration       int64
 | 
			
		||||
	CachePrefix      string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generate key string
 | 
			
		||||
func (c *Captcha) key(id string) string {
 | 
			
		||||
	return c.CachePrefix + id
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generate rand chars with default chars
 | 
			
		||||
func (c *Captcha) genRandChars() string {
 | 
			
		||||
	return string(com.RandomCreateBytes(c.ChallengeNums, defaultChars...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tempalte func for output html
 | 
			
		||||
func (c *Captcha) CreateHtml() template.HTML {
 | 
			
		||||
	value, err := c.CreateCaptcha()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(fmt.Errorf("fail to create captcha: %v", err))
 | 
			
		||||
	}
 | 
			
		||||
	return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">
 | 
			
		||||
	<a class="captcha" href="javascript:">
 | 
			
		||||
		<img onclick="this.src=('%s%s%s.png?reload='+(new Date()).getTime())" class="captcha-img" src="%s%s%s.png">
 | 
			
		||||
	</a>`, c.FieldIdName, value, c.SubURL, c.URLPrefix, value, c.SubURL, c.URLPrefix, value))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// create a new captcha id
 | 
			
		||||
func (c *Captcha) CreateCaptcha() (string, error) {
 | 
			
		||||
	id := string(com.RandomCreateBytes(15))
 | 
			
		||||
	if err := c.store.Put(c.key(id), c.genRandChars(), c.Expiration); err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return id, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// verify from a request
 | 
			
		||||
func (c *Captcha) VerifyReq(req macaron.Request) bool {
 | 
			
		||||
	req.ParseForm()
 | 
			
		||||
	return c.Verify(req.Form.Get(c.FieldIdName), req.Form.Get(c.FieldCaptchaName))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// direct verify id and challenge string
 | 
			
		||||
func (c *Captcha) Verify(id string, challenge string) bool {
 | 
			
		||||
	if len(challenge) == 0 || len(id) == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var chars string
 | 
			
		||||
 | 
			
		||||
	key := c.key(id)
 | 
			
		||||
 | 
			
		||||
	if v, ok := c.store.Get(key).(string); ok {
 | 
			
		||||
		chars = v
 | 
			
		||||
	} else {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer c.store.Delete(key)
 | 
			
		||||
 | 
			
		||||
	if len(chars) != len(challenge) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// verify challenge
 | 
			
		||||
	for i, c := range []byte(chars) {
 | 
			
		||||
		if c != challenge[i]-48 {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Options struct {
 | 
			
		||||
	// Suburl path. Default is empty.
 | 
			
		||||
	SubURL string
 | 
			
		||||
	// URL prefix of getting captcha pictures. Default is "/captcha/".
 | 
			
		||||
	URLPrefix string
 | 
			
		||||
	// Hidden input element ID. Default is "captcha_id".
 | 
			
		||||
	FieldIdName string
 | 
			
		||||
	// User input value element name in request form. Default is "captcha".
 | 
			
		||||
	FieldCaptchaName string
 | 
			
		||||
	// Challenge number. Default is 6.
 | 
			
		||||
	ChallengeNums int
 | 
			
		||||
	// Captcha image width. Default is 240.
 | 
			
		||||
	Width int
 | 
			
		||||
	// Captcha image height. Default is 80.
 | 
			
		||||
	Height int
 | 
			
		||||
	// Captcha expiration time in seconds. Default is 600.
 | 
			
		||||
	Expiration int64
 | 
			
		||||
	// Cache key prefix captcha characters. Default is "captcha_".
 | 
			
		||||
	CachePrefix string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func prepareOptions(options []Options) Options {
 | 
			
		||||
	var opt Options
 | 
			
		||||
	if len(options) > 0 {
 | 
			
		||||
		opt = options[0]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	opt.SubURL = strings.TrimSuffix(opt.SubURL, "/")
 | 
			
		||||
 | 
			
		||||
	// Defaults.
 | 
			
		||||
	if len(opt.URLPrefix) == 0 {
 | 
			
		||||
		opt.URLPrefix = "/captcha/"
 | 
			
		||||
	} else if opt.URLPrefix[len(opt.URLPrefix)-1] != '/' {
 | 
			
		||||
		opt.URLPrefix += "/"
 | 
			
		||||
	}
 | 
			
		||||
	if len(opt.FieldIdName) == 0 {
 | 
			
		||||
		opt.FieldIdName = "captcha_id"
 | 
			
		||||
	}
 | 
			
		||||
	if len(opt.FieldCaptchaName) == 0 {
 | 
			
		||||
		opt.FieldCaptchaName = "captcha"
 | 
			
		||||
	}
 | 
			
		||||
	if opt.ChallengeNums == 0 {
 | 
			
		||||
		opt.ChallengeNums = 6
 | 
			
		||||
	}
 | 
			
		||||
	if opt.Width == 0 {
 | 
			
		||||
		opt.Width = stdWidth
 | 
			
		||||
	}
 | 
			
		||||
	if opt.Height == 0 {
 | 
			
		||||
		opt.Height = stdHeight
 | 
			
		||||
	}
 | 
			
		||||
	if opt.Expiration == 0 {
 | 
			
		||||
		opt.Expiration = 600
 | 
			
		||||
	}
 | 
			
		||||
	if len(opt.CachePrefix) == 0 {
 | 
			
		||||
		opt.CachePrefix = "captcha_"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return opt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewCaptcha initializes and returns a captcha with given options.
 | 
			
		||||
func NewCaptcha(opt Options) *Captcha {
 | 
			
		||||
	return &Captcha{
 | 
			
		||||
		SubURL:           opt.SubURL,
 | 
			
		||||
		URLPrefix:        opt.URLPrefix,
 | 
			
		||||
		FieldIdName:      opt.FieldIdName,
 | 
			
		||||
		FieldCaptchaName: opt.FieldCaptchaName,
 | 
			
		||||
		StdWidth:         opt.Width,
 | 
			
		||||
		StdHeight:        opt.Height,
 | 
			
		||||
		ChallengeNums:    opt.ChallengeNums,
 | 
			
		||||
		Expiration:       opt.Expiration,
 | 
			
		||||
		CachePrefix:      opt.CachePrefix,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Captchaer is a middleware that maps a captcha.Captcha service into the Macaron handler chain.
 | 
			
		||||
// An single variadic captcha.Options struct can be optionally provided to configure.
 | 
			
		||||
// This should be register after cache.Cacher.
 | 
			
		||||
func Captchaer(options ...Options) macaron.Handler {
 | 
			
		||||
	return func(ctx *macaron.Context, cache cache.Cache) {
 | 
			
		||||
		cpt := NewCaptcha(prepareOptions(options))
 | 
			
		||||
		cpt.store = cache
 | 
			
		||||
 | 
			
		||||
		if strings.HasPrefix(ctx.Req.URL.Path, cpt.URLPrefix) {
 | 
			
		||||
			var chars string
 | 
			
		||||
			id := path.Base(ctx.Req.URL.Path)
 | 
			
		||||
			if i := strings.Index(id, "."); i > -1 {
 | 
			
		||||
				id = id[:i]
 | 
			
		||||
			}
 | 
			
		||||
			key := cpt.key(id)
 | 
			
		||||
 | 
			
		||||
			// Reload captcha.
 | 
			
		||||
			if len(ctx.Query("reload")) > 0 {
 | 
			
		||||
				chars = cpt.genRandChars()
 | 
			
		||||
				if err := cpt.store.Put(key, chars, cpt.Expiration); err != nil {
 | 
			
		||||
					ctx.Status(500)
 | 
			
		||||
					ctx.Write([]byte("captcha reload error"))
 | 
			
		||||
					panic(fmt.Errorf("reload captcha: %v", err))
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				if v, ok := cpt.store.Get(key).(string); ok {
 | 
			
		||||
					chars = v
 | 
			
		||||
				} else {
 | 
			
		||||
					ctx.Status(404)
 | 
			
		||||
					ctx.Write([]byte("captcha not found"))
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if _, err := NewImage([]byte(chars), cpt.StdWidth, cpt.StdHeight).WriteTo(ctx.Resp); err != nil {
 | 
			
		||||
				panic(fmt.Errorf("write captcha: %v", err))
 | 
			
		||||
			}
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ctx.Data["Captcha"] = cpt
 | 
			
		||||
		ctx.Map(cpt)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										498
									
								
								vendor/github.com/go-macaron/captcha/image.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										498
									
								
								vendor/github.com/go-macaron/captcha/image.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,498 @@
 | 
			
		||||
// Copyright 2013 Beego Authors
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
 | 
			
		||||
// not use this file except in compliance with the License. You may obtain
 | 
			
		||||
// a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
// License for the specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
 | 
			
		||||
package captcha
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"image"
 | 
			
		||||
	"image/color"
 | 
			
		||||
	"image/png"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	fontWidth  = 11
 | 
			
		||||
	fontHeight = 18
 | 
			
		||||
	blackChar  = 1
 | 
			
		||||
 | 
			
		||||
	// Standard width and height of a captcha image.
 | 
			
		||||
	stdWidth  = 240
 | 
			
		||||
	stdHeight = 80
 | 
			
		||||
 | 
			
		||||
	// Maximum absolute skew factor of a single digit.
 | 
			
		||||
	maxSkew = 0.7
 | 
			
		||||
	// Number of background circles.
 | 
			
		||||
	circleCount = 20
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var font = [][]byte{
 | 
			
		||||
	{ // 0
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
	},
 | 
			
		||||
	{ // 1
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
	},
 | 
			
		||||
	{ // 2
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
	},
 | 
			
		||||
	{ // 3
 | 
			
		||||
		0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
		1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
 | 
			
		||||
		1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
	},
 | 
			
		||||
	{ // 4
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
	},
 | 
			
		||||
	{ // 5
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
	},
 | 
			
		||||
	{ // 6
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
		1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
 | 
			
		||||
		1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
 | 
			
		||||
		0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
	},
 | 
			
		||||
	{ // 7
 | 
			
		||||
		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
		1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
	},
 | 
			
		||||
	{ // 8
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
 | 
			
		||||
		0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
		0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
	},
 | 
			
		||||
	{ // 9
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1,
 | 
			
		||||
		0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
 | 
			
		||||
		0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
 | 
			
		||||
		0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
 | 
			
		||||
		0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Image struct {
 | 
			
		||||
	*image.Paletted
 | 
			
		||||
	numWidth  int
 | 
			
		||||
	numHeight int
 | 
			
		||||
	dotSize   int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var prng = &siprng{}
 | 
			
		||||
 | 
			
		||||
// randIntn returns a pseudorandom non-negative int in range [0, n).
 | 
			
		||||
func randIntn(n int) int {
 | 
			
		||||
	return prng.Intn(n)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// randInt returns a pseudorandom int in range [from, to].
 | 
			
		||||
func randInt(from, to int) int {
 | 
			
		||||
	return prng.Intn(to+1-from) + from
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// randFloat returns a pseudorandom float64 in range [from, to].
 | 
			
		||||
func randFloat(from, to float64) float64 {
 | 
			
		||||
	return (to-from)*prng.Float64() + from
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func randomPalette() color.Palette {
 | 
			
		||||
	p := make([]color.Color, circleCount+1)
 | 
			
		||||
	// Transparent color.
 | 
			
		||||
	p[0] = color.RGBA{0xFF, 0xFF, 0xFF, 0x00}
 | 
			
		||||
	// Primary color.
 | 
			
		||||
	prim := color.RGBA{
 | 
			
		||||
		uint8(randIntn(129)),
 | 
			
		||||
		uint8(randIntn(129)),
 | 
			
		||||
		uint8(randIntn(129)),
 | 
			
		||||
		0xFF,
 | 
			
		||||
	}
 | 
			
		||||
	p[1] = prim
 | 
			
		||||
	// Circle colors.
 | 
			
		||||
	for i := 2; i <= circleCount; i++ {
 | 
			
		||||
		p[i] = randomBrightness(prim, 255)
 | 
			
		||||
	}
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewImage returns a new captcha image of the given width and height with the
 | 
			
		||||
// given digits, where each digit must be in range 0-9.
 | 
			
		||||
func NewImage(digits []byte, width, height int) *Image {
 | 
			
		||||
	m := new(Image)
 | 
			
		||||
	m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), randomPalette())
 | 
			
		||||
	m.calculateSizes(width, height, len(digits))
 | 
			
		||||
	// Randomly position captcha inside the image.
 | 
			
		||||
	maxx := width - (m.numWidth+m.dotSize)*len(digits) - m.dotSize
 | 
			
		||||
	maxy := height - m.numHeight - m.dotSize*2
 | 
			
		||||
	var border int
 | 
			
		||||
	if width > height {
 | 
			
		||||
		border = height / 5
 | 
			
		||||
	} else {
 | 
			
		||||
		border = width / 5
 | 
			
		||||
	}
 | 
			
		||||
	x := randInt(border, maxx-border)
 | 
			
		||||
	y := randInt(border, maxy-border)
 | 
			
		||||
	// Draw digits.
 | 
			
		||||
	for _, n := range digits {
 | 
			
		||||
		m.drawDigit(font[n], x, y)
 | 
			
		||||
		x += m.numWidth + m.dotSize
 | 
			
		||||
	}
 | 
			
		||||
	// Draw strike-through line.
 | 
			
		||||
	m.strikeThrough()
 | 
			
		||||
	// Apply wave distortion.
 | 
			
		||||
	m.distort(randFloat(5, 10), randFloat(100, 200))
 | 
			
		||||
	// Fill image with random circles.
 | 
			
		||||
	m.fillWithCircles(circleCount, m.dotSize)
 | 
			
		||||
	return m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// encodedPNG encodes an image to PNG and returns
 | 
			
		||||
// the result as a byte slice.
 | 
			
		||||
func (m *Image) encodedPNG() []byte {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	if err := png.Encode(&buf, m.Paletted); err != nil {
 | 
			
		||||
		panic(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	return buf.Bytes()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteTo writes captcha image in PNG format into the given writer.
 | 
			
		||||
func (m *Image) WriteTo(w io.Writer) (int64, error) {
 | 
			
		||||
	n, err := w.Write(m.encodedPNG())
 | 
			
		||||
	return int64(n), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Image) calculateSizes(width, height, ncount int) {
 | 
			
		||||
	// Goal: fit all digits inside the image.
 | 
			
		||||
	var border int
 | 
			
		||||
	if width > height {
 | 
			
		||||
		border = height / 4
 | 
			
		||||
	} else {
 | 
			
		||||
		border = width / 4
 | 
			
		||||
	}
 | 
			
		||||
	// Convert everything to floats for calculations.
 | 
			
		||||
	w := float64(width - border*2)
 | 
			
		||||
	h := float64(height - border*2)
 | 
			
		||||
	// fw takes into account 1-dot spacing between digits.
 | 
			
		||||
	fw := float64(fontWidth + 1)
 | 
			
		||||
	fh := float64(fontHeight)
 | 
			
		||||
	nc := float64(ncount)
 | 
			
		||||
	// Calculate the width of a single digit taking into account only the
 | 
			
		||||
	// width of the image.
 | 
			
		||||
	nw := w / nc
 | 
			
		||||
	// Calculate the height of a digit from this width.
 | 
			
		||||
	nh := nw * fh / fw
 | 
			
		||||
	// Digit too high?
 | 
			
		||||
	if nh > h {
 | 
			
		||||
		// Fit digits based on height.
 | 
			
		||||
		nh = h
 | 
			
		||||
		nw = fw / fh * nh
 | 
			
		||||
	}
 | 
			
		||||
	// Calculate dot size.
 | 
			
		||||
	m.dotSize = int(nh / fh)
 | 
			
		||||
	// Save everything, making the actual width smaller by 1 dot to account
 | 
			
		||||
	// for spacing between digits.
 | 
			
		||||
	m.numWidth = int(nw) - m.dotSize
 | 
			
		||||
	m.numHeight = int(nh)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Image) drawHorizLine(fromX, toX, y int, colorIdx uint8) {
 | 
			
		||||
	for x := fromX; x <= toX; x++ {
 | 
			
		||||
		m.SetColorIndex(x, y, colorIdx)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Image) drawCircle(x, y, radius int, colorIdx uint8) {
 | 
			
		||||
	f := 1 - radius
 | 
			
		||||
	dfx := 1
 | 
			
		||||
	dfy := -2 * radius
 | 
			
		||||
	xo := 0
 | 
			
		||||
	yo := radius
 | 
			
		||||
 | 
			
		||||
	m.SetColorIndex(x, y+radius, colorIdx)
 | 
			
		||||
	m.SetColorIndex(x, y-radius, colorIdx)
 | 
			
		||||
	m.drawHorizLine(x-radius, x+radius, y, colorIdx)
 | 
			
		||||
 | 
			
		||||
	for xo < yo {
 | 
			
		||||
		if f >= 0 {
 | 
			
		||||
			yo--
 | 
			
		||||
			dfy += 2
 | 
			
		||||
			f += dfy
 | 
			
		||||
		}
 | 
			
		||||
		xo++
 | 
			
		||||
		dfx += 2
 | 
			
		||||
		f += dfx
 | 
			
		||||
		m.drawHorizLine(x-xo, x+xo, y+yo, colorIdx)
 | 
			
		||||
		m.drawHorizLine(x-xo, x+xo, y-yo, colorIdx)
 | 
			
		||||
		m.drawHorizLine(x-yo, x+yo, y+xo, colorIdx)
 | 
			
		||||
		m.drawHorizLine(x-yo, x+yo, y-xo, colorIdx)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Image) fillWithCircles(n, maxradius int) {
 | 
			
		||||
	maxx := m.Bounds().Max.X
 | 
			
		||||
	maxy := m.Bounds().Max.Y
 | 
			
		||||
	for i := 0; i < n; i++ {
 | 
			
		||||
		colorIdx := uint8(randInt(1, circleCount-1))
 | 
			
		||||
		r := randInt(1, maxradius)
 | 
			
		||||
		m.drawCircle(randInt(r, maxx-r), randInt(r, maxy-r), r, colorIdx)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Image) strikeThrough() {
 | 
			
		||||
	maxx := m.Bounds().Max.X
 | 
			
		||||
	maxy := m.Bounds().Max.Y
 | 
			
		||||
	y := randInt(maxy/3, maxy-maxy/3)
 | 
			
		||||
	amplitude := randFloat(5, 20)
 | 
			
		||||
	period := randFloat(80, 180)
 | 
			
		||||
	dx := 2.0 * math.Pi / period
 | 
			
		||||
	for x := 0; x < maxx; x++ {
 | 
			
		||||
		xo := amplitude * math.Cos(float64(y)*dx)
 | 
			
		||||
		yo := amplitude * math.Sin(float64(x)*dx)
 | 
			
		||||
		for yn := 0; yn < m.dotSize; yn++ {
 | 
			
		||||
			r := randInt(0, m.dotSize)
 | 
			
		||||
			m.drawCircle(x+int(xo), y+int(yo)+(yn*m.dotSize), r/2, 1)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Image) drawDigit(digit []byte, x, y int) {
 | 
			
		||||
	skf := randFloat(-maxSkew, maxSkew)
 | 
			
		||||
	xs := float64(x)
 | 
			
		||||
	r := m.dotSize / 2
 | 
			
		||||
	y += randInt(-r, r)
 | 
			
		||||
	for yo := 0; yo < fontHeight; yo++ {
 | 
			
		||||
		for xo := 0; xo < fontWidth; xo++ {
 | 
			
		||||
			if digit[yo*fontWidth+xo] != blackChar {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			m.drawCircle(x+xo*m.dotSize, y+yo*m.dotSize, r, 1)
 | 
			
		||||
		}
 | 
			
		||||
		xs += skf
 | 
			
		||||
		x = int(xs)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Image) distort(amplude float64, period float64) {
 | 
			
		||||
	w := m.Bounds().Max.X
 | 
			
		||||
	h := m.Bounds().Max.Y
 | 
			
		||||
 | 
			
		||||
	oldm := m.Paletted
 | 
			
		||||
	newm := image.NewPaletted(image.Rect(0, 0, w, h), oldm.Palette)
 | 
			
		||||
 | 
			
		||||
	dx := 2.0 * math.Pi / period
 | 
			
		||||
	for x := 0; x < w; x++ {
 | 
			
		||||
		for y := 0; y < h; y++ {
 | 
			
		||||
			xo := amplude * math.Sin(float64(y)*dx)
 | 
			
		||||
			yo := amplude * math.Cos(float64(x)*dx)
 | 
			
		||||
			newm.SetColorIndex(x, y, oldm.ColorIndexAt(x+int(xo), y+int(yo)))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	m.Paletted = newm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func randomBrightness(c color.RGBA, max uint8) color.RGBA {
 | 
			
		||||
	minc := min3(c.R, c.G, c.B)
 | 
			
		||||
	maxc := max3(c.R, c.G, c.B)
 | 
			
		||||
	if maxc > max {
 | 
			
		||||
		return c
 | 
			
		||||
	}
 | 
			
		||||
	n := randIntn(int(max-maxc)) - int(minc)
 | 
			
		||||
	return color.RGBA{
 | 
			
		||||
		uint8(int(c.R) + n),
 | 
			
		||||
		uint8(int(c.G) + n),
 | 
			
		||||
		uint8(int(c.B) + n),
 | 
			
		||||
		uint8(c.A),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func min3(x, y, z uint8) (m uint8) {
 | 
			
		||||
	m = x
 | 
			
		||||
	if y < m {
 | 
			
		||||
		m = y
 | 
			
		||||
	}
 | 
			
		||||
	if z < m {
 | 
			
		||||
		m = z
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func max3(x, y, z uint8) (m uint8) {
 | 
			
		||||
	m = x
 | 
			
		||||
	if y > m {
 | 
			
		||||
		m = y
 | 
			
		||||
	}
 | 
			
		||||
	if z > m {
 | 
			
		||||
		m = z
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										277
									
								
								vendor/github.com/go-macaron/captcha/siprng.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								vendor/github.com/go-macaron/captcha/siprng.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,277 @@
 | 
			
		||||
// Copyright 2013 Beego Authors
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
 | 
			
		||||
// not use this file except in compliance with the License. You may obtain
 | 
			
		||||
// a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
// License for the specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
 | 
			
		||||
package captcha
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"io"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// siprng is PRNG based on SipHash-2-4.
 | 
			
		||||
type siprng struct {
 | 
			
		||||
	mu          sync.Mutex
 | 
			
		||||
	k0, k1, ctr uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// siphash implements SipHash-2-4, accepting a uint64 as a message.
 | 
			
		||||
func siphash(k0, k1, m uint64) uint64 {
 | 
			
		||||
	// Initialization.
 | 
			
		||||
	v0 := k0 ^ 0x736f6d6570736575
 | 
			
		||||
	v1 := k1 ^ 0x646f72616e646f6d
 | 
			
		||||
	v2 := k0 ^ 0x6c7967656e657261
 | 
			
		||||
	v3 := k1 ^ 0x7465646279746573
 | 
			
		||||
	t := uint64(8) << 56
 | 
			
		||||
 | 
			
		||||
	// Compression.
 | 
			
		||||
	v3 ^= m
 | 
			
		||||
 | 
			
		||||
	// Round 1.
 | 
			
		||||
	v0 += v1
 | 
			
		||||
	v1 = v1<<13 | v1>>(64-13)
 | 
			
		||||
	v1 ^= v0
 | 
			
		||||
	v0 = v0<<32 | v0>>(64-32)
 | 
			
		||||
 | 
			
		||||
	v2 += v3
 | 
			
		||||
	v3 = v3<<16 | v3>>(64-16)
 | 
			
		||||
	v3 ^= v2
 | 
			
		||||
 | 
			
		||||
	v0 += v3
 | 
			
		||||
	v3 = v3<<21 | v3>>(64-21)
 | 
			
		||||
	v3 ^= v0
 | 
			
		||||
 | 
			
		||||
	v2 += v1
 | 
			
		||||
	v1 = v1<<17 | v1>>(64-17)
 | 
			
		||||
	v1 ^= v2
 | 
			
		||||
	v2 = v2<<32 | v2>>(64-32)
 | 
			
		||||
 | 
			
		||||
	// Round 2.
 | 
			
		||||
	v0 += v1
 | 
			
		||||
	v1 = v1<<13 | v1>>(64-13)
 | 
			
		||||
	v1 ^= v0
 | 
			
		||||
	v0 = v0<<32 | v0>>(64-32)
 | 
			
		||||
 | 
			
		||||
	v2 += v3
 | 
			
		||||
	v3 = v3<<16 | v3>>(64-16)
 | 
			
		||||
	v3 ^= v2
 | 
			
		||||
 | 
			
		||||
	v0 += v3
 | 
			
		||||
	v3 = v3<<21 | v3>>(64-21)
 | 
			
		||||
	v3 ^= v0
 | 
			
		||||
 | 
			
		||||
	v2 += v1
 | 
			
		||||
	v1 = v1<<17 | v1>>(64-17)
 | 
			
		||||
	v1 ^= v2
 | 
			
		||||
	v2 = v2<<32 | v2>>(64-32)
 | 
			
		||||
 | 
			
		||||
	v0 ^= m
 | 
			
		||||
 | 
			
		||||
	// Compress last block.
 | 
			
		||||
	v3 ^= t
 | 
			
		||||
 | 
			
		||||
	// Round 1.
 | 
			
		||||
	v0 += v1
 | 
			
		||||
	v1 = v1<<13 | v1>>(64-13)
 | 
			
		||||
	v1 ^= v0
 | 
			
		||||
	v0 = v0<<32 | v0>>(64-32)
 | 
			
		||||
 | 
			
		||||
	v2 += v3
 | 
			
		||||
	v3 = v3<<16 | v3>>(64-16)
 | 
			
		||||
	v3 ^= v2
 | 
			
		||||
 | 
			
		||||
	v0 += v3
 | 
			
		||||
	v3 = v3<<21 | v3>>(64-21)
 | 
			
		||||
	v3 ^= v0
 | 
			
		||||
 | 
			
		||||
	v2 += v1
 | 
			
		||||
	v1 = v1<<17 | v1>>(64-17)
 | 
			
		||||
	v1 ^= v2
 | 
			
		||||
	v2 = v2<<32 | v2>>(64-32)
 | 
			
		||||
 | 
			
		||||
	// Round 2.
 | 
			
		||||
	v0 += v1
 | 
			
		||||
	v1 = v1<<13 | v1>>(64-13)
 | 
			
		||||
	v1 ^= v0
 | 
			
		||||
	v0 = v0<<32 | v0>>(64-32)
 | 
			
		||||
 | 
			
		||||
	v2 += v3
 | 
			
		||||
	v3 = v3<<16 | v3>>(64-16)
 | 
			
		||||
	v3 ^= v2
 | 
			
		||||
 | 
			
		||||
	v0 += v3
 | 
			
		||||
	v3 = v3<<21 | v3>>(64-21)
 | 
			
		||||
	v3 ^= v0
 | 
			
		||||
 | 
			
		||||
	v2 += v1
 | 
			
		||||
	v1 = v1<<17 | v1>>(64-17)
 | 
			
		||||
	v1 ^= v2
 | 
			
		||||
	v2 = v2<<32 | v2>>(64-32)
 | 
			
		||||
 | 
			
		||||
	v0 ^= t
 | 
			
		||||
 | 
			
		||||
	// Finalization.
 | 
			
		||||
	v2 ^= 0xff
 | 
			
		||||
 | 
			
		||||
	// Round 1.
 | 
			
		||||
	v0 += v1
 | 
			
		||||
	v1 = v1<<13 | v1>>(64-13)
 | 
			
		||||
	v1 ^= v0
 | 
			
		||||
	v0 = v0<<32 | v0>>(64-32)
 | 
			
		||||
 | 
			
		||||
	v2 += v3
 | 
			
		||||
	v3 = v3<<16 | v3>>(64-16)
 | 
			
		||||
	v3 ^= v2
 | 
			
		||||
 | 
			
		||||
	v0 += v3
 | 
			
		||||
	v3 = v3<<21 | v3>>(64-21)
 | 
			
		||||
	v3 ^= v0
 | 
			
		||||
 | 
			
		||||
	v2 += v1
 | 
			
		||||
	v1 = v1<<17 | v1>>(64-17)
 | 
			
		||||
	v1 ^= v2
 | 
			
		||||
	v2 = v2<<32 | v2>>(64-32)
 | 
			
		||||
 | 
			
		||||
	// Round 2.
 | 
			
		||||
	v0 += v1
 | 
			
		||||
	v1 = v1<<13 | v1>>(64-13)
 | 
			
		||||
	v1 ^= v0
 | 
			
		||||
	v0 = v0<<32 | v0>>(64-32)
 | 
			
		||||
 | 
			
		||||
	v2 += v3
 | 
			
		||||
	v3 = v3<<16 | v3>>(64-16)
 | 
			
		||||
	v3 ^= v2
 | 
			
		||||
 | 
			
		||||
	v0 += v3
 | 
			
		||||
	v3 = v3<<21 | v3>>(64-21)
 | 
			
		||||
	v3 ^= v0
 | 
			
		||||
 | 
			
		||||
	v2 += v1
 | 
			
		||||
	v1 = v1<<17 | v1>>(64-17)
 | 
			
		||||
	v1 ^= v2
 | 
			
		||||
	v2 = v2<<32 | v2>>(64-32)
 | 
			
		||||
 | 
			
		||||
	// Round 3.
 | 
			
		||||
	v0 += v1
 | 
			
		||||
	v1 = v1<<13 | v1>>(64-13)
 | 
			
		||||
	v1 ^= v0
 | 
			
		||||
	v0 = v0<<32 | v0>>(64-32)
 | 
			
		||||
 | 
			
		||||
	v2 += v3
 | 
			
		||||
	v3 = v3<<16 | v3>>(64-16)
 | 
			
		||||
	v3 ^= v2
 | 
			
		||||
 | 
			
		||||
	v0 += v3
 | 
			
		||||
	v3 = v3<<21 | v3>>(64-21)
 | 
			
		||||
	v3 ^= v0
 | 
			
		||||
 | 
			
		||||
	v2 += v1
 | 
			
		||||
	v1 = v1<<17 | v1>>(64-17)
 | 
			
		||||
	v1 ^= v2
 | 
			
		||||
	v2 = v2<<32 | v2>>(64-32)
 | 
			
		||||
 | 
			
		||||
	// Round 4.
 | 
			
		||||
	v0 += v1
 | 
			
		||||
	v1 = v1<<13 | v1>>(64-13)
 | 
			
		||||
	v1 ^= v0
 | 
			
		||||
	v0 = v0<<32 | v0>>(64-32)
 | 
			
		||||
 | 
			
		||||
	v2 += v3
 | 
			
		||||
	v3 = v3<<16 | v3>>(64-16)
 | 
			
		||||
	v3 ^= v2
 | 
			
		||||
 | 
			
		||||
	v0 += v3
 | 
			
		||||
	v3 = v3<<21 | v3>>(64-21)
 | 
			
		||||
	v3 ^= v0
 | 
			
		||||
 | 
			
		||||
	v2 += v1
 | 
			
		||||
	v1 = v1<<17 | v1>>(64-17)
 | 
			
		||||
	v1 ^= v2
 | 
			
		||||
	v2 = v2<<32 | v2>>(64-32)
 | 
			
		||||
 | 
			
		||||
	return v0 ^ v1 ^ v2 ^ v3
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// rekey sets a new PRNG key, which is read from crypto/rand.
 | 
			
		||||
func (p *siprng) rekey() {
 | 
			
		||||
	var k [16]byte
 | 
			
		||||
	if _, err := io.ReadFull(rand.Reader, k[:]); err != nil {
 | 
			
		||||
		panic(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	p.k0 = binary.LittleEndian.Uint64(k[0:8])
 | 
			
		||||
	p.k1 = binary.LittleEndian.Uint64(k[8:16])
 | 
			
		||||
	p.ctr = 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Uint64 returns a new pseudorandom uint64.
 | 
			
		||||
// It rekeys PRNG on the first call and every 64 MB of generated data.
 | 
			
		||||
func (p *siprng) Uint64() uint64 {
 | 
			
		||||
	p.mu.Lock()
 | 
			
		||||
	if p.ctr == 0 || p.ctr > 8*1024*1024 {
 | 
			
		||||
		p.rekey()
 | 
			
		||||
	}
 | 
			
		||||
	v := siphash(p.k0, p.k1, p.ctr)
 | 
			
		||||
	p.ctr++
 | 
			
		||||
	p.mu.Unlock()
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *siprng) Int63() int64 {
 | 
			
		||||
	return int64(p.Uint64() & 0x7fffffffffffffff)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *siprng) Uint32() uint32 {
 | 
			
		||||
	return uint32(p.Uint64())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *siprng) Int31() int32 {
 | 
			
		||||
	return int32(p.Uint32() & 0x7fffffff)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *siprng) Intn(n int) int {
 | 
			
		||||
	if n <= 0 {
 | 
			
		||||
		panic("invalid argument to Intn")
 | 
			
		||||
	}
 | 
			
		||||
	if n <= 1<<31-1 {
 | 
			
		||||
		return int(p.Int31n(int32(n)))
 | 
			
		||||
	}
 | 
			
		||||
	return int(p.Int63n(int64(n)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *siprng) Int63n(n int64) int64 {
 | 
			
		||||
	if n <= 0 {
 | 
			
		||||
		panic("invalid argument to Int63n")
 | 
			
		||||
	}
 | 
			
		||||
	max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
 | 
			
		||||
	v := p.Int63()
 | 
			
		||||
	for v > max {
 | 
			
		||||
		v = p.Int63()
 | 
			
		||||
	}
 | 
			
		||||
	return v % n
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *siprng) Int31n(n int32) int32 {
 | 
			
		||||
	if n <= 0 {
 | 
			
		||||
		panic("invalid argument to Int31n")
 | 
			
		||||
	}
 | 
			
		||||
	max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
 | 
			
		||||
	v := p.Int31()
 | 
			
		||||
	for v > max {
 | 
			
		||||
		v = p.Int31()
 | 
			
		||||
	}
 | 
			
		||||
	return v % n
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *siprng) Float64() float64 { return float64(p.Int63()) / (1 << 63) }
 | 
			
		||||
		Reference in New Issue
	
	Block a user