| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 | 
							- /*
 
-  * Public Domain Software
 
-  *
 
-  * I (Matthias Ladkau) am the author of the source code in this file.
 
-  * I have placed the source code in this file in the public domain.
 
-  *
 
-  * For further information see: http://creativecommons.org/publicdomain/zero/1.0/
 
-  */
 
- package user
 
- import (
 
- 	"crypto/rand"
 
- 	"errors"
 
- 	"fmt"
 
- 	"io"
 
- 	"net/http"
 
- 	"net/url"
 
- 	"sync"
 
- 	"devt.de/krotik/common/datautil"
 
- 	"devt.de/krotik/common/errorutil"
 
- )
 
- /*
 
- cookieName defines the session cookie name
 
- */
 
- const cookieNameSession = "~sid"
 
- /*
 
- CookieMaxLifetime is the max life time of a session cookie in seconds
 
- */
 
- var CookieMaxLifetime = 3600
 
- /*
 
- UserSessionManager manages all user sessions.
 
- */
 
- var UserSessionManager = &SessionManager{sync.Mutex{},
 
- 	NewMemorySessionProvider()}
 
- /*
 
- SessionManager manages web sessions.
 
- */
 
- type SessionManager struct {
 
- 	Lock     sync.Mutex
 
- 	Provider SessionProvider
 
- }
 
- /*
 
- newSessionId creates a new session id.
 
- */
 
- func (manager *SessionManager) newSessionID() string {
 
- 	b := make([]byte, 32)
 
- 	_, err := io.ReadFull(rand.Reader, b)
 
- 	errorutil.AssertOk(err)
 
- 	return fmt.Sprintf("S-%x", b)
 
- }
 
- /*
 
- CheckSessionCookie checks if a request contains a session cookie and if the
 
- session is active. Returns has cookie and is active.
 
- */
 
- func (manager *SessionManager) CheckSessionCookie(r *http.Request) (bool, bool) {
 
- 	var session Session
 
- 	cookie, _ := r.Cookie(cookieNameSession)
 
- 	if cookie != nil {
 
- 		sid, _ := url.QueryUnescape(cookie.Value)
 
- 		session, _ = manager.Provider.Get(sid)
 
- 	}
 
- 	return cookie != nil, session != nil
 
- }
 
- /*
 
- RemoveSessionCookie removes the session cookie in a given response object.
 
- */
 
- func (manager *SessionManager) RemoveSessionCookie(w http.ResponseWriter) {
 
- 	cookie := http.Cookie{
 
- 		Name:     cookieNameSession,
 
- 		Value:    "",
 
- 		Path:     "/",
 
- 		HttpOnly: true,
 
- 		MaxAge:   -1,
 
- 	}
 
- 	http.SetCookie(w, &cookie)
 
- }
 
- /*
 
- GetSession retrieves an existing or creates a new session
 
- */
 
- func (manager *SessionManager) GetSession(user string, w http.ResponseWriter,
 
- 	r *http.Request, create bool) (Session, error) {
 
- 	manager.Lock.Lock()
 
- 	defer manager.Lock.Unlock()
 
- 	var session Session
 
- 	var err error
 
- 	var sid string
 
- 	// Retrieve the cookie
 
- 	cookie, cerr := r.Cookie(cookieNameSession)
 
- 	if cookie == nil || cookie.Value == "" {
 
- 		if !create {
 
- 			// Session is not present and it should not be created
 
- 			return nil, nil
 
- 		}
 
- 		// Session is not created if no user is present
 
- 		if user == "" {
 
- 			return nil, errors.New("Cannot create a session without a user")
 
- 		}
 
- 		// No cookie present - create a new session
 
- 		sid = manager.newSessionID()
 
- 		session, _ = manager.Provider.Init(sid, user)
 
- 	} else {
 
- 		// Session should be available
 
- 		sid, _ = url.QueryUnescape(cookie.Value)
 
- 		session, err = manager.Provider.Get(sid)
 
- 	}
 
- 	if create {
 
- 		// Write the session cookie in the response
 
- 		cookie = &http.Cookie{
 
- 			Name:     cookieNameSession,
 
- 			Value:    url.QueryEscape(sid),
 
- 			Path:     "/",
 
- 			HttpOnly: true,
 
- 			MaxAge:   CookieMaxLifetime,
 
- 		}
 
- 		http.SetCookie(w, cookie)
 
- 	}
 
- 	if cerr == http.ErrNoCookie {
 
- 		// Also register the cookie in the request so the session can
 
- 		// can be found by subsequent calls
 
- 		r.AddCookie(cookie)
 
- 	}
 
- 	return session, err
 
- }
 
- /*
 
- SessionProvider is a session storage provider. Sessions should expire
 
- after a certain amount of time.
 
- */
 
- type SessionProvider interface {
 
- 	/*
 
- 		Create a new session for a given user. The session has an explicit
 
- 		expiry time after which a get will fail.
 
- 	*/
 
- 	Init(sid string, user string) (Session, error)
 
- 	/*
 
- 		Get retrieves a session.
 
- 	*/
 
- 	Get(sid string) (Session, error)
 
- 	/*
 
- 		GetAll returns a list of all sessions.
 
- 	*/
 
- 	GetAll() ([]Session, error)
 
- 	/*
 
- 		Destroy destroys a session.
 
- 	*/
 
- 	Destroy(sid string) error
 
- }
 
- /*
 
- MemorySessionProvider keeps all session related data in memory.
 
- */
 
- type MemorySessionProvider struct {
 
- 	sessions *datautil.MapCache // Thread safe memory cache
 
- }
 
- /*
 
- NewMemorySessionProvider creates a new memory session provider. By default
 
- sessions have the same expiry time as cookies.
 
- */
 
- func NewMemorySessionProvider() SessionProvider {
 
- 	ret := &MemorySessionProvider{}
 
- 	ret.SetExpiry(CookieMaxLifetime)
 
- 	return ret
 
- }
 
- /*
 
- SetExpiry sets the session expiry time in seconds. All existing sessions
 
- are deleted during this function call. This call is not thread safe - only
 
- use it during initialisation!
 
- */
 
- func (ms *MemorySessionProvider) SetExpiry(secs int) {
 
- 	ms.sessions = datautil.NewMapCache(0, int64(secs))
 
- }
 
- /*
 
- Init creates a new session for a given user. The session has an explicit
 
- expiry time after which a get will fail.
 
- */
 
- func (ms *MemorySessionProvider) Init(sid string, user string) (Session, error) {
 
- 	session := NewDefaultSession(sid, user)
 
- 	ms.sessions.Put(sid, session)
 
- 	return session, nil
 
- }
 
- /*
 
- Get retrieves a session.
 
- */
 
- func (ms *MemorySessionProvider) Get(sid string) (Session, error) {
 
- 	if session, _ := ms.sessions.Get(sid); session != nil {
 
- 		return session.(Session), nil
 
- 	}
 
- 	return nil, nil
 
- }
 
- /*
 
- GetAll returns a list of all sessions.
 
- */
 
- func (ms *MemorySessionProvider) GetAll() ([]Session, error) {
 
- 	sessions := make([]Session, 0, ms.sessions.Size())
 
- 	for _, s := range ms.sessions.GetAll() {
 
- 		sessions = append(sessions, s.(Session))
 
- 	}
 
- 	return sessions, nil
 
- }
 
- /*
 
- Destroy destroys a session.
 
- */
 
- func (ms *MemorySessionProvider) Destroy(sid string) error {
 
- 	ms.sessions.Remove(sid)
 
- 	return nil
 
- }
 
 
  |