Security fixes: - Block /proc /sys /dev /run /boot in /api/browse-dirs (path traversal) - Verify yt-dlp output stays inside TEMP_DIR before registration - Remove Access-Control-Allow-Origin: * from /api/proxy-audio - TTL-based temp file registry (default 2h) to prevent disk fill Performance: - Cache settings + routing rules in memory (mtime-checked); eliminates per-request disk reads on every TTS call UI: - Add container name (optional) field to Docker stack TTS/STT engine cards (Qwen3 Voice Clone, Voice Design, Custom Voice, Streaming, NVIDIA Magpie, Parakeet) — enables Stop/Start/Restart buttons on all engine cards, matching the existing Other Local TTS/STT cards Refactor — backend: - server.py: 5560 lines → 43-line entry point - core/ package: constants, registry, validation, docker_client, config, routing, audio, voice, presets, tts_helpers - routes/ package: admin, settings, library, stt, sources, docker, tts, conversation (FastAPI APIRouter modules) - Dockerfile + docker-compose.yml updated to include core/ and routes/ Refactor — frontend: - static/app.js: 8744 lines → 16 modules in static/js/ utils, voice-inspector, voice-sources, integrations, routing, settings, voice-clone, voice-library, tts-preview, benchmark, stt, init, engines, ai-backends, generation, conversation - static/loader.js updated to load modules sequentially Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
32 lines
859 B
Python
32 lines
859 B
Python
"""Temp-file registry with TTL-based GC."""
|
|
from __future__ import annotations
|
|
|
|
import contextlib
|
|
import os
|
|
import tempfile
|
|
import time
|
|
from pathlib import Path
|
|
|
|
TEMP_DIR = Path(tempfile.mkdtemp(prefix="vcf_"))
|
|
_REGISTRY_TTL = float(os.environ.get("TEMP_FILE_TTL_SECONDS", "7200")) # 2 h default
|
|
_registry: dict[str, tuple[Path, float]] = {}
|
|
|
|
|
|
def _registry_put(fid: str, path: Path) -> None:
|
|
_registry[fid] = (path, time.monotonic())
|
|
_registry_gc()
|
|
|
|
|
|
def _registry_get(fid: str) -> Path | None:
|
|
entry = _registry.get(fid)
|
|
return entry[0] if entry else None
|
|
|
|
|
|
def _registry_gc() -> None:
|
|
cutoff = time.monotonic() - _REGISTRY_TTL
|
|
stale = [k for k, (_, ts) in _registry.items() if ts < cutoff]
|
|
for k in stale:
|
|
path, _ = _registry.pop(k)
|
|
with contextlib.suppress(Exception):
|
|
path.unlink(missing_ok=True)
|