security/authentication/session.go
2024-09-30 19:02:10 -04:00

107 lines
2.1 KiB
Go

package authentication
import (
"crypto/rand"
"fmt"
"time"
"somehole.com/common/security/identity"
)
const (
RetryCreateSessionToken = 3
MaxSessionAge = 1 * time.Hour
)
type SessionToken [8]byte
func NewSessionToken() (st SessionToken) {
var stBytes = make([]byte, 8)
rand.Read(stBytes)
st = SessionToken(stBytes)
return
}
type NextToken [4]byte
func NewNextToken() (nt NextToken) {
var ntBytes = make([]byte, 4)
rand.Read(ntBytes)
nt = NextToken(ntBytes)
return
}
type Session struct {
identity.Identity
nextTokens []NextToken
expiration time.Time
}
func NewSession(identity identity.Identity) (s *Session) {
s = &Session{
Identity: identity,
nextTokens: make([]NextToken, 0),
expiration: time.Now().Add(MaxSessionAge),
}
return
}
func (s *Session) Active() (ok bool) {
ok = time.Now().Before(s.expiration)
return
}
func (s *Session) NewNextToken() (nt NextToken) {
nt = NewNextToken()
s.nextTokens = append(s.nextTokens, nt)
return
}
func (s *Session) NextTokenIsCurrent(nt NextToken) (ok bool) {
ok = s.nextTokens[len(s.nextTokens)-1] == nt
return
}
type SessionService struct {
sessions map[SessionToken]*Session
}
func NewSessionService() (srv *SessionService) {
srv = &SessionService{
sessions: make(map[SessionToken]*Session),
}
return
}
func (srv *SessionService) NewSessionToken() (st SessionToken, err error) {
for i := 0; i < RetryCreateSessionToken; i++ {
st = NewSessionToken()
if _, exists := srv.sessions[st]; exists {
err = fmt.Errorf("could only creat colliding session tokens in %d tries", RetryCreateSessionToken)
continue
}
err = nil
break
}
return
}
func (srv *SessionService) AddSession(st SessionToken, session *Session) (err error) {
if _, exists := srv.sessions[st]; exists {
err = fmt.Errorf("session already exists")
return
}
srv.sessions[st] = session
return
}
func (srv *SessionService) GetSession(sessionToken SessionToken) (session *Session, err error) {
var exists bool
session, exists = srv.sessions[sessionToken]
if !exists {
err = fmt.Errorf("session not found")
return
}
return
}