security: fix #2 — wire hardened mpv options into _MpvGLWidget
Replaces the inline mpv.MPV(...) literal kwargs with a call through build_mpv_kwargs(), which adds ytdl=no, load_scripts=no, a lavf protocol whitelist (file,http,https,tls,tcp), and POSIX input_conf lockdown. Closes the yt-dlp delegation surface (CVE-prone extractors invoked on attacker-supplied URLs) and the concat:/subfile: local- file-read gadget via ffmpeg's lavf demuxer. behavior change from v0.2.5: any file_url whose host is only handled by yt-dlp (youtube.com, reddit.com, etc.) will no longer play. Boorus do not legitimately return such URLs, so in practice this only affects hostile responses. Cached local files and direct https .mp4/.webm/.mkv continue to work. Manually smoke tested: played a cached local .mp4 from the library (file: protocol) and a fresh network .webm from a danbooru search (https: protocol) — both work. Audit-Ref: SECURITY_AUDIT.md finding #2 Severity: High
This commit is contained in:
parent
22744c48af
commit
72803f0b14
@ -3,6 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
from PySide6.QtCore import Signal
|
from PySide6.QtCore import Signal
|
||||||
from PySide6.QtOpenGLWidgets import QOpenGLWidget as _QOpenGLWidget
|
from PySide6.QtOpenGLWidgets import QOpenGLWidget as _QOpenGLWidget
|
||||||
@ -10,6 +11,8 @@ from PySide6.QtWidgets import QWidget, QVBoxLayout
|
|||||||
|
|
||||||
import mpv as mpvlib
|
import mpv as mpvlib
|
||||||
|
|
||||||
|
from ._mpv_options import build_mpv_kwargs
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -35,57 +38,14 @@ class _MpvGLWidget(QWidget):
|
|||||||
self._frame_ready.connect(self._gl.update)
|
self._frame_ready.connect(self._gl.update)
|
||||||
# Create mpv eagerly on the main thread.
|
# Create mpv eagerly on the main thread.
|
||||||
#
|
#
|
||||||
# `ao=pulse` is critical for Linux Discord screen-share audio
|
# Options come from `build_mpv_kwargs` (see `_mpv_options.py`
|
||||||
# capture. Discord on Linux only enumerates audio clients via
|
# for the full rationale). Summary: Discord screen-share audio
|
||||||
# the libpulse API; it does not see clients that talk to
|
# fix via `ao=pulse`, fast-load vd-lavc options, network cache
|
||||||
# PipeWire natively (which is mpv's default `ao=pipewire`).
|
# tuning for the uncached-video fast path, and the SECURITY
|
||||||
# Forcing the pulseaudio output here makes mpv go through
|
# hardening from audit #2 (ytdl=no, load_scripts=no,
|
||||||
# PipeWire's pulseaudio compatibility layer, which Discord
|
# demuxer_lavf_o protocol whitelist, POSIX input_conf null).
|
||||||
# picks up the same way it picks up Firefox. Without this,
|
|
||||||
# videos play locally but the audio is silently dropped from
|
|
||||||
# any Discord screen share. See:
|
|
||||||
# https://github.com/mpv-player/mpv/issues/11100
|
|
||||||
# https://github.com/edisionnano/Screenshare-with-audio-on-Discord-with-Linux
|
|
||||||
# On Windows mpv ignores `ao=pulse` and falls through to the
|
|
||||||
# next entry, so listing `wasapi` second keeps Windows playback
|
|
||||||
# working without a platform branch here.
|
|
||||||
#
|
|
||||||
# `audio_client_name` is the name mpv registers with the audio
|
|
||||||
# backend. Sets `application.name` and friends so capture tools
|
|
||||||
# group mpv's audio under the booru-viewer app identity instead
|
|
||||||
# of the default "mpv Media Player".
|
|
||||||
self._mpv = mpvlib.MPV(
|
self._mpv = mpvlib.MPV(
|
||||||
vo="libmpv",
|
**build_mpv_kwargs(is_windows=sys.platform == "win32"),
|
||||||
hwdec="auto",
|
|
||||||
keep_open="yes",
|
|
||||||
ao="pulse,wasapi,",
|
|
||||||
audio_client_name="booru-viewer",
|
|
||||||
input_default_bindings=False,
|
|
||||||
input_vo_keyboard=False,
|
|
||||||
osc=False,
|
|
||||||
# Fast-load options: shave ~50-100ms off first-frame decode
|
|
||||||
# for h264/hevc by skipping a few bitstream-correctness checks
|
|
||||||
# (`vd-lavc-fast`) and the in-loop filter on non-keyframes
|
|
||||||
# (`vd-lavc-skiploopfilter=nonkey`). The artifacts are only
|
|
||||||
# visible on the first few frames before the decoder steady-
|
|
||||||
# state catches up, and only on degraded sources. mpv
|
|
||||||
# documents these as safe for "fast load" use cases like
|
|
||||||
# ours where we want the first frame on screen ASAP and
|
|
||||||
# don't care about a tiny quality dip during ramp-up.
|
|
||||||
vd_lavc_fast="yes",
|
|
||||||
vd_lavc_skiploopfilter="nonkey",
|
|
||||||
# Network streaming tuning for the uncached-video fast path.
|
|
||||||
# cache=yes is mpv's default for network sources but explicit
|
|
||||||
# is clearer. cache_pause=no keeps playback running through
|
|
||||||
# brief buffer underruns instead of pausing — for short booru
|
|
||||||
# clips a momentary stutter beats a pause icon. demuxer caps
|
|
||||||
# keep RAM bounded. network_timeout=10 replaces mpv's ~60s
|
|
||||||
# default so stalled connections surface errors promptly.
|
|
||||||
cache="yes",
|
|
||||||
cache_pause="no",
|
|
||||||
demuxer_max_bytes="50MiB",
|
|
||||||
demuxer_readahead_secs="20",
|
|
||||||
network_timeout="10",
|
|
||||||
)
|
)
|
||||||
# Wire up the GL surface's callbacks to us
|
# Wire up the GL surface's callbacks to us
|
||||||
self._gl._owner = self
|
self._gl._owner = self
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user