Files
DndGamePlayerLicenseServer/README.md
T
Ivan Fontosh e299cfc7dd Revoke licenses by product key instead of shared sub.
Add revokedKeys storage and accept key in admin revoke API so DND/TTRPG keys with the same sub can be revoked independently.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 16:44:16 +08:00

3.5 KiB

DndGamePlayerLicenseServer

Сервис лицензирования для DNDGamePlayer: активация по продуктовому ключу, выдача подписанного токена Ed25519, отзыв по sub (клиент опрашивает GET /v1/status, если задан DND_LICENSE_STATUS_URL в Electron main).

Репозиторий клиента: отдельный проект dnd_player — публичный ключ вшит в app/shared/license/bundledPublicKey.ts и должен соответствовать LICENSE_PRIVATE_KEY_PEM здесь.

Переменные окружения

Переменная Описание
LICENSE_PRIVATE_KEY_PEM Приватный ключ Ed25519 в PEM (PKCS#8), обязательно
LICENSE_ADMIN_TOKEN Bearer-токен для /v1/admin/* (по умолчанию change-me-admin)
DND_LICENSE_DATA_PATH Путь к data.json (по умолчанию ./data.json в корне репозитория)
PORT Порт (по умолчанию 3847)

Подготовка

  1. Скопируйте data.example.jsondata.json.
  2. Сгенерируйте пару Ed25519; публичный ключ (SPKI DER base64) вставьте в клиент в bundledPublicKey.ts.
node -e "const c=require('crypto');const kp=c.generateKeyPairSync('ed25519');console.log(kp.privateKey.export({type:'pkcs8',format:'pem'}));"

Демо-ключ (только для разработки)

Публичный ключ по умолчанию в клиенте соответствует этому приватному PEM:

-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIDNxA9U1VSG9zoOvcJ5uB+JUe25UD5m9UwMi6slXzW44
-----END PRIVATE KEY-----

Запуск

На Windows перед запуском задайте переменную окружения LICENSE_PRIVATE_KEY_PEM (многострочное значение в кавычках или через .env и загрузчик по желанию).

npm start

Продакшен

Публичный endpoint: https://license.ttrpgplayer.ru/ (nginx → 127.0.0.1:3847 на VPS).

Проверка: curl https://license.ttrpgplayer.ru/health{"ok":true}.

Код на сервере: /var/www/license_mailib_ru, PM2-процесс dnd-license.

Тесты

Из корня репозитория:

npm test

Запускает модульные тесты Node (node --test, см. package.jsontest).

API

  • POST /v1/activate{ "productKey": "...", "deviceId": "..." }{ token, sub }.
  • GET /v1/status?sub=...{ revoked: boolean }.
  • POST /v1/admin/revokeAuthorization: Bearer <LICENSE_ADMIN_TOKEN>, тело { "key": "TTRPG-..." } (один продуктовый ключ) или { "sub": "..." } (все ключи с этим sub, legacy).
  • POST /v1/admin/issue — админская выдача (sub, pid, iat, exp, did).
  • GET /v1/admin/licenses — список продуктовых ключей с активациями и флагом revoked.
  • POST /v1/admin/product-keys — создание нового продуктового ключа (pid, maxDevices, expiresAtSec, опционально key, sub).
  • GET /health{ ok: true }.

Клиент

DND_LICENSE_STATUS_URL=http://localhost:3847/ (база URL для сборки пути v1/status).