Files
xTeVe/tasks/todo.md
T
nathan 36303fecea
continuous-integration/drone/push Build encountered an error
Phase 1b/1c: server-side input handling and authentication
Input handling:
- uploadLogo: client file name reduced to a safe base name with an image
  extension (path traversal and arbitrary-extension writes closed).
- extractZIP: zip-slip guard; entries that resolve outside the target are
  refused. Per-entry closes no longer pile up as defers.
- ffmpeg.path / vlc.path must be an existing regular file named ffmpeg,
  vlc or cvlc, checked both when saved and right before exec.
- Stream URLs passed to the external buffer must use a network scheme
  (http, https, rtsp, rtmp, rtp, udp, mms); file:, concat:, pipe: are
  refused.
- /download/ (backups with settings.json and authentication.json) requires
  the web session when web authentication is enabled.
- settings.json is written 0600; the Plex token is masked in every payload
  sent to the UI and the mask round-trips as "unchanged" on save.

Authentication:
- Passwords are stored with bcrypt. Existing HMAC-SHA256 records still
  verify (constant time) and are re-hashed on the first successful login.
  Username lookups compare in constant time.
- URL (?username=&password=) and HTTP Basic authentication verify the
  credentials per request via AuthenticateUser and no longer create a
  session token, which removes the unbounded token growth under Plex
  polling. Expired sessions are evicted whenever a new one is created.
- createFirstUserForAuthentication and checkAuthorizationLevel now return
  real errors instead of calling no-op closures.

Tests: src/security_test.go and src/internal/authentication/
authentication_test.go cover each of the above.
2026-09-26 13:04:54 +10:00

6.5 KiB

xTeVe improvement checklist

Detailed rationale, file references and effort estimates: tasks/improvement-plan.md. Status: Phase 0 committed on branch improvements 2026-09-26.

Phase 0: Hygiene

  • .gitignore (.gocache/), deleted .gocache/, extended .dockerignore
  • agent.md / skill.md git-ignored and docker-ignored (left in place)
  • Version drift fixed (xteve.go now 0201) and Drone drift check added
  • Auto-updater deleted (BinaryUpdate, internal/up2date, GitHub/Update structs, xteveAutoUpdate + update.url settings, UI rows, en.json); migrations kept in migrate.go; kardianos/osext gone
  • go 1.27.1; Dockerfile and Drone golang images pinned to 1.27.1
  • Four go vet unreachable-code warnings fixed (vet clean)
  • staticcheck baseline via go run honnef.co/go/tools/cmd/staticcheck@latest ./...: 408 findings (S1002 113, SA5008 79, S1039 67, S1038 40, S1023 35, ST1005 20, SA1019 14, SA4006 9, misc 11). Mostly style; SA5008/SA4006/SA1019 worth a pass in Phase 3 cleanup

Phase 1: Security

  • textContent for provider-controlled strings (cells, client info, in-place edits, logs, popup descriptions with an explicit static-HTML flag)
  • Websocket uses gorilla's same-origin check; token read from the HttpOnly cookie (query param kept for legacy clients); payload/token console logging removed. Tests in src/websocket_test.go
  • Cookie HttpOnly, SameSite=Strict, Path=/, cleared on logout
  • Wizard GET no longer mutates AuthenticationWEB; the wizard page just bypasses login while active
  • uploadLogo filename sanitised (base name, image extensions only)
  • Zip-slip guard in extractZIP (also no more defer-in-loop there)
  • ffmpeg.path/vlc.path must be a regular file named ffmpeg/vlc/cvlc; stream URLs handed to the external buffer must use a network scheme
  • /download/ requires the web session when web auth is on
  • [~] Host-header-derived URLs kept by design (LAN, many interfaces; URLs must match how the client reached the server)
  • bcrypt for new passwords and credential changes; legacy SHA256 records verified in constant time and upgraded on first login; username compare constant-time
  • Expired tokens evicted on every new session; URL/Basic auth no longer mint tokens at all (AuthenticateUser)
  • [~] Not applicable: xTeVe has no roles, every web user is an administrator by design (documented in README security notes)
  • settings.json written 0600; Plex token masked in every payload to the UI, mask round-trips as "unchanged" on save
  • Decide default for web auth on fresh installs (keep off; LAN only, decided 2026-09-25)

