fix: address code review findings

- Preserve MBID and last_synced across periodic artist syncs (INSERT OR
  REPLACE was wiping them, forcing MusicBrainz re-resolution every cycle)
- Exclude unmonitored artists from unnotified-release digest query
- Require telegram.cron_schedule when telegram.enabled is true
- Add same-origin CSRF defense to state-changing web POST routes
- Skip WAL/busy_timeout pragmas for :memory: databases (no-op there)
- Scan mbid as sql.NullString in GetAllArtistSettings to tolerate NULLs
This commit is contained in:
2026-07-19 23:51:15 +03:00
parent 7cdb473d9c
commit ce1c39e14b
7 changed files with 90 additions and 18 deletions

View File

@@ -10,6 +10,7 @@ import (
"fmt"
"log"
"net/http"
"net/url"
"strings"
"time"
@@ -138,6 +139,35 @@ func unauthorized(w http.ResponseWriter) {
_, _ = w.Write([]byte("401 Unauthorized\n"))
}
// sameOrigin returns true when the request's Origin (or, lacking that, Referer)
// header matches the server's own origin. State-changing POST routes use this
// as a lightweight CSRF defense: a cross-site request from a logged-in
// operator's browser will carry a different Origin/Referer and be rejected.
// When the header is absent (e.g. a same-origin form POST from older browsers
// or curl), the request is allowed rather than blocked, since the dashboard
// only ever issues same-origin form posts.
func (s *Server) sameOrigin(r *http.Request) bool {
origin := r.Header.Get("Origin")
if origin == "" {
origin = r.Header.Get("Referer")
}
if origin == "" {
return true
}
got, err := url.Parse(origin)
if err != nil || got.Host == "" {
return false
}
// Accept the actual Host the client reached (covers 0.0.0.0 bind with
// localhost/127.0.0.1 access) as well as the configured bind address.
gotHost := got.Host
reqHost := r.Host
if reqHost == "" {
reqHost = s.Addr()
}
return gotHost == reqHost || gotHost == s.Addr()
}
// ArtistSummary is the dashboard projection of a single monitored artist and
// its missing-release count.
type ArtistSummary struct {