mirror of
https://github.com/rommapp/romm.git
synced 2026-06-28 14:56:01 +00:00
Adds rejection + acceptance tests for update_rom, add_collection, and update_collection artwork uploads, mirroring the existing avatar tests: non-image content returns 400, and a real PNG uploaded under a misleading filename like payload.html is stored with the trusted .png extension. Also fixes two `return HTTPException(...)` → `raise` in raw.py so the 404 path actually surfaces instead of silently returning the exception object. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
75 lines
2.3 KiB
Python
75 lines
2.3 KiB
Python
from mimetypes import guess_type
|
|
from pathlib import Path
|
|
|
|
from fastapi import HTTPException, Request
|
|
from fastapi.responses import FileResponse
|
|
|
|
from decorators.auth import protected_route
|
|
from handler.auth.constants import Scope
|
|
from handler.filesystem import fs_asset_handler
|
|
from handler.filesystem.assets_handler import SAFE_IMAGE_MIME_TYPES
|
|
from utils.router import APIRouter
|
|
|
|
router = APIRouter(
|
|
prefix="/raw",
|
|
tags=["raw"],
|
|
)
|
|
|
|
|
|
def _build_asset_response(resolved_path: Path) -> FileResponse:
|
|
guessed_type, _ = guess_type(resolved_path.name)
|
|
if guessed_type in SAFE_IMAGE_MIME_TYPES:
|
|
return FileResponse(
|
|
path=str(resolved_path),
|
|
filename=resolved_path.name,
|
|
media_type=guessed_type,
|
|
content_disposition_type="inline",
|
|
)
|
|
|
|
return FileResponse(
|
|
path=str(resolved_path),
|
|
filename=resolved_path.name,
|
|
media_type="application/octet-stream",
|
|
content_disposition_type="attachment",
|
|
)
|
|
|
|
|
|
@protected_route(router.head, "/assets/{path:path}", [Scope.ASSETS_READ])
|
|
def head_raw_asset(request: Request, path: str):
|
|
try:
|
|
resolved_path = fs_asset_handler.validate_path(path)
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=404, detail="Asset not found") from exc
|
|
|
|
# Check if file exists and is a file (not directory)
|
|
if not resolved_path.exists() or not resolved_path.is_file():
|
|
raise HTTPException(status_code=404, detail="Asset not found")
|
|
|
|
return _build_asset_response(resolved_path)
|
|
|
|
|
|
@protected_route(router.get, "/assets/{path:path}", [Scope.ASSETS_READ])
|
|
def get_raw_asset(request: Request, path: str):
|
|
"""Download a single asset file
|
|
|
|
Args:
|
|
request (Request): Fastapi Request object
|
|
path (str): Relative path to the asset file
|
|
|
|
Returns:
|
|
FileResponse: Returns a single asset file
|
|
|
|
Raises:
|
|
HTTPException: 404 if asset not found or access denied
|
|
"""
|
|
try:
|
|
resolved_path = fs_asset_handler.validate_path(path)
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=404, detail="Asset not found") from exc
|
|
|
|
# Check if file exists and is a file (not directory)
|
|
if not resolved_path.exists() or not resolved_path.is_file():
|
|
raise HTTPException(status_code=404, detail="Asset not found")
|
|
|
|
return _build_asset_response(resolved_path)
|