172 lines
3.9 KiB
Go

package auth
import (
"dk/internal/cookies"
"dk/internal/helpers"
"dk/internal/models/users"
"dk/internal/router"
"dk/internal/session"
"fmt"
"time"
"github.com/valyala/fasthttp"
)
const SessionCookieName = "dk_session"
func Middleware() router.Middleware {
return func(next router.Handler) router.Handler {
return func(ctx router.Ctx, params []string) {
sessionID := cookies.GetCookie(ctx, SessionCookieName)
var sess *session.Session
if sessionID != "" {
if existingSess, exists := session.Get(sessionID); exists {
sess = existingSess
sess.Touch()
if sess.UserID > 0 { // User session
user, err := users.Find(sess.UserID)
if err == nil && user != nil {
ctx.SetUserValue("user", user)
} else {
// User not found, reset to guest session
sess.SetUserID(0)
}
}
session.Store(sess)
setSessionCookie(ctx, sessionID)
}
}
// Create guest session if none exists
if sess == nil {
sess = session.Create(0) // Guest session
setSessionCookie(ctx, sess.ID)
}
ctx.SetUserValue("session", sess)
next(ctx, params)
}
}
}
func RequireAuth(paths ...string) router.Middleware {
redirect := "/login"
if len(paths) > 0 && paths[0] != "" {
redirect = paths[0]
}
return func(next router.Handler) router.Handler {
return func(ctx router.Ctx, params []string) {
if !IsAuthenticated(ctx) {
ctx.Redirect(redirect, fasthttp.StatusFound)
return
}
user := ctx.UserValue("user").(*users.User)
user.UpdateLastOnline()
user.Save()
next(ctx, params)
}
}
}
func RequireGuest(paths ...string) router.Middleware {
redirect := "/"
if len(paths) > 0 && paths[0] != "" {
redirect = paths[0]
}
return func(next router.Handler) router.Handler {
return func(ctx router.Ctx, params []string) {
if IsAuthenticated(ctx) {
fmt.Println("RequireGuest: user is authenticated")
ctx.Redirect(redirect, fasthttp.StatusFound)
return
}
next(ctx, params)
}
}
}
func IsAuthenticated(ctx router.Ctx) bool {
if user, ok := ctx.UserValue("user").(*users.User); ok && user != nil {
return true
}
return false
}
func GetCurrentUser(ctx router.Ctx) *users.User {
if user, ok := ctx.UserValue("user").(*users.User); ok {
return user
}
return nil
}
func GetCurrentSession(ctx router.Ctx) *session.Session {
if sess, ok := ctx.UserValue("session").(*session.Session); ok {
return sess
}
return nil
}
func Login(ctx router.Ctx, user *users.User) {
sess := ctx.UserValue("session").(*session.Session)
// Update the session to be authenticated
sess.SetUserID(user.ID) // This updates the struct field
sess.RegenerateID() // Generate new ID for security
sess.SetFlash("success", fmt.Sprintf("Welcome back, %s!", user.Username))
// Remove any old user_id from session data if it exists
sess.Delete("user_id")
session.Store(sess)
// Update context values
ctx.SetUserValue("session", sess)
ctx.SetUserValue("user", user)
// Update cookie with new session ID
setSessionCookie(ctx, sess.ID)
}
func Logout(ctx router.Ctx) {
sess := ctx.UserValue("session").(*session.Session)
if sess != nil {
// Convert back to guest session
sess.SetUserID(0) // Reset to guest
sess.RegenerateID() // Generate new ID for security
// Clean up any user-related session data
sess.Delete("user_id")
session.Store(sess)
ctx.SetUserValue("session", sess)
// Update cookie with new session ID
setSessionCookie(ctx, sess.ID)
}
ctx.SetUserValue("user", nil)
}
// Helper functions for session cookies
func setSessionCookie(ctx router.Ctx, sessionID string) {
cookies.SetSecureCookie(ctx, cookies.CookieOptions{
Name: SessionCookieName,
Value: sessionID,
Path: "/",
Expires: time.Now().Add(24 * time.Hour),
HTTPOnly: true,
Secure: helpers.IsHTTPS(ctx),
SameSite: "lax",
})
}
func deleteSessionCookie(ctx router.Ctx) {
cookies.DeleteCookie(ctx, SessionCookieName)
}