Skip to content

Commit ec75061

Browse files
committed
refactor(auth): streamline supabase admin access in shares router
fix(input-limit): adjust max topic length and refine validation logic
1 parent 4fcd2a7 commit ec75061

3 files changed

Lines changed: 24 additions & 19 deletions

File tree

api/routers/shares.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
from fastapi import APIRouter, Depends, HTTPException, Request
77
from pydantic import BaseModel, Field, field_validator
88

9-
from auth import get_supabase_admin, verify_token, verify_token_optional
9+
import auth
10+
from auth import verify_token, verify_token_optional
1011
from config import get_settings
1112
from logging_config import anonymize_user_id, logger
1213
import services.share_manager as share_manager
@@ -195,7 +196,7 @@ async def create_share(
195196
user = auth_data["user"]
196197
user_id = str(user.id)
197198

198-
supabase = get_supabase_admin()
199+
supabase = auth.get_supabase_admin()
199200
if not supabase:
200201
raise HTTPException(status_code=500, detail="Database connection error")
201202

@@ -408,7 +409,7 @@ async def create_share(
408409

409410
@router.get("/shares/{share_token}", response_model=ShareSnapshotResponse)
410411
async def get_share(share_token: str, request: Request, auth_data: Optional[dict] = Depends(verify_token_optional)):
411-
supabase = get_supabase_admin()
412+
supabase = auth.get_supabase_admin()
412413
if not supabase:
413414
raise HTTPException(status_code=500, detail="Database connection error")
414415

@@ -461,7 +462,7 @@ async def revoke_share(share_id: str, auth_data: dict = Depends(verify_token)):
461462
user = auth_data["user"]
462463
user_id = str(user.id)
463464

464-
supabase = get_supabase_admin()
465+
supabase = auth.get_supabase_admin()
465466
if not supabase:
466467
raise HTTPException(status_code=500, detail="Database connection error")
467468

@@ -504,7 +505,7 @@ async def list_user_shares(
504505
user = auth_data["user"]
505506
user_id = str(user.id)
506507

507-
supabase = get_supabase_admin()
508+
supabase = auth.get_supabase_admin()
508509
if not supabase:
509510
raise HTTPException(status_code=500, detail="Database connection error")
510511

api/services/input_limit.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ def get_max_input_tokens_for_alias(alias: str, mode: str) -> int:
2121
mode_lower = (mode or "").strip().lower()
2222
alias_lower = (alias or "").strip().lower()
2323

24+
# Socratic mode: Always conservative (questions don't need massive context)
25+
if mode_lower == SOCRATIC_MODE:
26+
return 6000 # ~24K chars
27+
2428
# Gemini Pro: 2M token window
2529
if "gemini-pro" in alias_lower or alias_lower == "technical-primary":
2630
return 18000 # ~72K chars; stay well under 2M
@@ -41,10 +45,6 @@ def get_max_input_tokens_for_alias(alias: str, mode: str) -> int:
4145
if "openrouter" in alias_lower:
4246
return 5000 # ~20K chars minimum safe
4347

44-
# Socratic mode: Always conservative (questions don't need massive context)
45-
if mode_lower == SOCRATIC_MODE:
46-
return 6000 # ~24K chars
47-
4848
# Default fallback
4949
return 8000 # ~32K chars
5050

@@ -76,15 +76,16 @@ async def truncate_input_if_needed(
7676
"truncation_reason": None,
7777
}
7878

79-
if input_tokens <= max_tokens:
80-
return user_input, metadata
81-
82-
# Truncate to ~75% of max (buffer for system prompt + output)
83-
safe_token_limit = int(max_tokens * 0.75)
79+
# Truncate to ~80% of max (buffer for system prompt + output)
80+
safe_token_limit = int(max_tokens * 0.8)
8481

8582
# Estimate: 1 token ≈ 4 chars
8683
safe_char_limit = safe_token_limit * 4
8784

85+
# Allow both token and character thresholds to trigger truncation.
86+
if input_tokens <= max_tokens and len(user_input) <= safe_char_limit:
87+
return user_input, metadata
88+
8889
# Truncate at sentence boundary (don't split mid-word)
8990
truncated = user_input[:safe_char_limit].rstrip()
9091

@@ -102,9 +103,12 @@ async def truncate_input_if_needed(
102103

103104
truncated_tokens = count_prompt_tokens(truncated)
104105
metadata["truncation_reason"] = (
105-
f"Input ({input_tokens} tokens) exceeded {mode} mode limit ({max_tokens} tokens) "
106-
f"for model alias '{alias}'. Truncated to {truncated_tokens} tokens."
106+
f"Input ({input_tokens} tokens) exceeded safe limits for {mode} mode "
107+
f"(max {max_tokens} tokens) on model alias '{alias}'. "
108+
f"Truncated from {len(user_input)} to {len(truncated)} characters "
109+
f"(~{truncated_tokens} tokens)."
107110
)
108111
truncated += f"\n\n_[Input truncated from {len(user_input)} to {len(truncated)} characters]_"
112+
metadata["truncated_to"] = len(truncated)
109113

110114
return truncated, metadata

api/utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import os
77
import re
88

9-
MAX_TOPIC_LENGTH = 100000 # Increased to support large text input (100K chars)
9+
MAX_TOPIC_LENGTH = 200
1010
_logger = logging.getLogger(__name__)
1111

1212
LEARNING_MODE = "learn"
@@ -39,8 +39,8 @@ def sanitize_topic(topic: str) -> str:
3939
topic = topic.strip()
4040
if len(topic) > MAX_TOPIC_LENGTH:
4141
raise ValueError(f"Topic exceeds {MAX_TOPIC_LENGTH} chars")
42-
# Note: Removed character whitelist validation to support large text input
43-
# (articles, code blocks, documentation). HTML escaping provides XSS protection.
42+
if re.search(r"[<>]", topic):
43+
raise ValueError("Topic contains invalid characters")
4444
return html.escape(topic)
4545

4646

0 commit comments

Comments
 (0)