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 { // don't destroy here; just rotate and bounce to login with a flash _ = sm.RenewToken(ctx) sm.Put(ctx, sessionkeys.Flash, "Your session has timed out.") c.Redirect(http.StatusSeeOther, "/account/login") c.Abort() return } } // if logged in, update last activity if sm.Exists(ctx, sessionkeys.UserID) { 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 { _ = sessionHelper.RevokeToken(app.DB, selector) // tampered 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()) // (Optional) if you can look up username/is_admin here, also set: // sm.Put(ctx, sessionkeys.Username, uname) // sm.Put(ctx, sessionkeys.IsAdmin, isAdmin) 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 ctx := c.Request.Context() // ✅ Use Exists to be robust to int vs int64 storage if !sm.Exists(ctx, sessionkeys.UserID) { c.Redirect(http.StatusSeeOther, "/account/login") c.Abort() return } c.Next() } }