fix: validate upload date, close upload races (REQ-178)

This commit is contained in:
Andrew-AAAA committed 2026-09-29 08:55:14 +07:00
1 parent 712cdeabf1
commit 92360660c7
1 file changed
+19 -4
+19 -4
View File
@@ -104,13 +104,17 @@ class LibraryConflict(LibraryError):
def create_date(video_root: str, date: str) -> str:
"""Make a YYYY-MM-DD folder; never touch an existing one (REQ-171)."""
"""Make a YYYY-MM-DD folder; never touch an existing one (REQ-178)."""
if not re.fullmatch(r"\d{4}-\d{2}-\d{2}", date):
raise LibraryError("Folder name must be YYYY-MM-DD")
folder = _safe_join(_effective_root(video_root), date)
if os.path.exists(folder):
raise LibraryConflict(f"Folder already exists: {date}")
os.makedirs(folder)
try:
os.makedirs(folder)
except FileExistsError:
# Lost the race against a concurrent mkdir; same 409 as above.
raise LibraryConflict(f"Folder already exists: {date}")
return folder
@@ -119,6 +123,8 @@ def upload_video(video_root: str, date: str, filename: str, chunks) -> str:
name = os.path.basename(filename or "")
if not name or name != filename or not name.lower().endswith(video.VIDEO_EXTS):
raise LibraryError(f"Unsupported file: {filename}")
if not re.fullmatch(r"\d{4}-\d{2}-\d{2}", date):
raise LibraryError("Folder name must be YYYY-MM-DD")
root = _effective_root(video_root)
if not os.path.isdir(_safe_join(root, date)):
raise LibraryError(f"No such date in the archive: {date}")
@@ -127,13 +133,22 @@ def upload_video(video_root: str, date: str, filename: str, chunks) -> str:
raise LibraryConflict(f"Already exists: {date}/{name}")
part = dest + ".part"
try:
with open(part, "wb") as handle:
fd = os.open(part, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
except FileExistsError:
raise LibraryConflict(f"Already exists: {date}/{name}")
try:
with os.fdopen(fd, "wb") as handle:
for chunk in chunks:
handle.write(chunk)
if os.path.exists(dest):
raise LibraryConflict(f"Already exists: {date}/{name}")
os.replace(part, dest)
except BaseException:
if os.path.exists(part):
os.unlink(part)
try:
os.unlink(part)
except OSError:
pass
raise
return f"{date}/{name}"