Skip to content

Создание дополнения ​

Эта страница для разработчиков, которые хотят написать дополнение для Nexora: отдельную программу, которая работает с панелью по сети, с ограниченным API-токеном, подписанными событиями панели и манифестом, где сказано, что ей нужно. Здесь разобраны части, из которых состоит дополнение, и инструменты, которые пишут большую их часть за вас. Поля манифеста описаны в Манифест дополнения.

Что вы создаёте ​

Дополнение — самостоятельная программа: своя служба или контейнер, свой интерфейс, своя база. Панель никогда не выполняет его код и не хранит его данные. У дополнения четыре части, с которыми работает панель:

ЧастьЧто делает
Манифестnexora-addon.json: кто такое дополнение, что оно запрашивает, как устанавливается. Работающее дополнение отдаёт его по адресу /.well-known/nexora-addon.json.
Путь настройкиКуда панель при регистрации доставляет токен и секрет вебхука вместе с кодом привязки.
Путь вебхукаКуда панель отправляет запрошенные дополнением события, каждое подписанное.
Путь проверки состоянияОтвечает 200, пока дополнение исправно. Панель обращается к нему раз в минуту.

Всё остальное (ваши страницы, ваш API, ваша база) вы проектируете сами. Как панель обращается с дополнением, описано в Платформа дополнений.

Kit и шаблон ​

Большую часть этого за вас пишут два публичных репозитория.

  • Addon kit — модуль Go github.com/nexora-vpn/addon-kit под лицензией Apache-2.0, поэтому построенное на нём дополнение может быть открытым или закрытым. Панель проверяет манифесты тем же кодом.
  • Шаблон, github.com/nexora-vpn/addon-template: полное минимальное дополнение с файлом compose, бинарным выпуском и скриптом установки. Оно регистрируется по коду привязки, получает события, отвечает на проверку состояния и показывает страницу с числом учётных записей панели.
Пакет kitЧто делает
manifestЧитает, проверяет и подписывает манифест.
addonРабочая часть: отдаёт манифест, принимает учётные данные при регистрации, проверяет доставки событий, отвечает на проверку состояния, читает ответы установки.
panelНебольшой клиент API панели с токеном дополнения, ключами идемпотентности и ожиданием при 429.
authСобственный вход администратора дополнения: хешированные пароли, сессии, второй фактор TOTP, ограничение неудачных попыток.
telegramНебольшой клиент Telegram Bot API, через прокси или зеркало Bot API; также Bale.
webОтдаёт админку под базовым путём установки, а публичные страницы — вне его, с HTTPS от панели, через ACME или с самоподписанным сертификатом.
cmd/nexora-addoncheck, keygen, sign и verify для манифеста; sign-sums и verify-sums для контрольных сумм выпуска.

Самое маленькое дополнение:

go
raw, _ := os.ReadFile("nexora-addon.json")
a, err := addon.New(addon.Config{Manifest: raw, DataDir: "data"}.FromEnv())
if err != nil { log.Fatal(err) }
a.OnEvent(func(e addon.Event) { log.Printf("%s %s", e.Event, e.Data) })
mux := http.NewServeMux()
a.Mount(mux) // the manifest, setup, webhook and health paths
log.Fatal(http.ListenAndServe(":8090", mux))

Сделайте шаблон своим ​

  1. Измените slug, name, publisher, области и события в nexora-addon.json, а также SLUG, REPO и BIN в начале install.sh.
  2. Объявите вопросы, нужные вашей установке, в install.options (Манифест дополнения).
  3. Храните свои данные в своей базе, а панель читайте через токен.
  4. Поставьте тег выпуска. Процесс выпуска шаблона собирает бинарные файлы, контрольные суммы, выпуск и образ. Затем подпишите контрольные суммы (см. ниже).

Регистрация по коду привязки ​

Дополнение начинает работу незарегистрированным. Установка передаёт ему одноразовый код привязки в NEXORA_CLAIM_CODE; если запустить его вручную без кода, kit сам создаст код и запишет его в журнал.

  1. Панель читает манифест по адресу дополнения и проверяет его подпись.
  2. Она показывает оператору, что запрашивает дополнение: каждую область с её назначением, лимит запросов и каждое событие.
  3. После одобрения панель создаёт ровно такой токен и вебхук и отправляет их на путь setup дополнения вместе с кодом привязки. Дополнение принимает их только со своим кодом, поэтому неверный код ничего после себя не оставляет.

Kit хранит учётные данные в своём каталоге данных и, когда они приходят, вызывает функцию, заданную через OnSetup. Credentials() возвращает их или nil до регистрации; ClaimCode() возвращает ещё ожидающий код.

По коду привязки панель регистрирует только манифест, подписанный ключом, которому она доверяет: ключом Nexora или ключом разработчика, за который ручается каталог. Во время разработки регистрируйте дополнение вручную (Дополнения → Добавить своё дополнение): вы сами выбираете права токена и события вебхука, а панель один раз показывает токен и секрет подписи вебхука для настроек вашей программы.

Удаление и новая установка ​

Когда оператор удаляет дополнение, панель сначала отправляет ему panel.addon_removed, какие бы события оно ни запрашивало, а затем удаляет его токен и вебхук. Тогда вызовите Forget(), чтобы дополнение можно было зарегистрировать снова.

Новый код привязки поверх данных прежней установки (удалённой с сохранением данных и установленной снова) — это новая установка. Kit отбрасывает старую регистрацию, а NewInstall() сообщает дополнению, что нужно применить ответы, которые иначе используются только один раз, например пароль первого администратора. Когда они сохранены, вызовите NewInstallApplied(). Обновление сохраняет код привязки и никогда не считается новой установкой.

Получение событий ​

