Skip to content

Манифест дополнения ​

Манифест nexora-addon.json — это договор между дополнением и панелью, каталогом дополнений и формой установки в панели. Он сообщает, кто такое дополнение, что оно запрашивает и как устанавливается. Эта страница перечисляет все поля; как ими пользоваться, объясняет Создание дополнения.

Пакет manifest из addon kit следит за соблюдением этого договора, и панель проверяет манифест тем же кодом. Проверяйте манифест перед публикацией:

bash
nexora-addon check nexora-addon.json

Где он лежит ​

  • В корне публичного репозитория дополнения. Каталог и форма установки читают его там ещё до того, как что-либо запущено. Для закрытого дополнения это его публичный репозиторий распространения.
  • Его отдаёт работающее дополнение по адресу /.well-known/nexora-addon.json; оттуда его читает регистрация.

Полный пример ​

json
{
  "api": 1,
  "slug": "template",
  "name": "Addon template",
  "version": "0.1.0",
  "publisher": "Example Ltd",
  "license": "Apache-2.0",
  "description": { "en": "A minimal addon to start from." },
  "docs": "https://github.com/nexora-vpn/addon-template",
  "install": {
    "docker": { "image": "ghcr.io/nexora-vpn/addon-template", "compose": "deploy/compose.yml" },
    "binary": { "linux-amd64": "addon-template-linux-amd64.tar.gz" },
    "options": [
      { "key": "port", "type": "port", "default": 8090, "label": { "en": "Port" } }
    ]
  },
  "scopes": [
    { "scope": "users:read", "purpose": "to show how many accounts the panel has" }
  ],
  "events": ["user.created", "panel.addon_removed"],
  "webhook": "/nexora/events",
  "setup": "/nexora/setup",
  "health": "/health",
  "ui": "/",
  "rateLimit": 60,
  "signature": "…"
}

Поля ​

ПолеОбязательноЗначение
apiдаВерсия манифеста: 1 (эта страница) или 0 (прежняя версия, в которой не может быть полей, отмеченных ниже как v1).
slugдаИдентификатор дополнения: a-z, 0-9, _ и -, начинается с буквы или цифры, не длиннее 32 символов.
nameдаНе длиннее 64 символов.
versionВыпуск в формате semver. Каталог сравнивает его, чтобы показать доступное обновление.
publisherНе длиннее 64 символов.
scopesодно из scopes или webhook[{"scope": …, "purpose": …}]: права API-токена, каждое с причиной, которая показывается на экране одобрения.
events, webhookвместеСобытия, которые получает дополнение, и путь, на который они отправляются. См. События и области.
setupдаПуть, на который доставляются учётные данные вместе с кодом привязки.
healthПуть, который отвечает 200, когда дополнение исправно. Опрашивается раз в минуту.
uiТочка входа дополнения: путь или абсолютный URL http(s).
descriptionv1По языкам (en, fa, ru, zh); если поле задано, английский обязателен; не длиннее 500 символов каждое.
licensev1Идентификатор SPDX или proprietary, не длиннее 64 символов.
paidv1Дополнение продаётся. Лицензия у него своя; панель ничего не проверяет.
docsv1Абсолютный URL http(s).
requires.panelv1">=X.Y.Z". Панель старше этой версии отклоняет дополнение и объясняет почему.
installv1Как устанавливается дополнение (ниже). Дополнение без этого раздела можно только зарегистрировать по его адресу.
rateLimitv1Сколько запросов в минуту может делать токен, от 1 до 600. Если не задано — значение панели по умолчанию, 120. Показывается на экране одобрения; более новый манифест, который просит больше, ждёт одобрения.
signatureПодпись Ed25519 в base64 (Подпись).

Пути ​

setup, webhook и health — три разных чистых пути, и ни один из них не совпадает с путём самого манифеста. Каждый:

  • начинается с /;
  • не содержит пустых сегментов, . или .. (завершающий / допустим);
  • не содержит ?, #, %, {, }, \ и пробелов.

События и области ​

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

Повторяющийся ключ ​

Манифест, в котором какой-либо объект дважды называет один ключ, отклоняется.

install ​

json
"install": {
  "docker": { "image": "ghcr.io/nexora-vpn/shop", "compose": "deploy/compose.yml" },
  "binary": { "linux-amd64": "shop-linux-amd64.tar.gz", "linux-arm64": "shop-linux-arm64.tar.gz" },
  "options": [ … ]
}

Нужен хотя бы один из docker и binary.