Phase 2: Streaming stability

  • Race tests: two concurrent tuners against a fake TS server, run with -race
  • *Playlist with own mutex; remove stale store-backs
  • Atomic tuner reservation; clean BufferClients on force kill
  • RWMutex around StreamingURLS
  • Remove defer inside read loops (buffer, compression, imgcache)
  • Single external-process buffer (exec.CommandContext + request context) with ffmpeg and VLC argument builders; drop CloseNotifier
  • Real mutex for screen log
  • http.Server with timeouts; timeouts on all outbound clients
  • imgcache: download outside the lock
  • Atomic write helper (temp + fsync + rename)
  • Fix listed concrete bugs (xepg append, range mutation, log overflow, headers after WriteHeader, random notification eviction, unchecked assertions, API double write, WS struct reuse)
  • Error hygiene: no-op closures, os.Exit/panic outside main, ignored results

Phase 3: Build, embed, CI, Docker

  • //go:embed via html/embed.go; deleted webUI.go, html-build.go, cmd/webui-gen; ETag + Cache-Control on static assets
  • i18n dropped: 254 placeholders inlined, en.json deleted, only HTML pages templated (authenticationErr)
  • package.json + ts/tsconfig.json (tsc 5.9.3, ES2020, single outFile html/js/app.js, committed, CI-verified); 10 dead JS files deleted; 6 tsc errors fixed incl. a real ASI bug in the search shortcut
  • CI: vet, gofmt check, staticcheck v0.8.1 (config in staticcheck.conf), bundle freshness check. go test -race still to add once tests exist
  • Version-tagged images (amd64 only)
  • PUID/PGID via su-exec at runtime; static-ffmpeg pinned to 7.1.1; VOLUME /xteve/config; /xteve removed from LEGACY_CONFIG_DIRS; compose files pull from the registry and document SSDP/host networking
  • /healthz endpoint; Dockerfile healthcheck uses it
  • README-DEV.md and fork-specific README.md (about, container usage, env vars, security notes)
  • staticcheck 399 -> 0; dead code and duplicates removed; ioutil/rand.Seed gone. Real bugs fixed on the way: leaked file handle per ffmpeg segment, unchecked http.NewRequest, migration writing null xepg.json, silent user-write failures, unwritable config/temp dir now fatal at start
  • Resolve missing docs/design-system/ referenced by agent.md (user decision: agent.md is a personal, git-ignored file)

Phase 4: Data model and performance

Not planned (lineup is ~170 channels, decided 2026-09-25). See plan for the reference list.

Phase 5: Frontend architecture

  • Persistent websocket with request IDs, queue, backoff reconnect
  • Section-level re-render instead of full createLayout()
  • Virtualised mapping table
  • Split menu_ts.ts; addEventListener; data-driven settings rows
  • Accessibility follow-ups; light theme via prefers-color-scheme
  • Consolidate CSS layers

Phase 6: Optional features

  • Regex filters
  • Per-playlist tuner limit and buffer choice
  • Bulk channel edit
  • Versioned backup/restore
  • Dummy EPG durations

Review

Phase 0 (2026-09-26, branch improvements)

  • go build, go vet, go test ./... all clean. src/webUI.go regenerated.
  • Smoke run against an empty config dir on port 34499: /web/, /lineup_status.json, /discover.json all 200, no errors logged.
  • Not verified locally: Docker image build (no daemon on this machine); Drone will cover it.
  • Compiled JS in html/js/ was hand-edited to mirror the TS change because a current tsc does not reproduce the committed output (different shim, 5 type errors in menu_ts.ts). Phase 3 replaces this with a pinned toolchain.
  • html/js/menu.js still mentions xteveAutoUpdate; it is one of the ten dead legacy files scheduled for deletion in Phase 3.
  • Settings.Branch (git.branch) was kept: it still drives whether the build number is shown in the UI and XMLTV header.