98 lines
2.3 KiB
Go
98 lines
2.3 KiB
Go
package middleware
|
||
|
||
import (
|
||
"net/http"
|
||
"strings"
|
||
"time"
|
||
|
||
sessionHelper "synlotto-website/internal/helpers/session"
|
||
"synlotto-website/internal/platform/bootstrap"
|
||
"synlotto-website/internal/platform/sessionkeys"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// Tracks idle timeout using LastActivity; redirects on timeout.
|
||
func AuthMiddleware() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
app := c.MustGet("app").(*bootstrap.App)
|
||
sm := app.SessionManager
|
||
ctx := c.Request.Context()
|
||
|
||
if v := sm.Get(ctx, sessionkeys.LastActivity); v != nil {
|
||
if last, ok := v.(time.Time); ok && time.Since(last) > sm.Lifetime {
|
||
_ = sm.RenewToken(ctx)
|
||
sm.Put(ctx, sessionkeys.Flash, "Your session has timed out.")
|
||
c.Redirect(http.StatusSeeOther, "/account/login")
|
||
c.Abort()
|
||
return
|
||
}
|
||
}
|
||
|
||
sm.Put(ctx, sessionkeys.LastActivity, time.Now().UTC())
|
||
c.Next()
|
||
}
|
||
}
|
||
|
||
// Optional remember-me using selector:verifier token pair.
|
||
func RememberMiddleware(app *bootstrap.App) gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
sm := app.SessionManager
|
||
ctx := c.Request.Context()
|
||
|
||
// Already logged in? Skip.
|
||
if sm.Exists(ctx, sessionkeys.UserID) {
|
||
c.Next()
|
||
return
|
||
}
|
||
|
||
cookie, err := c.Request.Cookie(app.Config.Session.RememberCookieName)
|
||
if err != nil {
|
||
c.Next()
|
||
return
|
||
}
|
||
|
||
parts := strings.SplitN(cookie.Value, ":", 2)
|
||
if len(parts) != 2 {
|
||
c.Next()
|
||
return
|
||
}
|
||
selector, verifier := parts[0], parts[1]
|
||
|
||
userID, hash, expires, revokedAt, err := sessionHelper.FindToken(app.DB, selector)
|
||
if err != nil || revokedAt != nil || time.Now().After(expires) {
|
||
c.Next()
|
||
return
|
||
}
|
||
|
||
if sessionHelper.HashVerifier(verifier) != hash {
|
||
// Tampered token – revoke for safety.
|
||
_ = sessionHelper.RevokeToken(app.DB, selector)
|
||
c.Next()
|
||
return
|
||
}
|
||
|
||
// Success → create fresh SCS session
|
||
_ = sm.RenewToken(ctx)
|
||
sm.Put(ctx, sessionkeys.UserID, userID)
|
||
sm.Put(ctx, sessionkeys.LastActivity, time.Now().UTC())
|
||
|
||
c.Next()
|
||
}
|
||
}
|
||
|
||
// Blocks anonymous users; redirects to login.
|
||
func RequireAuth() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
app := c.MustGet("app").(*bootstrap.App)
|
||
sm := app.SessionManager
|
||
|
||
if sm.GetInt(c.Request.Context(), sessionkeys.UserID) == 0 {
|
||
c.Redirect(http.StatusSeeOther, "/account/login")
|
||
c.Abort()
|
||
return
|
||
}
|
||
c.Next()
|
||
}
|
||
}
|