feat: add safe filename handling for backup and sync processes to prevent invalid paths
This commit is contained in:
+26
-2
@@ -1,5 +1,7 @@
|
||||
import os
|
||||
import zipfile
|
||||
import hashlib
|
||||
import re
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
from app.utils.logger import logger
|
||||
@@ -19,6 +21,28 @@ BACKUP_DIR = os.path.abspath(
|
||||
)
|
||||
|
||||
|
||||
def _safe_zip_entry_name(name: str, extension: str = ".m3u8") -> str:
|
||||
"""Return a safe zip entry filename.
|
||||
|
||||
Prevents zip-slip style paths and avoids problematic characters.
|
||||
"""
|
||||
|
||||
original = (name or "").strip()
|
||||
base = os.path.basename(original)
|
||||
base = re.sub(r"[\x00-\x1f\x7f]", "_", base)
|
||||
invalid = set('<>:"/\\|?*')
|
||||
cleaned = "".join(("_" if ch in invalid else ch) for ch in base).strip().strip(". ")
|
||||
if not cleaned:
|
||||
cleaned = "playlist"
|
||||
|
||||
cleaned = cleaned[:160].rstrip().strip(". ")
|
||||
if cleaned != original:
|
||||
digest = hashlib.sha1(original.encode("utf-8", errors="ignore")).hexdigest()[:8]
|
||||
cleaned = f"{cleaned}__{digest}"
|
||||
|
||||
return f"{cleaned}{extension}"
|
||||
|
||||
|
||||
def ensure_backup_dir():
|
||||
"""Ensure the backup directory exists."""
|
||||
if not os.path.exists(BACKUP_DIR):
|
||||
@@ -118,7 +142,7 @@ def backup_local_playlists(local_path: str) -> str | None:
|
||||
|
||||
# Get the playlist name without extension and add .m3u8 extension
|
||||
playlist_name = os.path.splitext(entry.name)[0]
|
||||
archive_name = f"{playlist_name}.m3u8"
|
||||
archive_name = _safe_zip_entry_name(playlist_name)
|
||||
|
||||
# Write to zip
|
||||
zipf.writestr(archive_name, content)
|
||||
@@ -217,7 +241,7 @@ def backup_cloud_playlists(library_name: str) -> str | None:
|
||||
|
||||
if len(lines) > 1: # More than just #EXTM3U
|
||||
content = "\n".join(lines)
|
||||
archive_name = f"{playlist.title}.m3u8"
|
||||
archive_name = _safe_zip_entry_name(getattr(playlist, "title", "playlist"))
|
||||
zipf.writestr(archive_name, content)
|
||||
playlist_count += 1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user