ZapretKVN-android/docs/IMPORT_FORMATS.md
2026-07-25 01:33:04 +03:00

186 lines
15 KiB
Markdown
Raw Permalink 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.

# Zapret KVN — политика форматов импорта
> Каноническая граница импортера. Документ определяет, какие входные форматы
> допустимы, что именно они меняют и при каких условиях можно расширять MVP.
| Поле | Значение |
|---|---|
| Статус | WireGuard/AmneziaWG `.conf` реализован; Clash YAML исследован и отложен |
| Последний аудит | 24 июля 2026 года |
| Ядро | `sing-box-extended` `ff11f007ec798136a5de258f947a4f34011a37ea` |
| Источник сетевой истины | Только итоговый sing-box JSON профиля |
## Неподвижная граница
Любой импорт заканчивается созданием настоящего sing-box JSON до preview и
сохранения. YAML, URI и subscription response — только входные данные, а не
второй формат профиля или маршрутизации.
- импорт не переносит чужие DNS, route rules или proxy groups скрыто;
- неизвестное поле или тип нельзя молча отбросить и показать импорт успешным;
- исходный YAML не хранится и не участвует в runtime;
- перед сохранением итог проходит native `Libbox.CheckConfig()`;
- перед запуском сохранённый JSON может получить только явно документированные runtime overlays из DNS/Routing/VPN Hiding ADR; stored profile при этом не переписывается;
- URL обновляется только вручную, без фонового scheduler;
- секреты маскируются в preview, ошибках, логах и диагностике.
## Форматы MVP
- полный sing-box JSON;
- нативный WireGuard и AmneziaWG 2.0 INI `.conf`;
- JSON/raw/base64 subscription, который уже распознаёт реализованный importer;
- VLESS, VMess, Trojan, Shadowsocks, Hysteria2 и TUIC URI;
- URL, QR, буфер обмена и системный file picker как способы доставки тех же
данных.
Текстовый файл или буфер могут содержать несколько URI разных поддерживаемых
протоколов, подписи, маркеры списка и несколько ссылок в одной строке. Импортер
извлекает все поддерживаемые URI в исходном порядке и создаёт одну managed-группу
с preview полного количества серверов. Найденная конфигурационная URI-схема,
которую приложение не поддерживает, останавливает импорт явной ошибкой, чтобы
частичный результат нельзя было принять за полный.
## F-IMPORT-XHTTP — VLESS XHTTP URI
Граница конвертации разделяет два формата:
- вход соответствует XTLS VLESS share-link: `extra` — JSON-объект, целиком
обработанный `encodeURIComponent`, а не Base64;
- выход соответствует `V2RayXHTTPOptions` закреплённого sing-box-extended:
camelCase-поля XTLS явно преобразуются в snake_case-поля transport JSON.
Поддерживаются `headers`, padding/session/sequence/uplink options,
`noGRPCHeader`, `noSSEHeader`, packet/stream limits и все поля `xmux`, которые
есть в закреплённой схеме core. Типы JSON не превращаются в строки: ranges могут
остаться строками, а числа и bool — числами и bool. Неизвестное поле завершает
импорт явной ошибкой вместо silent drop.
Устаревшее Xray-поле `xmux.cMaxLifetimeMs` совместимо преобразуется в актуальное
`h_max_reusable_secs`: одиночное значение или обе границы диапазона делятся на
1000. Одновременное указание старого `cMaxLifetimeMs` и нового
`hMaxReusableSecs`, а также потеря миллисекунд при преобразовании отклоняются
явной ошибкой.
Link parser закреплённого core здесь не является источником синтаксиса входной
ссылки: в commit `ff11f007` его XHTTP-ветка ошибочно ожидает Base64. Источник
истины для URI — [XTLS share-link proposal](https://github.com/XTLS/Xray-core/discussions/716),
а источник истины для результата —
[точная схема `V2RayXHTTPOptions`](https://github.com/shtorm-7/sing-box-extended/blob/ff11f007ec798136a5de258f947a4f34011a37ea/option/v2ray_transport.go).
## F-IMPORT-WG — WireGuard и AmneziaWG 2.0 `.conf`
Импорт является прямым преобразованием INI в единственный сохраняемый sing-box
JSON. Отдельный WireGuard-процесс, локальный SOCKS и второй VPN не создаются.
Поскольку закреплённый sing-box 1.13 использует новую схему, результат содержит
`wireguard` в верхнеуровневом `endpoints`, а не deprecated outbound:
- `[Interface] PrivateKey`, `Address`, `ListenPort`, `MTU` переходят в endpoint;
- `[Peer] PublicKey`, `PresharedKey`, `Endpoint`, `AllowedIPs` и
`PersistentKeepalive` переходят в `peers`;
- AWG `Jc`, `Jmin`, `Jmax`, `S1`…`S4`, `H1`…`H4` и AWG 2.0 `I1`…`I5`
переходят в нативный объект `amnezia`;
- `AllowedIPs` становятся одновременно peer policy и явным sing-box route
rule; остальной трафик идёт в `direct`, как при split-tunnel WireGuard;
- числовые `DNS` становятся sing-box UDP DNS; сервер направляется через endpoint
только если он входит в `AllowedIPs`. Для bootstrap имени `Endpoint`
используется системный DNS underlying-сети;
- исходный INI после preview не хранится.
Private/public/pre-shared keys принимаются только как стандартный Base64 ровно
32 байт и записываются обратно в каноническом виде с `=` padding. Числовые
поля AWG ограничены UInt16, а `Jmin` не может превышать `Jmax`. `H1`…`H4`
принимают UInt32 либо диапазон `A-B`. Непустые `I1`…`I5` проверяются как цепочки
AWG 2.0 тегов (`b`, `c`, `t`, `r`, `rc`, `rd`, `d`, `ds`, `dz`). Пустые
`I2`…`I5` допустимы и не попадают в JSON.
Неизвестные секции и параметры, повторные scalar keys, hostname/search-domain в
`DNS`, `PostUp`/`Table`/`FwMark`, `IncludedApplications` и
`ExcludedApplications` завершают импорт явной ошибкой: их нельзя молча потерять
или исполнять. Per-app область настраивается только в UI Zapret KVN.
Схема сверена с
[option закреплённого core](https://github.com/shtorm-7/sing-box-extended/blob/ff11f007ec798136a5de258f947a4f34011a37ea/option/wireguard.go),
[примером Amnezia endpoint](https://github.com/shtorm-7/sing-box-extended/blob/ff11f007ec798136a5de258f947a4f34011a37ea/examples/amnezia/client.json)
и [parser AmneziaWG Android `2.0.0`](https://github.com/amnezia-vpn/amneziawg-android/blob/4116c836241f737badb99dcd4e990600d46e4c65/tunnel/src/main/java/org/amnezia/awg/config/Interface.java).
## F-IMPORT-01 — Clash YAML
### Что подтверждено
Pinned source уже содержит общий subscription parser и вызывает парсеры
sing-box, Clash YAML, SIP008 и raw URI именно в таком порядке. Clash parser
читает только верхнеуровневый список `proxies` и преобразует его в sing-box
outbounds. Он не является импортом Clash DNS, rules или proxy groups:
- [общий parser точного commit](https://github.com/shtorm-7/sing-box-extended/blob/ff11f007ec798136a5de258f947a4f34011a37ea/parser/parser.go);
- [Clash parser точного commit](https://github.com/shtorm-7/sing-box-extended/blob/ff11f007ec798136a5de258f947a4f34011a37ea/parser/clash/parser.go).
Реальный сигнал спроса есть, но частичный импорт опасен: отдельно зафиксированы
запрос VLESS XHTTP из Mihomo YAML и случай, когда потеря ECH-параметра делала
импортированный сервер нерабочим:
- [NekoBox: Clash YAML с VLESS XHTTP](https://github.com/qr243vbi/nekobox/issues/228);
- [NekoBox: потеря ECH config при разборе Clash YAML](https://github.com/MatsuriDayo/NekoBoxForAndroid/pull/1173).
При этом собранный из точного commit Android `libbox.aar` не экспортирует
`ParseSubscription` или `ParseClashSubscription`. Повторять parser и его YAML
семантику на Kotlin означало бы добавить второй конвертер, новую зависимость и
риск расхождения с ядром.
### Решение MVP
Clash YAML не поддерживать. Не добавлять Kotlin YAML parser и не угадывать
значение неподдержанных полей. Если вход похож на YAML, показывать явное
сообщение «Clash YAML пока не поддерживается», а не общую ошибку JSON.
Вернуться к реализации можно только если выполнено всё следующее:
1. Parser точного ядра экспортирован через libbox, либо отдельная ADR явно
разрешила ровно один поддерживаемый converter boundary.
2. Собрано минимум 10 обезличенных реальных subscriptions, включая VLESS
XHTTP, ECH, Hysteria2, TUIC, Shadowsocks plugin, YAML anchors/aliases и разные
типы scalar values.
3. Для каждого неподдержанного proxy type или значимого поля импорт завершается
явной ошибкой; silent drop запрещён.
4. Golden-тест сравнивает полученные outbounds, а итог проходит native
`CheckConfig()` и реальное подключение.
5. Clash `rules`, `dns`, `proxy-groups` и `rule-providers` остаются вне импорта.
## F-IMPORT-02 — дополнительные extended URI
[Link parser точного commit](https://github.com/shtorm-7/sing-box-extended/blob/ff11f007ec798136a5de258f947a4f34011a37ea/parser/link/parser.go)
распознаёт `tuic`, `trojan`, `vless`, `hysteria`, `hy2`, `hysteria2`, `ss` и
`vmess`. Из этого списка в приложении пока отсутствует только Hysteria v1
(`hysteria://`). Это кандидат, а не разрешение немедленно добавить протокол.
До нового протокола приоритетнее закрывать подтверждённые реальными ссылками
пробелы уже заявленных форматов: VLESS XHTTP, Shadowsocks plugin, aliases и
дополнительные параметры TUIC/Hysteria2. AnyTLS, SSH, ShadowTLS и другие
outbounds ядра не считаются URI-форматами только потому, что существуют в JSON:
без зафиксированного URI contract их синтаксис не придумывается. WireGuard/AWG
поддерживается отдельно только в нативном INI `.conf`, а не в придуманном URI.
Hysteria v1 можно включить, когда есть минимум три обезличенных реально
неподдержанных URI от пользователей, golden-тесты всех встреченных вариантов,
native `CheckConfig()` и device connection test. Сбор образцов — только после
явного действия пользователя, без аналитики; credentials удаляются до
диагностического экспорта.
SIP008 рассматривается отдельно: pinned core умеет этот JSON subscription
format, но это не extended URI. Его также нельзя объявлять поддержанным без
реальных образцов и доступного libbox binding.
## Таблица решений
| Формат | Статус | Следующий gate |
|---|---|---|
| WireGuard / AmneziaWG 2.0 `.conf` | Реализован как sing-box endpoint | Device connection test с реальным обезличенным WG и AWG 2.0 сервером |
| Clash YAML `proxies` | Отложен, не входит в MVP | libbox binding + 10 реальных образцов + отсутствие silent drop |
| Hysteria v1 URI | Первый кандидат | 3 обезличенных URI + native/device tests |
| Расширения текущих URI | Приоритет по фактическим ошибкам | Реальный образец + golden/native test на каждый вариант |
| SIP008 | Отложен отдельно от URI | Реальные subscriptions + libbox binding |
| Прочие extended outbounds | Не определены как URI | Публичный contract и реальные неподдержанные ссылки |
Checkbox исследовательского пункта означает завершённый аудит, а не наличие
формата в приложении. Реальная поддержка отмечается только отдельной задачей и
после прохождения её gate.