playlist_download, download_epg, upload_snapshot, and get_logo all
built filesystem paths by concatenating a caller-supplied string
(filename/id_channel/id_device) with no validation, so a '../'
payload could read or write files outside the intended directory.
upload_snapshot was the most exploitable: fully attacker-controlled
bytes written to an attacker-chosen path with no prior lookup gating
it. Add a safe_join() helper that resolves the path and rejects
anything that escapes the base directory, and use it at all four
call sites.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The settings endpoint returned the raw key to any caller, and the
frontend used that response to pre-fill the input field, which also
meant saving with an untouched field would silently resubmit the
plaintext key. /gemini_key now reports only whether a key is set and
a masked preview; the UI shows that as a placeholder and only updates
the stored key when the field is actually filled in.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
requests.get() calls had no timeout and ran directly on the aiohttp
event loop, so a single dead logo host would hang for minutes and
block every other request. Add timeouts and move logo downloads in
get_logo to a thread executor so a slow/dead host no longer stalls
the whole server.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The app now listens on plain HTTP (127.0.0.1:5023 only) instead of
binding 443 and terminating TLS itself. Nginx handles TLS for
iptv.mrk.ovh and proxies to the app internally.
IPTV.py now writes logs to a rotating file and forwards critical VLC
playback errors (start timeout, MediaPlayerEncounteredError) to the
server instead of losing everything to unredirected print() calls.
The web UI's device menu gets a working Terminal (to run diagnostic
commands like tail on the log) and a Recent errors view backed by a
capped last_errors list on each device document, keeping DB volume
bounded to the last 5 entries per device.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>