Implement Monlet MVP stack and UI updates
This commit is contained in:
0
server/monlet_server/middleware/__init__.py
Normal file
0
server/monlet_server/middleware/__init__.py
Normal file
22
server/monlet_server/middleware/auth.py
Normal file
22
server/monlet_server/middleware/auth.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.requests import Request
|
||||
|
||||
from ..errors import error_response
|
||||
from ..settings import get_settings
|
||||
|
||||
NO_AUTH_PATHS = {"/api/v1/health", "/api/v1/ready", "/metrics"}
|
||||
|
||||
|
||||
class BearerAuthMiddleware(BaseHTTPMiddleware):
|
||||
async def dispatch(self, request: Request, call_next):
|
||||
if request.url.path in NO_AUTH_PATHS:
|
||||
return await call_next(request)
|
||||
|
||||
expected = get_settings().auth_token
|
||||
header = request.headers.get("authorization")
|
||||
if not header or not header.lower().startswith("bearer "):
|
||||
return error_response(request, 401, "unauthorized", "authentication required")
|
||||
token = header.split(" ", 1)[1].strip()
|
||||
if token != expected:
|
||||
return error_response(request, 401, "unauthorized", "authentication required")
|
||||
return await call_next(request)
|
||||
32
server/monlet_server/middleware/body_limit.py
Normal file
32
server/monlet_server/middleware/body_limit.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.requests import Request
|
||||
|
||||
from ..errors import error_response
|
||||
from ..settings import get_settings
|
||||
|
||||
|
||||
class BodyLimitMiddleware(BaseHTTPMiddleware):
|
||||
async def dispatch(self, request: Request, call_next):
|
||||
limit = get_settings().body_limit_bytes
|
||||
cl = request.headers.get("content-length")
|
||||
if cl is not None:
|
||||
try:
|
||||
if int(cl) > limit:
|
||||
return error_response(request, 413, "payload_too_large", "body too large")
|
||||
except ValueError:
|
||||
return error_response(request, 400, "validation", "invalid content-length")
|
||||
return await call_next(request)
|
||||
|
||||
total = 0
|
||||
chunks: list[bytes] = []
|
||||
async for chunk in request.stream():
|
||||
total += len(chunk)
|
||||
if total > limit:
|
||||
return error_response(request, 413, "payload_too_large", "body too large")
|
||||
chunks.append(chunk)
|
||||
|
||||
async def receive():
|
||||
return {"type": "http.request", "body": b"".join(chunks), "more_body": False}
|
||||
|
||||
request._receive = receive # type: ignore[attr-defined]
|
||||
return await call_next(request)
|
||||
23
server/monlet_server/middleware/request_id.py
Normal file
23
server/monlet_server/middleware/request_id.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import re
|
||||
import uuid
|
||||
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.requests import Request
|
||||
|
||||
from ..logging_config import request_id_var
|
||||
|
||||
_UUID_RE = re.compile(r"^[0-9a-fA-F-]{8,64}$")
|
||||
|
||||
|
||||
class RequestIdMiddleware(BaseHTTPMiddleware):
|
||||
async def dispatch(self, request: Request, call_next):
|
||||
incoming = request.headers.get("X-Request-Id")
|
||||
rid = incoming if incoming and _UUID_RE.match(incoming) else str(uuid.uuid4())
|
||||
request.state.request_id = rid
|
||||
token = request_id_var.set(rid)
|
||||
try:
|
||||
response = await call_next(request)
|
||||
finally:
|
||||
request_id_var.reset(token)
|
||||
response.headers["X-Request-Id"] = rid
|
||||
return response
|
||||
Reference in New Issue
Block a user