# Système de licences saadikERP — côté client (hub)

Implémentation client-side du système décrit dans `saadik-licence-specs/`. Le
serveur (génération de licences + distribution des paquets) est construit ailleurs
(autre agent) ; il est ici **simulé** tant que `LICENCE_MOCK_SERVER = true`.

## Configuration (URLs dans le code)

Tout est dans `licence/config.php` :

| Constante | Rôle |
|---|---|
| `LICENCE_SERVER_URL` | Serveur d'activation/heartbeat (local dev : `http://localhost:8081/api/v1`). |
| `DISTRIBUTION_SERVER_URL` | Serveur des paquets (manifeste/download). |
| `LICENCE_MOCK_SERVER` | `false` = activation via le vrai serveur ; `true` = simulée hors ligne. |
| `LICENCE_MOCK_DISTRIBUTION` | `true` = téléchargement des paquets en mock local. |
| `LICENCE_ENFORCE` | `true` = un module n'est actif que si la licence est active ET le module souscrit. |
| `LICENCE_BINDING_MODE/VALUE` | Liaison (dev : domaine `localhost`). |
| `LICENCE_STORAGE_PATH` | Emplacement de `license.key` (hors web public). |

### Serveur d'activation local (plateforme éditeur)
La plateforme est dans `C:\wamp64\www\saadik-plateforme-serveur-specs\platform`
(CodeIgniter 4, **PHP 8.1**). Apache WAMP étant en PHP 7.4, on la lance via son
serveur intégré :
```
cd C:\wamp64\www\saadik-plateforme-serveur-specs\platform
C:\wamp64\bin\php\php8.1.0\php.exe spark serve --host localhost --port 8081
```
- La clé publique A1 de la plateforme est copiée dans `licence/keys/pubA.php`.
- Générer une licence : `php spark licgen --client <id> --module <key:spec> …`.

### Extension sodium (obligatoire)
La crypto Ed25519 exige l'extension **sodium**. Elle a été activée dans le
`php.ini` d'Apache et du CLI 7.4 (`extension=sodium`). **Redémarrer Apache** après
activation. Sans sodium, l'enforcement est suspendu (l'ERP n'est jamais verrouillé).

## Mise en route (dev)

```bash
php licence/migrate.php     # tables lic_* (déjà exécuté)
php licence/keygen.php      # paires de clés A + B/module (déjà exécuté)
php licence/licgen.php      # forge une licence de test -> storage/license.key
```
Puis, en admin : `app/licence/activation.php` → « Activer » (lie la machine).

## Composants

| Fichier | Rôle |
|---|---|
| `Crypto.php` | Signature/vérif Ed25519 (+RSA), `json_canonical`, jetons. |
| `Fingerprint.php` | Empreinte machine. |
| `LicenseVerifier.php` | Vérifie `license.key` (signature A + fenêtre + liaison). |
| `LicenseClient.php` | activate/heartbeat/deactivate (mock ou HTTP réel). |
| `LicenseManager.php` | Machine à états + `authorize()` + `entitlementsFor()`. |
| `ModuleRegistry.php` | Registre local (croise `modules` × licence). |
| `SeatManager.php` | Sièges named/concurrent. |
| `SsoIssuer.php` | Émet les jetons SSO signés (clé privée B du module). |
| `sso_gate.php` | Greffe d'enforcement sur `sso_bridge.php`. |
| `Installer.php` + `MockDistribution.php` | Installateur (download→BDD→activation). |
| `ModuleGuard.php` | Librairie autonome à livrer DANS chaque module. |
| `bootstrap.php` | Évaluation licence au démarrage du hub. |
| `cron_heartbeat.php` | Revalidation planifiée (tâche Windows). |

Écrans hub : `app/licence/activation.php`, `bloque.php`, `refus.php`, `ioncube.php`.

## Clés d'activation (mode mock)

Format : `SAADIK-<CODE_MODULE_MAJ>-2026` (voir `licence_expected_activation_key`).

## Passage en production

1. Le serveur (autre paquet) est en ligne → mettre `LICENCE_MOCK_SERVER = false`.
2. Remplacer `keys/pubA.php` par la vraie clé publique A du serveur.
3. Baker les clés publiques B dans chaque module (`keys/pub_B/<module>.php` →
   `licence/keys/pub.php` du module), garder les privées B dans le trousseau du hub.
4. Encoder les fichiers sensibles avec ionCube : `powershell licence/build-dist.ps1`
   (définir `$env:IONCUBE_ENCODER`). Liste des fichiers : spec 08 §1.
5. Activer `LICENCE_ENFORCE = true` pour bloquer selon l'état de la licence.

## Sécurité

- Clés **privées** (A de dev, trousseau B) et `license.key` : hors dépôt (`.gitignore`).
- La clé **privée A** de production ne doit JAMAIS être chez le client (serveur seul).
- Vérifier la **signature avant** toute confiance au contenu (fait partout).
