package server import ( "net/http" "strings" "github.com/gin-gonic/gin" "warpbox/lib/config" ) const adminSessionCookie = "warpbox_admin_session" const adminSessionMarker = "1" func (app *App) adminLoginEnabled() bool { return app.config.AdminLoginEnabled(app.config.AdminPassword != "") } func (app *App) adminAuthMiddleware(ctx *gin.Context) { if !app.adminLoginEnabled() { ctx.Redirect(http.StatusSeeOther, "/") ctx.Abort() return } token, err := ctx.Cookie(adminSessionCookie) if err != nil || token != app.adminSessionToken() { ctx.Redirect(http.StatusSeeOther, "/admin/login") ctx.Abort() return } ctx.Next() } func (app *App) adminSessionToken() string { // A simple deterministic token derived from the admin credentials. // This will improve when proper user/session storage is added. return app.config.AdminUsername + ":" + app.config.AdminPassword } func (app *App) handleAdminLogin(ctx *gin.Context) { if !app.adminLoginEnabled() { ctx.Redirect(http.StatusSeeOther, "/") return } // Already logged in. if token, err := ctx.Cookie(adminSessionCookie); err == nil && token == app.adminSessionToken() { ctx.Redirect(http.StatusSeeOther, "/admin/dashboard") return } ctx.HTML(http.StatusOK, "admin/login.html", gin.H{}) } func (app *App) handleAdminLoginPost(ctx *gin.Context) { if !app.adminLoginEnabled() { ctx.Redirect(http.StatusSeeOther, "/") return } username := strings.TrimSpace(ctx.PostForm("username")) password := ctx.PostForm("password") if username != app.config.AdminUsername || password != app.config.AdminPassword { ctx.HTML(http.StatusUnauthorized, "admin/login.html", gin.H{ "ErrorMessage": "Invalid username or password.", }) return } secure := app.config.AdminCookieSecure maxAge := int(app.config.SessionTTLSeconds) ctx.SetCookie(adminSessionCookie, app.adminSessionToken(), maxAge, "/admin", "", secure, true) ctx.Redirect(http.StatusSeeOther, "/admin/dashboard") } func (app *App) handleAdminLogout(ctx *gin.Context) { secure := app.config.AdminCookieSecure ctx.SetCookie(adminSessionCookie, "", -1, "/admin", "", secure, true) ctx.Redirect(http.StatusSeeOther, "/admin/login") } func (app *App) handleAdminDashboard(ctx *gin.Context) { if !app.adminLoginEnabled() { ctx.Redirect(http.StatusSeeOther, "/") return } dashboardEnabled := config.AdminEnabledTrue if cfgVal := app.config.AdminEnabled; cfgVal == config.AdminEnabledAuto || cfgVal == config.AdminEnabledTrue { dashboardEnabled = cfgVal } ctx.HTML(http.StatusOK, "admin/dashboard.html", gin.H{ "AdminUsername": app.config.AdminUsername, "AdminEmail": app.config.AdminEmail, "ActivePage": "dashboard", "DashboardEnabled": string(dashboardEnabled), }) } func (app *App) handleAdminAlerts(ctx *gin.Context) { if !app.adminLoginEnabled() { ctx.Redirect(http.StatusSeeOther, "/") return } ctx.HTML(http.StatusOK, "admin/alerts.html", gin.H{ "AdminUsername": app.config.AdminUsername, "AdminEmail": app.config.AdminEmail, "ActivePage": "alerts", }) }