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 și GET /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

  1. Rulați testele existente cu vendor/bin/phpunit. Pentru rulări rapide folosiți filtrul pe teste noi: vendor/bin/phpunit --filter DomainNormalizationTest.
  2. Test manual: Folosiți curl pentru a trimite cereri; folosiți SDK-ul pentru a valida semnătura răspunsului.
  3. 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)
  1. Instalați pachetul client (din repo oficial):
    composer require master-data-ro/hearth-license-client:dev-main
  2. 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 --show

    Observații: comanda salvează `storage/license.json` criptat folosind implicit `APP_KEY`. Puteți furniza `--passphrase` sau seta `APP_LICENSE_PASSPHRASE` în `.env`.

  3. Înregistrați middleware-ul furnizat (`Hearth\\LicenseClient\\Middleware\\EnsureHasValidLicense`) în `app/Http/Kernel.php` pentru a proteja rute sau întregul grup `web`.
  4. 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.
  5. 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:

  1. Client (aplicație) trimite cheie + domeniu la `POST /api/verify`.
  2. Server răspunde cu obiectul semnat (data + signature + kid).
  3. Client descarcă JWKS de la `/.well-known/jwks.json` și folosește jsonwebtoken sau jose pentru 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 și nonce pentru 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

Recomandare: integrați verificarea semnăturii în client pentru a preveni fraudarea răspunsurilor.