diff --git a/auth.go b/auth.go
index 4013159..e9ab2ee 100644
--- a/auth.go
+++ b/auth.go
@@ -224,11 +224,23 @@ func (s *Server) authRequired(next http.Handler) http.Handler {
})
}
-// viewerOnly restricts access to live wall only (port 8090).
+// viewerOnly restricts access when viewer port is disabled, or to live wall only.
func (s *Server) viewerOnly(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // Check if viewer port is enabled in config.
+ s.mu.RLock()
+ enabled := s.appConfig.Server.ViewerPort != "" && s.appConfig.Server.ViewerPort != ":0"
+ s.mu.RUnlock()
+
+ if !enabled {
+ msg := `
NextNVR`
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ w.WriteHeader(http.StatusForbidden)
+ w.Write([]byte(msg))
+ return
+ }
+
path := r.URL.Path
- // Allow live wall assets and recordings.
if path == "/" || path == "/index.html" ||
strings.HasPrefix(path, "/app.js") ||
strings.HasPrefix(path, "/style.css") ||
@@ -241,7 +253,6 @@ func (s *Server) viewerOnly(next http.Handler) http.Handler {
next.ServeHTTP(w, r)
return
}
- // Block everything else (settings, playback API, config).
jsonResponse(w, http.StatusForbidden, APIResponse{Error: "viewer access only"})
})
}
diff --git a/config.go b/config.go
index 3477d4b..3f400bb 100644
--- a/config.go
+++ b/config.go
@@ -85,7 +85,7 @@ func DefaultConfig() Config {
Server: ServerConfig{
Port: ":8080",
BindHost: "0.0.0.0",
- ViewerPort: "",
+ ViewerPort: ":8090",
},
Storage: StorageConfig{
RecordingsPath: "/mnt/recordings",
diff --git a/config.json.sample b/config.json.sample
index 3e352cf..e469649 100644
--- a/config.json.sample
+++ b/config.json.sample
@@ -2,7 +2,7 @@
"server": {
"port": ":8080",
"bind_host": "0.0.0.0",
- "viewer_port": ""
+ "viewer_port": ":8090"
},
"storage": {
"recordings_path": "/mnt/recordings",
diff --git a/main.go b/main.go
index f6077ad..0f8749a 100644
--- a/main.go
+++ b/main.go
@@ -90,18 +90,6 @@ func main() {
app.server.mu.RUnlock()
// Handle viewer server toggle via viewer_port.
- viewerOn := liveCfg.Server.ViewerPort != "" && liveCfg.Server.ViewerPort != ":0"
- if viewerOn && app.viewerSrv == nil {
- go func() {
- v, err := app.server.StartViewerServer()
- if err != nil { log.Printf("Viewer server: %v", err) }
- app.viewerSrv = v
- }()
- } else if !viewerOn && app.viewerSrv != nil {
- log.Println("Stopping viewer server...")
- app.viewerSrv.Close()
- app.viewerSrv = nil
- }
if liveCfg.Go2RTC.Enabled {
app.go2rtc = NewGo2RTCManager(liveCfg.Go2RTC)
app.go2rtc.Start(liveCfg.Cameras)
@@ -120,17 +108,12 @@ func main() {
}()
// Start viewer server only if enabled.
- if cfg.Server.ViewerPort != "" && cfg.Server.ViewerPort != ":0" {
- go func() {
- v, err := app.server.StartViewerServer()
- if err != nil {
- log.Printf("Viewer server: %v", err)
- }
- app.viewerSrv = v
- }()
- } else {
- log.Println("Viewer server: disabled (viewer_port empty)")
- }
+ // Start viewer server always — access controlled by config at request level.
+ go func() {
+ v, err := app.server.StartViewerServer()
+ if err != nil { log.Printf("Viewer server: %v", err) }
+ app.viewerSrv = v
+ }()
select {
case sig := <-sigCh: