-
Notifications
You must be signed in to change notification settings - Fork 4
Operator API Headers ru
Легенда статусов:
- v1 — реализовано сейчас (или запланировано в текущей ветке)
- v2 — следующая волна (расширенное инфо оператора + показ политик)
- v3 — позже (упрощение UI, контролируемое оператором)
- proposed — принято в спеку, ещё не запланировано
Все заголовки матчатся регистронезависимо. Пустые / blank значения = «заголовок отсутствует». Строковые поля могут быть plain UTF-8 или с префиксом base64: (X-Brand-Name: base64:U3dpZnRWUE4=) — клиент декодит оба.
Основная тема ClashFest — тёмная. Где есть «светлая» альтернатива — это опциональный оверрайд.
| Тип | boolean |
| Статус | v1 |
| Требуется для |
Любого косметического брендинга. Без этого заголовка со значением true все X-Brand-* identity/tab/info поля игнорируются, и клиент показывает дефолтный UI ClashFest. Исключение: заголовки политики оператора (§4b, напр. X-Brand-Hide-Global-Mode) применяются без этого переключателя. |
| По умолчанию | отсутствует / false / null → брендинг выключен
|
| Заметки | Брендинг — явный opt-in на каждую подписку. Задать X-Brand-Name, X-Brand-Logo-URL и т.д. без X-Branding-Enabled: true — no-op: заголовки парсятся и персистятся, но UI остаётся дефолтным. Чтобы откатить кривой деплой — уберите этот заголовок (или поставьте false); brand-состояние на клиенте откатывается сразу после следующего обновления подписки. |
Пример включения брендинга:
X-Branding-Enabled: true
X-Brand-Name: SwiftVPN
X-Brand-Logo-URL: https://cdn.example.com/logo-dark.png
X-Brand-Accent-Color: #5E35B1
Пример выключения / kill switch:
X-Branding-Enabled: false
| Тип | string |
| Макс. длина | 32 символа |
| Статус | v1 |
| Применяется к | Заголовку главного экрана (заменяет «ClashFest»); экрану About |
| Фолбэк | «ClashFest» |
| Валидация | trim; control-символы удаляются; blank → игнорируется |
Пример:
X-Brand-Name: SwiftVPN
| Тип | string |
| Макс. длина | 64 символа |
| Статус | v1 |
| Применяется к | Подзаголовку About; опциональному сабтайтлу под именем бренда в хедере |
| Фолбэк | пусто (тэглайн не показан) |
Пример:
X-Brand-Tagline: Fast and private since 2024
| Тип | URL (только https) |
| Статус | v1 |
| Применяется к | Круглой плитке лого в хедере (слева от имени); иконке About |
| Форматы | PNG, WebP, JPEG. Без SVG (см. Security) |
| Рек. размер | 256×256, ≤200KB |
| Жёсткий лимит | 512KB |
| Кэш | диск <filesDir>/brand/<sha256(url)>, атомарная запись |
| Валидация | только https, whitelist content-type, SSRF-guard (нет приватных IP / редиректов на приватные IP), лимит размера |
| Фолбэк | иконка лаунчера |
| Заметки | Это основное лого, по умолчанию. Ожидается корректным на тёмном фоне (тёмная тема — дефолт). |
Пример:
X-Brand-Logo-URL: https://swiftvpn.example.com/static/logo-256.png
| Тип | URL (только https) |
| Статус | v1 |
| Применяется к | То же, что X-Brand-Logo-URL, но для светлой темы |
| Валидация | как у X-Brand-Logo-URL
|
| Фолбэк |
X-Brand-Logo-URL (тёмное лого используется на светлой теме, если оператор не отдал светлый вариант) |
| Заметки | Опционально. Большинству операторов хватает одного лого. |
| Тип | hex-цвет #RRGGBB
|
| Статус | v1 |
| Применяется к | Runtime-оверрайд colorPrimary — power-кнопка, тумблеры, свитчи, прогресс-бары, filled-чипы, selected-состояния, акцентные поверхности по всему приложению |
| Валидация | regex ^#[0-9A-Fa-f]{6}$; отклоняется, если контраст с поверхностью < 3:1 (минимум WCAG AA для крупного текста) |
| Фолбэк | встроенный акцент темы |
| Заметки | Это ручка «полного white-label». Выберите цвет, работающий и в тёмной, и в светлой теме (контраст-фильтр отклонит односторонний). Рек. насыщенность 30–70%. |
Пример:
X-Brand-Accent-Color: #5E35B1
Все URL-поля имеют одну валидацию: должно быть https://, tg://, mailto: или t.me/ (auto-промоут в https://t.me/). Иначе игнорируется.
| Тип | URL · Статус v1 · Применяется к |
| Тип | URL · Статус v1 (расширение существующего support-url) · Применяется к |
Обратная совместимость: также принимает
support-url,Profile-Support-URL,Subscription-Support-URL. При наличии обоихX-Brand-Support-URLвыигрывает.
| Тип | URL (https / tg / t.me) · Статус v1 · Применяется к |
| Тип | URL (https / tg / t.me) · Статус v1 · Применяется к |
| Тип | URL · Статус v1 · Применяется к |
| Тип | URL · Статус v2 · Применяется к |
| Тип | URL |
| Статус | v2 |
| Применяется к | Когда истечение подписки критично (<3 дней или уже истекло): • тап по critical-expiry чипу на карточке профиля • кнопка «Renew» в шторке профиля рядом с инфо об истечении • пункт «Renew subscription» в overflow-меню профиля About тоже получает кнопку Renew, когда URL задан. |
| Заметки | Все точки входа появляются только при наличии URL. Нет URL → нет Renew-UI. |
| Тип | URL (https / tg / mailto) — почти всегда с шаблонной переменной панели |
| Статус | v3 |
| Применяется к | Кнопке «My account» на Operator-табе, tonal-secondary под Renew CTA (или одна, если Renew нет). |
| Заметки | Оператор строит пер-юзер URL через шаблонный идентификатор панели — {{SHORT_UUID}}, {{ID}}, {{USERNAME}}. Примеры:• Telegram Mini App: https://t.me/<bot>?startapp={{SHORT_UUID}}• Web-кабинет: https://billing.example.com/account?ref={{ID}}• Bot со start-payload: https://t.me/<bot>?start={{SHORT_UUID}}Клиент открывает через ACTION_VIEW — Android роутит tg:// / https://t.me/... в Telegram, прочие https:// в браузер. |
Клиент использует только одно поле для юзер-facing идентичности. Пер-юзер персонализация живёт в profile-title — оператор кладёт туда что угодно. Свободная форма, контролируется панелью.
| Тип | string · Статус v1 · Применяется к |
| Тип | string · Макс. 64 · Статус v2 · Применяется к |
| Заметки | Заполняется шаблонной переменной, напр. X-Brand-User-Display-Name: {{USERNAME}}. См. Шаблонные переменные. |
| Тип | string · Макс. 120 · Статус v2 · Применяется к |
| Заметки | Свободная форма, обычно через шаблоны панели: X-Brand-Greeting: Welcome back, {{USERNAME}}! {{DAYS_LEFT}} days remaining. Если отсутствует, но задан X-Brand-User-Display-Name — фолбэк на встроенное «Hello, !».
|
| Тип | boolean · Статус v1 |
| Применяется к | Добавляет отдельный таб «Operator» в нижнюю навигацию с лого + именем + тэглайном + Renew CTA + списком инфо-ссылок. |
| Заметки | Явный opt-in. Одни identity-заголовки (name / logo / accent) НЕ добавляют таб автоматически. Свяжите с X-Brand-Hide-Routing, чтобы заменить Routing, а не добавлять 5-й таб. |
| Тип | boolean · Статус v1 |
| Применяется к | В паре с X-Brand-Show-Operator-Tab=true Operator-таб заменяет Routing в нижней навигации (по-прежнему 4 таба). В одиночку — no-op. |
Всё выше — косметический брендинг и требует X-Branding-Enabled: true. Заголовки ниже — политика оператора (ограничения поведения, не внешний вид) — применяются по одному наличию, не требуют включённого брендинга и переживают kill-switch X-Branding-Enabled: false (он стирает только косметику).
| Тип | boolean · Статус v4 |
Нужен X-Branding-Enabled? |
Нет — единственный заголовок, работающий полностью unbranded. |
| Применяется к | Скрывает кнопку Global на Главной и пинит приложение в Rule (если юзер был в Global — вернёт в Rule). Строка «Mode» и кнопка Rule остаются. |
| Заметки | Контроль оператора, не брендинг: не даёт юзерам пускать весь трафик через прокси в обход правил. Работает при X-Branding-Enabled absent / true / false. |
| Формат |
upload=N; download=N; total=N; expire=UNIX · Статус v1 · Применяется к |
| Тип | integer (часы) · Статус v1 · Применяется к |
| Тип | boolean (true/1/yes/on = отключить шаринг) · Статус v1
|
| Применяется к | Скрывает «Copy node link» / «Share» в пикере И блокирует редактирование URL подписки только для этой подписки |
| Заметки | Хранится пер-профиль. Разные подписки могут иметь разную политику шаринга. |
| Тип | enum: system | gvisor | mixed | auto · Статус v1
|
Нужен X-Branding-Enabled? |
Нет — это политика оператора, работает без брендинга. |
| Применяется к | TUN-стек, передаваемый в VpnService. system/gvisor/mixed лочат стек для этой подписки, перебивая ручную настройку «Режим стека» у пользователя. auto = оператор не лочит (отдаёт настройке пользователя / дефолту system). |
| По умолчанию | Хедер отсутствует → дефолт клиента (system). |
| Заметки | Хранится пер-профиль (subscriptionNetworkStackFor(uuid)), как share-links — разные подписки могут форсить разный стек на одном устройстве. Приоритет: хедер оператора > ручная настройка > Auto (тянет tun.stack из подписки) > дефолт system. Дефолт приложения — system; пользователь может выбрать auto, чтобы следовать tun.stack подписки, а этот хедер перебивает и то, и другое. Рекомендуется system — kernel-стек быстрее на teardown и легче по батарее, чем userspace-нетстек gVisor; gvisor/mixed — только если реально нужно устройству/сети. Написания (регистронезависимо): X-Network-Stack, Network-Stack, X-NetworkStack, X-NetworkStack-enabled. |
Пример (залочить всех пользователей этой подписки на kernel-стек):
X-Network-Stack: system
| Тип | boolean · Статус v1 · Применяется к |
| Тип | string (UTF-8 или base64:) · Макс. 256 · Статус v1 · Применяется к |
| Тип | URL · Статус v1 · Применяется к |
-
X-Brand-Default-Mode— mihomo уже читаетmode:из YAML. -
X-Brand-Recommended-Group— Selector по дефолту берёт первый прокси из списка; оператор рулит через YAML. -
X-Brand-Locale/X-Brand-Theme— это пользовательские настройки; тихий оверрайд оператором — hostile UX. -
X-Brand-Max-Devices/X-Brand-Current-Devices— без текущего счётчика чип читается как филлер; текущий счёт ненадёжен через response-заголовки.
Если будущий кейс реально потребует одного из них — сначала добавим под proposed и обсудим.
📱 User Guide
- Getting Started
- Profiles & Nodes
- Routing & Rules
- Settings
- Deep Links
- Encrypted Subscriptions
- Troubleshooting
🏢 Operator API
📺 Companion