From c563672043f8c592dad124df130b1f441c21ce5f Mon Sep 17 00:00:00 2001 From: Luke Mino-Altherr Date: Wed, 11 Mar 2026 22:00:12 -0700 Subject: [PATCH] Move blake3 hash resolution to asset_management service Extract resolve_hash_to_path() into asset_management.py and remove _resolve_blake3_to_path from server.py. Also revert loopback origin check to original logic. Amp-Thread-ID: https://ampcode.com/threads/T-019ce023-3384-7560-bacf-de40b0de0dd2 Co-authored-by: Amp --- app/assets/services/asset_management.py | 33 ++++++++++++++++++++++ server.py | 37 ++++--------------------- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/app/assets/services/asset_management.py b/app/assets/services/asset_management.py index b85e77edb..bcdbf8689 100644 --- a/app/assets/services/asset_management.py +++ b/app/assets/services/asset_management.py @@ -280,6 +280,39 @@ def list_assets_page( return ListAssetsResult(items=items, total=total) +def resolve_hash_to_path( + asset_hash: str, +) -> DownloadResolutionResult | None: + """Resolve a blake3 hash to an on-disk file path. + + Returns a DownloadResolutionResult with abs_path, content_type, and + download_name, or None if no asset or live path is found. + """ + with create_session() as session: + asset = queries_get_asset_by_hash(session, asset_hash) + if not asset: + return None + refs = list_references_by_asset_id(session, asset_id=asset.id) + abs_path = select_best_live_path(refs) + if not abs_path: + return None + display_name = os.path.basename(abs_path) + for ref in refs: + if ref.file_path == abs_path and ref.name: + display_name = ref.name + break + ctype = ( + asset.mime_type + or mimetypes.guess_type(display_name)[0] + or "application/octet-stream" + ) + return DownloadResolutionResult( + abs_path=abs_path, + content_type=ctype, + download_name=display_name, + ) + + def resolve_asset_for_download( reference_id: str, owner_id: str = "", diff --git a/server.py b/server.py index e6db520a9..3aad6ecff 100644 --- a/server.py +++ b/server.py @@ -36,6 +36,7 @@ from comfy_api.internal import _ComfyNodeInternal from app.assets.seeder import asset_seeder from app.assets.api.routes import register_assets_routes from app.assets.services.ingest import register_file_in_place +from app.assets.services.asset_management import resolve_hash_to_path from app.user_manager import UserManager from app.model_manager import ModelFileManager @@ -164,11 +165,7 @@ def create_origin_only_middleware(): if host_domain_parsed.port is None: origin_domain = parsed.hostname - # When both host and origin are loopback, allow port differences - # (e.g. frontend dev server on :5173 proxying to backend on :8188) - if loopback and is_loopback(parsed.hostname): - pass - elif loopback and host_domain is not None and origin_domain is not None and len(host_domain) > 0 and len(origin_domain) > 0: + if loopback and host_domain is not None and origin_domain is not None and len(host_domain) > 0 and len(origin_domain) > 0: if host_domain != origin_domain: logging.warning("WARNING: request with non matching host and origin {} != {}, returning 403".format(host_domain, origin_domain)) return web.Response(status=403) @@ -507,9 +504,10 @@ class PromptServer(): # node preview, it constructs /view?filename=, so this # endpoint must resolve blake3 hashes to their on-disk file paths. if filename.startswith("blake3:"): - file, filename = self._resolve_blake3_to_path(filename) - if file is None: + result = resolve_hash_to_path(filename) + if result is None: return web.Response(status=404) + file, filename = result.abs_path, result.download_name else: filename, output_dir = folder_paths.annotated_filepath(filename) @@ -1027,31 +1025,6 @@ class PromptServer(): timeout = aiohttp.ClientTimeout(total=None) # no timeout self.client_session = aiohttp.ClientSession(timeout=timeout) - def _resolve_blake3_to_path(self, asset_hash: str) -> tuple[str | None, str]: - """Resolve a blake3 hash to an absolute file path via the asset database. - - Returns (abs_path, display_filename) or (None, "") if not found. - """ - from app.database.db import create_session - from app.assets.database.queries import get_asset_by_hash, list_references_by_asset_id - from app.assets.helpers import select_best_live_path - - with create_session() as session: - asset = get_asset_by_hash(session, asset_hash) - if not asset: - return None, "" - refs = list_references_by_asset_id(session, asset_id=asset.id) - abs_path = select_best_live_path(refs) - if not abs_path: - return None, "" - display_name = os.path.basename(abs_path) - # Prefer the reference name if available - for ref in refs: - if ref.file_path == abs_path and ref.name: - display_name = ref.name - break - return abs_path, display_name - def add_routes(self): self.user_manager.add_routes(self.routes) self.model_file_manager.add_routes(self.routes)