67 lines
1.5 KiB
Go
67 lines
1.5 KiB
Go
package middleware
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
sessionHelper "synlotto-website/internal/helpers/session"
|
|
"synlotto-website/internal/platform/bootstrap"
|
|
"synlotto-website/internal/platform/sessionkeys"
|
|
)
|
|
|
|
// Remember checks if a remember-me cookie exists and restores the session if valid.
|
|
func Remember(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
|
|
}
|
|
|
|
// Look for remember-me cookie
|
|
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]
|
|
if selector == "" || verifier == "" {
|
|
c.Next()
|
|
return
|
|
}
|
|
|
|
userID, hash, expiresAt, revokedAt, err := sessionHelper.FindToken(app.DB, selector)
|
|
if err != nil || revokedAt != nil || time.Now().After(expiresAt) {
|
|
c.Next()
|
|
return
|
|
}
|
|
|
|
// Constant-time compare via hashing the verifier
|
|
if sessionHelper.HashVerifier(verifier) != hash {
|
|
_ = sessionHelper.RevokeToken(app.DB, selector) // tampered → revoke
|
|
c.Next()
|
|
return
|
|
}
|
|
|
|
// ✅ Valid token → create a new session for the user
|
|
_ = sm.RenewToken(ctx)
|
|
sm.Put(ctx, sessionkeys.UserID, userID)
|
|
sm.Put(ctx, sessionkeys.LastActivity, time.Now().UTC())
|
|
|
|
// (Optional TODO): rotate token and set a fresh cookie.
|
|
|
|
c.Next()
|
|
}
|
|
}
|