Files
web-vnc/AGENTS.md
T
Codex 120d4e9498 Add embedded favicon and suppress noVNC secure-context warning
- serve /favicon.ico outside session middleware so it loads on the login
  page too (was 404 via the catch-all -> requireSession redirect)
- add embedded internal/server/static/favicon.ico (monitor icon) and
  <link rel=icon> on the login page and vnc.html
- in vnc.html wrap console.error before importing core/rfb.js to drop only
  the harmless 'noVNC requires a secure context (TLS). Expect crashes!' line
  (plain VNC-password auth uses pure-JS DES, not crypto.subtle); reword the
  now-redundant disconnect hint
- update AGENTS.md with the favicon route and the secure-context note
2026-07-31 10:51:39 +03:00

128 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md
Руководство для агентов (и людей), работающих с этим репозиторием.
## Сопровождение этого файла (ВАЖНО)
- **AGENTS.md должен отражать актуальное состояние кода.** Это живой документ,
а не одноразовая справка.
- При любом изменении, влияющем на: архитектуру, состав пакетов/файлов, флаги
CLI или env-переменные (`WEBVNC_*`), протокол/поведение гейтвея, скрипты,
кодировки файлов, процесс сборки/запуска или известные ограничения —
**обязательно обнови соответствующий раздел AGENTS.md в том же коммите**.
- Если заметил расхождение между AGENTS.md и реальным кодом (функция переименована,
файл удалён, флаг изменён и т.п.) — сначала приведи AGENTS.md в соответствие
с кодом, затем продолжай работу. Не оставляй устаревшие инструкции.
- Коммит, меняющий поведение/структуру, но не трогающий AGENTS.md при расхождении,
считается неполным.
## Что это
`web-vnc` — один Go-бинарник, который открывает доступ к рабочему столу (VNC)
через браузер (noVNC) с защитой по паролю. Гейтвей сам раздаёт noVNC-клиент,
проверяет пароль, ставит HMAC-сессию и прозрачно релеит WebSocket браузера в
TCP VNC-сервера (RFB). Опционально сам находит и запускает VNC-сервер.
## Ключевые принципы (НЕ нарушать)
- **Только стандартная библиотека Go.** Внешних Go-модулей нет и быть не должно —
проект собирается офлайн (в среде сборки нет интернета/Go-proxy).
WebSocket (RFC 6455) и хэш пароля (PBKDF2-HMAC-SHA256) реализованы вручную
в `internal/relay` и `internal/auth`.
- **noVNC-клиент скачивается отдельно** (`scripts/get-novnc.*`) во встроенную
статику `internal/server/static/`. Эти папки (`core/`,`app/`,`vendor/`,
`utils/`,`novnc-original.html`) в git не коммитятся (см. `.gitignore`).
Наша собственная обёртка — `internal/server/static/vnc.html` (коммитится).
- **Пароль** — один общий для всех (по требованию). Веб-пароль (PBKDF2) хранится
как `--password-hash`; тот же пароль может передаваться VNC-серверу через
`--vnc-password`/`WEBVNC_VNC_PASSWORD`, чтобы noVNC авторизовался
автоматически (одно поле ввода для пользователя).
## Сборка и запуск
```powershell
# среда без интернета: Go уже установлен, прокси недоступен -> stdlib-only
$env:GOCACHE = "$env:TEMP\go-build" # дефолтный кэш бывает без прав на запись
go build -o web-vnc.exe ./cmd/web-vnc
.\web-vnc.exe --gen-hash "пароль" # напечатает хэш
.\web-vnc.exe --password-hash <хэш> --spawn
```
Проверка: `go vet ./...`, `gofmt -l internal cmd` (должно быть пусто).
## Структура
```
cmd/web-vnc/main.go CLI: флаги, спавн VNC, запуск сервера, --gen-hash
internal/config флаги + env (WEBVNC_*)
internal/auth PBKDF2-HMAC-SHA256, HMAC session-cookie, rate-limit
internal/relay websocket.go — RFC6455 на stdlib; relay.go — WS<->TCP
internal/vncspawner кросс-ОС поиск/запуск VNC-сервера (build-теги по ОС)
internal/server HTTP-роуты, /api/status, middleware сессии, embed.FS
internal/server/static встроенные ассеты (vnc.html, favicon.ico + noVNC core/app/vendor)
scripts/get-novnc.{ps1,sh} скачать noVNC
scripts/get-vnc.ps1 скачать портативный UltraVNC в vnc/ (с верификацией zip)
scripts/list-ips.ps1 список IPv4 машины (используется run.bat)
scripts/open-firewall.bat открыть порт 8080 в Windows Firewall (от админа)
scripts/ensure-vnc-password.ps1 синхронизирует VNC-пароль UltraVNC с паролем из run.bat (пишет только при несовпадении; UAC только при смене) — вызывается из run.bat
run.bat запуск в один клик (спрашивает только пароль); синхронизирует VNC-пароль UltraVNC с введённым (см. ensure-vnc-password.ps1); если 5900 уже занят (сервис UltraVNC) — не порождает второй VNC-сервер, а подключается к существующему
```
## Соглашения и подводные камни
- **Кодировка файлов `.bat`:** **UTF-8 с BOM**, окончания строк **CRLF**, и `chcp 65001 >nul`
после `@echo off`. Именно **BOM** заставляет `cmd` читать .bat как UTF-8 независимо
от OEM-кодировки консоли (без BOM + `chcp 65001` в `cmd` даёт `????` — cmd читает
файл по OEM-кодировке, а не по `chcp`). BOM + `chcp 65001` проверено: кириллица в
`echo`/`set /p`/`for /f` отображается корректно, `@echo off` работает. Альтернатива
без BOM — включить системную опцию «Beta: Use Unicode UTF-8 for worldwide language
support» (тогда OEM-кодировка = 65001), но это влияет на всю систему (нужен reboot,
могут ломаться legacy-приложения под cp866/cp1251) — поэтому по умолчанию BOM.
Пиши через `[System.IO.File]::WriteAllText(path, content -replace "(?<!\r)\n","`r`n", [Text.UTF8Encoding]::new($true))`.
- **Go-файлы:** UTF-8 **без BOM**, LF. То же самое правило — не использовать
`Set-Content -Encoding UTF8` (ставит BOM). Используй
`[System.IO.File]::WriteAllText(path, content, [Text.UTF8Encoding]::new($false))`.
- **`.gitignore`:** бинарники игнорируются **root-anchored** (`/web-vnc`,
`/web-vnc.exe`), иначе шаблон `web-vnc` ловит пакет `cmd/web-vnc/`.
- **vncspawner:** функции поиска VNC-сервера определены через build-теги
(`detect_windows.go`/`detect_linux.go`/`detect_darwin.go`), каждый файл
определяет `func candidates() []Candidate`. Не ссылаться на
платформо-специфичные функции из общих файлов.
- **Тесты в этой среде:** интернет отсутствует; проверяй через локальные
заглушки (TCP-эхо-сервер на 5900, `Get-NetIPAddress` часто пуст —
`list-ips.ps1` имеет фолбэк на `ipconfig`). Запущенный web-vnc.exe из
фонового job может остаться «зомби» (Stop-Process иногда access denied);
используй разные порты для тестов и по возможности запускай killable-способом.
- **favicon.ico:** браузер запрашивает `/favicon.ico` на каждой странице
(включая форму логина). Роут `/favicon.ico` зарегистрирован **вне** session-
middleware (чтобы без сессии не редиректил на /login и не давал 404) и отдаёт
встроенный `internal/server/static/favicon.ico` (иконка-монитор, коммитится;
не входит в скачиваемые noVNC-ассеты). На логине и vnc.html есть
`<link rel="icon" href="/favicon.ico">`.
- **Secure context (TLS) в noVNC:** noVNC (`core/rfb.js`, `app/ui.js`) печатает
`Log.Error("noVNC requires a secure context (TLS). Expect crashes!")` при
`!window.isSecureContext` — т.е. на plain-http по LAN-IP. Для обычной VNC-
password-авторизации это **безобидно**: noVNC использует чистый-JS DES из
`core/des.js` и НЕ нуждается в `crypto.subtle`. Чтобы не пугать пользователя
красной ошибкой в консоли, обёртка `vnc.html` ДО импорта `core/rfb.js`
оборачивает `console.error` фильтром, гасящим **только** эту строку (всё
остальное проходит в оригинальный `console.error`). Файлы noVNC (core/, app/,
…) НЕ правятся — они gitignored и перезаливаются `scripts/get-novnc.*`.
Корректный способ сделать контекст действительно secure — HTTPS (self-signed),
но это отдельная фича; пока — фильтр в vnc.html.
- **Hijack WebSocket:** `internal/relay` сам делает апгрейд через
`http.Hijacker`; гейтвей НЕ использует gorilla/websocket.
## Что делать дальше (известные TODO)
- Надёжный авто-скачиватель VNC-сервера (URL UltraVNC на SourceForge нестабилен —
`get-vnc.ps1` теперь верифицирует zip-магию и даёт фолбэк на ручную установку).
- На Windows захват экрана может требовать запуск VNC-сервера от администратора.
- VNC-сервер требует свой пароль; `--vnc-password` передаёт его noVNC
автоматически, но пароль VNC-сервера нужно один раз настроить под тот же.
**UltraVNC как сервис (`uvnc_service`, LocalSystem):** пароль хранится в
`%ProgramData%\UltraVNC\ultravnc.ini`; задать его обычным пользователем через
tray-иконку молча не получается (нет прав на запись).
`run.bat` синхронизирует этот пароль сам через `scripts/ensure-vnc-password.ps1`
(пишет только при несовпадении; UAC только при смене пароля). VNC-пароль = первые 8 байт,
поэтому используй ASCII-пароль <= 8 символов и там, и в `run.bat`.