94 lines
3.8 KiB
Python
94 lines
3.8 KiB
Python
import json
|
|
from fastapi import APIRouter, Depends, HTTPException, Request
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select, delete
|
|
|
|
from app.api.deps import db_session, get_current_user, require_admin
|
|
from app.core.security import encrypt_secret, CSRF_COOKIE
|
|
from app.models.user import User
|
|
from app.models.router import Router, RouterCredential, CredentialMethod
|
|
from app.models.dashboard import Permission
|
|
from app.schemas.router import RouterCreate, RouterOut, CredentialCreate
|
|
|
|
router = APIRouter()
|
|
|
|
def require_csrf(request: Request):
|
|
# minimalny CSRF: nagłówek X-CSRF-Token musi równać się cookie mt_csrf
|
|
cookie = request.cookies.get(CSRF_COOKIE)
|
|
header = request.headers.get("X-CSRF-Token")
|
|
if not cookie or not header or cookie != header:
|
|
raise HTTPException(status_code=403, detail="CSRF check failed")
|
|
|
|
@router.get("", response_model=list[RouterOut])
|
|
async def list_routers(user: User = Depends(get_current_user), session: AsyncSession = Depends(db_session)):
|
|
if user.role == "admin":
|
|
res = await session.execute(select(Router))
|
|
rows = res.scalars().all()
|
|
else:
|
|
res = await session.execute(
|
|
select(Router).join(Permission, Permission.router_id == Router.id)
|
|
.where(Permission.user_id == user.id, Permission.can_view == True) # noqa
|
|
)
|
|
rows = res.scalars().all()
|
|
return [RouterOut(
|
|
id=r.id, name=r.name, host=r.host,
|
|
port_rest=r.port_rest, port_ssh=r.port_ssh, port_api=r.port_api,
|
|
verify_ssl=r.verify_ssl, preferred_method=r.preferred_method,
|
|
tags=r.tags
|
|
) for r in rows]
|
|
|
|
@router.post("", response_model=RouterOut)
|
|
async def create_router(payload: RouterCreate, request: Request, user: User = Depends(get_current_user), session: AsyncSession = Depends(db_session)):
|
|
require_admin(user)
|
|
require_csrf(request)
|
|
r = Router(**payload.model_dump())
|
|
session.add(r)
|
|
await session.commit()
|
|
await session.refresh(r)
|
|
return RouterOut(
|
|
id=r.id, name=r.name, host=r.host,
|
|
port_rest=r.port_rest, port_ssh=r.port_ssh, port_api=r.port_api,
|
|
verify_ssl=r.verify_ssl, preferred_method=r.preferred_method, tags=r.tags
|
|
)
|
|
|
|
@router.post("/{router_id}/credentials")
|
|
async def add_credential(router_id: int, payload: CredentialCreate, request: Request, user: User = Depends(get_current_user), session: AsyncSession = Depends(db_session)):
|
|
require_admin(user)
|
|
require_csrf(request)
|
|
res = await session.execute(select(Router).where(Router.id == router_id))
|
|
r = res.scalar_one_or_none()
|
|
if not r:
|
|
raise HTTPException(status_code=404, detail="Router not found")
|
|
|
|
method = payload.method.lower()
|
|
if method not in ("rest", "ssh", "api"):
|
|
raise HTTPException(status_code=400, detail="Bad method")
|
|
|
|
c = RouterCredential(
|
|
router_id=router_id,
|
|
method=CredentialMethod(method),
|
|
username=payload.username,
|
|
secret_encrypted=encrypt_secret(payload.secret),
|
|
extra_json=json.dumps(payload.extra_json or {}),
|
|
)
|
|
session.add(c)
|
|
await session.commit()
|
|
return {"ok": True}
|
|
|
|
@router.post("/{router_id}/grant")
|
|
async def grant_router(router_id: int, target_user_id: int, can_edit: bool = False, request: Request = None,
|
|
user: User = Depends(get_current_user), session: AsyncSession = Depends(db_session)):
|
|
require_admin(user)
|
|
require_csrf(request)
|
|
# upsert permission
|
|
res = await session.execute(select(Permission).where(Permission.user_id == target_user_id, Permission.router_id == router_id))
|
|
p = res.scalar_one_or_none()
|
|
if not p:
|
|
p = Permission(user_id=target_user_id, router_id=router_id, can_view=True, can_edit=can_edit)
|
|
session.add(p)
|
|
else:
|
|
p.can_view = True
|
|
p.can_edit = bool(can_edit)
|
|
await session.commit()
|
|
return {"ok": True}
|