internal/commerce, потому что
клиенту, которому в чате велят поставить одно приложение, а в браузере — другое,
вручили два продукта.
Ссылка на подписку
Что это. URL, выпущенный и принадлежащий Remnawave, для одной подписки. Клиентское приложение запрашивает его, получает конфигурацию, которую даёт эта подписка, и подключается. Почему Omniflow не хранит копию. Ссылка — это учётные данные, а самый дешёвый способ гарантировать, что учётные данные никогда не попадут в резервную копию, строку лога или отчёт о сбое, — никогда их не держать. Omniflow читает ссылку из Remnawave в тот момент, когда клиент её запрашивает, и передаёт прямо на экран. Последствия видны по всему продукту:GET /v1/account/overview— payload дашборда — намеренно не несёт URL подписки. Ответ дашборда, всегда несущий его, поместил бы ссылку в каждый кэш, лог и запись истории браузера, которые касаются страницы.- Каждый ответ
/v1/accountотправляется сCache-Control: no-store,Referrer-Policy: no-referrerиContent-Security-Policyсо значениемdefault-src 'none'. Комментарий у этого промежуточного обработчика называет причину: клиентский ответ может содержать ссылку на подписку. - Выгрузка персональных данных объявляет
subscription_linksсреди своих постоянных изъятий, а не включает их. См. Приватность и ваши данные. - Собственный журнал безопасности клиента записывает смену ссылки по подписи подписки и ничего более: помещение ссылки в журнал свело бы на нет ту самую смену, которую он записывает.
409 not_provisioned и показывает «Ещё настраивается» вместо пустого
поля. Что происходит в это время, описано в Выдаче доступа.
Как перенести ссылку на устройство
Из веб-панели
1
Откройте подписку
На
/account нажмите Подключить на карточке подписки. Это ведёт на
/account/subscriptions/{id}/connect. Экран также принимает параметр запроса
?platform=, поэтому ссылка на него может заранее выбрать платформу.2
Выберите платформу
Выбор предлагает iOS, Android, Windows, macOS и Linux в этом фиксированном
порядке. Неизвестная или пустая платформа приводит к первой из них, а не к
ошибке.
3
Пройдите три шага
Установите первое рекомендованное приложение для этой платформы; нажмите
кнопку, которая добавляет подписку; если ничего не открылось, скопируйте
ссылку и вставьте её в приложение. Шаги называют конкретное приложение, а не
«ваше VPN-приложение», потому что клиенту придётся найти его в магазине.
4
Передайте ссылку
Нажмите кнопку Открыть в … для установленного вами приложения, наведите
камеру второго устройства на QR-код или нажмите Копировать и вставьте
ссылку вручную. Все три способа несут одну и ту же строку.
Из бота Telegram
На экране подписки есть кнопка Подключить. Она открывает тот же выбор платформы, и каждая платформа показывает те же пронумерованные шаги, называющие то же первое рекомендованное приложение. Разница — в кнопках. Встроенные кнопки Telegram принимают только URL со схемамиhttp, https и tg, поэтому deep-ссылка приложения вроде happ://add/… вообще
не может быть кнопкой-ссылкой. Поэтому бот отрисовывает по одной кнопке
копирования текста на каждое приложение, плюс кнопку копирования самой ссылки,
плюс кнопку-ссылку «Открыть подписку» для https-URL подписки. Копирование —
документированный запасной вариант везде, в том числе в десктопном браузере, где
для схемы не зарегистрирован обработчик.
Каждый экран бота отправляется как защищённое содержимое, поэтому Telegram не
позволит переслать сообщение со ссылкой на подписку. Полный путь в Telegram описан
на странице бота Telegram.
Клиентские приложения, которые документирует Omniflow
Каталог хранится в базе, а не вкомпилирован, и обе поверхности читают одни и те же строки — поэтому бот и браузер не могут рекомендовать разные приложения. Редактируется он по адресу/admin/settings/connect. Порядок — это
порядок рекомендации: первая запись — то приложение, которое называют шаги
настройки.
Новая установка засевается ровно тем, что прежние версии носили в бинарнике:
Deep-ссылка — это схема с приписанным к ней URL подписки, и ничего больше:
happ://add/https://panel.example.com/sub/…. Никакого сервиса редиректов между
ними нет, поэтому приложение, поддерживающее свою схему, импортирует подписку так,
что ни одна часть Omniflow не наблюдает этого события.
Оператор может также указать адрес загрузки приложения и написать собственные
инструкции по установке — для каждой платформы и каждого языка. Инструкции
заменяют общие три шага, а не добавляются к ним: тот, кто описал собственную
настройку, знает что-то, чего не знает общий текст, а показ обоих оставил бы
клиента выбирать между двумя рассказами об одном и том же.
Засеянный список намеренно короткий. Это приложения, которые установка
документирует и поддерживает, а не все приложения, способные прочитать ссылку на
подписку: клиент, использующий что-то другое, всё равно может вставить ссылку
туда, но шаги на экране не будут описывать его приложение.
Три способа, которыми путешествует ссылка
Deep-ссылки
В браузере каждое приложение — это обычный якорь, а не переход роутера, потому что deep-ссылка уводит со страницы в приложение. На устройстве с установленным приложением нажатие открывает его с уже заполненной подпиской. На устройстве без него браузер сообщает, что не может открыть адрес, — вот почему третий шаг говорит клиенту скопировать ссылку и почему бот предлагает deep-ссылку как копируемый текст.QR-код
QR генерируется в браузере. Кодировщик импортируется лениво, чтобы не попадать в бандл всех остальных экранов, а результат отрисовывается из data URL в обычном элементе<img>.
Стоит сказать, почему это не изображение, отрисованное сервером: URL изображения,
несущий ссылку на подписку, поместил бы эти учётные данные в строку запроса, лог
прокси и кэш браузера, а прогон через конвейер изображений Next.js отправил бы
несущий учётные данные payload на сервер для кэширования. Если кодировщик даёт
сбой, блок с QR не отрисовывается вовсе, а не показывается сломанным.
Наведите камеру другого устройства на код, и оно получит ту же строку, которую
несла бы deep-ссылка.
Копирование вручную
Ссылка показывается усечённой в моноширинной строке с кнопкой Копировать. Она усечена, потому что это учётные данные, и у клиента нет причин её читать — только перенести. Кнопка около двух секунд показывает «Скопировано» и возвращается в исходное состояние. Браузер, отказывающий в доступе к буферу обмена, — реальный случай: так бывает на небезопасных источниках и в некоторых встроенных браузерах, — поэтому неудавшееся копирование поднимает всплывающее уведомление с просьбой выделить и скопировать ссылку вручную, вместо того чтобы ничего не сделать и выглядеть сломанной кнопкой.Когда экран подключения не показывает ссылку
В боте подписка, у которой ещё нет ссылки, показывает вместо кнопок строку «Ссылка
на подписку появится, как только доступ станет активен».
API.
GET /v1/account/subscriptions/{subscriptionID}/connection?platform=
возвращает {subscriptionUrl, platform, platforms[], clients[{name, deepLink}]}.
Подключённые устройства
Что это. Устройства, сейчас привязанные к пользователю Remnawave одной подписки, со счётчиком относительно лимита устройств тарифа, элементом управления удалением для каждого устройства и элементом удаления всех. Зачем это нужно. Лимит устройств выполним, только если клиент может сам освободить слот. Без списка устройств достижение лимита означает открытие обращения в поддержку, чтобы отключить телефон, заменённый год назад. Как туда попасть. Устройств нет на панели вкладок: замена телефона — действие раз в год, а пять вкладок упорядочены по частоте потребности. Откройте/account/profile и перейдите в Устройства либо попадите на
/account/devices напрямую. Устройства принадлежат подписке, а не аккаунту,
поэтому, когда у клиента их больше одной, экран показывает над списком кнопки для
переключения между ними.
Каждая строка показывает иконку, выбранную по платформе, о которой сообщило
приложение (ноутбук для mac, Windows или Linux, планшет для планшета, иначе
телефон), модель устройства, о которой приложение сообщило само, — или «Неизвестное
устройство», если оно не сообщило ничего, — и дату. Под списком: «Одна ссылка
работает на всех устройствах. Отключение освобождает слот сразу».
Что намеренно не показывается
Ни на этом экране, ни в стоящем за ним ответе нет ни аппаратного идентификатора, ни IP-адреса. Это решение, а не упущение:- HWID никогда не покидает сервер. Он идентифицирует чью-то физическую машину.
Устройство называется клиенту дескриптором —
base64urlпервых 16 байтSHA-256("omniflow.device." + hwid), 128 бит, — который не раскрывает ничего об устройстве, за которое он стоит. - Дескриптор разрешается повторным хэшированием, а не сохранённым сопоставлением. Когда приходит запрос на удаление, сервер запрашивает текущий список устройств, хэширует каждый HWID, который держит, и сопоставляет. Поэтому вызывающий никогда не передаёт идентификатор, над которым выполняется действие. Индекс в массиве не подошёл бы: список может измениться между чтением и удалением, поэтому к моменту использования индекс может указывать на другое устройство.
- Последняя активность — это дата, а не момент. Достаточно, чтобы клиент узнал свой ноутбук, и недостаточно, чтобы построить журнал перемещений.
- IP-адрес не возвращается вообще, в том числе для домашней сети или
соединения, которым пользуется кто-то ещё. Выгрузка персональных данных объявляет
device_and_network_identifiersпостоянным изъятием по той же причине.
404 not_found — ровно так
же выглядит и устройство, удалённое из другой вкладки мгновение назад.
Удаление устройств
1
Удалите одно устройство
Нажмите Отключить на его строке. Диалог подтверждения объясняет, что
устройство перестанет подключаться, пока подписка не будет добавлена снова. При
успехе всплывающее уведомление подтверждает это, и список перезагружается. Слот
освобождается сразу.
2
Удалите все устройства
Когда в списке больше одного устройства, появляется кнопка во всю ширину
Отключить все устройства с собственным диалогом. Это один вызов Remnawave, а
не цикл, потому что поустройственное отключение оставило бы частично отключённую
подписку, если бы третий вызов провалился.
401 reauthentication_required, и панель
показывает «Войдите снова, чтобы подтвердить это действие», а не сырой отказ:
средство исправления доступно самому клиенту. Удаление одного устройства такого
требования не имеет: оно стоит одному устройству переподключения, а не всей
настройки.
Удаление всех без
?confirm=true отклоняется с 422 confirmation_required. При
нуле подключённых устройств оно возвращает {"removed": 0}, вовсе не обращаясь к
Remnawave.
Оба вида удаления пишутся в собственный журнал безопасности клиента —
device_removed с подписью подписки и сообщённым именем устройства,
devices_removed_all с подписью и числом удалённых. Ни то, ни другое не записывает
аппаратный идентификатор, а сам журнал доступен клиенту для чтения на
/account/security.
Оператор также может перечислить и удалить устройства из профиля клиента в
админ-панели под правами
subscriptions.read и subscriptions.write. Этот путь
пишет событие аудита с собственной ссылкой на устройство, но никогда с HWID. См.
Операции администратора.Смена ссылки на подписку
Что это. Отзыв текущей ссылки доступа и чтение новой обратно из Remnawave. Зачем это нужно. Это единственное средство исправления, когда ссылку передали или она утекла. Это же и самое разрушительное, что клиент может сделать со своей работающей настройкой: каждое устройство перестаёт подключаться, пока не будет импортирована новая ссылка. Обе половины этой фразы объясняют, зачем этот элемент управления существует и почему он защищён именно так. Как этим пользоваться. Откройте/account/subscriptions/{id} и прокрутите до
раздела Ссылка доступа. Карточка с предупреждением точно указывает, что
сломается. Нажмите Выпустить новую ссылку; диалог требует, чтобы клиент ввёл
фразу NEW LINK и вдобавок нажал подтверждение. При успехе всплывающее уведомление
подтверждает это, а подсказка отсылает обратно к экрану подключения, чтобы добавить
новую ссылку на каждое устройство.
В Telegram то же действие находится на экране подписки за клавиатурой
подтверждения/отмены, и его выполнение возвращает экран подключения с уже свежей
ссылкой.
API. POST /v1/account/subscriptions/{subscriptionID}/rotate-link, тело
{"confirm": true}, за требованием недавнего входа. Отвечает
{"subscriptionUrl": "…"}.
Новая ссылка читается обратно из Remnawave, а не предполагается: её выпускает
Remnawave, и показать клиенту старую после смены было бы хуже, чем не показать
никакой. В журнал безопасности клиента пишется запись
subscription_key_rotated,
называющая только подпись подписки.
Смежные страницы
Веб-панель клиента
Остальная часть браузерного продукта: дашборд, оформление заказа, кошелёк,
поддержка.
Бот Telegram
Тот же путь подключения в чате, с кнопками копирования текста.
Подписки
Права на услуги, лимиты устройств, окончание срока и что означает фаза.
Интеграция с Remnawave
Какая панель владеет ссылкой, устройствами и счётчиками трафика.