API de licence pour les auteurs de modules
Comment un module payant se licencie, la clé du manifeste, l'appel d'activation, le heartbeat et la politique de dégradation.
Un module payant est licencié par le même serveur avec lequel parle le core, en utilisant le même transport signé. Vous le déclarez dans le manifeste ; le kernel fait le reste.
La clé du manifeste#
"licensing": { "product_slug": "your-module" }
Sa présence signifie que le module est licencié : le panneau affiche un
écran Licence pour lui, et le module peut demander si les updates sont
autorisés. Son absence signifie que le module est gratuit et que rien n'est
vérifié. Les modules fournis en standard avec le core (paiements,
gamification) ne portent aucune clé licensing.
Le product_slug est ce sous quoi le serveur de licences connaît le
produit, et c'est ce qui se retrouve dans la claim prd du token.
Activation#
Le membre saisit le numéro de série dans Modules > License. Le kernel appelle le serveur :
POST /v1/activate
{ "serial": "...", "domain": "example.com", "host": "...", "app_version": "1.2.0" }
Un succès renvoie le token signé et le droit associé :
{
"ok": true,
"token": "<JWT RS256>",
"license": { "serial": "...", "product": "your-module", "updates_until": 1789000000, "domain": "example.com" },
"features": []
}
Un refus revient avec ok: false et une raison : invalid_serial,
domain_in_use, revoked ou rate_limited. Il arrive en HTTP 200 ; un 4xx
signifie que le serveur est indisponible, ce qui est une situation
totalement différente.
Une licence de module s'active sur le même domaine de production que la licence du core.
Le transport signé#
Chaque appel à /v1/* porte quatre en-têtes :
X-Bondry-Key: l'identifiant de la clé partagée
X-Bondry-Timestamp: heure unix, valide 300 secondes
X-Bondry-Nonce: uuid v4, à usage unique
X-Bondry-Signature: hex(hmac_sha256(secret, METHOD\nPATH\nTIMESTAMP\nNONCE\nsha256(body)))
Vous ne construisez jamais cela vous-même : le client de licence du kernel signe l'appel. C'est documenté ici pour que vous puissiez le reconnaître dans un log.
Le token#
RS256, vérifié localement avec la clé publique livrée avec Bondry. Claims :
iss, sub (le numéro de série), prd (votre product slug), dom (le
domaine activé), upd (la fin de la fenêtre de mises à jour), feat,
iat, exp (30 jours) et jti.
Le token est stocké chiffré et ne quitte jamais l'installation.
Le heartbeat#
Quotidiennement, depuis le scheduler :
POST /v1/heartbeat
{ "token": "...", "domain": "example.com", "app_version": "1.2.0" }
La réponse rafraîchit le token quand il est proche d'expirer et renvoie le
updates_until actuel, plus des indicateurs pour révoqué et expiré, avec un
message optionnel destiné à l'humain, affiché dans le panneau.
Si le serveur est injoignable, rien ne se dégrade pendant quatorze jours. Votre module ne doit pas traiter une erreur réseau comme un refus.
La politique de dégradation#
C'est une règle du produit, pas une suggestion.
| État | Ce que votre module peut faire |
|---|---|
| Actif | Tout |
| Fenêtre de mises à jour expirée | Tout ce que l'acheteur a déjà. Updates indisponibles. |
| Révoqué | Tout ce que l'acheteur a déjà. Un avis permanent dans le panneau. Updates indisponibles. |
| Hors ligne au-delà de la période de grâce | Comme pour l'expiration, réversible à la reconnexion |
Ne bloquez jamais le contenu ni les fonctionnalités de base. Une licence contrôle les updates et les extras marqués comme tels, pas le droit de continuer à utiliser ce qui a été acheté. Un module qui enferme un acheteur hors de ses propres données ne sera pas accepté, et c'est le moyen le plus rapide de provoquer une rétrofacturation.
Interroger la licence#
Interrogez le kernel, n'appelez jamais le serveur vous-même :
if (\App\Kernel\License\ModuleLicenses::allowsUpdates('your-module')) {
// Proposer l'update.
}
Tester sans serveur#
Pendant le développement, le client de licence peut tourner sans serveur configuré. Il enregistre l'intention et reste déverrouillé, afin que vous ne soyez jamais bloqué par l'accès réseau pendant l'écriture d'un module.