From 7bbf644dd5eaca77c3e8df57419180486bda0fc2 Mon Sep 17 00:00:00 2001
From: Unknwon <joe2010xtmf@163.com>
Date: Thu, 31 Jul 2014 17:25:34 -0400
Subject: [PATCH] Convert captcha, cache, csrf as middlewares

---
 cmd/web.go                     |  30 +-
 gogs.go                        |   2 +-
 modules/base/template.go       |   1 -
 modules/base/tool.go           |  28 --
 modules/captcha/captcha.go     | 201 --------------
 modules/captcha/image.go       | 487 ---------------------------------
 modules/captcha/image_test.go  |  42 ---
 modules/captcha/siprng.go      | 267 ------------------
 modules/captcha/siprng_test.go |  23 --
 modules/middleware/auth.go     |   9 +-
 modules/middleware/context.go  |  47 +---
 modules/setting/setting.go     |  19 +-
 routers/admin/admin.go         |   3 +-
 routers/user/auth.go           |   3 +-
 templates/.VERSION             |   2 +-
 templates/user/signin.tmpl     |   1 -
 templates/user/signup.tmpl     |   3 +-
 17 files changed, 46 insertions(+), 1122 deletions(-)
 delete mode 100644 modules/captcha/captcha.go
 delete mode 100644 modules/captcha/image.go
 delete mode 100644 modules/captcha/image_test.go
 delete mode 100644 modules/captcha/siprng.go
 delete mode 100644 modules/captcha/siprng_test.go

diff --git a/cmd/web.go b/cmd/web.go
index a0690cda25..bd2eb79dbd 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -14,6 +14,9 @@ import (
 
 	"github.com/Unknwon/macaron"
 	"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/session"
 
@@ -21,7 +24,6 @@ import (
 	"github.com/gogits/gogs/modules/auth/apiv1"
 	"github.com/gogits/gogs/modules/avatar"
 	"github.com/gogits/gogs/modules/base"
-	"github.com/gogits/gogs/modules/captcha"
 	"github.com/gogits/gogs/modules/log"
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware/binding"
@@ -78,10 +80,20 @@ func newMacaron() *macaron.Macaron {
 		Names:    setting.Names,
 		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{
 		Provider: setting.SessionProvider,
 		Config:   *setting.SessionConfig,
 	}))
+	m.Use(csrf.Generate(csrf.Options{
+		Secret:    setting.SecretKey,
+		SetCookie: true,
+	}))
 	m.Use(middleware.Contexter())
 	return m
 }
@@ -121,16 +133,12 @@ func runWeb(*cli.Context) {
 			// Repositories.
 			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})
 			})
 		})
 	})
 
