Prezentare generală
Acesta este API-ul de licențiere pentru aplicații care vor folosi autentificare/licențiere centralizată. Păstrează toți pașii de verificare semnați și verificabili de client. Pentru o integrare sigură, urmați pașii din această pagină.
Instalare SDK-uri
Laravel (client principal)
composer require master-data-ro/hearth-license-client:dev-main
Repo: github.com/master-data-ro/hearth-license-client
PHP SDK (standalone)
composer require master-data-ro/php-hearth-license-client
Repo: github.com/master-data-ro/php-hearth-license-client
Node SDK (standalone)
npm install node-fetch
Repo: github.com/master-data-ro/hearth-license-client (directorul sdk/node)
Cheile publice:
GET /.well-known/jwks.json— JWKS (fără prefix)GET /keys/pem— cheia publică PEM (fără prefix)- Alternative cu prefix API:
/api/.well-known/jwks.jsonși/api/keys/pem
Endpoint-uri importante
POST /api/verify— verifică o licență (cheie + domeniu).GET /.well-known/jwks.json— JWKS (public keys) folosit pentru verificarea semnăturilor.GET /keys/pem— cheia publică în format PEM.POST /api/verify-challengeșiGET /api/get-challenge— flux opțional challenge/response.
Formatul răspunsului (semnat)
Toate răspunsurile relevante sunt returnate în următorul format JSON:
{
"data": {
"valid": true|false,
"message": "...",
"expires_at": "2025-12-04T18:20:16Z",
"issued_at": "2025-11-06T10:00:00Z",
"nonce": "..."
},
"signature": "",
"kid": ""
}
Exemple
1) Test manual cu curl
curl -s -X POST https://hearth.master-data.ro/api/verify \
-H "Content-Type: application/json" \
-d '{"license_key":"AUTO-ABC123","domain":"example.com"}'
2) Verificare răspuns folosind SDK PHP inclus
Exemplu simplu care folosește sdk/php/LicenseVerifier.php:
<?php
require 'sdk/php/LicenseVerifier.php';
$verifier = new \SDK\PHP\LicenseVerifier('https://hearth.master-data.ro/.well-known/jwks.json');
$raw = file_get_contents('php://stdin'); // sau curl response
if ($verifier->verifyResponse($raw)) {
echo "Răspuns valid și semnat\n";
} else {
echo "Răspuns invalid\n";
}
3) Exemple de răspunsuri și erori
// 409 Conflict — cheia există deja pe un alt domeniu
{
"data": { "valid": false, "message": "Această cheie de licență există deja pentru domeniul: other.example.com.", "issued_at": "...", "nonce": "..." },
"signature": "...",
"kid": "..."
}
// 200 cu valid=false — cerere înregistrată pentru aprobare
{
"data": { "valid": false, "message": "Licența nu există pentru această pereche cheie/domeniu. Cererea a fost înregistrată pentru aprobare.", "issued_at": "...", "nonce": "..." },
"signature": "...",
"kid": "..."
}
Testare locală și unit tests
- Rulați testele existente cu
vendor/bin/phpunit. Pentru rulări rapide folosiți filtrul pe teste noi:vendor/bin/phpunit --filter DomainNormalizationTest. - Test manual: Folosiți
curlpentru a trimite cereri; folosiți SDK-ul pentru a valida semnătura răspunsului. - Test de integrare: integrați middleware-ul client (exemplu mai jos) și rulați scenarii end-to-end.
Exemplu de middleware client (Laravel)
Middleware-ul verifică forma răspunsului și semnătura semnată de server.
<?php
namespace App\Http\Middleware;
use Closure;
use SDK\PHP\LicenseVerifier;
class VerifyLicenseResponse
{
public function handle($request, Closure $next)
{
$response = $next($request);
$raw = $response->getContent();
$verifier = new LicenseVerifier(config('app.url') . '/.well-known/jwks.json');
if (!$verifier->verifyResponse($raw)) {
return response()->json(['error' => 'Invalid license response signature'], 403);
}
return $response;
}
}
Ghid complet de integrare (Laravel)
- Instalați pachetul client (din repo oficial):
composer require master-data-ro/hearth-license-client:dev-main - Rulați comanda de verificare (opțiuni):
php artisan make:license-server YOUR-LICENSE-KEY php artisan make:license-server --passphrase="your-passphrase" YOUR-LICENSE-KEY php artisan make:license-server --showObservații: comanda salvează `storage/license.json` criptat folosind implicit `APP_KEY`. Puteți furniza `--passphrase` sau seta `APP_LICENSE_PASSPHRASE` în `.env`.
- Înregistrați middleware-ul furnizat (`Hearth\\LicenseClient\\Middleware\\EnsureHasValidLicense`) în `app/Http/Kernel.php` pentru a proteja rute sau întregul grup `web`.
- Verificare semnături: aplicația client va descărca JWKS de la
/.well-known/jwks.json— folosiți librării JWKS (php-jwt sau web-token/jwt-framework) pentru fluxuri complexe. - Testare end-to-end: folosiți un mediu staging, rulați comanda de verificare și accesați rute protejate pentru a confirma 403 când nu există licență.
Exemple pentru alte framework-uri
Node.js / Express
Flow recomandat:
- Client (aplicație) trimite cheie + domeniu la `POST /api/verify`.
- Server răspunde cu obiectul semnat (data + signature + kid).
- Client descarcă JWKS de la `/.well-known/jwks.json` și folosește
jsonwebtokensaujosepentru a verifica semnătura manual (dacă server nu trimite JWT standard).
// Node.js (jose)
import fetch from 'node-fetch';
import { importJWK, flattenedVerify } from 'jose';
const resp = await fetch('https://hearth.master-data.ro/api/verify', { method: 'POST', body: JSON.stringify({ license_key, domain }) });
const body = await resp.json();
const jwks = await (await fetch('https://hearth.master-data.ro/.well-known/jwks.json')).json();
const jwk = jwks.keys.find(k => k.kid === body.kid);
const key = await importJWK(jwk, 'RS256');
const verified = await flattenedVerify(JSON.stringify(body.data), key);
Python (Flask / Django)
Usează cryptography sau jose libraries to parse JWKS and verify signature over the JSON payload. Example (high level):
# pseudo-code
from jwcrypto import jwk, jws
import requests
resp = requests.post('https://hearth.master-data.ro/api/verify', json={ 'license_key': key, 'domain': domain })
body = resp.json()
jwks = requests.get('https://hearth.master-data.ro/.well-known/jwks.json').json()
# find key by kid and verify signature over body['data']
PHP (raw / fără framework)
Exemplu minim în PHP pur pentru a verifica semnătura răspunsului (folosind endpoint-ul PEM). Acesta este util pentru aplicații PHP care nu folosesc un framework sau pentru scripturi CLI.
<?php
// 1) Trimite cererea
$body = json_encode(['license_key' => 'YOUR-KEY', 'domain' => 'example.com']);
$ch = curl_init('https://hearth.master-data.ro/api/verify');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
$resp = curl_exec($ch);
if ($resp === false) { die('Request failed: ' . curl_error($ch)); }
curl_close($ch);
$json = json_decode($resp, true);
if (empty($json['data']) || empty($json['signature'])) { die('Invalid authority response'); }
// 2) Fetch authority PEM (simpler than handling JWKS)
$pem = file_get_contents('https://hearth.master-data.ro/keys/pem');
if ($pem === false) { die('Failed to fetch public PEM'); }
// 3) Verify signature
$payloadJson = json_encode($json['data']);
$sig = base64_decode($json['signature']);
$pub = openssl_pkey_get_public($pem);
if ($pub === false) { die('Invalid public key'); }
$ok = openssl_verify($payloadJson, $sig, $pub, OPENSSL_ALGO_SHA256) === 1;
openssl_free_key($pub);
if (! $ok) { die('Signature invalid'); }
// 4) Save verified license (encrypted) — use a passphrase or env secret
$passphrase = getenv('LICENSE_PASSPHRASE') ?: 'change-me';
$key = substr(hash('sha256', $passphrase, true), 0, 32);
$iv = random_bytes(16);
$cipher = openssl_encrypt($payloadJson, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
file_put_contents(__DIR__ . '/storage/license.json', json_encode([ 'v' => 1, 'payload' => base64_encode($iv . $cipher) ]));
echo "License saved and verified\n";
Observații:
- Folosirea endpoint-ului PEM este cea mai simplă cale în PHP brut; dacă preferați JWKS, folosiți o bibliotecă care convertește JWK → PEM sau implementați transformarea manuală.
- Verificați câmpurile
issued_atșinoncepentru a preveni replay attacks. - Păstrați passphrase-ul în medii sigure; nu comitați fișierele criptate fără backup-ul cheii.
Enforcement automat (SDK-uri)
PHP
<?php
require 'HearthClient.php';
\Hearth\SDK\HearthClient::enforceOrExit();
Dacă licența locală nu este validă/expirată, execuția se oprește (HTTP 403 pentru web).
Node.js
const HearthClient = require('./index');
HearthClient.enforceOrExit({ baseUrl: 'https://hearth.master-data.ro' });
Resurse rapide
- JWKS:
/.well-known/jwks.json(sau/api/.well-known/jwks.json) - PEM public:
/keys/pem(sau/api/keys/pem) - SDK PHP: github.com/master-data-ro/php-hearth-license-client
- Route verify:
/api/verify
Recomandare: integrați verificarea semnăturii în client pentru a preveni fraudarea răspunsurilor.