fix(security): private temp dir for docker installer, https for OMDb, md5 non-security flag
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
4f30ee5c0d
commit
668681dd24
@ -13,6 +13,7 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
|
|||||||
- **Voice list rows no longer show the "Source unknown" badge** (it crowded the play buttons). The badge stays in the voice inspector, next to the Source & consent panel.
|
- **Voice list rows no longer show the "Source unknown" badge** (it crowded the play buttons). The badge stays in the voice inspector, next to the Source & consent panel.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- **Security hardening (Sonar findings).** The Docker installer downloads `get-docker.sh` into a private `mkdtemp` dir (not a predictable `/tmp` path) and removes it afterwards; the OMDb poster lookup uses HTTPS; the fish.audio cache key marks MD5 as `usedforsecurity=False`.
|
||||||
- **Background jobs could be garbage-collected mid-run.** Fire-and-forget `asyncio.create_task` calls (magazine, conversation, tts, stt, library, sources) now go through `core.tasks.spawn`, which keeps a strong reference until the task ends and logs failures by exception class only.
|
- **Background jobs could be garbage-collected mid-run.** Fire-and-forget `asyncio.create_task` calls (magazine, conversation, tts, stt, library, sources) now go through `core.tasks.spawn`, which keeps a strong reference until the task ends and logs failures by exception class only.
|
||||||
- **Voice archetype gallery broke `npm run check:frontend`**: its `say` helper collided with `magazine.js`; renamed to `archSay`.
|
- **Voice archetype gallery broke `npm run check:frontend`**: its `say` helper collided with `magazine.js`; renamed to `archSay`.
|
||||||
- **Export failed with HTTP 500 when provenance tagging failed** (EPUB/ZIP/article MP3 with audio ffmpeg cannot tag); it now ships the untagged file and logs a warning.
|
- **Export failed with HTTP 500 when provenance tagging failed** (EPUB/ZIP/article MP3 with audio ffmpeg cannot tag); it now ships the untagged file and logs a warning.
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import platform
|
|||||||
import queue
|
import queue
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
import webbrowser
|
import webbrowser
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -186,7 +187,7 @@ class GuidedInstaller(tk.Tk):
|
|||||||
self.log.see("end")
|
self.log.see("end")
|
||||||
self.after(120, self._drain_log)
|
self.after(120, self._drain_log)
|
||||||
|
|
||||||
def run_threaded(self, title: str, commands: list[list[str]]) -> None:
|
def run_threaded(self, title: str, commands: list[list[str]], cleanup_dir: str | None = None) -> None:
|
||||||
def worker():
|
def worker():
|
||||||
self.log_line(f"\n== {title} ==")
|
self.log_line(f"\n== {title} ==")
|
||||||
for cmd in commands:
|
for cmd in commands:
|
||||||
@ -203,6 +204,8 @@ class GuidedInstaller(tk.Tk):
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self.log_line(f"Failed: {exc}")
|
self.log_line(f"Failed: {exc}")
|
||||||
break
|
break
|
||||||
|
if cleanup_dir:
|
||||||
|
shutil.rmtree(cleanup_dir, ignore_errors=True)
|
||||||
threading.Thread(target=worker, daemon=True).start()
|
threading.Thread(target=worker, daemon=True).start()
|
||||||
|
|
||||||
def command_ok(self, cmd: list[str]) -> bool:
|
def command_ok(self, cmd: list[str]) -> bool:
|
||||||
@ -260,11 +263,13 @@ class GuidedInstaller(tk.Tk):
|
|||||||
"Run Docker's official Linux convenience installer?\n\nThis may ask for sudo privileges and needs internet access.",
|
"Run Docker's official Linux convenience installer?\n\nThis may ask for sudo privileges and needs internet access.",
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
tmp = tempfile.mkdtemp(prefix="docker-install-") # 0700, unpredictable name
|
||||||
|
script = os.path.join(tmp, "get-docker.sh")
|
||||||
self.run_threaded("Install Docker", [
|
self.run_threaded("Install Docker", [
|
||||||
["curl", "-fsSL", "https://get.docker.com", "-o", "/tmp/get-docker.sh"],
|
["curl", "-fsSL", "https://get.docker.com", "-o", script],
|
||||||
["sh", "/tmp/get-docker.sh"],
|
["sh", script],
|
||||||
["docker", "version"],
|
["docker", "version"],
|
||||||
])
|
], cleanup_dir=tmp)
|
||||||
|
|
||||||
def generate_compose(self) -> None:
|
def generate_compose(self) -> None:
|
||||||
GENERATED_DIR.mkdir(parents=True, exist_ok=True)
|
GENERATED_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|||||||
@ -875,7 +875,7 @@ async def fishaudio_voices(request: Request):
|
|||||||
params["tag"] = tags
|
params["tag"] = tags
|
||||||
import hashlib
|
import hashlib
|
||||||
cache_dir = CONFIG_DIR / "fishaudio_cache"
|
cache_dir = CONFIG_DIR / "fishaudio_cache"
|
||||||
cache_key = hashlib.md5(json.dumps(params, sort_keys=True, default=str).encode()).hexdigest()
|
cache_key = hashlib.md5(json.dumps(params, sort_keys=True, default=str).encode(), usedforsecurity=False).hexdigest()
|
||||||
cache_file = cache_dir / f"{cache_key}.json"
|
cache_file = cache_dir / f"{cache_key}.json"
|
||||||
try:
|
try:
|
||||||
r = await asyncio.to_thread(
|
r = await asyncio.to_thread(
|
||||||
@ -1176,7 +1176,7 @@ async def movie_poster(title: str = ""):
|
|||||||
clean = re.sub(r"\s*\(.*?\)\s*$", "", title).strip()
|
clean = re.sub(r"\s*\(.*?\)\s*$", "", title).strip()
|
||||||
result = {"poster": "", "year": "", "title": title}
|
result = {"poster": "", "year": "", "title": title}
|
||||||
try:
|
try:
|
||||||
url = f"http://www.omdbapi.com/?t={_q(clean)}&type=movie&apikey=trilogy"
|
url = f"https://www.omdbapi.com/?t={_q(clean)}&type=movie&apikey=trilogy"
|
||||||
r = await asyncio.to_thread(lambda: requests.get(url, timeout=8))
|
r = await asyncio.to_thread(lambda: requests.get(url, timeout=8))
|
||||||
if r.ok:
|
if r.ok:
|
||||||
d = r.json()
|
d = r.json()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user