Files
DndGamePlayerLicenseServer/README.md
T
Ivan Fontosh 6d4b74d410 Add download stats, key deletion, batch creation, and newest-first listing.
Track landing downloads per platform/month, support admin delete and bulk key issue, and sort licenses by createdAtSec.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 00:21:21 +08:00

77 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.json``data.json`.
2. Сгенерируйте пару Ed25519; **публичный** ключ (SPKI DER base64) вставьте в клиент в `bundledPublicKey.ts`.
```bash
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` и загрузчик по желанию).
```bash
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`.
## Тесты
Из корня репозитория:
```bash
npm test
```
Запускает модульные тесты Node (`node --test`, см. `package.json``test`).
## API
- `POST /v1/activate``{ "productKey": "...", "deviceId": "..." }``{ token, sub }`.
- `GET /v1/status?sub=...``{ revoked: boolean }`.
- `POST /v1/track/download``{ "platform": "windows"|"macos"|"linux" }` → учёт скачиваний в `data.json``downloadStats.byMonth`.
- `POST /v1/admin/revoke``Authorization: Bearer <LICENSE_ADMIN_TOKEN>`, тело `{ "key": "TTRPG-..." }` или `{ "sub": "..." }`.
- `POST /v1/admin/product-keys/delete` — hard delete ключа `{ "key": "..." }`.
- `POST /v1/admin/issue` — админская выдача (`sub`, `pid`, `iat`, `exp`, `did`).
- `GET /v1/admin/licenses` — список ключей (новые сверху), поля `createdAtSec`, `expiryMode`, `validDays`, …
- `GET /v1/admin/stats/downloads` — обзор `{ months, currentMonth }`; `?month=YYYY-MM` — статистика за месяц.
- `POST /v1/admin/product-keys` — создание ключа (`pid`, `maxDevices`, `validDays` или `expiresAtSec`, опционально `count` 1100).
- `GET /health``{ ok: true }`.
## Клиент
`DND_LICENSE_STATUS_URL=http://localhost:3847/` (база URL для сборки пути `v1/status`).