40 lines
1.3 KiB
Python
40 lines
1.3 KiB
Python
# File upload validator — internal CMS, pre-fix.
|
|
# Validates uploaded image, then moves it into a public web-root.
|
|
|
|
import os, shutil, hashlib
|
|
from PIL import Image
|
|
|
|
UPLOAD_TMP = "/var/uploads/tmp"
|
|
PUBLIC_DIR = "/var/www/static/uploads"
|
|
ALLOWED_MIME = {"image/png", "image/jpeg", "image/gif"}
|
|
|
|
def validate_image(tmp_path):
|
|
"""Open with PIL to verify it's a real image. Returns True if valid."""
|
|
try:
|
|
with Image.open(tmp_path) as im:
|
|
im.verify() # raises on malformed
|
|
with Image.open(tmp_path) as im:
|
|
return im.format.lower() in ("png", "jpeg", "gif")
|
|
except Exception:
|
|
return False
|
|
|
|
def upload_user_avatar(user_id, tmp_path):
|
|
"""Upload flow: client puts file at UPLOAD_TMP/<user_id>.upload, this
|
|
function validates and promotes to PUBLIC_DIR."""
|
|
|
|
# 1. validate the file at tmp_path
|
|
if not validate_image(tmp_path):
|
|
os.remove(tmp_path)
|
|
return {"ok": False, "error": "not_an_image"}
|
|
|
|
# 2. compute hash for de-dup
|
|
with open(tmp_path, "rb") as f:
|
|
digest = hashlib.sha256(f.read()).hexdigest()
|
|
|
|
# 3. move the file to public location
|
|
dest = os.path.join(PUBLIC_DIR, f"{user_id}-{digest[:16]}.bin")
|
|
shutil.move(tmp_path, dest)
|
|
|
|
# 4. server serves it via X-Sendfile so the extension doesn't matter
|
|
return {"ok": True, "path": dest}
|