107 lines
2.1 KiB
Go
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
|
|
}
|