Обновление файла
This commit is contained in:
@@ -8,11 +8,12 @@
|
|||||||
- Cookie PVEAuthCookie — если заданы PVE_USERNAME + PVE_PASSWORD
|
- Cookie PVEAuthCookie — если заданы PVE_USERNAME + PVE_PASSWORD
|
||||||
3. Проксирует бинарный VNC-поток между браузером клиента и Proxmox.
|
3. Проксирует бинарный VNC-поток между браузером клиента и Proxmox.
|
||||||
|
|
||||||
Особенности Proxmox:
|
Особенности:
|
||||||
- В Proxmox 8.x+ vncticket может содержать спецсимволы (#, /, %, :),
|
- В Proxmox 8.x+ vncticket может содержать спецсимволы (#, /, %, :),
|
||||||
которые ломают парсинг URL (RFC 3986). Кодируем их через quote().
|
которые ломают парсинг URL (RFC 3986). Кодируем через quote().
|
||||||
- PVE может вернуть HTTP redirect (302) на `https://...` вместо `wss://...`;
|
- process_redirect в websockets не работает на uvloop (используется
|
||||||
перехватываем и переписываем scheme через process_redirect.
|
uvicorn[standard]), поэтому редиректы не обрабатываем — Proxmox
|
||||||
|
обычно их и не делает при корректном URL.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
@@ -22,7 +23,6 @@ from urllib.parse import quote
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import websockets
|
import websockets
|
||||||
from websockets.http11 import Response
|
|
||||||
from fastapi import APIRouter, Query, WebSocket, WebSocketDisconnect
|
from fastapi import APIRouter, Query, WebSocket, WebSocketDisconnect
|
||||||
|
|
||||||
from ..config import settings
|
from ..config import settings
|
||||||
@@ -32,23 +32,6 @@ logger = logging.getLogger(__name__)
|
|||||||
router = APIRouter(prefix="/console", tags=["console"])
|
router = APIRouter(prefix="/console", tags=["console"])
|
||||||
|
|
||||||
|
|
||||||
def _process_redirect(request, response: Response) -> Optional[str]:
|
|
||||||
"""Перехватывает HTTP-redirect от Proxmox и переписывает https://→wss://.
|
|
||||||
|
|
||||||
Proxmox иногда возвращает Location со схемой https:// (хотя для WebSocket
|
|
||||||
положено wss://). Библиотека websockets в этом случае падает с
|
|
||||||
InvalidURI("scheme isn't ws or wss"). Возвращаем исправленный URL.
|
|
||||||
"""
|
|
||||||
location = response.headers.get("Location", "")
|
|
||||||
if not location:
|
|
||||||
return None
|
|
||||||
if location.startswith("https://"):
|
|
||||||
return "wss://" + location[len("https://"):]
|
|
||||||
if location.startswith("http://"):
|
|
||||||
return "ws://" + location[len("http://"):]
|
|
||||||
return location
|
|
||||||
|
|
||||||
|
|
||||||
async def _get_pve_auth_cookie() -> Optional[Tuple[str, str]]:
|
async def _get_pve_auth_cookie() -> Optional[Tuple[str, str]]:
|
||||||
"""Аутентифицируется в Proxmox по логину/паролю и возвращает (cookie_header, csrf_token).
|
"""Аутентифицируется в Proxmox по логину/паролю и возвращает (cookie_header, csrf_token).
|
||||||
|
|
||||||
@@ -94,9 +77,8 @@ async def console_ws(
|
|||||||
|
|
||||||
guest_path = "qemu" if guest_type == "vm" else "lxc"
|
guest_path = "qemu" if guest_type == "vm" else "lxc"
|
||||||
pve_host_only = settings.pve_host.replace("http://", "").replace("https://", "")
|
pve_host_only = settings.pve_host.replace("http://", "").replace("https://", "")
|
||||||
# quote() экранирует спецсимволы в тикете и порте по правилам RFC 3986,
|
# quote() экранирует спецсимволы в тикете и порте по правилам RFC 3986.
|
||||||
# не затрагивая уже экранированные символы. Без этого в Proxmox 8.x+
|
# Без этого в Proxmox 8.x+ vncticket может содержать # / % : которые ломают URL.
|
||||||
# vncticket может содержать # / % : которые ломают URL.
|
|
||||||
safe_ticket = quote(ticket, safe="")
|
safe_ticket = quote(ticket, safe="")
|
||||||
safe_port = quote(str(port), safe="")
|
safe_port = quote(str(port), safe="")
|
||||||
upstream_url = (
|
upstream_url = (
|
||||||
@@ -129,7 +111,6 @@ async def console_ws(
|
|||||||
extra_headers=headers,
|
extra_headers=headers,
|
||||||
subprotocols=["binary"],
|
subprotocols=["binary"],
|
||||||
ssl=None if settings.pve_verify_ssl else False,
|
ssl=None if settings.pve_verify_ssl else False,
|
||||||
process_redirect=_process_redirect,
|
|
||||||
) as upstream:
|
) as upstream:
|
||||||
logger.info("console_ws: upstream connected")
|
logger.info("console_ws: upstream connected")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user