66 lines
2.0 KiB
Go
66 lines
2.0 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/jukebox"
|
|
"git.noroutes.net/NoRoutes/vibetunes/internal/podcasts"
|
|
"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
|
|
EncryptionKey []byte // for auth.SetUserPassword; see internal/auth/subsonic_secret.go
|
|
Podcasts *podcasts.Manager
|
|
Jukebox *jukebox.Jukebox
|
|
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,
|
|
})
|
|
}
|