Маршруты, операциями которых продукт не владеет, отвечали заглушкой
"managed by orchestrator" или пустым списком:
POST /hysteria2ChangeVersion
GET /listRelease
POST /config/updateHysteria2Config
POST /config/importHysteria2Config
POST /config/restartServer
POST /config/uploadCertFile
GET /config/hysteria2AcmePath (не имел потребителя вовсе)
Они удалены, а не оставлены заглушками. Причины две. API-контракт не
должен обещать updater, которого у продукта принципиально нет:
маршрут, всегда возвращающий отказ, вводит в заблуждение. И это лишняя
attack surface плюс технический мусор от прежней архитектуры.
Вместе с маршрутами убраны мёртвые сервисы (StartHysteria2,
StopHysteria2, RestartHysteria2, SetHysteria2Config,
UpdateHysteria2Config, GetAuthHttpUrl, Hysteria2AcmePath), неиспользуемые
типы и клиентские функции фронтенда.
Отдельно - кнопки. "Перезапустить панель" и загрузка сертификатов
обращались к заглушкам, то есть гарантированно возвращали ошибку.
Кнопка, которая всегда падает, - не точка расширения на будущее, а
дефект UX. Удалены вместе со строками i18n.
Конфигурация Hysteria остаётся доступной панели на чтение и на
выгрузку: getHysteria2Config и exportHysteria2Config.
Версии были размазаны: PACKAGE_VERSION в build.sh, схема конфигурации в
profile.ts и в hy2xs.env, версии toolchain в deps.sh, Debian 13 в
нескольких местах. Расхождение уже перестало быть теоретическим - пакет
1.0.0 сообщал "HY2XS admin version v0.0.22".
Введён корневой versions.env: версия продукта, линия релиза, схема
конфигурации, целевая платформа, версии и контрольные суммы
Go/Bun/Node/pnpm, политика выбора Hysteria.
Чего в нём нет намеренно:
1. Прикладных зависимостей - у них есть pnpm-lock.yaml, bun.lock,
go.sum. Второй слой неизбежно разъедется с настоящим графом.
2. Конкретной версии Hysteria - здесь только политика
HYSTERIA_CHANNEL, результат резолва живёт в hysteria-lock.env.
Пин версии здесь вернул бы ручное обновление.
Подход - проверка, а не генерация. profile.ts, hy2xs.env и
packageManager в двух package.json остаются обычными файлами, чтобы
bun test, tsc и go test работали из чистого чекаута до сборки. Новый
шаг verify_versions_contract роняет сборку до создания tarball при
расхождении. Контракт оркестратора сверяется не grep'ом по исходникам,
а выводом print-contract.ts: это доказывает, что в бинарь попало то же
значение.
Версия админки перестала быть константой и приезжает через ldflags;
собранный бинарь проверяется запуском hy2xs-admin version.
Контрольные суммы toolchain больше не передаются через окружение. Для
Bun зафиксированы обе суммы: артефакт выбирается по наличию AVX2,
поэтому одной архитектурно недостаточно. Production-сборка снова
запускается одной командой.
Diagnostics-бандл уносил machine token наружу. Построчное правило
`.replace(/(auth:\s*).*/gi, ...)` подставляло маркер в заголовок
mapping'а и оставляло нетронутым вложенный
auth.http.url: http://127.0.0.1:8080/hui/hysteria2/auth?access_token=<секрет>
Это тот же trafficStats secret, который открывает и traffic API, и
auth-endpoint. Бандл собирается автоматически при любом падении
install/reconfigure и предназначен для передачи наружу.
Редакция YAML переписана структурно: документ разбирается и обходится
как дерево. Значение секрета может лежать где угодно, поэтому обходить
нужно дерево, а не строки. Для неразбираемого документа остаётся
консервативный построчный fallback.
В env-артефактах секрет теперь вырезается и из URL-значений:
HY2_AUTH_URL в post-install.env не подходит ни под один маркер имени
ключа, но несёт access_token в значении.
Семантическая проверка сгенерированного конфига:
- добавлен quic.maxIdleTimeout - он был в production-профиле, но не
проверялся, и конфиг с уехавшим idle timeout проходил проверку;
- auth.http.url сверяется целиком (host/port/path/token), а не по
наличию подстроки access_token=. Это единственный канал допуска
пиров, уехавший порт или путь остались бы незамеченными;
- сообщение об ошибке auth.http.url не печатает сам токен: текст
уходит в логи и в diagnostics-бандл;
- добавлены auth.http.insecure, поля ACME и запрет посторонних секций
верхнего уровня.
Маркеры секретных имён в Go-санитайзере расширены и синхронизированы с
оркестратором. Формулировка гарантии сужена до честной: известные
секреты и неизвестные поля с секретоподобным именем.
Сквозная миграция HY2XS на современную Hysteria (2.12.2) и переход на v1.
Build:
- версия Hysteria резолвится на этапе сборки из HyNetworks/hysteria и
замораживается в metadata пакета (version + immutable url + sha256);
- compatibility gate: реальный бинарник должен принять канонический конфиг
HY2XS для gecko и salamander до создания пакета;
- сборка прогоняет тесты оркестратора и админки.
Конфигурационный контракт:
- HY2XS_CONFIG_SCHEMA_VERSION=2, чужая схема отклоняется fail-fast;
- obfs стал настоящим union gecko|salamander, gecko — default;
- obfs-блок рендерится оркестратором целиком, два подтипа одновременно
структурно невозможны;
- современный baseline: congestion bbr/standard, disableLossCompensation=false,
disableStatelessReset=false, полный quic-блок.
Исправления:
- share URI для gecko: генератор был завязан на Obfs.Salamander.Password и
выдавал нерабочую ссылку при любой другой обфускации;
- SNI брался только из ACME-блока и уходил пустым при HY2XS_TLS_MODE=file;
- экспорт конфига выносил trafficStats.secret, access_token и obfs-пароль;
- экспорт терял неизвестные upstream-поля при round-trip через типизированную
модель;
- renderRuntimeEnv печатал тип обфускации литералом, расходясь с конфигом;
- namedotcom удалён из ACME-реестра (нет в Hysteria с 2.11.0).
Тесты:
- 95 тестов оркестратора: env, рендер, семантика профиля, резолвер, rollover;
- тесты URI и экспорта в Go;
- tools/test/e2e-hysteria.sh с реальным клиентом Hysteria.
UX:
- подсказки и примеры в форме создания пира.
Прочее: CHANGELOG.md, .gitattributes (LF для target-side файлов),
документация на русском.
HY2XS больше не описывается как форк H UI. Из README, docs, сообщений
builder'а и post-install metadata убрана вся fork/H UI терминология.
Лицензия:
- LICENSE: MIT заменён на полный текст AGPL-3.0-only
- README: бейдж и раздел лицензии, подпись Flamy Studio
- orchestrator/package.json, apps/frontend/package.json: license
- package.sh: LICENSE кладётся в install package, license=AGPL-3.0-only
в metadata
- verify.sh, acceptance.sh: проверки корневой AGPL и metadata
Документация:
- 04-admin-panel-h-ui-fork.md -> 04-admin-panel.md, переписан вокруг
модели Hysteria2 = external runtime dependency,
HY2XS admin = native HY2XS component
- docs 01, 02, 03, 08, 09, 11, 12, README: единая терминология HY2XS admin
post-install.env:
- блок HUI_* заменён на HY2XS_ADMIN_*, HUI_FORK_REF -> HY2XS_ADMIN_SOURCE
Внутренний legacy namespace (H_UI_* ключи SQLite, HUI_DATA/HUI_LOG,
API /hui, h_ui_db.sql) намеренно не тронут: он требует отдельной
миграции БД и выносится в отдельный этап.