package services import ( "encoding/gob" "fmt" "html/template" "log" "net/http" "time" "git.klink.asia/paul/certman/settings" "github.com/alexedwards/scs" "github.com/gorilla/securecookie" ) var ( // SessionName is the name of the session cookie SessionName = "session" // CookieKey is the key the cookies are encrypted and signed with CookieKey = string(securecookie.GenerateRandomKey(32)) // FlashesKey is the key used for the flashes in the cookie FlashesKey = "_flashes" // UserEmailKey is the key used to reference usernames UserEmailKey = "_user_email" ) func init() { // Register the Flash message type, so gob can serialize it gob.Register(Flash{}) } // SessionStore is a globally accessible sessions store for the application var SessionStore *Store // Store is a wrapped scs.Store in order to implement custom // logic type Store struct { *scs.Manager } // InitSession populates the default sessions Store func InitSession() { store := scs.NewCookieManager( CookieKey, ) store.HttpOnly(true) store.Lifetime(24 * time.Hour) // Use secure cookies (HTTPS only) in production store.Secure(settings.Get("ENVIRONMENT", "") == "production") SessionStore = &Store{store} } func (store *Store) GetUserEmail(req *http.Request) string { if store == nil { // if store was not initialized, all requests fail log.Println("Zero pointer when checking session for username") return "" } sess := store.Load(req) email, err := sess.GetString(UserEmailKey) if err != nil { // Username found return "" } // User is logged in return email } func (store *Store) SetUserEmail(w http.ResponseWriter, req *http.Request, email string) { if store == nil { // if store was not initialized, do nothing return } sess := store.Load(req) // renew token to avoid session pinning/fixation attack sess.RenewToken(w) sess.PutString(w, UserEmailKey, email) } type Flash struct { Message template.HTML Type string } // Render renders the flash message as a notification box func (flash Flash) Render() template.HTML { return template.HTML( fmt.Sprintf( "
%s
", flash.Type, flash.Message, ), ) } // Flash add flash message to session data func (store *Store) Flash(w http.ResponseWriter, req *http.Request, flash Flash) error { var flashes []Flash sess := store.Load(req) if err := sess.GetObject(FlashesKey, &flashes); err != nil { return err } flashes = append(flashes, flash) return sess.PutObject(w, FlashesKey, flashes) } // Flashes returns a slice of flash messages from session data func (store *Store) Flashes(w http.ResponseWriter, req *http.Request) []Flash { var flashes []Flash sess := store.Load(req) sess.PopObject(w, FlashesKey, &flashes) return flashes }