diff --git a/cmd/server/main.go b/cmd/server/main.go index a61a60c..5318068 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -54,6 +54,7 @@ type app struct { type accessScope struct { IsAdmin bool CanManage bool + CanAuth bool DeptID string } @@ -213,6 +214,7 @@ func (a *app) handleAccessMe(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{ "is_admin": scope.IsAdmin, "can_manage_department": scope.CanManage, + "can_auth_telegram": scope.CanAuth, "department_id": nullableString(scope.DeptID), }) } @@ -1192,7 +1194,7 @@ func (a *app) promptExists(ctx context.Context, deptID, vertical, section string func (a *app) proxyPython(w http.ResponseWriter, r *http.Request, path string) { scope := readAccess(r) - if strings.Contains(path, "/auth/") && !scope.IsAdmin { + if strings.Contains(path, "/auth/") && !scope.CanAuth { writeError(w, http.StatusNotFound, "not found") return } @@ -1251,9 +1253,12 @@ func (a *app) readScope(w http.ResponseWriter, r *http.Request, manage bool) (ac func readAccess(r *http.Request) accessScope { admin := r.Header.Get("X-User-Is-Admin") == "1" deptHead := r.Header.Get("X-User-Is-Department-Head") == "1" + canManage := r.Header.Get("X-Monitoring-TG-Can-Manage") == "1" + canAuth := r.Header.Get("X-Monitoring-TG-Can-Auth") == "1" return accessScope{ IsAdmin: admin, - CanManage: admin || deptHead, + CanManage: admin || deptHead || canManage, + CanAuth: admin || canAuth, DeptID: strings.TrimSpace(r.Header.Get("X-User-Department-Id")), } } diff --git a/src/parser_bot/access.py b/src/parser_bot/access.py index 18c05c6..d2462e1 100644 --- a/src/parser_bot/access.py +++ b/src/parser_bot/access.py @@ -17,8 +17,16 @@ def is_department_head_request(request: Request) -> bool: return request.headers.get("x-user-is-department-head") == "1" +def can_manage_monitoring_tg(request: Request) -> bool: + return request.headers.get("x-monitoring-tg-can-manage") == "1" + + +def can_auth_monitoring_tg(request: Request) -> bool: + return is_admin_request(request) or request.headers.get("x-monitoring-tg-can-auth") == "1" + + def can_manage_department(request: Request) -> bool: - return is_admin_request(request) or is_department_head_request(request) + return is_admin_request(request) or is_department_head_request(request) or can_manage_monitoring_tg(request) def require_department_manager(request: Request) -> None: @@ -34,3 +42,8 @@ def require_admin(request: Request) -> None: """ if not is_admin_request(request): raise HTTPException(status_code=404) + + +def require_telegram_auth_manager(request: Request) -> None: + if not can_auth_monitoring_tg(request): + raise HTTPException(status_code=404) diff --git a/src/parser_bot/api/routes.py b/src/parser_bot/api/routes.py index 812efbb..4e63d16 100644 --- a/src/parser_bot/api/routes.py +++ b/src/parser_bot/api/routes.py @@ -8,8 +8,8 @@ from sqlalchemy.ext.asyncio import AsyncSession from parser_bot.access import ( is_admin_request, portal_department_id, - require_admin, require_department_manager, + require_telegram_auth_manager, ) from parser_bot.config import settings from parser_bot.db.models import Channel, Section @@ -72,7 +72,7 @@ async def _require_channel_scope( raise HTTPException(status_code=404) -@router.get("/auth/status", response_model=AuthStatus, dependencies=[Depends(require_admin)]) +@router.get("/auth/status", response_model=AuthStatus, dependencies=[Depends(require_telegram_auth_manager)]) async def auth_status() -> AuthStatus: authorized = await tg.is_authorized() username = await tg.current_username() if authorized else None @@ -85,7 +85,7 @@ async def auth_status() -> AuthStatus: ) -@router.post("/auth/send-code", status_code=204, dependencies=[Depends(require_admin)]) +@router.post("/auth/send-code", status_code=204, dependencies=[Depends(require_telegram_auth_manager)]) async def auth_send_code() -> None: try: await tg.send_login_code() @@ -96,7 +96,7 @@ async def auth_send_code() -> None: @router.post( "/auth/submit-code", response_model=AuthCodeResult, - dependencies=[Depends(require_admin)], + dependencies=[Depends(require_telegram_auth_manager)], ) async def auth_submit_code(payload: AuthCode) -> AuthCodeResult: try: @@ -106,7 +106,7 @@ async def auth_submit_code(payload: AuthCode) -> AuthCodeResult: return AuthCodeResult(needs_password=needs_password) -@router.post("/auth/submit-password", status_code=204, dependencies=[Depends(require_admin)]) +@router.post("/auth/submit-password", status_code=204, dependencies=[Depends(require_telegram_auth_manager)]) async def auth_submit_password(payload: AuthPassword) -> None: try: await tg.submit_login_password(payload.password) @@ -114,7 +114,7 @@ async def auth_submit_password(payload: AuthPassword) -> None: raise HTTPException(status_code=400, detail=str(exc)) -@router.post("/auth/logout", status_code=204, dependencies=[Depends(require_admin)]) +@router.post("/auth/logout", status_code=204, dependencies=[Depends(require_telegram_auth_manager)]) async def auth_logout() -> None: await tg.logout()