Панель отправляет каждое запрошенное дополнением событие на его путь webhook. Доставка несёт X-Nexora-Signature: t=<unix>,v1=<hex>, где hex — HMAC-SHA256 от <t>.<body> с секретом вебхука, и идентификатор X-Nexora-Delivery, одинаковый при каждом повторе.

Kit проверяет подпись и отклоняет доставку, отклонившуюся по времени больше чем на пять минут, передаёт каждое проверенное событие вашему обработчику один раз на идентификатор доставки и отвечает панели:

  • OnEvent — для обработчика, который не может завершиться ошибкой.
  • OnEventErr — для того, который может: ошибка или паника отвечают 500, и панель доставляет событие снова.

Множество уже полученных доставок хранится в памяти, поэтому повтор после перезапуска будет передан обработчику снова. Делайте действия обработчика идемпотентными. Имена событий и их данные — в Каталог событий; как панель их доставляет — в Шина событий.

Каждое событие выдаётся по области: область, которую для него называет каталог событий панели (GET /api/events), или её :write должна быть среди scopes вашего манифеста, иначе панель отклонит манифест.

Вызовы панели ​

Токен действует ровно с выданными вам областями и с лимитом запросов, который запросил манифест (120 в минуту, если не указано иное). Клиент panel из kit говорит с API панели на JSON, отправляет Idempotency-Key, если вы его передали, и один раз ждёт при 429:

go
c := a.Credentials()
client := &panel.Client{Base: c.Panel.URL, Token: c.Token}
var list struct{ Total int `json:"total"` }
err := client.Get(ctx, "/users?limit=1", &list)

Me() — дешёвая проверка того, что учётные данные ещё работают. Маршруты и их тела описаны в описании API панели (Справочник API). Панель ничего вашего не хранит: свои данные, в том числе данные, которые вы держите рядом с пользователями, храните в своей базе.

Проверка состояния ​

Укажите в манифесте путь health, который отвечает 200, пока дополнение может выполнять свою работу. Kit отвечает на него за вас. Панель обращается к нему раз в минуту; две ошибки подряд помечают дополнение Не отвечает и порождают panel.addon_unhealthy, а следующий 200 порождает panel.addon_recovered. Дополнение без пути проверки состояния никогда не опрашивается.

Параметры установки ​

Каждый вопрос в install.options становится полем формы установки в панели и флагом вашего скрипта установки. Ответы приходят в дополнение как переменные окружения NEXORA_OPT_<KEY>, рядом с NEXORA_PANEL_URL и NEXORA_CLAIM_CODE; читайте их через addon.Option("key"). Типы параметров и их правила — в Манифест дополнения.

Два типа меняют то, как панель вас устанавливает:

  • password становится паролем вашего администратора. Форма панели ограничивает его 10 символами и 72 байтами — тем же правилом, что и пакет auth из kit, поэтому пароль, который дополнение отклонило бы, до него не доходит.
  • path — базовый путь, под которым отдаётся ваша админка. Панель предлагает случайный и включает ответ в адрес, по которому вас регистрирует. Отдавайте под ним админку, свой API и маршруты, которые вызывает панель (манифест, setup, вебхук, health), а страницы для клиентов — вне его (web.Mount).

HTTPS и сертификаты от панели ​

Пакет web из kit отдаёт ваш публичный адрес по HTTPS на единственном порту установки, с одним из вариантов:

  • Сертификат от панели: выбранный оператором в хранилище панели. Дополнение забирает его с панели каждые несколько минут (до регистрации — по коду привязки, после — по токену) и хранит копию, поэтому запускается с HTTPS даже при недоступной панели. Ему не нужен свой порт 443, так что несколько дополнений могут делить сервер с панелью.
  • ACME через TLS-ALPN-01 на порту 443 или через HTTP-01 на любом порту, когда удостоверяющий центр обращается на порт 80.
  • Самоподписанный сертификат для адреса по IP. Оператор одобряет его отпечаток на экране одобрения в панели.

Пакет также проверяет, что публичный адрес ведёт именно к этой программе. Как оператор выбирает между вариантами, описано в Каталог дополнений.

Выпуски и подписи ​

Выпуск публикует бинарные файлы, названные в install.binary манифеста, образ из install.docker, SHA256SUMS всех файлов и SHA256SUMS.sig, подписанный ключом, которым подписан манифест:

bash
go install github.com/nexora-vpn/addon-kit/cmd/nexora-addon@latest
nexora-addon check nexora-addon.json                    # would a panel accept it?
nexora-addon keygen -out addon.key                      # once: your signing key
nexora-addon sign -key addon.key nexora-addon.json > signed.json
nexora-addon sign-sums -key addon.key SHA256SUMS > SHA256SUMS.sig
gh release upload v1.2.3 SHA256SUMS.sig

keygen печатает ваш открытый ключ и никогда не перезаписывает существующий файл ключа. Не храните закрытый ключ в репозитории. Подпись покрывает все поля манифеста, поэтому подписывайте заново после любого изменения, включая версию каждого выпуска.

Панель устанавливает, обновляет или удаляет дополнение по SSH, только если install.sh выпуска, а при установке как службы — и его бинарный файл, совпадают с SHA256SUMS, подписанным тем же ключом, что и манифест выпуска. Выпуск без SHA256SUMS.sig всё равно можно установить его командой. Подробности — в Манифест дополнения.

Попадание в каталог ​

Дополнения публикуются на addons.nexora-panel.org как официальные, проверенные или неофициальные (Каталог дополнений). Чтобы попасть в каталог, подпишите манифест своим ключом (nexora-addon keygen, sign) и откройте pull request в каталог. Держите nexora-addon.json в корне своего публичного репозитория (для закрытого дополнения — его публичного репозитория распространения): каталог и мастер установки читают его оттуда.

Текст и изображения — CC BY 4.0.