/api/license/verify
Panelin dışarıya açtığı tek endpoint. Yapıştırılan bir Adisyon lisansının gerçek olup olmadığına sunucuda karar verir ve ekrana gösterilecek cümleleri döner.
Kaynak: app/api/license/verify/route.ts, lib/license/ altındaki saf
modülleri kullanır.
Neden sunucuda
Bir lisansın gerçek olup olmadığına karar veren yer, cevabı gösteren yer olmamalı. Açık anahtar, Ed25519 imza kontrolü ve gün aritmetiği sunucuda kalır; Lisans ekranı yalnızca sonucu alır.
Panel lisans üretmez ve üretememelidir. lib/ altında hiçbir yerde sign
yoktur; imzalama yalnızca testlerde, her koşuda üretilen anahtarlarla yapılır.
Private key tek bir makinede durur (SCRUM-229).
GET /api/license/verify
Sunucunun hangi anahtarı kullandığını söyler. Ekran, geliştirme anahtarıyla çalışıldığında uyarı şeridi göstermek için bunu okur.
{ "key": { "kind": "development", "fingerprint": "3f9a2b71" } }| Alan | Değer |
|---|---|
kind | development · production · invalid |
fingerprint | Anahtarın SHA-256’sının ilk 8 hex hanesi; invalid ise yok |
POST /api/license/verify
İstek gövdesi:
{ "token": "ADSN1.<base64url(payload)>.<base64url(signature)>" }token bir dize olmalı, boş olmamalı ve 4096 karakteri aşmamalıdır (yerel
veritabanındaki license_state.token kısıtıyla aynı sınır).
Başarılı yanıt — 200
{
"ok": true,
"view": { "licensee": "...", "machine": "XXXX-XXXX-...", "lastDay": "17 Ekim 2026", "daysLeft": 17, "...": "..." },
"key": { "kind": "development", "fingerprint": "3f9a2b71" }
}view, lib/license/evaluate.ts içindeki describe() çıktısıdır: lisans
sahibi, gruplanmış makine kodu, son geçerli gün ve kalan gün sayısı.
Reddedilen lisans — 200, ok: false
Lisans okundu ama kabul edilmedi. HTTP durumu yine 200’dür: istek geçerliydi,
cevap olumsuz.
reason | Anlamı |
|---|---|
malformed | Metin ADSN1.<payload>.<signature> biçiminde değil |
badSignature | Biçim doğru, ama bu anahtarla üretilmemiş ya da metin bozulmuş |
badPayload | İmza geçerli, ama içerik biçimin izin vermediği bir şey söylüyor (detail alanı nedeni verir) |
Her yanıt Türkçe bir message taşır.
Hatalar
| Durum | reason | Ne zaman |
|---|---|---|
400 | badRequest | Gövde JSON değil, token yok, boş ya da 4096 karakterden uzun |
503 | keyInvalid | Sunucudaki ADISYON_LICENSE_PUBLIC_KEY geçerli bir açık anahtar değil |
503, bilinçli bir davranıştır: bozuk bir anahtar değeri geliştirme
anahtarına düşmez. Düşseydi bir geliştirme lisansı üretim panelinde gerçek
gibi görünürdü.
Yapılandırma
| Değişken | Zorunlu | Anlamı |
|---|---|---|
ADISYON_LICENSE_PUBLIC_KEY | Hayır | base64, 32 bayt açık anahtar. Boş bırakılırsa ekibin geliştirme anahtarı kullanılır — backend’in derlemeye gömdüğü varsayılanla aynıdır. Bozuk bir değer doğrulamayı kapatır (503). |
Lisans biçimi
ADSN1.<base64url(payload JSON)>.<base64url(signature)>İmza, ADSN1.<base64url(payload)> ASCII baytlarını kapsar — yani sürüm öneki de
imzalıdır. base64url dolgusuzdur (RFC 4648 §5).
Payload alanları: v, id (UUID), licensee (en çok 120 karakter), machine
(32 karakterlik base32 makine kodu), issuedAt, expiresAt (RFC 3339, tam
saniye).
expiresAt, lisansın artık kapsamadığı ilk an’dır; son geçerli gün bunun
bir saniye öncesidir ve Türkiye takvim saatine göre hesaplanır. daysLeft son
geçerli günde 0, sonrasında negatiftir — müşteriye söylediğimiz sayı ile
kasadaki sayı aynı olmak zorundadır.
Aynı biçimin diğer iki uygulaması smart-menu-adisyon-license/license/license.go
ve backend’deki internal/license’tır. lib/license/testdata/golden.json üç
repoda da birebir aynı dosyadır; aralarındaki diff boş olmalıdır. Biçim
değişecekse önek ve payload’daki v birlikte, üç yerde birden değişir.