126 lines
2.8 KiB
Go
126 lines
2.8 KiB
Go
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(
|
|
"<div class=\"notification is-radiusless is-%s\"><div class=\"container has-text-centered\">%s</div></div>",
|
|
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
|
|
}
|