1 // Package sessions is used to store session information for a web server 2 package sessions // import "vimagination.zapto.org/sessions" 3 4 import ( 5 "encoding/base64" 6 "net/http" 7 "time" 8 9 "vimagination.zapto.org/authenticate" 10 ) 11 12 // Store is the interface for any stores in this package 13 type Store interface { 14 Get(*http.Request) []byte 15 Set(http.ResponseWriter, []byte) 16 } 17 18 type store struct { 19 cookie http.Cookie 20 expires time.Duration 21 } 22 23 func (s *store) GetData(r *http.Request) string { 24 for _, cookie := range r.Cookies() { 25 if cookie.Name == s.cookie.Name && 26 (s.cookie.Domain == "" || s.cookie.Domain == cookie.Domain) && 27 s.cookie.Secure == cookie.Secure { 28 return cookie.Value 29 } 30 } 31 return "" 32 } 33 34 func (s *store) SetData(w http.ResponseWriter, data string) { 35 cookie := s.cookie 36 if s.expires > 0 { 37 cookie.Expires = time.Now().Add(s.expires) 38 } 39 cookie.Value = data 40 w.Header().Add("Set-Cookie", cookie.String()) 41 } 42 43 func (s *store) RemoveData(w http.ResponseWriter) { 44 w.Header().Add("Set-Cookie", s.cookie.String()) 45 } 46 47 func (s *store) Init(opts ...optFunc) { 48 s.cookie.Name = "session" 49 s.cookie.Expires = time.Unix(0, 0) 50 for _, opt := range opts { 51 opt(s) 52 } 53 } 54 55 // CookieStore stores and retrieves authenticated data from a clients cookies 56 type CookieStore struct { 57 store store 58 codec authenticate.Codec 59 } 60 61 // NewCookieStore creates a new CookieStore and initialises it. 62 // The options optFunc's are to set non-default values on the cookie. 63 func NewCookieStore(encKey []byte, opts ...optFunc) (*CookieStore, error) { 64 c := new(CookieStore) 65 c.store.Init(opts...) 66 cd, err := authenticate.NewCodec(encKey, c.store.expires) 67 if err != nil { 68 return nil, err 69 } 70 c.codec = *cd 71 return c, nil 72 } 73 74 // Get retrieves authenticated data from the cookie 75 func (c *CookieStore) Get(r *http.Request) []byte { 76 data, err := base64.StdEncoding.DecodeString(c.store.GetData(r)) 77 if err != nil || len(data) < 12 { 78 return nil 79 } 80 dst, _ := c.codec.Decode(data, nil) 81 return dst 82 } 83 84 // Set stores authenticated data in a clients cookies 85 func (c *CookieStore) Set(w http.ResponseWriter, data []byte) { 86 if len(data) == 0 { 87 c.store.RemoveData(w) 88 } else { 89 c.store.SetData(w, base64.StdEncoding.EncodeToString(c.codec.Encode(data, nil))) 90 } 91 } 92 93 /* 94 type FSStore struct { 95 store 96 path string 97 } 98 99 type MemStore struct { 100 store 101 data sync.Map 102 } 103 */