package router import ( "io/fs" "log/slog" "net/http" "net/http/pprof" "os" "path/filepath" "vctp/db" "vctp/dist" "vctp/internal/secrets" "vctp/internal/settings" "vctp/internal/vcenter" "vctp/server/handler" "vctp/server/middleware" ) func New(logger *slog.Logger, database db.Database, buildTime string, sha1ver string, goVersion string, creds *vcenter.VcenterLogin, secret *secrets.Secrets, settings *settings.Settings) http.Handler { h := &handler.Handler{ Logger: logger, Database: database, BuildTime: buildTime, SHA1Ver: sha1ver, GoVersion: goVersion, VcCreds: creds, Secret: secret, Settings: settings, } mux := http.NewServeMux() requireAuth := middleware.RequireAuth(logger, settings) withAuth := func(next http.HandlerFunc) http.Handler { return requireAuth(http.HandlerFunc(next)) } withAuthRole := func(next http.HandlerFunc, roles ...string) http.Handler { wrapped := http.Handler(http.HandlerFunc(next)) if len(roles) > 0 { wrapped = middleware.RequireRole(roles...)(wrapped) } return requireAuth(wrapped) } reportsDir := settings.Values.Settings.ReportsDir if reportsDir == "" { reportsDir = "/var/lib/vctp/reports" } if err := os.MkdirAll(reportsDir, 0o755); err != nil { logger.Warn("failed to create reports directory", "error", err, "path", reportsDir) } mux.Handle("/assets/", middleware.CacheMiddleware(http.FileServer(http.FS(dist.AssetsDir)))) mux.Handle("/favicon.ico", middleware.CacheMiddleware(http.FileServer(http.FS(dist.AssetsDir)))) mux.Handle("/favicon-16x16.png", middleware.CacheMiddleware(http.FileServer(http.FS(dist.AssetsDir)))) mux.Handle("/favicon-32x32.png", middleware.CacheMiddleware(http.FileServer(http.FS(dist.AssetsDir)))) mux.Handle("/reports/", http.StripPrefix("/reports/", http.FileServer(http.Dir(filepath.Clean(reportsDir))))) mux.HandleFunc("/", h.Home) mux.Handle("/api/event/vm/create", withAuthRole(h.VmCreateEvent, middleware.RoleAdmin)) mux.Handle("/api/event/vm/modify", withAuthRole(h.VmModifyEvent, middleware.RoleAdmin)) mux.Handle("/api/event/vm/move", withAuthRole(h.VmMoveEvent, middleware.RoleAdmin)) mux.Handle("/api/event/vm/delete", withAuthRole(h.VmDeleteEvent, middleware.RoleAdmin)) mux.Handle("/api/import/vm", withAuthRole(h.VmImport, middleware.RoleAdmin)) // Use this when we need to manually remove a VM from the database to clean up mux.Handle("/api/inventory/vm/delete", withAuthRole(h.VmCleanup, middleware.RoleAdmin)) // add missing data to VMs mux.Handle("/api/inventory/vm/update", withAuthRole(h.VmUpdateDetails, middleware.RoleAdmin)) // Legacy/maintenance endpoints are gated by settings.enable_legacy_api. mux.Handle("/api/cleanup/updates", withAuthRole(h.UpdateCleanup, middleware.RoleAdmin)) //mux.HandleFunc("/api/cleanup/vcenter", h.VcCleanup) mux.Handle("/api/report/inventory", withAuthRole(h.InventoryReportDownload, middleware.RoleViewer)) mux.Handle("/api/report/updates", withAuthRole(h.UpdateReportDownload, middleware.RoleViewer)) mux.Handle("/api/report/snapshot", withAuthRole(h.SnapshotReportDownload, middleware.RoleViewer)) mux.Handle("/api/snapshots/aggregate", withAuthRole(h.SnapshotAggregateForce, middleware.RoleAdmin)) mux.Handle("/api/snapshots/hourly/force", withAuthRole(h.SnapshotForceHourly, middleware.RoleAdmin)) mux.Handle("/api/snapshots/migrate", withAuthRole(h.SnapshotMigrate, middleware.RoleAdmin)) mux.Handle("/api/snapshots/repair", withAuthRole(h.SnapshotRepair, middleware.RoleAdmin)) mux.Handle("/api/snapshots/repair/all", withAuthRole(h.SnapshotRepairSuite, middleware.RoleAdmin)) mux.Handle("/api/snapshots/regenerate-hourly-reports", withAuthRole(h.SnapshotRegenerateHourlyReports, middleware.RoleAdmin)) mux.Handle("/api/diagnostics/daily-creation", withAuthRole(h.DailyCreationDiagnostics, middleware.RoleViewer)) mux.HandleFunc("/api/auth/login", h.AuthLogin) mux.Handle("/api/auth/me", withAuth(h.AuthMe)) mux.HandleFunc("/vm/trace", h.VmTrace) mux.HandleFunc("/vcenters", h.VcenterList) mux.HandleFunc("/vcenters/totals", h.VcenterTotals) mux.HandleFunc("/vcenters/totals/daily", h.VcenterTotalsDaily) mux.HandleFunc("/vcenters/totals/hourly", h.VcenterTotalsHourlyDetailed) mux.Handle("/api/vcenters/cache/rebuild", withAuthRole(h.VcenterCacheRebuild, middleware.RoleAdmin)) mux.HandleFunc("/metrics", h.Metrics) mux.HandleFunc("/snapshots/hourly", h.SnapshotHourlyList) mux.HandleFunc("/snapshots/daily", h.SnapshotDailyList) mux.HandleFunc("/snapshots/monthly", h.SnapshotMonthlyList) // endpoint for encrypting vcenter credential mux.Handle("/api/encrypt", withAuthRole(h.EncryptData, middleware.RoleAdmin)) // serve swagger related components from the embedded fs swaggerSub, err := fs.Sub(swaggerUI, "swagger-ui-dist") if err != nil { logger.Error("failed to load swagger ui assets", "error", err) } else { mux.Handle("/swagger/", middleware.CacheMiddleware(http.StripPrefix("/swagger/", http.FileServer(http.FS(swaggerSub))))) } mux.HandleFunc("/swagger", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/swagger/", http.StatusPermanentRedirect) }) mux.Handle("/swagger.json", middleware.CacheMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) w.Write(swaggerSpec) }))) // Register pprof handlers only when enabled, and gate them behind admin auth. if settings.Values.Settings.EnablePprof { mux.Handle("/debug/pprof/", withAuthRole(pprof.Index, middleware.RoleAdmin)) mux.Handle("/debug/pprof/cmdline", withAuthRole(pprof.Cmdline, middleware.RoleAdmin)) mux.Handle("/debug/pprof/profile", withAuthRole(pprof.Profile, middleware.RoleAdmin)) mux.Handle("/debug/pprof/symbol", withAuthRole(pprof.Symbol, middleware.RoleAdmin)) mux.Handle("/debug/pprof/trace", withAuthRole(pprof.Trace, middleware.RoleAdmin)) } return middleware.NewLoggingMiddleware(logger, mux) }