forked from iarv/pyMC_Repeater
Features Neighbour details modal with full info and map view WebSocket support with heartbeat and automatic reconnection Improved signal quality calculations (SNR-based RSSI) Route-based pagination for faster initial loads UI Mobile sidebar tweaks (logout, version info, lazy-loaded charts) Sorting added to the neighbour table Packet view now shows multi-hop paths CAD calibration charts respect light/dark themes Statistics charts now show the full requested time range Performance Reduced polling when WebSocket is active Lazy loading for heavier components Noise floor data capped to keep charts responsive Technical Improved type safety across API responses Contrast improvements for accessibility Cleaner WebSocket and MQTT reconnection handling Additional metrics added to heartbeat stats Bug fixes Corrected noise floor history query Fixed authentication for CAD calibration streams Nothing major required from users — just update and carry on. As always, shout if something looks off.
84 lines
2.9 KiB
Python
84 lines
2.9 KiB
Python
import logging
|
|
import cherrypy
|
|
|
|
logger = logging.getLogger("HTTPServer")
|
|
|
|
|
|
def check_auth():
|
|
"""
|
|
CherryPy tool to check authentication before processing request.
|
|
|
|
Checks for either JWT in Authorization header, API token in X-API-Key header,
|
|
or JWT token in query parameter (for EventSource/SSE connections).
|
|
Sets cherrypy.request.user on success.
|
|
Returns 401 JSON response on failure.
|
|
"""
|
|
# Skip auth check for OPTIONS requests (CORS preflight)
|
|
if cherrypy.request.method == "OPTIONS":
|
|
return
|
|
|
|
# Skip auth check for /auth/login endpoint
|
|
if cherrypy.request.path_info == "/auth/login":
|
|
return
|
|
|
|
# Get auth handlers from config
|
|
jwt_handler = cherrypy.config.get("jwt_handler")
|
|
token_manager = cherrypy.config.get("token_manager")
|
|
|
|
if not jwt_handler or not token_manager:
|
|
logger.error("Auth handlers not initialized in cherrypy.config")
|
|
cherrypy.response.status = 500
|
|
return {"success": False, "error": "Authentication system not configured"}
|
|
|
|
# Check for JWT token in Authorization header first
|
|
auth_header = cherrypy.request.headers.get("Authorization", "")
|
|
if auth_header.startswith("Bearer "):
|
|
token = auth_header[7:] # Remove "Bearer " prefix
|
|
payload = jwt_handler.verify_jwt(token)
|
|
|
|
if payload:
|
|
cherrypy.request.user = {
|
|
"username": payload.get("sub"),
|
|
"client_id": payload.get("client_id"),
|
|
"auth_type": "jwt"
|
|
}
|
|
return
|
|
|
|
# Check for JWT token in query parameter (for EventSource/SSE)
|
|
# EventSource doesn't support custom headers, so we use query param
|
|
query_token = cherrypy.request.params.get("token")
|
|
if query_token:
|
|
payload = jwt_handler.verify_jwt(query_token)
|
|
|
|
if payload:
|
|
cherrypy.request.user = {
|
|
"username": payload.get("sub"),
|
|
"client_id": payload.get("client_id"),
|
|
"auth_type": "jwt_query"
|
|
}
|
|
# Remove token from params to avoid exposing it in logs
|
|
del cherrypy.request.params["token"]
|
|
return
|
|
|
|
# Check for API token in X-API-Key header
|
|
api_key = cherrypy.request.headers.get("X-API-Key", "")
|
|
if api_key:
|
|
token_info = token_manager.verify_token(api_key)
|
|
|
|
if token_info:
|
|
cherrypy.request.user = {
|
|
"token_id": token_info["id"],
|
|
"token_name": token_info["name"],
|
|
"auth_type": "api_token"
|
|
}
|
|
return
|
|
|
|
# No valid authentication found
|
|
logger.warning(f"Unauthorized access attempt to {cherrypy.request.path_info}")
|
|
raise cherrypy.HTTPError(401, "Unauthorized - Valid JWT or API token required")
|
|
|
|
|
|
# Register the tool
|
|
cherrypy.tools.require_auth = cherrypy.Tool('before_handler', check_auth)
|
|
logger.info("CherryPy require_auth tool registered")
|