mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
Ensure media files are passed relative to the media folder (#4041)
We were (partially) doing this for MpvManager, but not for
Windows' SimpleMpvPlayer. By passing a media file starting
with a special scheme, a malicious actor could have caused a file to
be written to the filesystem on Windows.
Thanks once again to Michael Lappas for the report.
(cherry picked from commit 96ff27d1fb
)
This commit is contained in:
parent
229819236d
commit
f3acf5fe59
3 changed files with 14 additions and 8 deletions
|
@ -76,7 +76,7 @@ class MediaManager(DeprecatedNamesMixin):
|
||||||
return self.col._backend.strip_av_tags(text)
|
return self.col._backend.strip_av_tags(text)
|
||||||
|
|
||||||
def _extract_filenames(self, text: str) -> list[str]:
|
def _extract_filenames(self, text: str) -> list[str]:
|
||||||
"This only exists do support a legacy function; do not use."
|
"This only exists to support a legacy function; do not use."
|
||||||
out = self.col._backend.extract_av_tags(text=text, question_side=True)
|
out = self.col._backend.extract_av_tags(text=text, question_side=True)
|
||||||
return [
|
return [
|
||||||
x.filename
|
x.filename
|
||||||
|
|
|
@ -9,10 +9,13 @@ These can be accessed via eg card.question_av_tags()
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
from anki import hooks
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TTSTag:
|
class TTSTag:
|
||||||
|
@ -38,6 +41,13 @@ class SoundOrVideoTag:
|
||||||
|
|
||||||
filename: str
|
filename: str
|
||||||
|
|
||||||
|
def path(self, media_folder: str) -> str:
|
||||||
|
"Prepend the media folder to the filename."
|
||||||
|
# Ensure filename doesn't reference parent folder
|
||||||
|
filename = os.path.basename(self.filename)
|
||||||
|
filename = hooks.media_file_filter(filename)
|
||||||
|
return os.path.join(media_folder, filename)
|
||||||
|
|
||||||
|
|
||||||
# note this does not include image tags, which are handled with HTML.
|
# note this does not include image tags, which are handled with HTML.
|
||||||
AVTag = Union[SoundOrVideoTag, TTSTag]
|
AVTag = Union[SoundOrVideoTag, TTSTag]
|
||||||
|
|
|
@ -23,7 +23,6 @@ from markdown import markdown
|
||||||
import aqt
|
import aqt
|
||||||
import aqt.mpv
|
import aqt.mpv
|
||||||
import aqt.qt
|
import aqt.qt
|
||||||
from anki import hooks
|
|
||||||
from anki.cards import Card
|
from anki.cards import Card
|
||||||
from anki.sound import AV_REF_RE, AVTag, SoundOrVideoTag
|
from anki.sound import AV_REF_RE, AVTag, SoundOrVideoTag
|
||||||
from anki.utils import is_lin, is_mac, is_win, namedtmp
|
from anki.utils import is_lin, is_mac, is_win, namedtmp
|
||||||
|
@ -321,7 +320,7 @@ class SimpleProcessPlayer(Player): # pylint: disable=abstract-method
|
||||||
def _play(self, tag: AVTag) -> None:
|
def _play(self, tag: AVTag) -> None:
|
||||||
assert isinstance(tag, SoundOrVideoTag)
|
assert isinstance(tag, SoundOrVideoTag)
|
||||||
self._process = subprocess.Popen(
|
self._process = subprocess.Popen(
|
||||||
self.args + ["--", tag.filename],
|
self.args + ["--", tag.path(self._media_folder)],
|
||||||
env=self.env,
|
env=self.env,
|
||||||
cwd=self._media_folder,
|
cwd=self._media_folder,
|
||||||
stdout=subprocess.DEVNULL,
|
stdout=subprocess.DEVNULL,
|
||||||
|
@ -447,8 +446,7 @@ class MpvManager(MPV, SoundOrVideoPlayer):
|
||||||
def play(self, tag: AVTag, on_done: OnDoneCallback) -> None:
|
def play(self, tag: AVTag, on_done: OnDoneCallback) -> None:
|
||||||
assert isinstance(tag, SoundOrVideoTag)
|
assert isinstance(tag, SoundOrVideoTag)
|
||||||
self._on_done = on_done
|
self._on_done = on_done
|
||||||
filename = hooks.media_file_filter(tag.filename)
|
path = tag.path(self.media_folder)
|
||||||
path = os.path.join(self.media_folder, filename)
|
|
||||||
|
|
||||||
if self.mpv_version is None or self.mpv_version >= (0, 38, 0):
|
if self.mpv_version is None or self.mpv_version >= (0, 38, 0):
|
||||||
self.command("loadfile", path, "replace", -1, "pause=no")
|
self.command("loadfile", path, "replace", -1, "pause=no")
|
||||||
|
@ -500,10 +498,8 @@ class SimpleMplayerSlaveModePlayer(SimpleMplayerPlayer):
|
||||||
def _play(self, tag: AVTag) -> None:
|
def _play(self, tag: AVTag) -> None:
|
||||||
assert isinstance(tag, SoundOrVideoTag)
|
assert isinstance(tag, SoundOrVideoTag)
|
||||||
|
|
||||||
filename = hooks.media_file_filter(tag.filename)
|
|
||||||
|
|
||||||
self._process = subprocess.Popen(
|
self._process = subprocess.Popen(
|
||||||
self.args + ["--", filename],
|
self.args + ["--", tag.path(self.media_folder)],
|
||||||
env=self.env,
|
env=self.env,
|
||||||
cwd=self.media_folder,
|
cwd=self.media_folder,
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
|
|
Loading…
Reference in a new issue