Spaces:
Sleeping
Sleeping
client detect
Browse files- core/schemas.py +1 -1
- routers/auth.py +21 -0
core/schemas.py
CHANGED
|
@@ -12,7 +12,7 @@ class GoogleAuthRequest(BaseModel):
|
|
| 12 |
"""Request with Google ID token from frontend Sign-In."""
|
| 13 |
id_token: str = Field(..., min_length=1, description="Google ID token from Sign-In")
|
| 14 |
temp_user_id: Optional[str] = Field(None, description="Optional temp user ID for linking")
|
| 15 |
-
client_type: str = Field(
|
| 16 |
|
| 17 |
|
| 18 |
class AuthResponse(BaseModel):
|
|
|
|
| 12 |
"""Request with Google ID token from frontend Sign-In."""
|
| 13 |
id_token: str = Field(..., min_length=1, description="Google ID token from Sign-In")
|
| 14 |
temp_user_id: Optional[str] = Field(None, description="Optional temp user ID for linking")
|
| 15 |
+
client_type: Optional[str] = Field(None, description="Client type: 'web' or 'mobile' (auto-detected if not provided)")
|
| 16 |
|
| 17 |
|
| 18 |
class AuthResponse(BaseModel):
|
routers/auth.py
CHANGED
|
@@ -69,6 +69,22 @@ async def check_registration(
|
|
| 69 |
return {"is_registered": client_user is not None}
|
| 70 |
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
@router.post("/google", response_model=AuthResponse)
|
| 73 |
async def google_auth(
|
| 74 |
request: GoogleAuthRequest,
|
|
@@ -82,10 +98,15 @@ async def google_auth(
|
|
| 82 |
Supports two client types:
|
| 83 |
- "web": Sets refresh_token in HttpOnly cookie (secure)
|
| 84 |
- "mobile": Returns refresh_token in JSON body
|
|
|
|
|
|
|
| 85 |
"""
|
| 86 |
response = JSONResponse(content={}) # Placeholder, will be populated later
|
| 87 |
ip = req.client.host
|
| 88 |
|
|
|
|
|
|
|
|
|
|
| 89 |
# Rate Limit: 10 attempts per minute per IP
|
| 90 |
if not await check_rate_limit(db, ip, "/auth/google", 10, 1):
|
| 91 |
raise HTTPException(
|
|
|
|
| 69 |
return {"is_registered": client_user is not None}
|
| 70 |
|
| 71 |
|
| 72 |
+
|
| 73 |
+
def detect_client_type(request: Request) -> str:
|
| 74 |
+
"""
|
| 75 |
+
Detect client type from User-Agent header.
|
| 76 |
+
Browsers get 'web', native apps get 'mobile'.
|
| 77 |
+
"""
|
| 78 |
+
user_agent = request.headers.get("user-agent", "").lower()
|
| 79 |
+
|
| 80 |
+
# Browser indicators
|
| 81 |
+
browser_keywords = ["mozilla", "chrome", "firefox", "safari", "edge", "opera"]
|
| 82 |
+
|
| 83 |
+
if any(keyword in user_agent for keyword in browser_keywords):
|
| 84 |
+
return "web"
|
| 85 |
+
return "mobile"
|
| 86 |
+
|
| 87 |
+
|
| 88 |
@router.post("/google", response_model=AuthResponse)
|
| 89 |
async def google_auth(
|
| 90 |
request: GoogleAuthRequest,
|
|
|
|
| 98 |
Supports two client types:
|
| 99 |
- "web": Sets refresh_token in HttpOnly cookie (secure)
|
| 100 |
- "mobile": Returns refresh_token in JSON body
|
| 101 |
+
|
| 102 |
+
Client type is auto-detected from User-Agent if not provided.
|
| 103 |
"""
|
| 104 |
response = JSONResponse(content={}) # Placeholder, will be populated later
|
| 105 |
ip = req.client.host
|
| 106 |
|
| 107 |
+
# Auto-detect client type if not explicitly provided
|
| 108 |
+
client_type = request.client_type if request.client_type else detect_client_type(req)
|
| 109 |
+
|
| 110 |
# Rate Limit: 10 attempts per minute per IP
|
| 111 |
if not await check_rate_limit(db, ip, "/auth/google", 10, 1):
|
| 112 |
raise HTTPException(
|