a8d18d8812
safari complains about bare async calls not being triggered by user action after a click allow admins to have multiple open sessions general webapp tweaks to background colors and button widths
82 lines
1.7 KiB
Go
82 lines
1.7 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright © 2022 Roberto Hidalgo <nidito@un.rob.mx>
|
|
package auth
|
|
|
|
import (
|
|
"math/rand"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.rob.mx/nidito/puerta/internal/user"
|
|
"github.com/upper/db/v4"
|
|
)
|
|
|
|
var letterSrc = rand.NewSource(time.Now().UnixNano())
|
|
|
|
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
const (
|
|
// 6 bits to represent a letter index
|
|
letterIdxBits = 6
|
|
// All 1-bits, as many as letterIdxBits
|
|
letterIdxMask = 1<<letterIdxBits - 1
|
|
// # of letter indices fitting in 63 bits
|
|
letterIdxMax = 63 / letterIdxBits
|
|
)
|
|
|
|
func NewToken() string {
|
|
sb := strings.Builder{}
|
|
n := 32
|
|
sb.Grow(n)
|
|
|
|
for i, cache, remain := n-1, letterSrc.Int63(), letterIdxMax; i >= 0; {
|
|
if remain == 0 {
|
|
cache, remain = letterSrc.Int63(), letterIdxMax
|
|
}
|
|
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
|
sb.WriteByte(letterBytes[idx])
|
|
i--
|
|
}
|
|
cache >>= letterIdxBits
|
|
remain--
|
|
}
|
|
|
|
return sb.String()
|
|
}
|
|
|
|
type Session struct {
|
|
Token string `db:"token"`
|
|
UserID int `db:"user"`
|
|
Expires time.Time `db:"expires"`
|
|
}
|
|
|
|
func (s *Session) Store(sess db.Session) db.Store {
|
|
return sess.Collection("session")
|
|
}
|
|
|
|
type SessionUser struct {
|
|
Token string `db:"token"`
|
|
UserID int `db:"user"`
|
|
Expires time.Time `db:"expires"`
|
|
user.User `db:",inline"`
|
|
}
|
|
|
|
func (s *SessionUser) Expired() bool {
|
|
return s.Expires.After(time.Now())
|
|
}
|
|
|
|
func NewSession(user *user.User, table db.Collection) (*Session, error) {
|
|
sess := &Session{
|
|
Token: NewToken(),
|
|
UserID: user.ID,
|
|
Expires: user.TTL.FromNow(),
|
|
}
|
|
|
|
if !user.IsAdmin {
|
|
// delete previous sessions
|
|
table.Find(db.Cond{"user": user.ID}).Delete()
|
|
}
|
|
// insert new one
|
|
_, err := table.Insert(sess)
|
|
return sess, err
|
|
}
|