Создание дополнения
Эта страница для разработчиков, которые хотят написать дополнение для 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-addon | check, keygen, sign и verify для манифеста; sign-sums и verify-sums для контрольных сумм выпуска. |
Самое маленькое дополнение:
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))Сделайте шаблон своим
- Измените
slug,name,publisher, области и события вnexora-addon.json, а такжеSLUG,REPOиBINв началеinstall.sh. - Объявите вопросы, нужные вашей установке, в
install.options(Манифест дополнения). - Храните свои данные в своей базе, а панель читайте через токен.
- Поставьте тег выпуска. Процесс выпуска шаблона собирает бинарные файлы, контрольные суммы, выпуск и образ. Затем подпишите контрольные суммы (см. ниже).
Регистрация по коду привязки
Дополнение начинает работу незарегистрированным. Установка передаёт ему одноразовый код привязки в NEXORA_CLAIM_CODE; если запустить его вручную без кода, kit сам создаст код и запишет его в журнал.
- Панель читает манифест по адресу дополнения и проверяет его подпись.
- Она показывает оператору, что запрашивает дополнение: каждую область с её назначением, лимит запросов и каждое событие.
- После одобрения панель создаёт ровно такой токен и вебхук и отправляет их на путь
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:
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, подписанный ключом, которым подписан манифест:
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.sigkeygen печатает ваш открытый ключ и никогда не перезаписывает существующий файл ключа. Не храните закрытый ключ в репозитории. Подпись покрывает все поля манифеста, поэтому подписывайте заново после любого изменения, включая версию каждого выпуска.
Панель устанавливает, обновляет или удаляет дополнение по SSH, только если install.sh выпуска, а при установке как службы — и его бинарный файл, совпадают с SHA256SUMS, подписанным тем же ключом, что и манифест выпуска. Выпуск без SHA256SUMS.sig всё равно можно установить его командой. Подробности — в Манифест дополнения.
Попадание в каталог
Дополнения публикуются на addons.nexora-panel.org как официальные, проверенные или неофициальные (Каталог дополнений). Чтобы попасть в каталог, подпишите манифест своим ключом (nexora-addon keygen, sign) и откройте pull request в каталог. Держите nexora-addon.json в корне своего публичного репозитория (для закрытого дополнения — его публичного репозитория распространения): каталог и мастер установки читают его оттуда.