-	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.
 	m.Group("/user", func(r *macaron.Router) {
 		r.Get("/login", user.SignIn)
@@ -165,10 +173,10 @@ func runWeb(*cli.Context) {
 
 	m.Get("/user/:username", ignSignIn, user.Profile) // TODO: Legacy
 
-	// Captcha service.
-	cpt := captcha.NewCaptcha("/captcha/", setting.Cache)
-	m.Map(cpt)
-	m.Get("/captcha/*", cpt.Handler)
+	// Gravatar service.
+	avt := avatar.CacheServer("public/img/avatar/", "public/img/avatar_default.jpg")
+	os.MkdirAll("public/img/avatar/", os.ModePerm)
+	m.Get("/avatar/:hash", avt.ServeHTTP)
 
 	adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true})
 
@@ -199,7 +207,7 @@ func runWeb(*cli.Context) {
 	m.Get("/:username", ignSignIn, user.Profile)
 
 	if macaron.Env == macaron.DEV {
-		m.Get("/template/**", dev.TemplatePreview)
+		m.Get("/template/*", dev.TemplatePreview)
 		dev.RegisterDebugRoutes(m)
 	}
 
diff --git a/gogs.go b/gogs.go
index e55d387288..8e3635a1e5 100644
--- a/gogs.go
+++ b/gogs.go
@@ -17,7 +17,7 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 )
 
-const APP_VER = "0.4.7.0730 Alpha"
+const APP_VER = "0.4.7.0731 Alpha"
 
 func init() {
 	runtime.GOMAXPROCS(runtime.NumCPU())
diff --git a/modules/base/template.go b/modules/base/template.go
index b9968bae65..51b1dfff01 100644
--- a/modules/base/template.go
+++ b/modules/base/template.go
@@ -103,7 +103,6 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
 	"ActionContent2Commits": ActionContent2Commits,
 	"Oauth2Icon":            Oauth2Icon,
 	"Oauth2Name":            Oauth2Name,
-	"CreateCaptcha":         func() string { return "" },
 }
 
 type Actioner interface {
diff --git a/modules/base/tool.go b/modules/base/tool.go
index 830c37f697..a2a155d61f 100644
--- a/modules/base/tool.go
+++ b/modules/base/tool.go
@@ -13,7 +13,6 @@ import (
 	"fmt"
 	"hash"
 	"math"
-	r "math/rand"
 	"strings"
 	"time"
 
@@ -45,33 +44,6 @@ func GetRandomString(n int, alphabets ...byte) string {
 	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
 func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
 	prf := hmac.New(h, password)
diff --git a/modules/captcha/captcha.go b/modules/captcha/captcha.go
deleted file mode 100644
index e43e09dc59..0000000000
--- a/modules/captcha/captcha.go
+++ /dev/null
@@ -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
-}
diff --git a/modules/captcha/image.go b/modules/captcha/image.go
deleted file mode 100644
index c9972ba2c3..0000000000
--- a/modules/captcha/image.go
+++ /dev/null
@@ -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
-}
diff --git a/modules/captcha/image_test.go b/modules/captcha/image_test.go
deleted file mode 100644
index 35810d0c72..0000000000
--- a/modules/captcha/image_test.go
+++ /dev/null
@@ -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
-	}
-}
diff --git a/modules/captcha/siprng.go b/modules/captcha/siprng.go
deleted file mode 100644
index c059b9f7bf..0000000000
--- a/modules/captcha/siprng.go
+++ /dev/null
@@ -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) }
diff --git a/modules/captcha/siprng_test.go b/modules/captcha/siprng_test.go
deleted file mode 100644
index 3b10fe58bf..0000000000
--- a/modules/captcha/siprng_test.go
+++ /dev/null
@@ -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()
-	}
-}
diff --git a/modules/middleware/auth.go b/modules/middleware/auth.go
index 741337da0b..29a2d68110 100644
--- a/modules/middleware/auth.go
+++ b/modules/middleware/auth.go
@@ -9,6 +9,7 @@ import (
 	"strings"
 
 	"github.com/Unknwon/macaron"
+	"github.com/macaron-contrib/csrf"
 
 	"github.com/gogits/gogs/modules/setting"
 )
@@ -34,9 +35,11 @@ func Toggle(options *ToggleOptions) macaron.Handler {
 			return
 		}
 
-		if !options.DisableCsrf && ctx.Req.Method == "POST" && !ctx.CsrfTokenValid() {
-			ctx.Error(403, "CSRF token does not match")
-			return
+		if !options.SignOutRequire && !options.DisableCsrf && ctx.Req.Method == "POST" {
+			csrf.Validate(ctx.Context, ctx.csrf)
+			if ctx.Written() {
+				return
+			}
 		}
 
 		if options.SignInRequire {
diff --git a/modules/middleware/context.go b/modules/middleware/context.go
index ee203b762d..5300539d42 100644
--- a/modules/middleware/context.go
+++ b/modules/middleware/context.go
@@ -14,6 +14,8 @@ import (
 	"time"
 
 	"github.com/Unknwon/macaron"
+	"github.com/macaron-contrib/cache"
+	"github.com/macaron-contrib/csrf"
 	"github.com/macaron-contrib/i18n"
 	"github.com/macaron-contrib/session"
 
@@ -29,14 +31,14 @@ import (
 type Context struct {
 	*macaron.Context
 	i18n.Locale
+	Cache   cache.Cache
+	csrf    csrf.CSRF
 	Flash   *session.Flash
 	Session session.Store
 
 	User     *models.User
 	IsSigned bool
 
-	csrfToken string
-
 	Repo struct {
 		IsOwner     bool
 		IsTrueOwner bool
@@ -70,10 +72,6 @@ func (ctx *Context) Query(name string) string {
 	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.
 func (ctx *Context) HasApiError() bool {
 	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)))
 }
 
-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) {
 	var name string
 	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.
 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{
 			Context: c,
 			Locale:  l,
+			Cache:   cache,
+			csrf:    x,
 			Flash:   f,
 			Session: sess,
 		}
-		// Cache:  setting.Cache,
 
 		// Compute current URL for real-time change language.
 		link := ctx.Req.RequestURI
@@ -231,9 +203,8 @@ func Contexter() macaron.Handler {
 			}
 		}
 
-		// get or create csrf token
-		ctx.Data["CsrfToken"] = ctx.CsrfToken()
-		ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + ctx.csrfToken + `">`)
+		ctx.Data["CsrfToken"] = x.GetToken()
+		ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + x.GetToken() + `">`)
 
 		c.Map(ctx)
 	}
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index dbd01051bf..24d041eae5 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -16,8 +16,6 @@ import (
 	"github.com/Unknwon/goconfig"
 	"github.com/macaron-contrib/session"
 
-	"github.com/gogits/cache"
-
 	"github.com/gogits/gogs/modules/log"
 	// "github.com/gogits/gogs-ng/modules/ssh"
 )