ПолеЗначение
docker.imageПуть в реестре без тега: тегом служит версия выпуска.
docker.composeОтносительный путь к файлу compose в репозитории и в выпуске.
binaryСопоставляет платформе имя файла из выпуска. Скрипт установки дополнения ставит его под systemd (--method script).
optionsВопросы, которые задаёт установка (ниже).

Платформы для binary: linux-amd64, linux-arm64, linux-armv7, linux-armv6, linux-armv5, linux-386, linux-s390x, linux-riscv64.

install.options ​

Вопросы, которые задаёт установка, не больше 32, в порядке показа:

json
{ "key": "database", "type": "choice", "choices": ["sqlite", "postgres"], "default": "sqlite",
  "label": { "en": "Database" } },
{ "key": "database_dsn", "type": "secret", "required": true, "when": { "database": "postgres" },
  "label": { "en": "PostgreSQL DSN" } }
ПолеЗначение
keya-z, 0-9 и _, начинается с буквы, не длиннее 32 символов; уникален.
typeОдин из типов ниже.
labelПо языкам, английский обязателен, не длиннее 80 символов каждое.
helpПо языкам, не длиннее 300 символов каждое.
defaultЗначение JSON того же типа, что и параметр. Никогда не задаётся для secret и password.
requiredБез ответа установка не продолжится.
choicesЗначения для choice, от 1 до 32, каждое не длиннее 64 символов.
when{"<key>": "<value>"}: показывается, только пока тот параметр, объявленный раньше этого и имеющий тип choice или bool, имеет это значение ("true" или "false" для bool).

Типы параметров ​

ТипЧто запрашивает
stringПроизвольный текст.
secretТекст, который панель никогда не хранит; команда, содержащая его, показывается один раз.
passwordsecret, который становится паролем администратора дополнения: не меньше 10 символов и не больше 72 байт. Форма панели отклоняет пароль вне этих границ.
numberЧисло.
portНомер порта.
boolДа или нет.
choiceОдно из choices.
urlАдрес.
pathБазовый путь, под которым дополнение отдаёт свою админку. Не больше одного на манифест (ниже).

Это полный список. Панель, которая старше какого-либо типа, отклоняет манифест с ним ещё до того, как прочитает requires.panel. Всё равно задавайте requires.panel и указывайте в описании выпуска, какая панель нужна вашему дополнению.

Как ответы попадают в дополнение ​

Ответы приходят как переменные окружения NEXORA_OPT_<KEY> — в .env рядом с файлом compose или в EnvironmentFile юнита systemd. Рядом с ними приходят NEXORA_PANEL_URL и NEXORA_CLAIM_CODE — код, который панель выдала для этой установки. bool передаётся как true или false, число — в записи JSON.

Тип path ​

Один сегмент из букв, цифр, - и _ (не длиннее 64), со слешами или без, либо пусто для корня. Форма установки в панели предлагает случайный путь, если у параметра нет default, и включает ответ в адрес, по которому регистрирует дополнение, так же как port. Установка скриптом выбирает путь сама, если команда его не передала.

Дополнение отдаёт под ним свою админку, свой API и маршруты, которые вызывает панель (манифест, setup, вебхук, health), а страницы для своих клиентов — вне его.

Новая установка ​

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

Подпись ​

Манифест ​

  • Официальное дополнение подписывает Nexora.
  • Проверенное дополнение подписано собственным ключом разработчика (nexora-addon keygen, nexora-addon sign), за который ручается подписанный индекс каталога.
  • Дополнение без подписи регистрируется вручную.

Подпись покрывает все поля, кроме signature, перекодированные с отсортированными ключами, поэтому файл можно свободно форматировать и переупорядочивать.

Контрольные суммы выпуска ​

Выпуск публикует SHA256SUMS, который покрывает все файлы (в том числе install.sh и бинарные файлы) в формате sha256sum, и SHA256SUMS.sig — подпись над ним, сделанную после сборки тем же ключом, которым подписан манифест:

bash
nexora-addon sign-sums -key addon.key SHA256SUMS > SHA256SUMS.sig
gh release upload v1.2.3 SHA256SUMS.sig

Это подпись Ed25519 в base64 над строкой nexora-addon SHA256SUMS v1\n, за которой следуют байты файла, поэтому её никогда нельзя выдать за подпись манифеста.

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

Сам манифест не содержит хеша: дополнение встраивает манифест в свой бинарный файл, поэтому хеш бинарного файла не может в нём быть.

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