- Зачем:
- CLI и спека были переусложнены относительно принятой модели угроз
(один пользователь, доверенная машина): лишняя ось версий Xray и
защита от входов, которые не возникают при ручном редактировании.
- Что:
- убрана поддержка Xray 25.12.8 — поддерживается только 26.3.27;
allowInsecure валидируется, но никогда не эмитится в JSON.
- удалена проверка владения сокетом через /proc/net/tcp; идентичность
процесса и сверка адрес/порт со state сохранены.
- валидация INI/профиля/адреса/query сведена к отказам на реальные
опечатки; scoped IPv6 отклоняется одинаково на Python 3.8 и 3.9+.
- удалены fsync/O_EXCL-церемония, SIGALRM-таймер, zombie-инспекция,
мёртвый отпечаток профиля и двойной разбор extra/alpn.
- shell.bash принимает вывод env без ре-валидации, сохранив атомарность;
спека и issue 01–05 приведены к новому объёму (тикет 06, леджер).
- Проверка:
- python3 -m unittest discover -s tests — 34 теста OK.
- bash tests/test_proxy_launchers.sh — 8 проверок PASS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
75 lines
7.8 KiB
Markdown
75 lines
7.8 KiB
Markdown
# 02 — Управляемый Xray: полный штатный путь
|
||
|
||
**What to build:** Пользователь с уже установленным поддерживаемым Xray кладёт
|
||
одну VLESS-ссылку в закрытый файл и получает полный штатный сценарий локального
|
||
прокси: проверку профиля, запуск на переднем плане, диагностику, запуск команд
|
||
через прокси и штатную остановку.
|
||
|
||
**Blocked by:** 01 — Внешний прокси и переносимый Bash-интерфейс.
|
||
|
||
**Status:** done
|
||
|
||
Часть требований пересмотрена в 06 — см. 06-simplification-pass.md.
|
||
|
||
- [x] `start` разрешён только при явном типе `xray`, требует loopback-адрес и
|
||
согласованный локальный порт, никогда не скачивает бинарник и выбирает первый
|
||
`xray` из `PATH`. Один разрешённый путь используется для `version`,
|
||
`run -test` и основного процесса и показывается перед запуском.
|
||
- [x] Успешный `xray version` разбирается только по первой строке в форме
|
||
`Xray VERSION` с концом строки либо ASCII-пробелом после полного токена
|
||
версии. Принимаются только `25.12.8` и `26.3.27`; ведущий мусор, похожий
|
||
префикс вроде `26.3.270`, пустой, неверный или завершившийся ошибкой вывод
|
||
запрещает преобразование и запуск. Запрошенная или указанная в профиле версия
|
||
не подменяет фактическую версию выбранного бинарника.
|
||
- [x] Профиль берётся из предусмотренного файла по умолчанию либо из явно
|
||
переданного `-f`, содержит ровно одну VLESS-ссылку, а конечный файл после
|
||
разрешения симлинка недоступен группе и остальным пользователям.
|
||
- [x] Строгий преобразователь поддерживает TCP/RAW с REALITY и XHTTP с TLS,
|
||
сохраняет все предусмотренные спецификацией поля, отклоняет повторы,
|
||
любой неизвестный query-параметр, отсутствующие обязательные поля и
|
||
неподдерживаемые сочетания до запуска Xray.
|
||
- [x] Для Xray 26.3.27 корректно обрабатываются `pcs`/`vcn`, а устаревшие
|
||
`allowInsecure`/`insecure` не переносятся и дают предупреждение; для явно
|
||
выбранного Xray 25.12.8 сохраняется совместимое insecure-поведение, а новые
|
||
поля отклоняются без автоматического отката версии.
|
||
- [x] `allowInsecure` и `insecure` принимают только точные значения `true` или
|
||
`false`; при одновременном присутствии значения должны совпадать. Для
|
||
25.12.8 только согласованное истинное значение включает `allowInsecure` с
|
||
предупреждением, а для 26.3.27 поле никогда не попадает в JSON и истинное
|
||
значение предупреждает об обычной проверке сертификата.
|
||
- [x] Созданный клиентский JSON слушает только loopback, предоставляет HTTP и
|
||
SOCKS на одном порту, отключает журнал доступа и проходит `xray run -test`
|
||
до запуска основного процесса.
|
||
- [x] `start` остаётся на переднем плане как супервизор одного дочернего Xray;
|
||
после запуска процесс жив и порт принимает соединения, а сбой отдельной
|
||
проверки внешнего IP остаётся предупреждением.
|
||
- [x] Штатный `start` создаёт закрытое состояние с PID супервизора и дочернего
|
||
Xray, разрешённым путём к бинарнику, портом и безопасным отпечатком профиля.
|
||
`status`, `env`, `run` и `stop` требуют это состояние, живой супервизор,
|
||
ожидаемый дочерний процесс и настроенный порт; один чужой listener или PID
|
||
никогда не считается управляемым Xray и не затрагивается.
|
||
- [x] `status`, `env`, `run` и `stop` обеспечивают штатный путь управляемого
|
||
Xray; `run` никогда не запускает его скрыто, а `stop` может завершить
|
||
управляемый процесс после переключения машинного типа на `external`.
|
||
Успешный `stop` посылает сигнал супервизору, ограниченно ждёт завершения
|
||
супервизора и Xray, очищает штатное состояние и возвращает исходный
|
||
foreground-вызов `start` в терминал.
|
||
- [x] Диагностика внешнего IP действительно делает запрос через настроенный
|
||
локальный HTTP-прокси. Её сбой явно показан как предупреждение и не отменяет
|
||
уже успешные проверки процесса и порта.
|
||
- [x] Безопасная сводка показывает только полезные несекретные свойства
|
||
профиля; XHTTP `path` показывается только как скрытое значение с длиной, а
|
||
UUID, ключи, short ID и другие секреты — без фрагментов исходного значения.
|
||
Полная VLESS-ссылка и уникальные секреты отсутствуют в stdout, stderr и argv
|
||
дочерних процессов при успехе, любом отказе разбора и сбое `run -test`.
|
||
- [x] Модульные и интеграционные тесты покрывают обе семьи ссылок, варианты
|
||
ALPN, типичную ссылку Hiddify XHTTP/TLS, обе поддержанные версии Xray и
|
||
понятные отказы на неподдерживаемом вводе.
|
||
- [x] Чёрный ящик для каждой поддержанной версии доказывает полный порядок:
|
||
профиль по умолчанию и `-f`, `version`, успешный `run -test` до основного
|
||
запуска, живое управляемое состояние и порт, `status`, `env`, дочернюю
|
||
команду через `run`, проксированную IP-диагностику, `stop` и ограниченное
|
||
завершение исходного `start`. Через один настроенный локальный порт реально
|
||
завершаются отдельный HTTP-proxy-запрос и отдельный SOCKS-proxy-запрос.
|
||
Подмена порта или состояния чужим процессом даёт безопасный отказ.
|