-
Notifications
You must be signed in to change notification settings - Fork 77
Expand file tree
/
Copy pathdeps.py
More file actions
81 lines (63 loc) · 2.48 KB
/
deps.py
File metadata and controls
81 lines (63 loc) · 2.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
"""FastAPI dependencies for authentication (via Next.js internal API)."""
from typing import Annotated
import httpx
from fastapi import Depends, Header, HTTPException, status
from shared.config import settings
from shared.enums import MemberRole
class ProjectAccessInfo:
"""Information about user's access to a project."""
def __init__(self, project_id: str, user_id: str, role: str):
self.project_id = project_id
self.user_id = user_id
self.role = role
async def get_project_access(
project_id: str,
x_user_id: Annotated[str | None, Header()] = None,
) -> ProjectAccessInfo:
"""
Validate user has access to a project via Next.js internal API.
The frontend should pass:
- x-user-id: User's unique ID (from session)
Raises 401 if missing user ID, 403 if no access, 404 if project not found.
"""
if not x_user_id:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing x-user-id header",
)
# Validate access via Next.js internal API
try:
async with httpx.AsyncClient(timeout=10.0) as client:
response = await client.post(
f"{settings.traceroot_ui_url}/api/internal/validate-project-access",
json={"userId": x_user_id, "projectId": project_id},
headers={"X-Internal-Secret": settings.internal_api_secret},
)
except httpx.RequestError as e:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail=f"Authentication service unavailable: {e}",
) from e
if response.status_code == 401:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Unauthorized",
)
if response.status_code != 200:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Authentication service error",
)
data = response.json()
if not data.get("hasAccess"):
error = data.get("error", "No access to this project")
status_code = (
status.HTTP_404_NOT_FOUND if "not found" in error.lower() else status.HTTP_403_FORBIDDEN
)
raise HTTPException(status_code=status_code, detail=error)
return ProjectAccessInfo(
project_id=project_id,
user_id=x_user_id,
role=data.get("role", MemberRole.VIEWER),
)
ProjectAccess = Annotated[ProjectAccessInfo, Depends(get_project_access)]