Files
Bridge-and-Join-s/docs/license-server-api.md
T
zuevav 5115ed7223 refactor: сервер лицензий вынесен в репозиторий lic_Bridge-and-Join-s
cmd/bj-license-server, cmd/bj-license и deploy/license перенесены в zuevav/lic_Bridge-and-Join-s
(наша инфраструктура, клиентам не поставляется). Здесь остаются клиентская часть
лицензирования, формат токена internal/license и контракт API в docs.
TestTokenCompat — одинаковый тест формата токена в обоих репозиториях.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 20:07:14 +03:00

5.1 KiB

Сервер лицензирования и обновлений bj — контракт API

Сервер лицензий живёт в отдельном репозитории zuevav/lic_Bridge-and-Join-s (наша инфраструктура, клиентам не поставляется). Здесь — контракт API для клиентской части bj (internal/lkgateway/licenseclient.go). Формат токена общий: internal/license, тест TestTokenCompat одинаков в обоих репозиториях.

Сервер: https://lic.zetit.ru (ВМ 46.173.19.220, Ubuntu 26.04). Адрес зашит в bj (internal/lkgateway, константа), в интерфейсе не меняется. С этого же сервера bj получает обновления.

Модель

  • Лицензия — прежний токен internal/license: подписанный Ed25519 JSON License, строка base64(payload).base64(sig).keyid. Ключ подписи — ~/keys/license.priv (keyid main); открытый ключ зашит в bj.
  • Клиенту выдаётся код активации (BJ-XXXX-XXXX-XXXX), один на лицензию; им активируется до max_nodes установок (0 — без лимита).
  • При активации сервер выдаёт токен на 60 дней (expires_at), но не дольше contract_until; в токене install_id установки и contract_until договора.
  • bj продлевает токен раз в сутки. Отзыв = сервер больше не продлевает; уже выданный токен доживает свой срок (запас на недоступность сервера).
  • Офлайн-ключи (bj-license issue, без install_id) продолжают работать — для закрытых контуров без интернета.

Идентификатор установки

install_id — UUID v4, создаётся bj при первом запуске и хранится в /var/lib/bj/.bj/setup.json (license.install_id). Вместе с ним bj передаёт machine — sha256(/etc/machine-id) в hex (для учёта и обнаружения клонов, не для отказа).

Запросы

Все тела — JSON, Content-Type: application/json. Ошибки — HTTP 4xx/5xx и {"error": "<код>", "message": "<текст по-русски>"}.

POST /v1/activate

{"code": "BJ-7K3M-Q9XP-2HDA", "install_id": "…uuid…", "machine": "…sha256…",
 "hostname": "bj-server-01", "version": "0.1.0"}

200:

{"token": "<payload.sig.main>", "license_id": "…uuid…", "tenant": "ИК Фонтвьель",
 "expires_at": "2026-11-14T10:00:00Z", "contract_until": "2027-09-14T00:00:00Z",
 "renew_after_sec": 86400}

Коды ошибок: bad_request, unknown_code, revoked, contract_expired, max_nodes (лимит установок исчерпан). Повторная активация той же install_id — не новая установка, просто новый токен.

POST /v1/renew

{"token": "<текущий токен>", "install_id": "…", "machine": "…", "hostname": "…", "version": "…"}

Сервер проверяет подпись токена (срок не проверяет — продлить можно и истёкший), совпадение install_id с токеном, что установка известна и лицензия не отозвана. 200 — тот же формат, что у activate. Ошибки: bad_token, install_mismatch, unknown_install, revoked, contract_expired. Каждый успешный renew обновляет last_seen, version, hostname, IP установки.

Обновления

  • GET /v1/{channel}/manifest.json — подписанный манифест (internal/release), без авторизации.
  • GET /v1/{channel}/files/{file} — только с заголовком Authorization: License <token>: подпись верна, срок не истёк, лицензия не отозвана, в признаках есть updates (или план enterprise). Иначе 401/403 с JSON-ошибкой. Ключ подписи манифестов отдельный от лицензионного.

GET /healthz

ok.

Кабинет администратора

https://lic.zetit.ru/admin/ — вход по логину и паролю (bcrypt), только для нас: клиенты (название, ИНН), лицензии (план, признаки, max_nodes, contract_until, код активации, отзыв/восстановление), установки (install_id, hostname, версия, IP, последнее продление, срок токена), журнал событий, выпуск офлайн-ключа для закрытого контура.