@@ -80,9 +78,9 @@ var (
 	AttachmentEnabled      bool
 
 	// Cache settings.
-	Cache        cache.Cache
-	CacheAdapter string
-	CacheConfig  string
+	CacheAdapter  string
+	CacheInternal int
+	CacheConn     string
 
 	EnableRedis    bool
 	EnableMemcache bool
@@ -325,20 +323,13 @@ func newCacheService() {
 
 	switch CacheAdapter {
 	case "memory":
-		CacheConfig = fmt.Sprintf(`{"interval":%d}`, Cfg.MustInt("cache", "INTERVAL", 60))
+		CacheInternal = Cfg.MustInt("cache", "INTERVAL", 60)
 	case "redis", "memcache":
-		CacheConfig = fmt.Sprintf(`{"conn":"%s"}`, strings.Trim(Cfg.MustValue("cache", "HOST"), "\" "))
+		CacheConn = strings.Trim(Cfg.MustValue("cache", "HOST"), "\" ")
 	default:
 		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")
 }
 
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index efdc803b95..4091cb8999 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -263,7 +263,8 @@ func Config(ctx *middleware.Context) {
 	}
 
 	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["SessionConfig"] = setting.SessionConfig
diff --git a/routers/user/auth.go b/routers/user/auth.go
index 163df34a4a..90194e0c46 100644
--- a/routers/user/auth.go
+++ b/routers/user/auth.go
@@ -8,10 +8,11 @@ import (
 	"net/url"
 	"strings"
 
+	"github.com/macaron-contrib/captcha"
+
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/auth"
 	"github.com/gogits/gogs/modules/base"
-	"github.com/gogits/gogs/modules/captcha"
 	"github.com/gogits/gogs/modules/log"
 	// "github.com/gogits/gogs/modules/mailer"
 	"github.com/gogits/gogs/modules/middleware"
diff --git a/templates/.VERSION b/templates/.VERSION
index df75938808..82b0c22eb5 100644
--- a/templates/.VERSION
+++ b/templates/.VERSION
@@ -1 +1 @@
-0.4.7.0730 Alpha
\ No newline at end of file
+0.4.7.0731 Alpha
\ No newline at end of file
diff --git a/templates/user/signin.tmpl b/templates/user/signin.tmpl
index a66dd285b2..8b67dbd86e 100644
--- a/templates/user/signin.tmpl
+++ b/templates/user/signin.tmpl
@@ -2,7 +2,6 @@
 {{template "ng/base/header" .}}
 <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">
-        {{.CsrfTokenHtml}}
         <div class="panel-header">
             <h2>{{.i18n.Tr "sign_in"}}</h2>
         </div>
diff --git a/templates/user/signup.tmpl b/templates/user/signup.tmpl
index 5b52850c0f..723314956c 100644
--- a/templates/user/signup.tmpl
+++ b/templates/user/signup.tmpl
@@ -2,7 +2,6 @@
 {{template "ng/base/header" .}}
 <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">
-        {{.CsrfTokenHtml}}
         <div class="panel-header">
             <h2>{{.i18n.Tr "sign_up"}}</h2>
         </div>
@@ -29,7 +28,7 @@
             </p>
             <p class="field">
                 <label></label>
-                {{CreateCaptcha}}
+                {{.Captcha.CreateHtml}}
             </p>
             <p class="field">
                 <label class="req" for="captcha">{{.i18n.Tr "captcha"}}</label>