123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- package csrf
- import (
- "net/http"
- "time"
- "github.com/Unknwon/com"
- "github.com/go-macaron/session"
- "gopkg.in/macaron.v1"
- )
- const _VERSION = "0.1.0"
- func Version() string {
- return _VERSION
- }
- type CSRF interface {
-
- GetHeaderName() string
-
- GetFormName() string
-
- GetCookieName() string
-
- GetCookiePath() string
-
- GetToken() string
-
- ValidToken(t string) bool
-
- Error(w http.ResponseWriter)
- }
- type csrf struct {
-
- Header string
-
- Form string
-
- Cookie string
-
- CookiePath string
-
- Token string
-
- ID string
-
- Secret string
-
- ErrorFunc func(w http.ResponseWriter)
- }
- func (c *csrf) GetHeaderName() string {
- return c.Header
- }
- func (c *csrf) GetFormName() string {
- return c.Form
- }
- func (c *csrf) GetCookieName() string {
- return c.Cookie
- }
- func (c *csrf) GetCookiePath() string {
- return c.CookiePath
- }
- func (c *csrf) GetToken() string {
- return c.Token
- }
- func (c *csrf) ValidToken(t string) bool {
- return ValidToken(t, c.Secret, c.ID, "POST")
- }
- func (c *csrf) Error(w http.ResponseWriter) {
- c.ErrorFunc(w)
- }
- type Options struct {
-
- Secret string
-
- Header string
-
- Form string
-
- Cookie string
-
- CookiePath string
-
- SessionKey string
-
- oldSeesionKey string
-
- SetHeader bool
-
- SetCookie bool
-
- Secure bool
-
- Origin bool
-
- ErrorFunc func(w http.ResponseWriter)
- }
- func prepareOptions(options []Options) Options {
- var opt Options
- if len(options) > 0 {
- opt = options[0]
- }
-
- if len(opt.Secret) == 0 {
- opt.Secret = string(com.RandomCreateBytes(10))
- }
- if len(opt.Header) == 0 {
- opt.Header = "X-CSRFToken"
- }
- if len(opt.Form) == 0 {
- opt.Form = "_csrf"
- }
- if len(opt.Cookie) == 0 {
- opt.Cookie = "_csrf"
- }
- if len(opt.CookiePath) == 0 {
- opt.CookiePath = "/"
- }
- if len(opt.SessionKey) == 0 {
- opt.SessionKey = "uid"
- }
- opt.oldSeesionKey = "_old_" + opt.SessionKey
- if opt.ErrorFunc == nil {
- opt.ErrorFunc = func(w http.ResponseWriter) {
- http.Error(w, "Invalid csrf token.", http.StatusBadRequest)
- }
- }
- return opt
- }
- func Generate(options ...Options) macaron.Handler {
- opt := prepareOptions(options)
- return func(ctx *macaron.Context, sess session.Store) {
- x := &csrf{
- Secret: opt.Secret,
- Header: opt.Header,
- Form: opt.Form,
- Cookie: opt.Cookie,
- CookiePath: opt.CookiePath,
- ErrorFunc: opt.ErrorFunc,
- }
- ctx.MapTo(x, (*CSRF)(nil))
- if opt.Origin && len(ctx.Req.Header.Get("Origin")) > 0 {
- return
- }
- x.ID = "0"
- uid := sess.Get(opt.SessionKey)
- if uid != nil {
- x.ID = com.ToStr(uid)
- }
- needsNew := false
- oldUid := sess.Get(opt.oldSeesionKey)
- if oldUid == nil || oldUid.(string) != x.ID {
- needsNew = true
- sess.Set(opt.oldSeesionKey, x.ID)
- } else {
-
- if val := ctx.GetCookie(opt.Cookie); len(val) > 0 {
-
- x.Token = val
- } else {
- needsNew = true
- }
- }
- if needsNew {
-
- x.Token = GenerateToken(x.Secret, x.ID, "POST")
- if opt.SetCookie {
- ctx.SetCookie(opt.Cookie, x.Token, 0, opt.CookiePath, "", false, true, time.Now().AddDate(0, 0, 1))
- }
- }
- if opt.SetHeader {
- ctx.Resp.Header().Add(opt.Header, x.Token)
- }
- }
- }
- func Csrfer(options ...Options) macaron.Handler {
- return Generate(options...)
- }
- func Validate(ctx *macaron.Context, x CSRF) {
- if token := ctx.Req.Header.Get(x.GetHeaderName()); len(token) > 0 {
- if !x.ValidToken(token) {
- ctx.SetCookie(x.GetCookieName(), "", -1, x.GetCookiePath())
- x.Error(ctx.Resp)
- }
- return
- }
- if token := ctx.Req.FormValue(x.GetFormName()); len(token) > 0 {
- if !x.ValidToken(token) {
- ctx.SetCookie(x.GetCookieName(), "", -1, x.GetCookiePath())
- x.Error(ctx.Resp)
- }
- return
- }
- http.Error(ctx.Resp, "Bad Request: no CSRF token present", http.StatusBadRequest)
- }
|