From bdbc9e323d1b0de60386967816dbdb7a1413f445 Mon Sep 17 00:00:00 2001 From: hay-kot Date: Sun, 28 Mar 2021 12:30:45 -0800 Subject: [PATCH] secure routes --- mealie/routes/backup_routes.py | 7 +++-- mealie/routes/debug_routes.py | 9 +++--- mealie/routes/mealplans/crud.py | 23 +++++++-------- mealie/routes/mealplans/helpers.py | 13 ++++---- mealie/routes/migration_routes.py | 7 +++-- mealie/routes/recipe/category_routes.py | 3 +- mealie/routes/recipe/recipe_crud_routes.py | 31 ++++++++++++++++---- mealie/routes/recipe/tag_routes.py | 11 +++---- mealie/routes/site_settings/custom_pages.py | 7 ++++- mealie/routes/site_settings/site_settings.py | 13 ++++---- mealie/routes/theme_routes.py | 18 ++++++++---- 11 files changed, 89 insertions(+), 53 deletions(-) diff --git a/mealie/routes/backup_routes.py b/mealie/routes/backup_routes.py index 8c186a737..28786a1d0 100644 --- a/mealie/routes/backup_routes.py +++ b/mealie/routes/backup_routes.py @@ -4,6 +4,7 @@ import shutil from fastapi import APIRouter, Depends, File, HTTPException, UploadFile from mealie.core.config import BACKUP_DIR, TEMPLATE_DIR from mealie.db.db_setup import generate_session +from mealie.routes.deps import get_current_user from mealie.schema.backup import BackupJob, ImportJob, Imports, LocalBackup from mealie.schema.snackbar import SnackResponse from mealie.services.backups import imports @@ -11,7 +12,7 @@ from mealie.services.backups.exports import backup_all from sqlalchemy.orm.session import Session from starlette.responses import FileResponse -router = APIRouter(prefix="/api/backups", tags=["Backups"]) +router = APIRouter(prefix="/api/backups", tags=["Backups"], dependencies=[Depends(get_current_user)]) @router.get("/available", response_model=Imports) @@ -52,7 +53,7 @@ def export_database(data: BackupJob, session: Session = Depends(generate_session @router.post("/upload") -def upload_backup_zipfile(archive: UploadFile = File(...)): +def upload_backup_file(archive: UploadFile = File(...)): """ Upload a .zip File to later be imported into Mealie """ dest = BACKUP_DIR.joinpath(archive.filename) @@ -66,7 +67,7 @@ def upload_backup_zipfile(archive: UploadFile = File(...)): @router.get("/{file_name}/download") -async def upload_nextcloud_zipfile(file_name: str): +async def download_backup_file(file_name: str): """ Upload a .zip File to later be imported into Mealie """ file = BACKUP_DIR.joinpath(file_name) diff --git a/mealie/routes/debug_routes.py b/mealie/routes/debug_routes.py index b71a83056..72d1eeb3c 100644 --- a/mealie/routes/debug_routes.py +++ b/mealie/routes/debug_routes.py @@ -1,9 +1,10 @@ import json +from fastapi import APIRouter, Depends from mealie.core.config import APP_VERSION, DEBUG_DIR, LOGGER_FILE -from fastapi import APIRouter +from mealie.routes.deps import get_current_user -router = APIRouter(prefix="/api/debug", tags=["Debug"]) +router = APIRouter(prefix="/api/debug", tags=["Debug"], dependencies=[Depends(get_current_user)]) @router.get("/version") @@ -25,9 +26,7 @@ async def get_log(num: int): """ Doc Str """ with open(LOGGER_FILE, "rb") as f: log_text = tail(f, num) - HTML_RESPONSE = log_text - - return HTML_RESPONSE + return log_text def tail(f, lines=20): diff --git a/mealie/routes/mealplans/crud.py b/mealie/routes/mealplans/crud.py index 906d0029d..f5196c785 100644 --- a/mealie/routes/mealplans/crud.py +++ b/mealie/routes/mealplans/crud.py @@ -25,9 +25,7 @@ def get_all_meals( @router.post("/create") def create_meal_plan( - data: MealPlanIn, - session: Session = Depends(generate_session), - current_user=Depends(get_current_user), + data: MealPlanIn, session: Session = Depends(generate_session), current_user=Depends(get_current_user) ): """ Creates a meal plan database entry """ processed_plan = process_meals(session, data) @@ -37,7 +35,12 @@ def create_meal_plan( @router.put("/{plan_id}") -def update_meal_plan(plan_id: str, meal_plan: MealPlanIn, session: Session = Depends(generate_session)): +def update_meal_plan( + plan_id: str, + meal_plan: MealPlanIn, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Updates a meal plan based off ID """ processed_plan = process_meals(session, meal_plan) processed_plan = MealPlanInDB(uid=plan_id, **processed_plan.dict()) @@ -47,7 +50,7 @@ def update_meal_plan(plan_id: str, meal_plan: MealPlanIn, session: Session = Dep @router.delete("/{plan_id}") -def delete_meal_plan(plan_id, session: Session = Depends(generate_session)): +def delete_meal_plan(plan_id, session: Session = Depends(generate_session), current_user=Depends(get_current_user)): """ Removes a meal plan from the database """ db.meals.delete(session, plan_id) @@ -56,20 +59,14 @@ def delete_meal_plan(plan_id, session: Session = Depends(generate_session)): @router.get("/this-week", response_model=MealPlanInDB) -def get_this_week( - session: Session = Depends(generate_session), - current_user: UserInDB = Depends(get_current_user), -): +def get_this_week(session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)): """ Returns the meal plan data for this week """ return db.groups.get_meals(session, current_user.group)[0] @router.get("/today", tags=["Meal Plan"]) -def get_today( - session: Session = Depends(generate_session), - current_user: UserInDB = Depends(get_current_user), -): +def get_today(session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)): """ Returns the recipe slug for the meal scheduled for today. If no meal is scheduled nothing is returned diff --git a/mealie/routes/mealplans/helpers.py b/mealie/routes/mealplans/helpers.py index 0bf3a9702..f1e90d531 100644 --- a/mealie/routes/mealplans/helpers.py +++ b/mealie/routes/mealplans/helpers.py @@ -1,6 +1,7 @@ +from fastapi import APIRouter, Depends from mealie.db.database import db from mealie.db.db_setup import generate_session -from fastapi import APIRouter, Depends +from mealie.routes.deps import get_current_user from mealie.schema.meal import MealPlanInDB from mealie.schema.recipe import Recipe from sqlalchemy.orm.session import Session @@ -9,13 +10,15 @@ router = APIRouter(prefix="/api/meal-plans", tags=["Meal Plan"]) @router.get("/{id}/shopping-list") -def get_shopping_list(id: str, session: Session = Depends(generate_session)): +def get_shopping_list( + id: str, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): #! Refactor into Single Database Call mealplan = db.meals.get(session, id) mealplan: MealPlanInDB slugs = [x.slug for x in mealplan.meals] recipes: list[Recipe] = [db.recipes.get(session, x) for x in slugs] - ingredients = [{"name": x.name, "recipeIngredient": x.recipeIngredient} for x in recipes if x] - - return ingredients + return [{"name": x.name, "recipeIngredient": x.recipeIngredient} for x in recipes if x] diff --git a/mealie/routes/migration_routes.py b/mealie/routes/migration_routes.py index 9acc51f09..3422439c7 100644 --- a/mealie/routes/migration_routes.py +++ b/mealie/routes/migration_routes.py @@ -2,16 +2,17 @@ import operator import shutil from typing import List +from fastapi import APIRouter, Depends, File, HTTPException, UploadFile from mealie.core.config import MIGRATION_DIR from mealie.db.db_setup import generate_session -from fastapi import APIRouter, Depends, File, HTTPException, UploadFile +from mealie.routes.deps import get_current_user from mealie.schema.migration import MigrationFile, Migrations +from mealie.schema.snackbar import SnackResponse from mealie.services.migrations.chowdown import chowdown_migrate as chowdow_migrate from mealie.services.migrations.nextcloud import migrate as nextcloud_migrate from sqlalchemy.orm.session import Session -from mealie.schema.snackbar import SnackResponse -router = APIRouter(prefix="/api/migrations", tags=["Migration"]) +router = APIRouter(prefix="/api/migrations", tags=["Migration"], dependencies=[Depends(get_current_user)]) @router.get("", response_model=List[Migrations]) diff --git a/mealie/routes/recipe/category_routes.py b/mealie/routes/recipe/category_routes.py index 979d712c8..055a19124 100644 --- a/mealie/routes/recipe/category_routes.py +++ b/mealie/routes/recipe/category_routes.py @@ -1,3 +1,4 @@ +from mealie.routes.deps import get_current_user from mealie.db.database import db from mealie.db.db_setup import generate_session from fastapi import APIRouter, Depends @@ -26,7 +27,7 @@ def get_all_recipes_by_category(category: str, session: Session = Depends(genera @router.delete("/{category}") -async def delete_recipe_category(category: str, session: Session = Depends(generate_session)): +async def delete_recipe_category(category: str, session: Session = Depends(generate_session), current_user=Depends(get_current_user)): """Removes a recipe category from the database. Deleting a category does not impact a recipe. The category will be removed from any recipes that contain it""" diff --git a/mealie/routes/recipe/recipe_crud_routes.py b/mealie/routes/recipe/recipe_crud_routes.py index 3a5e217e9..baa254dc1 100644 --- a/mealie/routes/recipe/recipe_crud_routes.py +++ b/mealie/routes/recipe/recipe_crud_routes.py @@ -1,8 +1,9 @@ -from mealie.db.database import db -from mealie.db.db_setup import generate_session from fastapi import APIRouter, Depends, File, Form, HTTPException from fastapi.logger import logger from fastapi.responses import FileResponse +from mealie.db.database import db +from mealie.db.db_setup import generate_session +from mealie.routes.deps import get_current_user from mealie.schema.recipe import Recipe, RecipeURLIn from mealie.schema.snackbar import SnackResponse from mealie.services.image_services import read_image, write_image @@ -16,7 +17,11 @@ router = APIRouter( @router.post("/create", status_code=201, response_model=str) -def create_from_json(data: Recipe, session: Session = Depends(generate_session)) -> str: +def create_from_json( + data: Recipe, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +) -> str: """ Takes in a JSON string and loads data into the database as a new entry""" recipe: Recipe = db.recipes.create(session, data.dict()) @@ -24,7 +29,11 @@ def create_from_json(data: Recipe, session: Session = Depends(generate_session)) @router.post("/create-url", status_code=201, response_model=str) -def parse_recipe_url(url: RecipeURLIn, session: Session = Depends(generate_session)): +def parse_recipe_url( + url: RecipeURLIn, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Takes in a URL and attempts to scrape data and load it into the database """ recipe = create_from_url(url.url) @@ -41,7 +50,12 @@ def get_recipe(recipe_slug: str, session: Session = Depends(generate_session)): @router.put("/{recipe_slug}") -def update_recipe(recipe_slug: str, data: Recipe, session: Session = Depends(generate_session)): +def update_recipe( + recipe_slug: str, + data: Recipe, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Updates a recipe by existing slug and data. """ recipe: Recipe = db.recipes.update(session, recipe_slug, data.dict()) @@ -50,7 +64,11 @@ def update_recipe(recipe_slug: str, data: Recipe, session: Session = Depends(gen @router.delete("/{recipe_slug}") -def delete_recipe(recipe_slug: str, session: Session = Depends(generate_session)): +def delete_recipe( + recipe_slug: str, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Deletes a recipe by slug """ try: @@ -77,6 +95,7 @@ def update_recipe_image( image: bytes = File(...), extension: str = Form(...), session: Session = Depends(generate_session), + current_user=Depends(get_current_user), ): """ Removes an existing image and replaces it with the incoming file. """ response = write_image(recipe_slug, image, extension) diff --git a/mealie/routes/recipe/tag_routes.py b/mealie/routes/recipe/tag_routes.py index 0da90e668..50dfd379a 100644 --- a/mealie/routes/recipe/tag_routes.py +++ b/mealie/routes/recipe/tag_routes.py @@ -1,10 +1,9 @@ +from fastapi import APIRouter, Depends from mealie.db.database import db from mealie.db.db_setup import generate_session -from fastapi import APIRouter, Depends +from mealie.routes.deps import get_current_user +from mealie.schema.snackbar import SnackResponse from sqlalchemy.orm.session import Session -from mealie.schema.snackbar import SnackResponse - -from mealie.schema.snackbar import SnackResponse router = APIRouter(tags=["Recipes"]) @@ -27,7 +26,9 @@ def get_all_recipes_by_tag(tag: str, session: Session = Depends(generate_session @router.delete("/{tag}") -async def delete_recipe_tag(tag: str, session: Session = Depends(generate_session)): +async def delete_recipe_tag( + tag: str, session: Session = Depends(generate_session), current_user=Depends(get_current_user) +): """Removes a recipe tag from the database. Deleting a tag does not impact a recipe. The tag will be removed from any recipes that contain it""" diff --git a/mealie/routes/site_settings/custom_pages.py b/mealie/routes/site_settings/custom_pages.py index 33bd27598..5f912de08 100644 --- a/mealie/routes/site_settings/custom_pages.py +++ b/mealie/routes/site_settings/custom_pages.py @@ -57,7 +57,12 @@ async def get_single_page( @router.put("/{id}") -async def update_single_age(data: CustomPageOut, id: int, session: Session = Depends(generate_session)): +async def update_single_age( + data: CustomPageOut, + id: int, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Removes a custom page from the database """ return db.custom_pages.update(session, id, data.dict()) diff --git a/mealie/routes/site_settings/site_settings.py b/mealie/routes/site_settings/site_settings.py index 4f7bf9772..52f47f89b 100644 --- a/mealie/routes/site_settings/site_settings.py +++ b/mealie/routes/site_settings/site_settings.py @@ -1,13 +1,12 @@ +from fastapi import APIRouter, Depends from mealie.db.database import db from mealie.db.db_setup import generate_session -from fastapi import APIRouter, Depends +from mealie.routes.deps import get_current_user from mealie.schema.settings import SiteSettings from mealie.schema.snackbar import SnackResponse from mealie.schema.user import GroupInDB, UserInDB -from sqlalchemy.orm.session import Session from mealie.utils.post_webhooks import post_webhooks - -from mealie.routes.deps import get_current_user +from sqlalchemy.orm.session import Session router = APIRouter(prefix="/api/site-settings", tags=["Settings"]) @@ -20,7 +19,11 @@ def get_main_settings(session: Session = Depends(generate_session)): @router.put("") -def update_settings(data: SiteSettings, session: Session = Depends(generate_session)): +def update_settings( + data: SiteSettings, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Returns Site Settings """ db.settings.update(session, 1, data.dict()) diff --git a/mealie/routes/theme_routes.py b/mealie/routes/theme_routes.py index 91cfea268..78f1a09cb 100644 --- a/mealie/routes/theme_routes.py +++ b/mealie/routes/theme_routes.py @@ -1,9 +1,10 @@ -from mealie.db.db_setup import generate_session from fastapi import APIRouter, Depends +from mealie.db.database import db +from mealie.db.db_setup import generate_session +from mealie.routes.deps import get_current_user +from mealie.schema.snackbar import SnackResponse from mealie.schema.theme import SiteTheme from sqlalchemy.orm.session import Session -from mealie.schema.snackbar import SnackResponse -from mealie.db.database import db router = APIRouter(prefix="/api", tags=["Themes"]) @@ -16,7 +17,7 @@ def get_all_themes(session: Session = Depends(generate_session)): @router.post("/themes/create") -def create_theme(data: SiteTheme, session: Session = Depends(generate_session)): +def create_theme(data: SiteTheme, session: Session = Depends(generate_session), current_user=Depends(get_current_user)): """ Creates a site color theme database entry """ db.themes.create(session, data.dict()) @@ -30,7 +31,12 @@ def get_single_theme(theme_name: str, session: Session = Depends(generate_sessio @router.put("/themes/{theme_name}") -def update_theme(theme_name: str, data: SiteTheme, session: Session = Depends(generate_session)): +def update_theme( + theme_name: str, + data: SiteTheme, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Update a theme database entry """ db.themes.update(session, theme_name, data.dict()) @@ -38,7 +44,7 @@ def update_theme(theme_name: str, data: SiteTheme, session: Session = Depends(ge @router.delete("/themes/{theme_name}") -def delete_theme(theme_name: str, session: Session = Depends(generate_session)): +def delete_theme(theme_name: str, session: Session = Depends(generate_session), current_user=Depends(get_current_user)): """ Deletes theme from the database """ db.themes.delete(session, theme_name)