Files
vibesonic/internal/web/web.go
T

61 lines
1.7 KiB
Go

// Package web implements VibeSonic's server-rendered Bootstrap 5 UI:
// setup, authentication, library browsing, playback, and admin pages.
package web
import (
"database/sql"
"log/slog"
"net/http"
"git.noroutes.net/NoRoutes/vibetunes/internal/auth"
"git.noroutes.net/NoRoutes/vibetunes/internal/config"
"git.noroutes.net/NoRoutes/vibetunes/internal/coverart"
"git.noroutes.net/NoRoutes/vibetunes/internal/scanner"
)
type Web struct {
DB *sql.DB
Config config.Config
Sessions *auth.Sessions
CSRF *auth.CSRF
Middleware *auth.Middleware
Scanner *scanner.Scanner
CoverArt *coverart.Store
Log *slog.Logger
}
// page renders a template with the standard envelope (current user, CSRF
// token, active nav item) filled in.
func (h *Web) page(w http.ResponseWriter, r *http.Request, name, active, title string, data any) {
render(w, name, PageData{
Active: active,
Title: title,
User: auth.UserFromContext(r.Context()),
CSRFToken: h.CSRF.Token(w, r),
Data: data,
})
}
// safeRedirectPath returns next if it's a same-site relative path, or
// "/" otherwise. Guards against open redirects: a bare "/foo" is fine,
// but "//evil.com" or "https://evil.com" are protocol-relative/absolute
// URLs a browser would follow off-site.
func safeRedirectPath(next string) string {
if next == "" || next[0] != '/' || len(next) > 1 && next[1] == '/' {
return "/"
}
return next
}
func (h *Web) flash(w http.ResponseWriter, r *http.Request, name, active, title, flash, kind string, data any) {
render(w, name, PageData{
Active: active,
Title: title,
User: auth.UserFromContext(r.Context()),
CSRFToken: h.CSRF.Token(w, r),
Flash: flash,
FlashKind: kind,
Data: data,
})
}