mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Convert captcha, cache, csrf as middlewares
This commit is contained in:
		
							
								
								
									
										30
									
								
								cmd/web.go
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								cmd/web.go
									
									
									
									
									
								
							@@ -14,6 +14,9 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/Unknwon/macaron"
 | 
						"github.com/Unknwon/macaron"
 | 
				
			||||||
	"github.com/codegangsta/cli"
 | 
						"github.com/codegangsta/cli"
 | 
				
			||||||
 | 
						"github.com/macaron-contrib/cache"
 | 
				
			||||||
 | 
						"github.com/macaron-contrib/captcha"
 | 
				
			||||||
 | 
						"github.com/macaron-contrib/csrf"
 | 
				
			||||||
	"github.com/macaron-contrib/i18n"
 | 
						"github.com/macaron-contrib/i18n"
 | 
				
			||||||
	"github.com/macaron-contrib/session"
 | 
						"github.com/macaron-contrib/session"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,7 +24,6 @@ import (
 | 
				
			|||||||
	"github.com/gogits/gogs/modules/auth/apiv1"
 | 
						"github.com/gogits/gogs/modules/auth/apiv1"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/avatar"
 | 
						"github.com/gogits/gogs/modules/avatar"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/base"
 | 
						"github.com/gogits/gogs/modules/base"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/captcha"
 | 
					 | 
				
			||||||
	"github.com/gogits/gogs/modules/log"
 | 
						"github.com/gogits/gogs/modules/log"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/middleware"
 | 
						"github.com/gogits/gogs/modules/middleware"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/middleware/binding"
 | 
						"github.com/gogits/gogs/modules/middleware/binding"
 | 
				
			||||||
@@ -78,10 +80,20 @@ func newMacaron() *macaron.Macaron {
 | 
				
			|||||||
		Names:    setting.Names,
 | 
							Names:    setting.Names,
 | 
				
			||||||
		Redirect: true,
 | 
							Redirect: true,
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
 | 
						m.Use(cache.Cacher(cache.Options{
 | 
				
			||||||
 | 
							Adapter:  setting.CacheAdapter,
 | 
				
			||||||
 | 
							Interval: setting.CacheInternal,
 | 
				
			||||||
 | 
							Conn:     setting.CacheConn,
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
						m.Use(captcha.Captchaer())
 | 
				
			||||||
	m.Use(session.Sessioner(session.Options{
 | 
						m.Use(session.Sessioner(session.Options{
 | 
				
			||||||
		Provider: setting.SessionProvider,
 | 
							Provider: setting.SessionProvider,
 | 
				
			||||||
		Config:   *setting.SessionConfig,
 | 
							Config:   *setting.SessionConfig,
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
 | 
						m.Use(csrf.Generate(csrf.Options{
 | 
				
			||||||
 | 
							Secret:    setting.SecretKey,
 | 
				
			||||||
 | 
							SetCookie: true,
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
	m.Use(middleware.Contexter())
 | 
						m.Use(middleware.Contexter())
 | 
				
			||||||
	return m
 | 
						return m
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -121,16 +133,12 @@ func runWeb(*cli.Context) {
 | 
				
			|||||||
			// Repositories.
 | 
								// Repositories.
 | 
				
			||||||
			r.Get("/orgs/:org/repos/search", v1.SearchOrgRepositoreis)
 | 
								r.Get("/orgs/:org/repos/search", v1.SearchOrgRepositoreis)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			r.Any("**", func(ctx *middleware.Context) {
 | 
								r.Any("/*", func(ctx *middleware.Context) {
 | 
				
			||||||
				ctx.JSON(404, &base.ApiJsonErr{"Not Found", v1.DOC_URL})
 | 
									ctx.JSON(404, &base.ApiJsonErr{"Not Found", v1.DOC_URL})
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	avt := avatar.CacheServer("public/img/avatar/", "public/img/avatar_default.jpg")
 | 
					 | 
				
			||||||
	os.MkdirAll("public/img/avatar/", os.ModePerm)
 | 
					 | 
				
			||||||
	m.Get("/avatar/:hash", avt.ServeHTTP)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// User routers.
 | 
						// User routers.
 | 
				
			||||||
	m.Group("/user", func(r *macaron.Router) {
 | 
						m.Group("/user", func(r *macaron.Router) {
 | 
				
			||||||
		r.Get("/login", user.SignIn)
 | 
							r.Get("/login", user.SignIn)
 | 
				
			||||||
@@ -165,10 +173,10 @@ func runWeb(*cli.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	m.Get("/user/:username", ignSignIn, user.Profile) // TODO: Legacy
 | 
						m.Get("/user/:username", ignSignIn, user.Profile) // TODO: Legacy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Captcha service.
 | 
						// Gravatar service.
 | 
				
			||||||
	cpt := captcha.NewCaptcha("/captcha/", setting.Cache)
 | 
						avt := avatar.CacheServer("public/img/avatar/", "public/img/avatar_default.jpg")
 | 
				
			||||||
	m.Map(cpt)
 | 
						os.MkdirAll("public/img/avatar/", os.ModePerm)
 | 
				
			||||||
	m.Get("/captcha/*", cpt.Handler)
 | 
						m.Get("/avatar/:hash", avt.ServeHTTP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true})
 | 
						adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -199,7 +207,7 @@ func runWeb(*cli.Context) {
 | 
				
			|||||||
	m.Get("/:username", ignSignIn, user.Profile)
 | 
						m.Get("/:username", ignSignIn, user.Profile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if macaron.Env == macaron.DEV {
 | 
						if macaron.Env == macaron.DEV {
 | 
				
			||||||
		m.Get("/template/**", dev.TemplatePreview)
 | 
							m.Get("/template/*", dev.TemplatePreview)
 | 
				
			||||||
		dev.RegisterDebugRoutes(m)
 | 
							dev.RegisterDebugRoutes(m)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								gogs.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								gogs.go
									
									
									
									
									
								
							@@ -17,7 +17,7 @@ import (
 | 
				
			|||||||
	"github.com/gogits/gogs/modules/setting"
 | 
						"github.com/gogits/gogs/modules/setting"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const APP_VER = "0.4.7.0730 Alpha"
 | 
					const APP_VER = "0.4.7.0731 Alpha"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	runtime.GOMAXPROCS(runtime.NumCPU())
 | 
						runtime.GOMAXPROCS(runtime.NumCPU())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,7 +103,6 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
 | 
				
			|||||||
	"ActionContent2Commits": ActionContent2Commits,
 | 
						"ActionContent2Commits": ActionContent2Commits,
 | 
				
			||||||
	"Oauth2Icon":            Oauth2Icon,
 | 
						"Oauth2Icon":            Oauth2Icon,
 | 
				
			||||||
	"Oauth2Name":            Oauth2Name,
 | 
						"Oauth2Name":            Oauth2Name,
 | 
				
			||||||
	"CreateCaptcha":         func() string { return "" },
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Actioner interface {
 | 
					type Actioner interface {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,6 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"hash"
 | 
						"hash"
 | 
				
			||||||
	"math"
 | 
						"math"
 | 
				
			||||||
	r "math/rand"
 | 
					 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -45,33 +44,6 @@ func GetRandomString(n int, alphabets ...byte) string {
 | 
				
			|||||||
	return string(bytes)
 | 
						return string(bytes)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RandomCreateBytes generate random []byte by specify chars.
 | 
					 | 
				
			||||||
func RandomCreateBytes(n int, alphabets ...byte) []byte {
 | 
					 | 
				
			||||||
	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
 | 
					 | 
				
			||||||
	var bytes = make([]byte, n)
 | 
					 | 
				
			||||||
	var randby bool
 | 
					 | 
				
			||||||
	if num, err := rand.Read(bytes); num != n || err != nil {
 | 
					 | 
				
			||||||
		r.Seed(time.Now().UnixNano())
 | 
					 | 
				
			||||||
		randby = true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for i, b := range bytes {
 | 
					 | 
				
			||||||
		if len(alphabets) == 0 {
 | 
					 | 
				
			||||||
			if randby {
 | 
					 | 
				
			||||||
				bytes[i] = alphanum[r.Intn(len(alphanum))]
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				bytes[i] = alphanum[b%byte(len(alphanum))]
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if randby {
 | 
					 | 
				
			||||||
				bytes[i] = alphabets[r.Intn(len(alphabets))]
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				bytes[i] = alphabets[b%byte(len(alphabets))]
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return bytes
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// http://code.google.com/p/go/source/browse/pbkdf2/pbkdf2.go?repo=crypto
 | 
					// http://code.google.com/p/go/source/browse/pbkdf2/pbkdf2.go?repo=crypto
 | 
				
			||||||
func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
 | 
					func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
 | 
				
			||||||
	prf := hmac.New(h, password)
 | 
						prf := hmac.New(h, password)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,201 +0,0 @@
 | 
				
			|||||||
// Copyright 2014 The Gogs Authors. 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 a middleware that provides captcha service for Macaron.
 | 
					 | 
				
			||||||
package captcha
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"html/template"
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"path"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/Unknwon/macaron"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/gogits/cache"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/gogits/gogs/modules/base"
 | 
					 | 
				
			||||||
	"github.com/gogits/gogs/modules/log"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	defaultChars = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	// default captcha attributes
 | 
					 | 
				
			||||||
	challengeNums    = 6
 | 
					 | 
				
			||||||
	expiration       = 600
 | 
					 | 
				
			||||||
	fieldIdName      = "captcha_id"
 | 
					 | 
				
			||||||
	fieldCaptchaName = "captcha"
 | 
					 | 
				
			||||||
	cachePrefix      = "captcha_"
 | 
					 | 
				
			||||||
	defaultURLPrefix = "/captcha/"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Captcha struct
 | 
					 | 
				
			||||||
type Captcha struct {
 | 
					 | 
				
			||||||
	store cache.Cache
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// url prefix for captcha image
 | 
					 | 
				
			||||||
	URLPrefix string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// specify captcha id input field name
 | 
					 | 
				
			||||||
	FieldIdName string
 | 
					 | 
				
			||||||
	// specify captcha result input field name
 | 
					 | 
				
			||||||
	FieldCaptchaName string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// captcha image width and height
 | 
					 | 
				
			||||||
	StdWidth  int
 | 
					 | 
				
			||||||
	StdHeight int
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// captcha chars nums
 | 
					 | 
				
			||||||
	ChallengeNums int
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// captcha expiration seconds
 | 
					 | 
				
			||||||
	Expiration int64
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// cache key prefix
 | 
					 | 
				
			||||||
	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() []byte {
 | 
					 | 
				
			||||||
	return base.RandomCreateBytes(c.ChallengeNums, defaultChars...)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// beego filter handler for serve captcha image
 | 
					 | 
				
			||||||
func (c *Captcha) Handler(ctx *macaron.Context) {
 | 
					 | 
				
			||||||
	var chars []byte
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	id := path.Base(ctx.Req.RequestURI)
 | 
					 | 
				
			||||||
	if i := strings.Index(id, "."); i != -1 {
 | 
					 | 
				
			||||||
		id = id[:i]
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	key := c.key(id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if v, ok := c.store.Get(key).([]byte); ok {
 | 
					 | 
				
			||||||
		chars = v
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		ctx.Status(404)
 | 
					 | 
				
			||||||
		ctx.Write([]byte("captcha not found"))
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// reload captcha
 | 
					 | 
				
			||||||
	if len(ctx.Query("reload")) > 0 {
 | 
					 | 
				
			||||||
		chars = c.genRandChars()
 | 
					 | 
				
			||||||
		if err := c.store.Put(key, chars, c.Expiration); err != nil {
 | 
					 | 
				
			||||||
			ctx.Status(500)
 | 
					 | 
				
			||||||
			ctx.Write([]byte("captcha reload error"))
 | 
					 | 
				
			||||||
			log.Error(4, "Reload Create Captcha Error: %v", err)
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	img := NewImage(chars, c.StdWidth, c.StdHeight)
 | 
					 | 
				
			||||||
	if _, err := img.WriteTo(ctx.RW()); err != nil {
 | 
					 | 
				
			||||||
		log.Error(4, "Write Captcha Image Error: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// tempalte func for output html
 | 
					 | 
				
			||||||
func (c *Captcha) CreateCaptchaHtml() template.HTML {
 | 
					 | 
				
			||||||
	value, err := c.CreateCaptcha()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Error(4, "Create Captcha Error: %v", err)
 | 
					 | 
				
			||||||
		return ""
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// create html
 | 
					 | 
				
			||||||
	return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">`+
 | 
					 | 
				
			||||||
		`<a class="captcha" href="javascript:">`+
 | 
					 | 
				
			||||||
		`<img onclick="this.src=('%s%s.png?reload='+(new Date()).getTime())" class="captcha-img" src="%s%s.png">`+
 | 
					 | 
				
			||||||
		`</a>`, c.FieldIdName, value, c.URLPrefix, value, c.URLPrefix, value))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// create a new captcha id
 | 
					 | 
				
			||||||
func (c *Captcha) CreateCaptcha() (string, error) {
 | 
					 | 
				
			||||||
	// generate captcha id
 | 
					 | 
				
			||||||
	id := string(base.RandomCreateBytes(15))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// get the captcha chars
 | 
					 | 
				
			||||||
	chars := c.genRandChars()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// save to store
 | 
					 | 
				
			||||||
	if err := c.store.Put(c.key(id), chars, c.Expiration); err != nil {
 | 
					 | 
				
			||||||
		return "", err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return id, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// verify from a request
 | 
					 | 
				
			||||||
func (c *Captcha) VerifyReq(req *http.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) (success bool) {
 | 
					 | 
				
			||||||
	if len(challenge) == 0 || len(id) == 0 {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var chars []byte
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	key := c.key(id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if v, ok := c.store.Get(key).([]byte); ok && len(v) == len(challenge) {
 | 
					 | 
				
			||||||
		chars = v
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	defer func() {
 | 
					 | 
				
			||||||
		// finally remove it
 | 
					 | 
				
			||||||
		c.store.Delete(key)
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// verify challenge
 | 
					 | 
				
			||||||
	for i, c := range chars {
 | 
					 | 
				
			||||||
		if c != challenge[i]-48 {
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// create a new captcha.Captcha
 | 
					 | 
				
			||||||
func NewCaptcha(urlPrefix string, store cache.Cache) *Captcha {
 | 
					 | 
				
			||||||
	cpt := &Captcha{}
 | 
					 | 
				
			||||||
	cpt.store = store
 | 
					 | 
				
			||||||
	cpt.FieldIdName = fieldIdName
 | 
					 | 
				
			||||||
	cpt.FieldCaptchaName = fieldCaptchaName
 | 
					 | 
				
			||||||
	cpt.ChallengeNums = challengeNums
 | 
					 | 
				
			||||||
	cpt.Expiration = expiration
 | 
					 | 
				
			||||||
	cpt.CachePrefix = cachePrefix
 | 
					 | 
				
			||||||
	cpt.StdWidth = stdWidth
 | 
					 | 
				
			||||||
	cpt.StdHeight = stdHeight
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(urlPrefix) == 0 {
 | 
					 | 
				
			||||||
		urlPrefix = defaultURLPrefix
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if urlPrefix[len(urlPrefix)-1] != '/' {
 | 
					 | 
				
			||||||
		urlPrefix += "/"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cpt.URLPrefix = urlPrefix
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	base.TemplateFuncs["CreateCaptcha"] = cpt.CreateCaptchaHtml
 | 
					 | 
				
			||||||
	return cpt
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,487 +0,0 @@
 | 
				
			|||||||
// Copyright 2014 The Gogs Authors. 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 (
 | 
					 | 
				
			||||||
	"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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,42 +0,0 @@
 | 
				
			|||||||
// Copyright 2014 The Gogs Authors. 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 (
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/gogits/gogs/modules/base"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type byteCounter struct {
 | 
					 | 
				
			||||||
	n int64
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (bc *byteCounter) Write(b []byte) (int, error) {
 | 
					 | 
				
			||||||
	bc.n += int64(len(b))
 | 
					 | 
				
			||||||
	return len(b), nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func BenchmarkNewImage(b *testing.B) {
 | 
					 | 
				
			||||||
	b.StopTimer()
 | 
					 | 
				
			||||||
	d := base.RandomCreateBytes(challengeNums, defaultChars...)
 | 
					 | 
				
			||||||
	b.StartTimer()
 | 
					 | 
				
			||||||
	for i := 0; i < b.N; i++ {
 | 
					 | 
				
			||||||
		NewImage(d, stdWidth, stdHeight)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func BenchmarkImageWriteTo(b *testing.B) {
 | 
					 | 
				
			||||||
	b.StopTimer()
 | 
					 | 
				
			||||||
	d := base.RandomCreateBytes(challengeNums, defaultChars...)
 | 
					 | 
				
			||||||
	b.StartTimer()
 | 
					 | 
				
			||||||
	counter := &byteCounter{}
 | 
					 | 
				
			||||||
	for i := 0; i < b.N; i++ {
 | 
					 | 
				
			||||||
		img := NewImage(d, stdWidth, stdHeight)
 | 
					 | 
				
			||||||
		img.WriteTo(counter)
 | 
					 | 
				
			||||||
		b.SetBytes(counter.n)
 | 
					 | 
				
			||||||
		counter.n = 0
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,267 +0,0 @@
 | 
				
			|||||||
// Copyright 2014 The Gogs Authors. 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 (
 | 
					 | 
				
			||||||
	"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) }
 | 
					 | 
				
			||||||
@@ -1,23 +0,0 @@
 | 
				
			|||||||
// Copyright 2014 The Gogs Authors. 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 "testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestSiphash(t *testing.T) {
 | 
					 | 
				
			||||||
	good := uint64(0xe849e8bb6ffe2567)
 | 
					 | 
				
			||||||
	cur := siphash(0, 0, 0)
 | 
					 | 
				
			||||||
	if cur != good {
 | 
					 | 
				
			||||||
		t.Fatalf("siphash: expected %x, got %x", good, cur)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func BenchmarkSiprng(b *testing.B) {
 | 
					 | 
				
			||||||
	b.SetBytes(8)
 | 
					 | 
				
			||||||
	p := &siprng{}
 | 
					 | 
				
			||||||
	for i := 0; i < b.N; i++ {
 | 
					 | 
				
			||||||
		p.Uint64()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Unknwon/macaron"
 | 
						"github.com/Unknwon/macaron"
 | 
				
			||||||
 | 
						"github.com/macaron-contrib/csrf"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gogits/gogs/modules/setting"
 | 
						"github.com/gogits/gogs/modules/setting"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -34,9 +35,11 @@ func Toggle(options *ToggleOptions) macaron.Handler {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if !options.DisableCsrf && ctx.Req.Method == "POST" && !ctx.CsrfTokenValid() {
 | 
							if !options.SignOutRequire && !options.DisableCsrf && ctx.Req.Method == "POST" {
 | 
				
			||||||
			ctx.Error(403, "CSRF token does not match")
 | 
								csrf.Validate(ctx.Context, ctx.csrf)
 | 
				
			||||||
			return
 | 
								if ctx.Written() {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if options.SignInRequire {
 | 
							if options.SignInRequire {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,8 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Unknwon/macaron"
 | 
						"github.com/Unknwon/macaron"
 | 
				
			||||||
 | 
						"github.com/macaron-contrib/cache"
 | 
				
			||||||
 | 
						"github.com/macaron-contrib/csrf"
 | 
				
			||||||
	"github.com/macaron-contrib/i18n"
 | 
						"github.com/macaron-contrib/i18n"
 | 
				
			||||||
	"github.com/macaron-contrib/session"
 | 
						"github.com/macaron-contrib/session"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,14 +31,14 @@ import (
 | 
				
			|||||||
type Context struct {
 | 
					type Context struct {
 | 
				
			||||||
	*macaron.Context
 | 
						*macaron.Context
 | 
				
			||||||
	i18n.Locale
 | 
						i18n.Locale
 | 
				
			||||||
 | 
						Cache   cache.Cache
 | 
				
			||||||
 | 
						csrf    csrf.CSRF
 | 
				
			||||||
	Flash   *session.Flash
 | 
						Flash   *session.Flash
 | 
				
			||||||
	Session session.Store
 | 
						Session session.Store
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	User     *models.User
 | 
						User     *models.User
 | 
				
			||||||
	IsSigned bool
 | 
						IsSigned bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	csrfToken string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Repo struct {
 | 
						Repo struct {
 | 
				
			||||||
		IsOwner     bool
 | 
							IsOwner     bool
 | 
				
			||||||
		IsTrueOwner bool
 | 
							IsTrueOwner bool
 | 
				
			||||||
@@ -70,10 +72,6 @@ func (ctx *Context) Query(name string) string {
 | 
				
			|||||||
	return ctx.Req.Form.Get(name)
 | 
						return ctx.Req.Form.Get(name)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// func (ctx *Context) Param(name string) string {
 | 
					 | 
				
			||||||
// 	return ctx.p[name]
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// HasError returns true if error occurs in form validation.
 | 
					// HasError returns true if error occurs in form validation.
 | 
				
			||||||
func (ctx *Context) HasApiError() bool {
 | 
					func (ctx *Context) HasApiError() bool {
 | 
				
			||||||
	hasErr, ok := ctx.Data["HasError"]
 | 
						hasErr, ok := ctx.Data["HasError"]
 | 
				
			||||||
@@ -131,33 +129,6 @@ func (ctx *Context) Handle(status int, title string, err error) {
 | 
				
			|||||||
	ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status)))
 | 
						ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status)))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ctx *Context) CsrfToken() string {
 | 
					 | 
				
			||||||
	if len(ctx.csrfToken) > 0 {
 | 
					 | 
				
			||||||
		return ctx.csrfToken
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	token := ctx.GetCookie("_csrf")
 | 
					 | 
				
			||||||
	if len(token) == 0 {
 | 
					 | 
				
			||||||
		token = base.GetRandomString(30)
 | 
					 | 
				
			||||||
		ctx.SetCookie("_csrf", token)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ctx.csrfToken = token
 | 
					 | 
				
			||||||
	return token
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *Context) CsrfTokenValid() bool {
 | 
					 | 
				
			||||||
	token := ctx.Query("_csrf")
 | 
					 | 
				
			||||||
	if token == "" {
 | 
					 | 
				
			||||||
		token = ctx.Req.Header.Get("X-Csrf-Token")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if token == "" {
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	} else if ctx.csrfToken != token {
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *Context) ServeFile(file string, names ...string) {
 | 
					func (ctx *Context) ServeFile(file string, names ...string) {
 | 
				
			||||||
	var name string
 | 
						var name string
 | 
				
			||||||
	if len(names) > 0 {
 | 
						if len(names) > 0 {
 | 
				
			||||||
@@ -195,14 +166,15 @@ func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interfa
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Contexter initializes a classic context for a request.
 | 
					// Contexter initializes a classic context for a request.
 | 
				
			||||||
func Contexter() macaron.Handler {
 | 
					func Contexter() macaron.Handler {
 | 
				
			||||||
	return func(c *macaron.Context, l i18n.Locale, sess session.Store, f *session.Flash) {
 | 
						return func(c *macaron.Context, l i18n.Locale, cache cache.Cache, sess session.Store, f *session.Flash, x csrf.CSRF) {
 | 
				
			||||||
		ctx := &Context{
 | 
							ctx := &Context{
 | 
				
			||||||
			Context: c,
 | 
								Context: c,
 | 
				
			||||||
			Locale:  l,
 | 
								Locale:  l,
 | 
				
			||||||
 | 
								Cache:   cache,
 | 
				
			||||||
 | 
								csrf:    x,
 | 
				
			||||||
			Flash:   f,
 | 
								Flash:   f,
 | 
				
			||||||
			Session: sess,
 | 
								Session: sess,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Cache:  setting.Cache,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Compute current URL for real-time change language.
 | 
							// Compute current URL for real-time change language.
 | 
				
			||||||
		link := ctx.Req.RequestURI
 | 
							link := ctx.Req.RequestURI
 | 
				
			||||||
@@ -231,9 +203,8 @@ func Contexter() macaron.Handler {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// get or create csrf token
 | 
							ctx.Data["CsrfToken"] = x.GetToken()
 | 
				
			||||||
		ctx.Data["CsrfToken"] = ctx.CsrfToken()
 | 
							ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + x.GetToken() + `">`)
 | 
				
			||||||
		ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + ctx.csrfToken + `">`)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		c.Map(ctx)
 | 
							c.Map(ctx)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,8 +16,6 @@ import (
 | 
				
			|||||||
	"github.com/Unknwon/goconfig"
 | 
						"github.com/Unknwon/goconfig"
 | 
				
			||||||
	"github.com/macaron-contrib/session"
 | 
						"github.com/macaron-contrib/session"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gogits/cache"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/gogits/gogs/modules/log"
 | 
						"github.com/gogits/gogs/modules/log"
 | 
				
			||||||
	// "github.com/gogits/gogs-ng/modules/ssh"
 | 
						// "github.com/gogits/gogs-ng/modules/ssh"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -80,9 +78,9 @@ var (
 | 
				
			|||||||
	AttachmentEnabled      bool
 | 
						AttachmentEnabled      bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Cache settings.
 | 
						// Cache settings.
 | 
				
			||||||
	Cache        cache.Cache
 | 
						CacheAdapter  string
 | 
				
			||||||
	CacheAdapter string
 | 
						CacheInternal int
 | 
				
			||||||
	CacheConfig  string
 | 
						CacheConn     string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	EnableRedis    bool
 | 
						EnableRedis    bool
 | 
				
			||||||
	EnableMemcache bool
 | 
						EnableMemcache bool
 | 
				
			||||||
@@ -325,20 +323,13 @@ func newCacheService() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	switch CacheAdapter {
 | 
						switch CacheAdapter {
 | 
				
			||||||
	case "memory":
 | 
						case "memory":
 | 
				
			||||||
		CacheConfig = fmt.Sprintf(`{"interval":%d}`, Cfg.MustInt("cache", "INTERVAL", 60))
 | 
							CacheInternal = Cfg.MustInt("cache", "INTERVAL", 60)
 | 
				
			||||||
	case "redis", "memcache":
 | 
						case "redis", "memcache":
 | 
				
			||||||
		CacheConfig = fmt.Sprintf(`{"conn":"%s"}`, strings.Trim(Cfg.MustValue("cache", "HOST"), "\" "))
 | 
							CacheConn = strings.Trim(Cfg.MustValue("cache", "HOST"), "\" ")
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		log.Fatal(4, "Unknown cache adapter: %s", CacheAdapter)
 | 
							log.Fatal(4, "Unknown cache adapter: %s", CacheAdapter)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var err error
 | 
					 | 
				
			||||||
	Cache, err = cache.NewCache(CacheAdapter, CacheConfig)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatal(4, "Init cache system failed, adapter: %s, config: %s, %v\n",
 | 
					 | 
				
			||||||
			CacheAdapter, CacheConfig, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	log.Info("Cache Service Enabled")
 | 
						log.Info("Cache Service Enabled")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -263,7 +263,8 @@ func Config(ctx *middleware.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Data["CacheAdapter"] = setting.CacheAdapter
 | 
						ctx.Data["CacheAdapter"] = setting.CacheAdapter
 | 
				
			||||||
	ctx.Data["CacheConfig"] = setting.CacheConfig
 | 
						ctx.Data["CacheInternal"] = setting.CacheInternal
 | 
				
			||||||
 | 
						ctx.Data["CacheConn"] = setting.CacheConn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Data["SessionProvider"] = setting.SessionProvider
 | 
						ctx.Data["SessionProvider"] = setting.SessionProvider
 | 
				
			||||||
	ctx.Data["SessionConfig"] = setting.SessionConfig
 | 
						ctx.Data["SessionConfig"] = setting.SessionConfig
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,11 @@ import (
 | 
				
			|||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/macaron-contrib/captcha"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gogits/gogs/models"
 | 
						"github.com/gogits/gogs/models"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/auth"
 | 
						"github.com/gogits/gogs/modules/auth"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/base"
 | 
						"github.com/gogits/gogs/modules/base"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/captcha"
 | 
					 | 
				
			||||||
	"github.com/gogits/gogs/modules/log"
 | 
						"github.com/gogits/gogs/modules/log"
 | 
				
			||||||
	// "github.com/gogits/gogs/modules/mailer"
 | 
						// "github.com/gogits/gogs/modules/mailer"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/middleware"
 | 
						"github.com/gogits/gogs/modules/middleware"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1 @@
 | 
				
			|||||||
0.4.7.0730 Alpha
 | 
					0.4.7.0731 Alpha
 | 
				
			||||||
@@ -2,7 +2,6 @@
 | 
				
			|||||||
{{template "ng/base/header" .}}
 | 
					{{template "ng/base/header" .}}
 | 
				
			||||||
<div id="sign-wrapper">
 | 
					<div id="sign-wrapper">
 | 
				
			||||||
    <form class="form-align form panel sign-panel sign-form container panel-radius" id="sign-up-form" action="/user/login" method="post">
 | 
					    <form class="form-align form panel sign-panel sign-form container panel-radius" id="sign-up-form" action="/user/login" method="post">
 | 
				
			||||||
        {{.CsrfTokenHtml}}
 | 
					 | 
				
			||||||
        <div class="panel-header">
 | 
					        <div class="panel-header">
 | 
				
			||||||
            <h2>{{.i18n.Tr "sign_in"}}</h2>
 | 
					            <h2>{{.i18n.Tr "sign_in"}}</h2>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,6 @@
 | 
				
			|||||||
{{template "ng/base/header" .}}
 | 
					{{template "ng/base/header" .}}
 | 
				
			||||||
<div id="sign-wrapper">
 | 
					<div id="sign-wrapper">
 | 
				
			||||||
    <form class="form-align form panel panel-radius sign-panel sign-form container" id="sign-up-form" action="/user/sign_up" method="post">
 | 
					    <form class="form-align form panel panel-radius sign-panel sign-form container" id="sign-up-form" action="/user/sign_up" method="post">
 | 
				
			||||||
        {{.CsrfTokenHtml}}
 | 
					 | 
				
			||||||
        <div class="panel-header">
 | 
					        <div class="panel-header">
 | 
				
			||||||
            <h2>{{.i18n.Tr "sign_up"}}</h2>
 | 
					            <h2>{{.i18n.Tr "sign_up"}}</h2>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
@@ -29,7 +28,7 @@
 | 
				
			|||||||
            </p>
 | 
					            </p>
 | 
				
			||||||
            <p class="field">
 | 
					            <p class="field">
 | 
				
			||||||
                <label></label>
 | 
					                <label></label>
 | 
				
			||||||
                {{CreateCaptcha}}
 | 
					                {{.Captcha.CreateHtml}}
 | 
				
			||||||
            </p>
 | 
					            </p>
 | 
				
			||||||
            <p class="field">
 | 
					            <p class="field">
 | 
				
			||||||
                <label class="req" for="captcha">{{.i18n.Tr "captcha"}}</label>
 | 
					                <label class="req" for="captcha">{{.i18n.Tr "captcha"}}</label>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user