diff --git a/mealie/routes/recipe/bulk_actions.py b/mealie/routes/recipe/bulk_actions.py index 2682564ca02f..678a157ccfb1 100644 --- a/mealie/routes/recipe/bulk_actions.py +++ b/mealie/routes/recipe/bulk_actions.py @@ -1,7 +1,7 @@ from functools import cached_property from pathlib import Path -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, HTTPException from mealie.core.dependencies.dependencies import temporary_zip_path from mealie.core.security import create_file_token @@ -50,6 +50,10 @@ class RecipeBulkActionsController(BaseUserController): @router.get("/export/download") def get_exported_data_token(self, path: Path): """Returns a token to download a file""" + path = Path(path).resolve() + + if not path.is_relative_to(self.folders.DATA_DIR): + raise HTTPException(400, "path must be relative to data directory") return {"fileToken": create_file_token(path)} diff --git a/mealie/routes/utility_routes.py b/mealie/routes/utility_routes.py index 21496b2e58fc..cc67f348d375 100644 --- a/mealie/routes/utility_routes.py +++ b/mealie/routes/utility_routes.py @@ -3,6 +3,7 @@ from pathlib import Path from fastapi import APIRouter, Depends, HTTPException, status from starlette.responses import FileResponse +from mealie.core.config import get_app_dirs from mealie.core.dependencies import validate_file_token router = APIRouter(prefix="/api/utils", tags=["Utils"], include_in_schema=True) @@ -12,6 +13,14 @@ router = APIRouter(prefix="/api/utils", tags=["Utils"], include_in_schema=True) async def download_file(file_path: Path = Depends(validate_file_token)): """Uses a file token obtained by an active user to retrieve a file from the operating system.""" + + file_path = Path(file_path).resolve() + + dirs = get_app_dirs() + + if not file_path.is_relative_to(dirs.DATA_DIR): + raise HTTPException(status.HTTP_400_BAD_REQUEST) + if not file_path.is_file(): raise HTTPException(status.HTTP_400_BAD_REQUEST)