mirror of
https://github.com/volatiletech/authboss.git
synced 2025-01-22 05:09:42 +02:00
89 lines
2.0 KiB
Go
89 lines
2.0 KiB
Go
|
// Package expire implements user
|
||
|
package expire
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"net/http"
|
||
|
"time"
|
||
|
|
||
|
"gopkg.in/authboss.v0"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
// UserLastAction is the session key to retrieve the last action of a user.
|
||
|
UserLastAction = "last_action"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
ErrExpired = errors.New("The user session has expired.")
|
||
|
)
|
||
|
|
||
|
// E is the singleton instance of the expire module which will have been
|
||
|
// configured and ready to use after authboss.Init()
|
||
|
var E *Expire
|
||
|
|
||
|
func init() {
|
||
|
E = &Expire{}
|
||
|
authboss.RegisterModule("expire", E)
|
||
|
}
|
||
|
|
||
|
type Expire struct {
|
||
|
window time.Duration
|
||
|
}
|
||
|
|
||
|
func (e *Expire) Initialize(config *authboss.Config) error {
|
||
|
e.window = config.ExpireAfter
|
||
|
|
||
|
config.Callbacks.Before(authboss.EventGet, e.BeforeAuth)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (_ *Expire) Routes() authboss.RouteTable { return nil }
|
||
|
func (_ *Expire) Storage() authboss.StorageOptions { return nil }
|
||
|
|
||
|
// BeforeAuth ensures the account is not locked.
|
||
|
func (e *Expire) BeforeAuth(ctx *authboss.Context) error {
|
||
|
if _, ok := ctx.SessionStorer.Get(authboss.SessionKey); !ok {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
dateStr, ok := ctx.SessionStorer.Get(UserLastAction)
|
||
|
if ok {
|
||
|
if date, err := time.Parse(time.RFC3339, dateStr); err != nil {
|
||
|
Touch(ctx.SessionStorer)
|
||
|
} else if time.Now().UTC().After(date.Add(e.window)) {
|
||
|
ctx.SessionStorer.Del(authboss.SessionKey)
|
||
|
return ErrExpired
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Touch updates the last action for the user, so he doesn't become expired.
|
||
|
func Touch(session authboss.ClientStorer) {
|
||
|
session.Put(UserLastAction, time.Now().UTC().Format(time.RFC3339))
|
||
|
}
|
||
|
|
||
|
type middleware struct {
|
||
|
sessionMaker authboss.SessionStoreMaker
|
||
|
next http.Handler
|
||
|
}
|
||
|
|
||
|
// TouchMiddleware ensures that the user's expiry information is kept up-to-date
|
||
|
// on each request.
|
||
|
func TouchMiddleware(sessionMaker authboss.SessionStoreMaker, next http.Handler) http.Handler {
|
||
|
return middleware{sessionMaker, next}
|
||
|
}
|
||
|
|
||
|
func (m middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||
|
session := m.sessionMaker(w, r)
|
||
|
|
||
|
if _, ok := session.Get(authboss.SessionKey); ok {
|
||
|
Touch(session)
|
||
|
}
|
||
|
|
||
|
m.next.ServeHTTP(w, r)
|
||
|
}
|