aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/gorilla/sessions/store.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gorilla/sessions/store.go')
-rw-r--r--vendor/github.com/gorilla/sessions/store.go270
1 files changed, 270 insertions, 0 deletions
diff --git a/vendor/github.com/gorilla/sessions/store.go b/vendor/github.com/gorilla/sessions/store.go
new file mode 100644
index 0000000..ba3b9e9
--- /dev/null
+++ b/vendor/github.com/gorilla/sessions/store.go
@@ -0,0 +1,270 @@
+// Copyright 2012 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sessions
+
+import (
+ "encoding/base32"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+
+ "github.com/gorilla/securecookie"
+)
+
+// Store is an interface for custom session stores.
+//
+// See CookieStore and FilesystemStore for examples.
+type Store interface {
+ // Get should return a cached session.
+ Get(r *http.Request, name string) (*Session, error)
+
+ // New should create and return a new session.
+ //
+ // Note that New should never return a nil session, even in the case of
+ // an error if using the Registry infrastructure to cache the session.
+ New(r *http.Request, name string) (*Session, error)
+
+ // Save should persist session to the underlying store implementation.
+ Save(r *http.Request, w http.ResponseWriter, s *Session) error
+}
+
+// CookieStore ----------------------------------------------------------------
+
+// NewCookieStore returns a new CookieStore.
+//
+// Keys are defined in pairs to allow key rotation, but the common case is
+// to set a single authentication key and optionally an encryption key.
+//
+// The first key in a pair is used for authentication and the second for
+// encryption. The encryption key can be set to nil or omitted in the last
+// pair, but the authentication key is required in all pairs.
+//
+// It is recommended to use an authentication key with 32 or 64 bytes.
+// The encryption key, if set, must be either 16, 24, or 32 bytes to select
+// AES-128, AES-192, or AES-256 modes.
+//
+// Use the convenience function securecookie.GenerateRandomKey() to create
+// strong keys.
+func NewCookieStore(keyPairs ...[]byte) *CookieStore {
+ cs := &CookieStore{
+ Codecs: securecookie.CodecsFromPairs(keyPairs...),
+ Options: &Options{
+ Path: "/",
+ MaxAge: 86400 * 30,
+ },
+ }
+
+ cs.MaxAge(cs.Options.MaxAge)
+ return cs
+}
+
+// CookieStore stores sessions using secure cookies.
+type CookieStore struct {
+ Codecs []securecookie.Codec
+ Options *Options // default configuration
+}
+
+// Get returns a session for the given name after adding it to the registry.
+//
+// It returns a new session if the sessions doesn't exist. Access IsNew on
+// the session to check if it is an existing session or a new one.
+//
+// It returns a new session and an error if the session exists but could
+// not be decoded.
+func (s *CookieStore) Get(r *http.Request, name string) (*Session, error) {
+ return GetRegistry(r).Get(s, name)
+}
+
+// New returns a session for the given name without adding it to the registry.
+//
+// The difference between New() and Get() is that calling New() twice will
+// decode the session data twice, while Get() registers and reuses the same
+// decoded session after the first call.
+func (s *CookieStore) New(r *http.Request, name string) (*Session, error) {
+ session := NewSession(s, name)
+ opts := *s.Options
+ session.Options = &opts
+ session.IsNew = true
+ var err error
+ if c, errCookie := r.Cookie(name); errCookie == nil {
+ err = securecookie.DecodeMulti(name, c.Value, &session.Values,
+ s.Codecs...)
+ if err == nil {
+ session.IsNew = false
+ }
+ }
+ return session, err
+}
+
+// Save adds a single session to the response.
+func (s *CookieStore) Save(r *http.Request, w http.ResponseWriter,
+ session *Session) error {
+ encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
+ s.Codecs...)
+ if err != nil {
+ return err
+ }
+ http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
+ return nil
+}
+
+// MaxAge sets the maximum age for the store and the underlying cookie
+// implementation. Individual sessions can be deleted by setting Options.MaxAge
+// = -1 for that session.
+func (s *CookieStore) MaxAge(age int) {
+ s.Options.MaxAge = age
+
+ // Set the maxAge for each securecookie instance.
+ for _, codec := range s.Codecs {
+ if sc, ok := codec.(*securecookie.SecureCookie); ok {
+ sc.MaxAge(age)
+ }
+ }
+}
+
+// FilesystemStore ------------------------------------------------------------
+
+var fileMutex sync.RWMutex
+
+// NewFilesystemStore returns a new FilesystemStore.
+//
+// The path argument is the directory where sessions will be saved. If empty
+// it will use os.TempDir().
+//
+// See NewCookieStore() for a description of the other parameters.
+func NewFilesystemStore(path string, keyPairs ...[]byte) *FilesystemStore {
+ if path == "" {
+ path = os.TempDir()
+ }
+ fs := &FilesystemStore{
+ Codecs: securecookie.CodecsFromPairs(keyPairs...),
+ Options: &Options{
+ Path: "/",
+ MaxAge: 86400 * 30,
+ },
+ path: path,
+ }
+
+ fs.MaxAge(fs.Options.MaxAge)
+ return fs
+}
+
+// FilesystemStore stores sessions in the filesystem.
+//
+// It also serves as a reference for custom stores.
+//
+// This store is still experimental and not well tested. Feedback is welcome.
+type FilesystemStore struct {
+ Codecs []securecookie.Codec
+ Options *Options // default configuration
+ path string
+}
+
+// MaxLength restricts the maximum length of new sessions to l.
+// If l is 0 there is no limit to the size of a session, use with caution.
+// The default for a new FilesystemStore is 4096.
+func (s *FilesystemStore) MaxLength(l int) {
+ for _, c := range s.Codecs {
+ if codec, ok := c.(*securecookie.SecureCookie); ok {
+ codec.MaxLength(l)
+ }
+ }
+}
+
+// Get returns a session for the given name after adding it to the registry.
+//
+// See CookieStore.Get().
+func (s *FilesystemStore) Get(r *http.Request, name string) (*Session, error) {
+ return GetRegistry(r).Get(s, name)
+}
+
+// New returns a session for the given name without adding it to the registry.
+//
+// See CookieStore.New().
+func (s *FilesystemStore) New(r *http.Request, name string) (*Session, error) {
+ session := NewSession(s, name)
+ opts := *s.Options
+ session.Options = &opts
+ session.IsNew = true
+ var err error
+ if c, errCookie := r.Cookie(name); errCookie == nil {
+ err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
+ if err == nil {
+ err = s.load(session)
+ if err == nil {
+ session.IsNew = false
+ }
+ }
+ }
+ return session, err
+}
+
+// Save adds a single session to the response.
+func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter,
+ session *Session) error {
+ if session.ID == "" {
+ // Because the ID is used in the filename, encode it to
+ // use alphanumeric characters only.
+ session.ID = strings.TrimRight(
+ base32.StdEncoding.EncodeToString(
+ securecookie.GenerateRandomKey(32)), "=")
+ }
+ if err := s.save(session); err != nil {
+ return err
+ }
+ encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
+ s.Codecs...)
+ if err != nil {
+ return err
+ }
+ http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
+ return nil
+}
+
+// MaxAge sets the maximum age for the store and the underlying cookie
+// implementation. Individual sessions can be deleted by setting Options.MaxAge
+// = -1 for that session.
+func (s *FilesystemStore) MaxAge(age int) {
+ s.Options.MaxAge = age
+
+ // Set the maxAge for each securecookie instance.
+ for _, codec := range s.Codecs {
+ if sc, ok := codec.(*securecookie.SecureCookie); ok {
+ sc.MaxAge(age)
+ }
+ }
+}
+
+// save writes encoded session.Values to a file.
+func (s *FilesystemStore) save(session *Session) error {
+ encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
+ s.Codecs...)
+ if err != nil {
+ return err
+ }
+ filename := filepath.Join(s.path, "session_"+session.ID)
+ fileMutex.Lock()
+ defer fileMutex.Unlock()
+ return ioutil.WriteFile(filename, []byte(encoded), 0600)
+}
+
+// load reads a file and decodes its content into session.Values.
+func (s *FilesystemStore) load(session *Session) error {
+ filename := filepath.Join(s.path, "session_"+session.ID)
+ fileMutex.RLock()
+ defer fileMutex.RUnlock()
+ fdata, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return err
+ }
+ if err = securecookie.DecodeMulti(session.Name(), string(fdata),
+ &session.Values, s.Codecs...); err != nil {
+ return err
+ }
+ return nil
+}