Vlasnik izlazi iz DAL price za ovaj projekat - postaje samostalan proizvod. Preimenovanje je mehanicko (import putanje, imena fajlova/baze/UI naslova), NIJEDNA linija poslovne logike u internal/handler ili internal/service nije dirana - go build, go vet i go test ./... prolaze cisto pod novim imenom. - go.mod: module dal-license-server -> licence-server; 28 import linija u 13 .go fajlova usaglaseno - internal/config/config.go (+test): default DB_NAME licence_db - HTML sabloni (7 stranica) + 7 Playwright e2e spec fajlova: "DAL License Server" -> "Licence Server" u title/nav-brand, testovi usaglaseni u istom prolazu (nista ne moze da se razdvoji) - package.json/package-lock.json/.gitignore/.claude/project.json: ime projekta/binarnog fajla/work_dir - Usput: package.json je u repository.url nosio OTVORENU Gitea lozinku u cistom tekstu - uklonjena (URL sad bez kredencijala). Lozinka je i dalje u staroj git istoriji - preporuka: rotirati je posebno. - CLAUDE.md/README/API/TESTING/docs/SPEC/ARCHITECTURE/SETUP: naslovi, ASCII dijagrami, git clone URL, mysqldump primer, systemd predlozak u SETUP.md zamenjen stvarnim (obrazac terminia.service - journal log + graceful shutdown, ne stari minimalni predlozak) - Debrendiranje: "Univerzalni licencni server za sve DAL proizvode" -> "za vise proizvoda i klijenata"; potpis "Nenad Djukic / DAL d.o.o." -> "Nenad Djukic". NE dirano: nazivi ESIR/ARV/LIGHT_TICKET (tudji proizvodi, ne DAL brend), "DAL" kao stvaran naziv org-a u RBAC modelu (docs/loggerservice/README.md) - to je podatak, ne branding ovog servera. - docs/asp-terminia/, docs/loggerservice/: prozni pomeni imena servera Baza (dal_license_db -> licence_db) i deploy na 151 idu u posebnom koraku, posle preimenovanja Gitea repoa - vidi CLAUDE.md istorijsku belesku na dnu. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
98 lines
5.0 KiB
Markdown
98 lines
5.0 KiB
Markdown
# Postojeće stanje (provereno na serveru 2026-07-24, read-only)
|
||
|
||
## 1. Server 151 — pristup i raspored
|
||
|
||
- **SSH:** `ssh root@157.180.119.151` (host se javlja kao `MCLaud`, Ubuntu; ključ
|
||
`~/.ssh/id_ed25519` sa razvojne mašine; samo root). Hetzner, van LAN-a.
|
||
- Na ISTOM serveru žive i drugi sistemi — **ne dirati**:
|
||
- `terminia` SaaS platforma za klubove (portovi 8091/8092) — IME SLIČNO, ali
|
||
NIJE naš proizvod;
|
||
- Gitea;
|
||
- ESIR backend (fiskalizacija).
|
||
|
||
## 2. `licence-server` (naš deo)
|
||
|
||
- **Kod:** `/root/projects/licence-server` — Go, bez frameworka, MySQL.
|
||
- **Port:** 8090 lokalno; javno preko nginx sajta **`arv`**.
|
||
- **Javni URL (ovo firmware već koristi):** `https://157.180.119.151/license/api/v1/`
|
||
- HTTPS 443, cert `/etc/nginx/ssl/arv.crt`, `server_name` = IP → **self-signed**
|
||
(zato firmware koristi `setInsecure()`; odluku štiti RSA potpis odgovora).
|
||
- Na portu 80 je izložen samo validator API; ostalo redirect na 443.
|
||
- **Produkcioni obim:** 3 proizvoda (ESIR, ARV, LIGHT_TICKET — seed u
|
||
`migrations/002_seed_products.sql`), ~140 licenci, ~19 aktivacija. **ŽIVO.**
|
||
|
||
### Kripto
|
||
|
||
- **RSA-2048**, potpis **RSA-SHA256**.
|
||
- Privatni ključ: na serveru (`crypto/` + `.env` konfiguracija) — **NE čitati, NE
|
||
kopirati, NE logovati.**
|
||
- Javni ključ: `crypto/public.pem` — VEĆ ugrađen u firmware (`licenca.cpp`,
|
||
`LIC_PUBKEY`). Ako se ključ ikad rotira, MORA i novi firmware — to je krupna
|
||
odluka, ne radi se usput.
|
||
- Potpis stiže kao string: `"signature": "RSA-SHA256:<base64>"` uz `license` objekat.
|
||
**Potpisuje se serijalizacija license objekta kakvu server pošalje** — klijent
|
||
verifikuje SIROVE bajtove (ne re-serijalizuje). Svaka izmena serijalizacije na
|
||
serveru lomi sve klijente u polju.
|
||
|
||
### Klijentski API (bez autentikacije, rate-limited)
|
||
|
||
| Ruta | Telo zahteva | Odgovor |
|
||
|---|---|---|
|
||
| `POST /api/v1/activate` | `{license_key, machine_fingerprint, app_version, os, hostname}` | `{license:{... expires_at, grace_days, limits, features, customer ...}, signature}` |
|
||
| `POST /api/v1/validate` | `{license_key, machine_fingerprint}` | `{valid, expires_at, revoked}` |
|
||
| `POST /api/v1/deactivate` | (transfer/oslobađanje) | — |
|
||
|
||
Greške (JSON `error` polje): `INVALID_KEY`, `ALREADY_ACTIVATED`, `KEY_EXPIRED`,
|
||
`KEY_REVOKED`, `PRODUCT_MISMATCH`.
|
||
|
||
### Admin API
|
||
|
||
- Header `X-API-Key` (ključ u `.env` — od vlasnika se traži ključ ili da on sam
|
||
klikne u dashboardu; agent NE vadi ključ iz `.env` bez izričite dozvole).
|
||
- Kreira proizvode i licence. Postoji i htmx admin dashboard.
|
||
|
||
## 3. Firmware klijent — GOTOV (od FW 0.10.0)
|
||
|
||
Fajlovi u firmware repou (`firmware/10_terminia/`):
|
||
|
||
| Šta | Gde |
|
||
|---|---|
|
||
| Modul | `licenca.h` / `licenca.cpp` |
|
||
| Ugrađen javni ključ | `licenca.cpp` → `LIC_PUBKEY` (PEM) |
|
||
| NVS | namespace `lic`: `raw` (sirovi license JSON) + `sig`; ključ/URL u configu: `licKey`, `licUrl` (podrazumevano `https://157.180.119.151/license/api/v1`) |
|
||
| Web API (SPA) | `/api/license` (status), `/api/license-save` (ključ/URL), `/api/license-activate`, `/api/license-check` — sve samo admin |
|
||
| UI | SPA → Podešavanja → Uređaj → kartica „Licenca" (status, izdanje, korisnik, važi do, otisak uređaja, unos ključa, Aktiviraj, Proveri na serveru) |
|
||
|
||
### Kako klijent radi (bitno za server stranu)
|
||
|
||
1. **Otisak:** `machine_fingerprint = "sha256:" + sha256hex(MAC)` gde je MAC oblika
|
||
`AA:BB:CC:DD:EE:FF` (velika slova, dvotačke). ⚠️ **PRETPOSTAVKA** — proveriti u
|
||
Go kodu servera kako računa fingerprint za poređenje; ako se razlikuje, uskladiti
|
||
NA SERVERU dokumentaciju/verifikaciju za ASP proizvod ILI javiti pa menjamo FW
|
||
(zadatak Z2).
|
||
2. **Aktivacija:** POST `/activate`; iz odgovora isecₐ SIROVE bajtove `license`
|
||
objekta (brojanje zagrada, string-safe), verifikuje `signature` RSA‑SHA256
|
||
javnim ključem, čuva sirovo+potpis u NVS.
|
||
3. **Svaki start (offline):** ponovo verifikuje potpis iz NVS + poredi
|
||
`machine_fingerprint` iz licence sa svojim + proverava `expires_at`
|
||
(poređenje po datumu `YYYY-MM-DD`; prazno = trajna; nepouzdan sat → grejs,
|
||
nikad pad).
|
||
4. **Statusi na uređaju:** `nema / vazi / grejs / los-potpis / drugi-uredjaj / istekla`.
|
||
5. **ENFORCEMENT NE POSTOJI** — uređaj samo prikazuje status. Gašenje funkcija bez
|
||
licence je odluka vlasnika (zadatak Z4).
|
||
|
||
### Polja koja klijent čita iz `license` objekta
|
||
|
||
`edition`, `customer` (ili `customer_name`), `expires_at`, `license_id` (ili `key`),
|
||
`grace_days`, `machine_fingerprint`. Nepoznata dodatna polja ne smetaju (parsira se
|
||
ciljano). `limits`/`features` se JOŠ ne čitaju — planirano uz enforcement.
|
||
|
||
## 4. Šta NE postoji (i pripada zadacima)
|
||
|
||
- Proizvod **„ASP-Terminia"** na serveru — ne postoji (zadatak Z1).
|
||
- Nijedan ASP ključ — ne postoji (Z1/Z2).
|
||
- Domen `licenca.terminia.net` + Let's Encrypt — ne postoji (Z3; domen kupuje vlasnik).
|
||
- Enforcement na uređaju + `features`/`limits` semantika za ASP (Z4/Z5).
|
||
- FW potpisivanje `.bin` + katalog firmvera (Z6; preduslov za auto-OTA, vidi i
|
||
ASP repo: `serviseri/03-provisioning-i-fw-katalog.md`).
|