Mercurial > gemma
view pkg/auth/store.go @ 904:e4b72a199258
New default bottleneck colors
Mainly to make the stroke color one actually selectable in the ui.
In addition the pink does better match the collors used on the ECDIS layer.
author | Sascha Wilde <wilde@intevation.de> |
---|---|
date | Tue, 02 Oct 2018 13:34:59 +0200 |
parents | be8b79109679 |
children | a244b18cb916 |
line wrap: on
line source
package auth import ( "bytes" "errors" "log" "time" bolt "github.com/etcd-io/bbolt" ) var ErrNoSuchToken = errors.New("No such token") // Sessions is the global connection pool. var Sessions *SessionStore type SessionStore struct { storage *bolt.DB sessions map[string]*Session cmds chan func() } var sessionsBucket = []byte("sessions") func NewSessionStore(filename string) (*SessionStore, error) { ss := &SessionStore{ sessions: make(map[string]*Session), cmds: make(chan func()), } if err := ss.openStorage(filename); err != nil { return nil, err } go ss.run() return ss, nil } // openStorage opens a storage file. func (ss *SessionStore) openStorage(filename string) error { // No file, nothing to restore/persist. if filename == "" { return nil } db, err := bolt.Open(filename, 0600, nil) if err != nil { return err } err = db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucketIfNotExists(sessionsBucket) if err != nil { return err } // pre-load sessions c := b.Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { var session Session if err := session.deserialize(bytes.NewReader(v)); err != nil { return err } ss.sessions[string(k)] = &session } return nil }) if err != nil { db.Close() return err } ss.storage = db return nil } func (ss *SessionStore) run() { for { select { case cmd := <-ss.cmds: cmd() case <-time.After(time.Minute * 5): ss.cleanToken() } } } func (ss *SessionStore) cleanToken() { now := time.Now() for token, session := range ss.sessions { expires := time.Unix(session.ExpiresAt, 0) if expires.Before(now) { delete(ss.sessions, token) ss.remove(token) } } } func (ss *SessionStore) remove(token string) { if ss.storage == nil { return } err := ss.storage.Update(func(tx *bolt.Tx) error { b := tx.Bucket(sessionsBucket) return b.Delete([]byte(token)) }) if err != nil { log.Printf("error: %v\n", err) } } func (ss *SessionStore) Delete(token string) bool { res := make(chan bool) ss.cmds <- func() { if _, found := ss.sessions[token]; !found { res <- false return } delete(ss.sessions, token) ss.remove(token) res <- true } return <-res } func (ss *SessionStore) store(token string, session *Session) { if ss.storage == nil { return } err := ss.storage.Update(func(tx *bolt.Tx) error { b := tx.Bucket(sessionsBucket) var buf bytes.Buffer if err := session.serialize(&buf); err != nil { return err } return b.Put([]byte(token), buf.Bytes()) }) if err != nil { log.Printf("error: %v\n", err) } } func (ss *SessionStore) Add(token string, session *Session) { res := make(chan struct{}) ss.cmds <- func() { defer close(res) s := ss.sessions[token] if s == nil { s = session ss.sessions[token] = session } s.touch() ss.store(token, s) } <-res } func (ss *SessionStore) Renew(token string) (string, error) { type result struct { newToken string err error } resCh := make(chan result) ss.cmds <- func() { session := ss.sessions[token] if session == nil { resCh <- result{err: ErrNoSuchToken} } else { delete(ss.sessions, token) ss.remove(token) newToken := GenerateSessionKey() // TODO: Ensure that this is not racy! session.ExpiresAt = time.Now().Add(maxTokenValid).Unix() ss.sessions[newToken] = session ss.store(newToken, session) resCh <- result{newToken: newToken} } } r := <-resCh return r.newToken, r.err } func (ss *SessionStore) Session(token string) *Session { res := make(chan *Session) ss.cmds <- func() { session := ss.sessions[token] if session == nil { res <- nil } else { session.touch() ss.store(token, session) res <- session } } return <-res } func (ss *SessionStore) Logout(user string) { ss.cmds <- func() { for token, session := range ss.sessions { if session.User == user { delete(ss.sessions, token) ss.remove(token) } } } } func (ss *SessionStore) Shutdown() error { if db := ss.storage; db != nil { log.Println("info: shutdown persistent session store.") ss.storage = nil return db.Close() } log.Println("info: shutdown in-memory session store.") return nil }