You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
2.1 KiB
92 lines
2.1 KiB
package models
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
type sessionCtxKeyType string
|
|
|
|
const sessionCtxKey = sessionCtxKeyType("luciter_session")
|
|
|
|
// The Session model represents a user being logged in.
|
|
type Session struct {
|
|
ID string `db:"id"`
|
|
UserID int `db:"user_id"`
|
|
Expires time.Time `db:"expire_date"`
|
|
}
|
|
|
|
// GenerateID generates a unique ID for the session that's 64 base36 digits long.
|
|
func (session *Session) GenerateID() error {
|
|
result := ""
|
|
offset := 0
|
|
data := make([]byte, 128)
|
|
|
|
_, err := rand.Read(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for len(result) < 64 {
|
|
result += strconv.FormatUint(binary.LittleEndian.Uint64(data[offset:]), 36)
|
|
offset += 8
|
|
|
|
if offset >= 128 {
|
|
_, err = rand.Read(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
offset = 0
|
|
}
|
|
}
|
|
|
|
session.ID = result[:64]
|
|
|
|
return nil
|
|
}
|
|
|
|
// Cookie gets a cookie that could be used to restore this session.
|
|
func (session *Session) Cookie() *http.Cookie {
|
|
return &http.Cookie{
|
|
Name: "lucifer_session",
|
|
Value: session.ID,
|
|
Path: "/",
|
|
Expires: session.Expires,
|
|
HttpOnly: true,
|
|
}
|
|
}
|
|
|
|
// Expired returns true if the session has expired.
|
|
func (session *Session) Expired() bool {
|
|
return time.Now().After(session.Expires)
|
|
}
|
|
|
|
// InContext returns a child context with the value.
|
|
func (session *Session) InContext(parent context.Context) context.Context {
|
|
return context.WithValue(parent, sessionCtxKey, session)
|
|
}
|
|
|
|
// SessionFromContext gets the session from context, or `nil` if no session is available.
|
|
func SessionFromContext(ctx context.Context) *Session {
|
|
v := ctx.Value(sessionCtxKey)
|
|
if v == nil {
|
|
return nil
|
|
}
|
|
|
|
return v.(*Session)
|
|
}
|
|
|
|
// SessionRepository is an interface for all database operations
|
|
// the user model makes.
|
|
type SessionRepository interface {
|
|
FindByID(ctx context.Context, id string) (Session, error)
|
|
Insert(ctx context.Context, session Session) error
|
|
Update(ctx context.Context, session Session) error
|
|
Remove(ctx context.Context, session Session) error
|
|
Clear(ctx context.Context, user User) error
|
|
}
|