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>
This commit is contained in:
zuevav
2026-09-15 20:07:14 +03:00
parent a6f11d6689
commit 5115ed7223
21 changed files with 62 additions and 4791 deletions
-71
View File
@@ -1,71 +0,0 @@
# Лицензирование Bridge-and-Join-s (#19)
Годовые лицензии с офлайн-проверкой по подписи Ed25519 + опциональный
онлайн-отзыв.
## Компоненты
- `internal/license` — формат лицензии + подпись/проверка (offline).
- `cmd/bj-license` — издательский CLI: keygen, issue, verify.
- `cmd/bj-license-server` — онлайн-реестр отзывов (revocation).
- Интеграция в bj-server: `internal/lkgateway/licensecheck.go` — проверка
лицензии + гейт обновлений; UI раздел «Лицензия».
## Модель
Лицензия — самодостаточный подписанный токен: `payload.signature.keyid`.
bj-server проверяет подпись зашитым публичным ключом и срок **офлайн** —
работает без связи с сервером. Online-сервер нужен только для отзыва.
**Гейт обновлений:** если лицензирование включено (есть публичный ключ),
авто-обновление (#20) выполняется только при валидной лицензии с фичей
`updates`. Без лицензирования (публичный ключ не зашит) — открытый режим,
гейты не действуют (бесплатная редакция / разработка).
## Издателю
```bash
# 1. Ключи лицензий (однократно; приватный — в секрете!)
bj-license keygen -out ./keys/license
# публичный base64 — зашить в bj-server (DefaultLicensePublicKey)
# 2. Выпустить годовую лицензию клиенту
bj-license issue -tenant "ООО Ромашка" -plan pro -days 365 \
-features updates,web-cabinet -key ./keys/license.priv -keyid main
# → выводит ключ payload.signature.keyid — отдать клиенту
# 3. Проверить
bj-license verify -key-file license.key -pub ./keys/license.pub
```
Планы: `free` (без фич), `pro` (перечисленные features), `enterprise`
(всё включено). Фичи: `updates`, `web-cabinet`, …
## Клиенту (on-prem bj-server)
Админ → Настройка → **Лицензия** → вставить ключ → «Активировать».
Проверка офлайн; статус (организация, план, срок, обновления) виден сразу.
## Онлайн-отзыв (опционально)
```bash
bj-license-server --addr :8091 --revoked /var/lib/bj-license/revoked.json
```
`revoked.json` — JSON-массив отозванных license ID:
```json
["28db4973-fde8-434c-b102-e83623eede2c"]
```
`GET /v1/check?id=<id>` → `{"revoked":true|false}`. Перечитывается раз в
минуту. В проде заменить файл на PostgreSQL + admin API выпуска/отзыва.
## Зашивка публичного ключа в релиз
```bash
go build -ldflags "\
-X .../lkgateway.DefaultLicensePublicKey=<base64-pub> \
-X .../lkgateway.DefaultUpdatePublicKey=<base64-pub-артефактории> \
-X .../lkgateway.BuildVersion=1.0.0" -o bj-server ./cmd/bj-server/
```
-11
View File
@@ -1,11 +0,0 @@
[Unit]
Description=Bridge&Join — команды защиты из кабинета сервера лицензий
[Path]
PathChanged=/var/lib/bj-license/fw-control.json
PathChanged=/var/lib/bj-license/allow-ips.txt
PathChanged=/var/lib/bj-license/trusted-ips.txt
Unit=bj-license-fw.service
[Install]
WantedBy=multi-user.target
-7
View File
@@ -1,7 +0,0 @@
[Unit]
Description=Bridge&Join — применение защиты сервера лицензий (белый список, режим обороны, команды fail2ban)
After=fail2ban.service
[Service]
Type=oneshot
ExecStart=/opt/bj-license/bj-license-server fw-apply -dir /var/lib/bj-license
-11
View File
@@ -1,11 +0,0 @@
[Unit]
Description=Bridge&Join — статус защиты сервера лицензий раз в 30 секунд (и восстановление правил после перезагрузки)
[Timer]
OnBootSec=30s
OnUnitActiveSec=30s
AccuracySec=5s
Unit=bj-license-fw.service
[Install]
WantedBy=timers.target
-22
View File
@@ -1,22 +0,0 @@
[Unit]
Description=Bridge&Join — сервер лицензирования (lic.zetit.ru)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=bj-license
Group=bj-license
ExecStart=/opt/bj-license/bj-license-server serve -addr 127.0.0.1:8091 -data /var/lib/bj-license/state.json -key /etc/bj-license/license.priv -keyid main
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/bj-license
ReadOnlyPaths=/etc/bj-license
[Install]
WantedBy=multi-user.target
@@ -1,6 +0,0 @@
# fail2ban: перебор паролей кабинета сервера лицензий bj
# (строки пишет bj-license-server в журнал systemd; IP клиента берётся из X-Real-IP nginx).
[Definition]
failregex = ^.*login failed: user=".*" ip=<HOST>$
ignoreregex =
journalmatch = _SYSTEMD_UNIT=bj-license-server.service
@@ -1,5 +0,0 @@
# fail2ban: перебор кодов активации и токенов API сервера лицензий bj.
[Definition]
failregex = ^.*api denied: (unknown_code|bad_token) ip=<HOST>$
ignoreregex =
journalmatch = _SYSTEMD_UNIT=bj-license-server.service
@@ -1,30 +0,0 @@
# Сервер лицензий lic.zetit.ru: блокировка IP на уровне файрвола.
# Вход в кабинет: не блокируется только белый список администраторов (раздел «Защита»).
[bj-license-admin]
enabled = true
backend = systemd
filter = bj-license-admin
port = http,https
maxretry = 10
findtime = 10m
bantime = 1h
ignorecommand = /opt/bj-license/bj-license-server fw-ignore -dir /var/lib/bj-license <ip> admin
# API активации и продления: не блокируются адреса установок, успешно активировавших или продливших
# лицензию (trusted-ips.txt), и белый список администраторов (allow-ips.txt).
[bj-license-api]
enabled = true
backend = systemd
filter = bj-license-api
port = http,https
maxretry = 10
findtime = 10m
bantime = 1h
ignorecommand = /opt/bj-license/bj-license-server fw-ignore -dir /var/lib/bj-license <ip> api
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1h