Persist, renew and delete sessions, refactor storage package, move reusable packages to pkg
This commit is contained in:
parent
121582f72a
commit
24f9553aa5
48 changed files with 1872 additions and 1171 deletions
106
pkg/session/session.go
Normal file
106
pkg/session/session.go
Normal file
|
@ -0,0 +1,106 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
CookieName = "session"
|
||||
|
||||
Expiration = time.Hour * 24 * 7
|
||||
RefreshInterval = time.Hour
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
UserID uint64
|
||||
|
||||
key string
|
||||
createdAt int64
|
||||
expiration *time.Timer
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func New(id uint64) (*Session, error) {
|
||||
key, err := newSessionKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Session{
|
||||
key: key,
|
||||
createdAt: time.Now().Unix(),
|
||||
UserID: id,
|
||||
expiration: time.NewTimer(Expiration),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Session) Init() {
|
||||
exp := time.Until(time.Unix(s.createdAt, 0).Add(Expiration))
|
||||
s.expiration = time.NewTimer(exp)
|
||||
}
|
||||
|
||||
func (s *Session) Key() string {
|
||||
s.lock.Lock()
|
||||
key := s.key
|
||||
s.lock.Unlock()
|
||||
return key
|
||||
}
|
||||
|
||||
func (s *Session) SetCookie(w http.ResponseWriter, r *http.Request) {
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: CookieName,
|
||||
Value: s.Key(),
|
||||
Path: "/",
|
||||
Expires: time.Now().Add(Expiration),
|
||||
HttpOnly: true,
|
||||
Secure: r.TLS != nil,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Session) Expired() bool {
|
||||
s.lock.Lock()
|
||||
created := time.Unix(s.createdAt, 0)
|
||||
s.lock.Unlock()
|
||||
return time.Since(created) > Expiration
|
||||
}
|
||||
|
||||
func (s *Session) Refresh() (string, bool, error) {
|
||||
s.lock.Lock()
|
||||
created := time.Unix(s.createdAt, 0)
|
||||
s.lock.Unlock()
|
||||
|
||||
if time.Since(created) > Expiration {
|
||||
return "", true, nil
|
||||
}
|
||||
|
||||
if time.Since(created) > RefreshInterval {
|
||||
key, err := newSessionKey()
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
s.expiration.Reset(Expiration)
|
||||
|
||||
s.lock.Lock()
|
||||
s.createdAt = time.Now().Unix()
|
||||
s.key = key
|
||||
s.lock.Unlock()
|
||||
return key, false, nil
|
||||
}
|
||||
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
func (s *Session) WaitUntilExpiration() {
|
||||
<-s.expiration.C
|
||||
}
|
||||
|
||||
func newSessionKey() (string, error) {
|
||||
key := make([]byte, 32)
|
||||
_, err := rand.Read(key)
|
||||
return base64.RawURLEncoding.EncodeToString(key), err
|
||||
}
|
5
pkg/session/session.schema
Normal file
5
pkg/session/session.schema
Normal file
|
@ -0,0 +1,5 @@
|
|||
struct Session {
|
||||
UserID uint64
|
||||
key string
|
||||
createdAt int64
|
||||
}
|
112
pkg/session/session.schema.gen.go
Normal file
112
pkg/session/session.schema.gen.go
Normal file
|
@ -0,0 +1,112 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
_ = unsafe.Sizeof(0)
|
||||
_ = io.ReadFull
|
||||
_ = time.Now()
|
||||
)
|
||||
|
||||
func (d *Session) Size() (s uint64) {
|
||||
|
||||
{
|
||||
l := uint64(len(d.key))
|
||||
|
||||
{
|
||||
|
||||
t := l
|
||||
for t >= 0x80 {
|
||||
t >>= 7
|
||||
s++
|
||||
}
|
||||
s++
|
||||
|
||||
}
|
||||
s += l
|
||||
}
|
||||
s += 16
|
||||
return
|
||||
}
|
||||
func (d *Session) Marshal(buf []byte) ([]byte, error) {
|
||||
size := d.Size()
|
||||
{
|
||||
if uint64(cap(buf)) >= size {
|
||||
buf = buf[:size]
|
||||
} else {
|
||||
buf = make([]byte, size)
|
||||
}
|
||||
}
|
||||
i := uint64(0)
|
||||
|
||||
{
|
||||
|
||||
*(*uint64)(unsafe.Pointer(&buf[0])) = d.UserID
|
||||
|
||||
}
|
||||
{
|
||||
l := uint64(len(d.key))
|
||||
|
||||
{
|
||||
|
||||
t := uint64(l)
|
||||
|
||||
for t >= 0x80 {
|
||||
buf[i+8] = byte(t) | 0x80
|
||||
t >>= 7
|
||||
i++
|
||||
}
|
||||
buf[i+8] = byte(t)
|
||||
i++
|
||||
|
||||
}
|
||||
copy(buf[i+8:], d.key)
|
||||
i += l
|
||||
}
|
||||
{
|
||||
|
||||
*(*int64)(unsafe.Pointer(&buf[i+8])) = d.createdAt
|
||||
|
||||
}
|
||||
return buf[:i+16], nil
|
||||
}
|
||||
|
||||
func (d *Session) Unmarshal(buf []byte) (uint64, error) {
|
||||
i := uint64(0)
|
||||
|
||||
{
|
||||
|
||||
d.UserID = *(*uint64)(unsafe.Pointer(&buf[i+0]))
|
||||
|
||||
}
|
||||
{
|
||||
l := uint64(0)
|
||||
|
||||
{
|
||||
|
||||
bs := uint8(7)
|
||||
t := uint64(buf[i+8] & 0x7F)
|
||||
for buf[i+8]&0x80 == 0x80 {
|
||||
i++
|
||||
t |= uint64(buf[i+8]&0x7F) << bs
|
||||
bs += 7
|
||||
}
|
||||
i++
|
||||
|
||||
l = t
|
||||
|
||||
}
|
||||
d.key = string(buf[i+8 : i+8+l])
|
||||
i += l
|
||||
}
|
||||
{
|
||||
|
||||
d.createdAt = *(*int64)(unsafe.Pointer(&buf[i+8]))
|
||||
|
||||
}
|
||||
return i + 16, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue