Restrict editor role navigation
This commit is contained in:
@@ -16,7 +16,7 @@ from zoneinfo import ZoneInfo
|
||||
|
||||
import aiohttp
|
||||
from fastapi import FastAPI, File, Form, Request, UploadFile, status
|
||||
from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse
|
||||
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse, RedirectResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from loguru import logger
|
||||
@@ -449,6 +449,34 @@ def base_context(request: Request, user: dict | None, **extra: Any) -> dict[str,
|
||||
return ctx
|
||||
|
||||
|
||||
EDITOR_ALLOWED_PATHS = (
|
||||
"/",
|
||||
"/raw",
|
||||
"/editor",
|
||||
"/sources",
|
||||
"/uploads",
|
||||
"/logout",
|
||||
"/login",
|
||||
"/favi.png",
|
||||
"/favicon.ico",
|
||||
"/health",
|
||||
)
|
||||
|
||||
|
||||
def is_editor_allowed_path(path: str) -> bool:
|
||||
return any(path == allowed or path.startswith(f"{allowed}/") for allowed in EDITOR_ALLOWED_PATHS if allowed != "/") or path == "/"
|
||||
|
||||
|
||||
@app.middleware("http")
|
||||
async def restrict_editor_access(request: Request, call_next):
|
||||
user = await get_current_user(request)
|
||||
if user and user.get("role") == "editor" and not is_editor_allowed_path(request.url.path):
|
||||
if request.method == "GET" and not request.headers.get("hx-request"):
|
||||
return redirect("/raw")
|
||||
return JSONResponse({"detail": "Forbidden"}, status_code=status.HTTP_403_FORBIDDEN)
|
||||
return await call_next(request)
|
||||
|
||||
|
||||
def client_ip(request: Request) -> str:
|
||||
forwarded = request.headers.get("x-forwarded-for", "")
|
||||
if forwarded:
|
||||
|
||||
@@ -178,6 +178,7 @@
|
||||
<i data-lucide="database" class="w-5 h-5"></i>
|
||||
Источники
|
||||
</a>
|
||||
{% if user.role != "editor" %}
|
||||
<a href="/workers" class="flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-colors {{ 'bg-app-primary/10 text-app-primary' if 'workers' in request.url.path else 'text-app-textMuted hover:bg-app-surfaceHover hover:text-app-textMain' }}">
|
||||
<i data-lucide="cpu" class="w-5 h-5"></i>
|
||||
Воркеры
|
||||
@@ -190,6 +191,7 @@
|
||||
<i data-lucide="file-text" class="w-5 h-5"></i>
|
||||
Логи
|
||||
</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
|
||||
<div class="p-4 border-t border-app-border">
|
||||
@@ -228,7 +230,9 @@
|
||||
<a href="/raw" class="block px-3 py-2 rounded-lg text-sm {{ 'bg-app-bg text-app-textMain' if 'raw' in request.url.path else 'text-app-textMuted' }}">Сырые посты</a>
|
||||
<a href="/editor" class="block px-3 py-2 rounded-lg text-sm {{ 'bg-app-bg text-app-textMain' if 'editor' in request.url.path else 'text-app-textMuted' }}">Редактор</a>
|
||||
<a href="/sources" class="block px-3 py-2 rounded-lg text-sm {{ 'bg-app-bg text-app-textMain' if 'sources' in request.url.path else 'text-app-textMuted' }}">Источники</a>
|
||||
{% if user.role != "editor" %}
|
||||
<a href="/workers" class="block px-3 py-2 rounded-lg text-sm {{ 'bg-app-bg text-app-textMain' if 'workers' in request.url.path else 'text-app-textMuted' }}">Воркеры</a>
|
||||
{% endif %}
|
||||
<div class="pt-2 mt-2 border-t border-app-border">
|
||||
<form method="post" action="/logout" class="m-0">
|
||||
<input type="hidden" name="csrf_token" value="{{ user.csrf_token }}">
|
||||
|
||||
Reference in New Issue
Block a user