package auth import ( "net/http" "instance-manager/internal/config" "instance-manager/internal/models" "github.com/gorilla/sessions" ) const sessionIDKey = "user_id" const sessionUsernameKey = "username" const sessionRoleKey = "role" const defaultCookieName = "_iM_s" type Manager struct { store *sessions.CookieStore cfg config.SessionConfig cookieName string } func New(cfg config.SessionConfig) *Manager { cookieName := cfg.CookieName if cookieName == "" { cookieName = defaultCookieName } key := []byte(cfg.Secret) // Ensure proper key lengths for securecookie // Hash key can be any length, block key needs 16, 24, or 32 bytes hashKey := key var blockKey []byte if len(key) >= 32 { blockKey = key[:32] } else { blockKey = make([]byte, 32) copy(blockKey, key) } store := sessions.NewCookieStore(hashKey, blockKey) store.Options = &sessions.Options{ Path: "/", MaxAge: cfg.MaxAge, Secure: cfg.Secure, HttpOnly: true, SameSite: http.SameSiteLaxMode, Domain: cfg.Domain, } return &Manager{store: store, cfg: cfg, cookieName: cookieName} } func (m *Manager) CreateSession(w http.ResponseWriter, r *http.Request, user *models.User) error { session, err := m.store.Get(r, m.cookieName) if err != nil { return err } session.Options = &sessions.Options{ Path: m.store.Options.Path, MaxAge: m.store.Options.MaxAge, Secure: m.store.Options.Secure, HttpOnly: m.store.Options.HttpOnly, SameSite: m.store.Options.SameSite, Domain: m.store.Options.Domain, } session.Values[sessionIDKey] = user.ID session.Values[sessionUsernameKey] = user.Username session.Values[sessionRoleKey] = user.Role session.IsNew = true return session.Save(r, w) } func (m *Manager) GetSession(r *http.Request) (*SessionData, error) { session, err := m.store.Get(r, m.cookieName) if err != nil { return nil, err } id, ok := session.Values[sessionIDKey] if !ok { return nil, nil } userID, ok := id.(int64) if !ok { return nil, nil } username, _ := session.Values[sessionUsernameKey].(string) role, _ := session.Values[sessionRoleKey].(string) return &SessionData{ UserID: userID, Username: username, Role: role, }, nil } func (m *Manager) DestroySession(w http.ResponseWriter, r *http.Request) error { session, err := m.store.Get(r, m.cookieName) if err != nil { return err } session.Values = make(map[interface{}]interface{}) session.Options.MaxAge = -1 return session.Save(r, w) } func (m *Manager) IsAdmin(r *http.Request) bool { sess, _ := m.GetSession(r) return sess != nil && sess.Role == "admin" } type SessionData struct { UserID int64 Username string Role string }