fix(player): mpv draws all Linux video, and no longer runs text from a URL
Security (DR-298, DR-299): - The pinned libmpv crate's Mpv::command joins its arguments and calls mpv_command_string, which parses `;` as a command separator. Stream URLs carry server-controlled ids and TranscodingUrl, and a download's file:// path carries its track title, so a crafted title could run any mpv command, `run` included. Every call now goes through mpv_command::command, an argv built for mpv_command. The same parse broke loadfile for every downloaded title containing a space. - mpv's tls-verify defaults to no, and its URLs carry the ApiKey. Every handle is now hardened with tls-verify=yes and ytdl=no before its first loadfile, and fails construction if it cannot be. Linux video (DR-235 phase 1): - native_video::enabled() is unconditional on Linux; the JELLYTAU_NATIVE_VIDEO opt-in is retired. No platform reports a webview video fallback, so the Settings switch no longer appears. Windows keeps the webview element until mpv reaches it (DR-237). - The Linux device profile is unchanged (still h264, DR-234), so this ships the configuration that was tested under the env var.
This commit is contained in:
@@ -148,6 +148,8 @@ impl MpvBackend {
|
||||
let mpv = Mpv::new().map_err(|e| PlayerError {
|
||||
message: format!("Failed to initialize MPV: {:?}", e),
|
||||
})?;
|
||||
// TRACES: UR-012 | DR-299
|
||||
super::mpv_command::harden(&mpv).map_err(|message| PlayerError { message })?;
|
||||
|
||||
// Detect and configure audio output
|
||||
let audio_driver = detect_audio_system();
|
||||
@@ -178,11 +180,11 @@ impl MpvBackend {
|
||||
|
||||
// Video is disabled unless this process is drawing it.
|
||||
//
|
||||
// `video: no` is why mpv has never decoded a frame here: Linux video has
|
||||
// always gone through the webview, and decoding it twice would burn a
|
||||
// core for a picture nobody sees. With native video on, mpv needs both
|
||||
// the decoder *and* `vo=libmpv` — the render API only works through that
|
||||
// output, and the default would try to open a window of its own.
|
||||
// Linux video went through the webview until DR-235, and decoding it
|
||||
// here too would have burned a core for a picture nobody saw — hence
|
||||
// `video: no`. With native video, mpv needs both the decoder *and*
|
||||
// `vo=libmpv` — the render API only works through that output, and the
|
||||
// default would try to open a window of its own.
|
||||
//
|
||||
// Set at construction because mpv resolves the video output when it
|
||||
// initialises; flipping it later does not re-open one.
|
||||
@@ -600,12 +602,14 @@ impl PlayerBackend for MpvBackend {
|
||||
// TRACES: UR-040, UR-005 | DR-253
|
||||
*self.pending_seek.lock_safe() = None;
|
||||
|
||||
// Load the media file
|
||||
self.mpv
|
||||
.command("loadfile", &[&stream_url])
|
||||
.map_err(|e| PlayerError {
|
||||
message: format!("Failed to load file: {:?}", e),
|
||||
})?;
|
||||
// Load the media file. Through `mpv_command::command`, never
|
||||
// `Mpv::command`: the URL carries server-controlled text.
|
||||
// TRACES: UR-003, UR-004 | DR-298
|
||||
super::mpv_command::command(&self.mpv, &["loadfile", &stream_url]).map_err(|e| {
|
||||
PlayerError {
|
||||
message: format!("Failed to load file: {e}"),
|
||||
}
|
||||
})?;
|
||||
|
||||
debug!("[MpvBackend] Load command sent successfully");
|
||||
Ok(())
|
||||
@@ -638,8 +642,8 @@ impl PlayerBackend for MpvBackend {
|
||||
fn stop(&mut self) -> Result<(), PlayerError> {
|
||||
debug!("[MpvBackend] Stop command");
|
||||
|
||||
self.mpv.command("stop", &[]).map_err(|e| PlayerError {
|
||||
message: format!("Failed to stop: {:?}", e),
|
||||
super::mpv_command::command(&self.mpv, &["stop"]).map_err(|e| PlayerError {
|
||||
message: format!("Failed to stop: {e}"),
|
||||
})?;
|
||||
|
||||
// Stopping ends the seek's subject along with the playback.
|
||||
|
||||
Reference in New Issue
Block a user