package db import ( "database/sql" "crypto/rand" "encoding/base64" "errors" "time" ) func (p *Phlox) CreateSession(user User) (Session, error) { bytes := make([]byte, 32) _, err := rand.Read(bytes) if err != nil { return Session{}, err } sessionid := base64.StdEncoding.EncodeToString(bytes) userid := user.Id now := time.Now().UTC() nowStr := now.Format(time.RFC3339) _, err = p.db.Exec( "insert into sessions (sessionid, userid, created, modified) values (?, ?, ?, ?);", sessionid, userid, nowStr, nowStr, ) if err != nil { return Session{}, err } return Session{ Id: sessionid, UserId: userid, Created: now, Modified: now, }, nil } func (p *Phlox) DeleteSession(session Session) error { _, err := p.db.Exec("delete from sessions where sessionid = ?;", session.Id) return err } func extractSession(s Scanner) (Session, error) { var ( session Session createdStr string modifiedStr string ) // scan err := s.Scan(&session.Id, &session.UserId, &createdStr, &modifiedStr) if err != nil { return Session{}, err } // parse times session.Created, err = time.Parse(time.RFC3339, createdStr) if err != nil { return Session{}, err } session.Modified, err = time.Parse(time.RFC3339, modifiedStr) if err != nil { return Session{}, err } return session, nil } func (p *Phlox) TouchSession(session Session) error { now := time.Now().UTC() nowStr := now.Format(time.RFC3339) _, err := p.db.Exec("update sessions set modified=? where sessionid=?;", nowStr, session.Id) return err } func (p *Phlox) CheckSession(session Session) (bool, error) { row := p.db.QueryRow("select * from sessions where sessionid = ?", session.Id) session, err := extractSession(row) if err != nil { if errors.Is(err, sql.ErrNoRows) { // no row returned, so invalid session return false, nil } else { // some other error return false, err } } return true, nil } func (p *Phlox) TouchSession(session Session) error { now := time.Now().UTC().Format(time.RFC3339) _, err := p.db.Exec( "update sessions set modified = ? where sessionid = ?;", now, session.Id, ) return err } func (p *Phlox) CleanSessions(maxIdle time.Duration) error { expire := time.Now().UTC().Add(-maxIdle).Format(time.RFC3339) _, err := p.db.Exec("delete from sessions where modified < ?;", expire) return err } func (p *Phlox) AllSessions() ([]Session, error) { sessions := make([]Session, 0) rows, err := p.db.Query("select * from sessions;") if err != nil { return sessions, err } defer rows.Close() for rows.Next() { session, err := extractSession(rows) if err != nil { return sessions, err } sessions = append(sessions, session) } return sessions, nil }