From 16c5e5ed29440cb0ee7837f0674f52abdcb15b9f Mon Sep 17 00:00:00 2001 From: Daniel Cumpton Date: Fri, 13 Mar 2026 16:26:42 -0600 Subject: [PATCH 1/2] sanitize geopackage path and change print statements to log statments --- app/routers/hydrofabric/router.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/app/routers/hydrofabric/router.py b/app/routers/hydrofabric/router.py index 7e103b2..c7111db 100644 --- a/app/routers/hydrofabric/router.py +++ b/app/routers/hydrofabric/router.py @@ -1,4 +1,7 @@ +import logging +import os import pathlib +import re import sqlite3 import tempfile import uuid @@ -34,6 +37,9 @@ QueryIdType, ) +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + api_router = APIRouter(prefix="/hydrofabric") @@ -95,7 +101,11 @@ async def get_hydrofabric_subset_gpkg( """ unique_id = str(uuid.uuid4())[:8] temp_dir = pathlib.Path(tempfile.gettempdir()) - tmp_path = temp_dir / f"subset_{identifier}_{unique_id}.gpkg" + #create sanitized path and filename + identifier_clean = re.sub(r"[^A-Za-z0-9_]", "_", identifier) + tmp_path = os.path.normpath(temp_dir / f"subset_{identifier_clean}_{unique_id}.gpkg") + if not tmp_path.startswith(temp_dir): + raise Exception("temporary path for geopackages not allowed") # Resolve namespace from domain/source combination (outside try block for error handling access) try: @@ -182,13 +192,13 @@ async def get_hydrofabric_subset_gpkg( else: nonspatial_layers[table_name] = layer_data else: - print(f"Warning: {table_name} layer is empty") + logger.warning(f"Warning: {table_name} layer is empty") # Write spatial layers first with pyogrio for table_name, layer_data in spatial_layers.items(): pyogrio.write_dataframe(layer_data, tmp_path, layer=table_name) layers_written += 1 - print(f"Written spatial layer '{table_name}' with {len(layer_data)} records") + logger.info(f"Written spatial layer '{table_name}' with {len(layer_data)} records") # Then write non-spatial layers with sqlite3 if nonspatial_layers: @@ -196,7 +206,7 @@ async def get_hydrofabric_subset_gpkg( for table_name, layer_data in nonspatial_layers.items(): layer_data.to_sql(table_name, conn, if_exists="replace", index=False) layers_written += 1 - print(f"Written non-spatial layer '{table_name}' with {len(layer_data)} records") + logger.info(f"Written non-spatial layer '{table_name}' with {len(layer_data)} records") conn.close() if layers_written == 0: From 41abc2f3c2d093c11e6d6ccce24c56ace563263c Mon Sep 17 00:00:00 2001 From: Daniel Cumpton Date: Thu, 19 Mar 2026 20:18:33 -0600 Subject: [PATCH 2/2] fix path datatype --- app/routers/hydrofabric/router.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/routers/hydrofabric/router.py b/app/routers/hydrofabric/router.py index c7111db..b2c0d19 100644 --- a/app/routers/hydrofabric/router.py +++ b/app/routers/hydrofabric/router.py @@ -1,5 +1,4 @@ import logging -import os import pathlib import re import sqlite3 @@ -103,8 +102,9 @@ async def get_hydrofabric_subset_gpkg( temp_dir = pathlib.Path(tempfile.gettempdir()) #create sanitized path and filename identifier_clean = re.sub(r"[^A-Za-z0-9_]", "_", identifier) - tmp_path = os.path.normpath(temp_dir / f"subset_{identifier_clean}_{unique_id}.gpkg") - if not tmp_path.startswith(temp_dir): + tmp_path = temp_dir / f"subset_{identifier_clean}_{unique_id}.gpkg" + tmp_path = tmp_path.resolve() + if not str(tmp_path).startswith(str(temp_dir)): raise Exception("temporary path for geopackages not allowed") # Resolve namespace from domain/source combination (outside try block for error handling access)