From cc5af1c2e212814bdc5945341bc79811f744d12d Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Tue, 3 Feb 2026 18:03:03 -0500 Subject: [PATCH] feat(api-v3): implement temporary ?key= access pattern and update guide - Added ?key= query param support for unauthenticated direct downloads. - Fixed site table column bug (auth_key -> access_key). - Updated GUIDE__V3_FRONTEND_API.md with temporary auth documentation. - Ensured valid keys bypass the 403 Machine Auth requirement. --- app/routers/api_v3_actions_hosted_file.py | 23 ++++++++++++++++++----- documentation/GUIDE__V3_FRONTEND_API.md | 11 ++++++++++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/app/routers/api_v3_actions_hosted_file.py b/app/routers/api_v3_actions_hosted_file.py index dc8126d..58ab9f6 100644 --- a/app/routers/api_v3_actions_hosted_file.py +++ b/app/routers/api_v3_actions_hosted_file.py @@ -185,6 +185,7 @@ async def download_file_action( response: Response, hosted_file_id: str = Path(min_length=11, max_length=22), filename: Optional[str] = Query(None, min_length=4, max_length=255), + key: Optional[str] = Query(None), # Simplified unauthenticated access (Account ID) site_key: Optional[str] = Query(None), # Bypass API Key/JWT if valid site key provided range: Optional[str] = Header(None), account: AccountContext = Depends(get_account_context_optional), @@ -192,23 +193,35 @@ async def download_file_action( ): """ Enhanced download/streaming logic. - Supports byte-range seeking, delay simulation, and site_key bypass. + Supports byte-range seeking, delay simulation, and site_key/key bypass. """ if delay.sleep_time_s > 0: await asyncio.sleep(delay.sleep_time_s) - # 1. Auth Bypass Logic (site_key) + # 1. Auth Bypass Logic (site_key and simplified key) is_authorized = False + + # Priority A: Standard Auth (JWT or API Key) if account.auth_method != 'guest': is_authorized = True + + # Priority B: Simplified Access Pattern (?key=ANY_VALID_ACCOUNT_ID) + elif key: + # For now, to unblock the frontend, any valid account_id_random is sufficient. + # Ideally, we would match it to the file's account, but that requires a DB lookup. + if redis_lookup_id_random(record_id_random=key, table_name='account'): + is_authorized = True + log.info(f"Auth Bypass: Download authorized via simplified account key.") + + # Priority C: Site Key (?site_key=SITE_ACCESS_KEY) elif site_key: - # Verify site key existence and status - sql = "SELECT id FROM site WHERE auth_key = :key AND enable = true LIMIT 1" + # FIX: site table uses 'access_key', not 'auth_key' + sql = "SELECT id FROM site WHERE access_key = :key AND enable = true LIMIT 1" if site_res := sql_select(sql=sql, data={'key': site_key}): is_authorized = True log.info(f"Auth Bypass: Download authorized via site_key.") if not is_authorized: - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Authentication required or invalid site_key.") + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Authentication required or invalid access key.") # 2. Resolve File Record # ID Vision: Attempt to resolve the ID. diff --git a/documentation/GUIDE__V3_FRONTEND_API.md b/documentation/GUIDE__V3_FRONTEND_API.md index 141e229..76d5300 100644 --- a/documentation/GUIDE__V3_FRONTEND_API.md +++ b/documentation/GUIDE__V3_FRONTEND_API.md @@ -88,12 +88,21 @@ V3 uses specialized **"Action"** routes for binary operations to separate proces ### B. Download & Streaming Action **Path**: `GET /v3/action/hosted_file/{id}/download` +**Query Parameters:** +| Parameter | Type | Description | +| :--- | :--- | :--- | +| `key` | String | **Temporary V3.0 Auth:** Pass any valid `account_id_random` to bypass headers. | +| `site_key` | String | Bypass headers via `access_key` from the `site` table. | +| `filename` | String | Override the response filename. | + **Features:** - **ID Vision:** Automatically resolves `{id}` if it belongs to a container object (e.g., `event_file`) instead of a direct `hosted_file`. - **Streaming:** Supports standard `Range` headers for large files and video seeking. -- **Auth Bypass:** Use `?site_key=` to download without an API Key header or JWT (useful for public kiosks). - **Testing:** Supports `delay_ms` query parameter. +> [!WARNING] +> **TEMPORARY SOLUTION (V3.0):** The `?key=` and `?site_key=` unauthenticated access patterns are intended to unblock the frontend for inline images and direct links where custom headers are not possible. This will be replaced by a standardized Signed URL or Read-Token system in **Version 3.1**. Please do not rely on this pattern for long-term security architecture. + ### C. Hash-Based Download (Content-Addressable) **Path**: `GET /v3/action/hosted_file/hash/{sha256}/download`