mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +09:00 
			
		
		
		
	Use gitea forked macaron (#7933)
Signed-off-by: Tamal Saha <tamal@appscode.com>
This commit is contained in:
		
				
					committed by
					
						 techknowlogick
						techknowlogick
					
				
			
			
				
	
			
			
			
						parent
						
							ca6fb004ac
						
					
				
				
					commit
					171b359877
				
			
							
								
								
									
										393
									
								
								vendor/gitea.com/macaron/session/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										393
									
								
								vendor/gitea.com/macaron/session/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,393 @@ | ||||
| // Copyright 2013 Beego Authors | ||||
| // Copyright 2014 The Macaron Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| // Package session a middleware that provides the session management of Macaron. | ||||
| package session | ||||
|  | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"time" | ||||
|  | ||||
| 	"gitea.com/macaron/macaron" | ||||
| ) | ||||
|  | ||||
| const _VERSION = "0.6.0" | ||||
|  | ||||
| func Version() string { | ||||
| 	return _VERSION | ||||
| } | ||||
|  | ||||
| // RawStore is the interface that operates the session data. | ||||
| type RawStore interface { | ||||
| 	// Set sets value to given key in session. | ||||
| 	Set(interface{}, interface{}) error | ||||
| 	// Get gets value by given key in session. | ||||
| 	Get(interface{}) interface{} | ||||
| 	// Delete deletes a key from session. | ||||
| 	Delete(interface{}) error | ||||
| 	// ID returns current session ID. | ||||
| 	ID() string | ||||
| 	// Release releases session resource and save data to provider. | ||||
| 	Release() error | ||||
| 	// Flush deletes all session data. | ||||
| 	Flush() error | ||||
| } | ||||
|  | ||||
| // Store is the interface that contains all data for one session process with specific ID. | ||||
| type Store interface { | ||||
| 	RawStore | ||||
| 	// Read returns raw session store by session ID. | ||||
| 	Read(string) (RawStore, error) | ||||
| 	// Destroy deletes a session. | ||||
| 	Destroy(*macaron.Context) error | ||||
| 	// RegenerateId regenerates a session store from old session ID to new one. | ||||
| 	RegenerateId(*macaron.Context) (RawStore, error) | ||||
| 	// Count counts and returns number of sessions. | ||||
| 	Count() int | ||||
| 	// GC calls GC to clean expired sessions. | ||||
| 	GC() | ||||
| } | ||||
|  | ||||
| type store struct { | ||||
| 	RawStore | ||||
| 	*Manager | ||||
| } | ||||
|  | ||||
| var _ Store = &store{} | ||||
|  | ||||
| // Options represents a struct for specifying configuration options for the session middleware. | ||||
| type Options struct { | ||||
| 	// Name of provider. Default is "memory". | ||||
| 	Provider string | ||||
| 	// Provider configuration, it's corresponding to provider. | ||||
| 	ProviderConfig string | ||||
| 	// Cookie name to save session ID. Default is "MacaronSession". | ||||
| 	CookieName string | ||||
| 	// Cookie path to store. Default is "/". | ||||
| 	CookiePath string | ||||
| 	// GC interval time in seconds. Default is 3600. | ||||
| 	Gclifetime int64 | ||||
| 	// Max life time in seconds. Default is whatever GC interval time is. | ||||
| 	Maxlifetime int64 | ||||
| 	// Use HTTPS only. Default is false. | ||||
| 	Secure bool | ||||
| 	// Cookie life time. Default is 0. | ||||
| 	CookieLifeTime int | ||||
| 	// Cookie domain name. Default is empty. | ||||
| 	Domain string | ||||
| 	// Session ID length. Default is 16. | ||||
| 	IDLength int | ||||
| 	// Configuration section name. Default is "session". | ||||
| 	Section string | ||||
| 	// Ignore release for websocket. Default is false. | ||||
| 	IgnoreReleaseForWebSocket bool | ||||
| } | ||||
|  | ||||
| func prepareOptions(options []Options) Options { | ||||
| 	var opt Options | ||||
| 	if len(options) > 0 { | ||||
| 		opt = options[0] | ||||
| 	} | ||||
| 	if len(opt.Section) == 0 { | ||||
| 		opt.Section = "session" | ||||
| 	} | ||||
| 	sec := macaron.Config().Section(opt.Section) | ||||
|  | ||||
| 	if len(opt.Provider) == 0 { | ||||
| 		opt.Provider = sec.Key("PROVIDER").MustString("memory") | ||||
| 	} | ||||
| 	if len(opt.ProviderConfig) == 0 { | ||||
| 		opt.ProviderConfig = sec.Key("PROVIDER_CONFIG").MustString("data/sessions") | ||||
| 	} | ||||
| 	if len(opt.CookieName) == 0 { | ||||
| 		opt.CookieName = sec.Key("COOKIE_NAME").MustString("MacaronSession") | ||||
| 	} | ||||
| 	if len(opt.CookiePath) == 0 { | ||||
| 		opt.CookiePath = sec.Key("COOKIE_PATH").MustString("/") | ||||
| 	} | ||||
| 	if opt.Gclifetime == 0 { | ||||
| 		opt.Gclifetime = sec.Key("GC_INTERVAL_TIME").MustInt64(3600) | ||||
| 	} | ||||
| 	if opt.Maxlifetime == 0 { | ||||
| 		opt.Maxlifetime = sec.Key("MAX_LIFE_TIME").MustInt64(opt.Gclifetime) | ||||
| 	} | ||||
| 	if !opt.Secure { | ||||
| 		opt.Secure = sec.Key("SECURE").MustBool() | ||||
| 	} | ||||
| 	if opt.CookieLifeTime == 0 { | ||||
| 		opt.CookieLifeTime = sec.Key("COOKIE_LIFE_TIME").MustInt() | ||||
| 	} | ||||
| 	if len(opt.Domain) == 0 { | ||||
| 		opt.Domain = sec.Key("DOMAIN").String() | ||||
| 	} | ||||
| 	if opt.IDLength == 0 { | ||||
| 		opt.IDLength = sec.Key("ID_LENGTH").MustInt(16) | ||||
| 	} | ||||
| 	if !opt.IgnoreReleaseForWebSocket { | ||||
| 		opt.IgnoreReleaseForWebSocket = sec.Key("IGNORE_RELEASE_FOR_WEBSOCKET").MustBool() | ||||
| 	} | ||||
|  | ||||
| 	return opt | ||||
| } | ||||
|  | ||||
| // Sessioner is a middleware that maps a session.SessionStore service into the Macaron handler chain. | ||||
| // An single variadic session.Options struct can be optionally provided to configure. | ||||
| func Sessioner(options ...Options) macaron.Handler { | ||||
| 	opt := prepareOptions(options) | ||||
| 	manager, err := NewManager(opt.Provider, opt) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	go manager.startGC() | ||||
|  | ||||
| 	return func(ctx *macaron.Context) { | ||||
| 		sess, err := manager.Start(ctx) | ||||
| 		if err != nil { | ||||
| 			panic("session(start): " + err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		// Get flash. | ||||
| 		vals, _ := url.ParseQuery(ctx.GetCookie("macaron_flash")) | ||||
| 		if len(vals) > 0 { | ||||
| 			f := &Flash{Values: vals} | ||||
| 			f.ErrorMsg = f.Get("error") | ||||
| 			f.SuccessMsg = f.Get("success") | ||||
| 			f.InfoMsg = f.Get("info") | ||||
| 			f.WarningMsg = f.Get("warning") | ||||
| 			ctx.Data["Flash"] = f | ||||
| 			ctx.SetCookie("macaron_flash", "", -1, opt.CookiePath) | ||||
| 		} | ||||
|  | ||||
| 		f := &Flash{ctx, url.Values{}, "", "", "", ""} | ||||
| 		ctx.Resp.Before(func(macaron.ResponseWriter) { | ||||
| 			if flash := f.Encode(); len(flash) > 0 { | ||||
| 				ctx.SetCookie("macaron_flash", flash, 0, opt.CookiePath) | ||||
| 			} | ||||
| 		}) | ||||
|  | ||||
| 		ctx.Map(f) | ||||
| 		s := store{ | ||||
| 			RawStore: sess, | ||||
| 			Manager:  manager, | ||||
| 		} | ||||
|  | ||||
| 		ctx.MapTo(s, (*Store)(nil)) | ||||
|  | ||||
| 		ctx.Next() | ||||
|  | ||||
| 		if manager.opt.IgnoreReleaseForWebSocket && ctx.Req.Header.Get("Upgrade") == "websocket" { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		if err = sess.Release(); err != nil { | ||||
| 			panic("session(release): " + err.Error()) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Provider is the interface that provides session manipulations. | ||||
| type Provider interface { | ||||
| 	// Init initializes session provider. | ||||
| 	Init(gclifetime int64, config string) error | ||||
| 	// Read returns raw session store by session ID. | ||||
| 	Read(sid string) (RawStore, error) | ||||
| 	// Exist returns true if session with given ID exists. | ||||
| 	Exist(sid string) bool | ||||
| 	// Destroy deletes a session by session ID. | ||||
| 	Destroy(sid string) error | ||||
| 	// Regenerate regenerates a session store from old session ID to new one. | ||||
| 	Regenerate(oldsid, sid string) (RawStore, error) | ||||
| 	// Count counts and returns number of sessions. | ||||
| 	Count() int | ||||
| 	// GC calls GC to clean expired sessions. | ||||
| 	GC() | ||||
| } | ||||
|  | ||||
| var providers = make(map[string]Provider) | ||||
|  | ||||
| // Register registers a provider. | ||||
| func Register(name string, provider Provider) { | ||||
| 	if provider == nil { | ||||
| 		panic("session: cannot register provider with nil value") | ||||
| 	} | ||||
| 	if _, dup := providers[name]; dup { | ||||
| 		panic(fmt.Errorf("session: cannot register provider '%s' twice", name)) | ||||
| 	} | ||||
| 	providers[name] = provider | ||||
| } | ||||
|  | ||||
| //    _____ | ||||
| //   /     \ _____    ____ _____     ____   ___________ | ||||
| //  /  \ /  \\__  \  /    \\__  \   / ___\_/ __ \_  __ \ | ||||
| // /    Y    \/ __ \|   |  \/ __ \_/ /_/  >  ___/|  | \/ | ||||
| // \____|__  (____  /___|  (____  /\___  / \___  >__| | ||||
| //         \/     \/     \/     \//_____/      \/ | ||||
|  | ||||
| // Manager represents a struct that contains session provider and its configuration. | ||||
| type Manager struct { | ||||
| 	provider Provider | ||||
| 	opt      Options | ||||
| } | ||||
|  | ||||
| // NewManager creates and returns a new session manager by given provider name and configuration. | ||||
| // It panics when given provider isn't registered. | ||||
| func NewManager(name string, opt Options) (*Manager, error) { | ||||
| 	p, ok := providers[name] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("session: unknown provider '%s'(forgotten import?)", name) | ||||
| 	} | ||||
| 	return &Manager{p, opt}, p.Init(opt.Maxlifetime, opt.ProviderConfig) | ||||
| } | ||||
|  | ||||
| // sessionID generates a new session ID with rand string, unix nano time, remote addr by hash function. | ||||
| func (m *Manager) sessionID() string { | ||||
| 	return hex.EncodeToString(generateRandomKey(m.opt.IDLength / 2)) | ||||
| } | ||||
|  | ||||
| // validSessionID tests whether a provided session ID is a valid session ID. | ||||
| func (m *Manager) validSessionID(sid string) (bool, error) { | ||||
| 	if len(sid) != m.opt.IDLength { | ||||
| 		return false, errors.New("invalid 'sid': " + sid) | ||||
| 	} | ||||
|  | ||||
| 	for i := range sid { | ||||
| 		switch { | ||||
| 		case '0' <= sid[i] && sid[i] <= '9': | ||||
| 		case 'a' <= sid[i] && sid[i] <= 'f': | ||||
| 		default: | ||||
| 			return false, errors.New("invalid 'sid': " + sid) | ||||
| 		} | ||||
| 	} | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| // Start starts a session by generating new one | ||||
| // or retrieve existence one by reading session ID from HTTP request if it's valid. | ||||
| func (m *Manager) Start(ctx *macaron.Context) (RawStore, error) { | ||||
| 	sid := ctx.GetCookie(m.opt.CookieName) | ||||
| 	valid, _ := m.validSessionID(sid) | ||||
| 	if len(sid) > 0 && valid && m.provider.Exist(sid) { | ||||
| 		return m.provider.Read(sid) | ||||
| 	} | ||||
|  | ||||
| 	sid = m.sessionID() | ||||
| 	sess, err := m.provider.Read(sid) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	cookie := &http.Cookie{ | ||||
| 		Name:     m.opt.CookieName, | ||||
| 		Value:    sid, | ||||
| 		Path:     m.opt.CookiePath, | ||||
| 		HttpOnly: true, | ||||
| 		Secure:   m.opt.Secure, | ||||
| 		Domain:   m.opt.Domain, | ||||
| 	} | ||||
| 	if m.opt.CookieLifeTime >= 0 { | ||||
| 		cookie.MaxAge = m.opt.CookieLifeTime | ||||
| 	} | ||||
| 	http.SetCookie(ctx.Resp, cookie) | ||||
| 	ctx.Req.AddCookie(cookie) | ||||
| 	return sess, nil | ||||
| } | ||||
|  | ||||
| // Read returns raw session store by session ID. | ||||
| func (m *Manager) Read(sid string) (RawStore, error) { | ||||
| 	// Ensure we're trying to read a valid session ID | ||||
| 	if _, err := m.validSessionID(sid); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return m.provider.Read(sid) | ||||
| } | ||||
|  | ||||
| // Destroy deletes a session by given ID. | ||||
| func (m *Manager) Destroy(ctx *macaron.Context) error { | ||||
| 	sid := ctx.GetCookie(m.opt.CookieName) | ||||
| 	if len(sid) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if _, err := m.validSessionID(sid); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if err := m.provider.Destroy(sid); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	cookie := &http.Cookie{ | ||||
| 		Name:     m.opt.CookieName, | ||||
| 		Path:     m.opt.CookiePath, | ||||
| 		HttpOnly: true, | ||||
| 		Expires:  time.Now(), | ||||
| 		MaxAge:   -1, | ||||
| 	} | ||||
| 	http.SetCookie(ctx.Resp, cookie) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // RegenerateId regenerates a session store from old session ID to new one. | ||||
| func (m *Manager) RegenerateId(ctx *macaron.Context) (sess RawStore, err error) { | ||||
| 	sid := m.sessionID() | ||||
| 	oldsid := ctx.GetCookie(m.opt.CookieName) | ||||
| 	_, err = m.validSessionID(oldsid) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	sess, err = m.provider.Regenerate(oldsid, sid) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	cookie := &http.Cookie{ | ||||
| 		Name:     m.opt.CookieName, | ||||
| 		Value:    sid, | ||||
| 		Path:     m.opt.CookiePath, | ||||
| 		HttpOnly: true, | ||||
| 		Secure:   m.opt.Secure, | ||||
| 		Domain:   m.opt.Domain, | ||||
| 	} | ||||
| 	if m.opt.CookieLifeTime >= 0 { | ||||
| 		cookie.MaxAge = m.opt.CookieLifeTime | ||||
| 	} | ||||
| 	http.SetCookie(ctx.Resp, cookie) | ||||
| 	ctx.Req.AddCookie(cookie) | ||||
| 	return sess, nil | ||||
| } | ||||
|  | ||||
| // Count counts and returns number of sessions. | ||||
| func (m *Manager) Count() int { | ||||
| 	return m.provider.Count() | ||||
| } | ||||
|  | ||||
| // GC starts GC job in a certain period. | ||||
| func (m *Manager) GC() { | ||||
| 	m.provider.GC() | ||||
| } | ||||
|  | ||||
| // startGC starts GC job in a certain period. | ||||
| func (m *Manager) startGC() { | ||||
| 	m.GC() | ||||
| 	time.AfterFunc(time.Duration(m.opt.Gclifetime)*time.Second, func() { m.startGC() }) | ||||
| } | ||||
|  | ||||
| // SetSecure indicates whether to set cookie with HTTPS or not. | ||||
| func (m *Manager) SetSecure(secure bool) { | ||||
| 	m.opt.Secure = secure | ||||
| } | ||||
		Reference in New Issue
	
	Block a user