Lifecycle d'un plugin Stormeo Connector
Du pairing initial à la sync continue en passant par les renouvellements. S'applique aux plugins WordPress et PrestaShop.
Vue d'ensemble
┌─────────────┐ ┌──────────────┐
│ Plugin │ │ StormeoOS │
│ (site WP) │ │ backend │
└──────┬──────┘ └──────┬───────┘
│ │
│ 1. Admin colle un token de pairing │
│ ──────────────────────────────────► │
│ POST /api/plugin/pair │
│ ◄────────────────────────────────── │
│ { apiKey, apiSecret, agencyId } │
│ │
│ 2. Heartbeat (toutes les 5min) │
│ ──────────────────────────────────► │
│ POST /v1/ping (Bearer apiSecret) │
│ ◄────────────────────────────────── │
│ │
│ 3. Sync events (event-driven) │
│ ──────────────────────────────────► │
│ POST /api/plugin/v2/security-event │
│ + HMAC signature │
│ ◄────────────────────────────────── │
│ │
│ 4. Pull commandes (poll cron) │
│ ──────────────────────────────────► │
│ GET /api/plugin/commands │
│ ◄────────────────────────────────── │
│ [{ id, type, payload }] │
│ │
│ 5. Push résultat de commande │
│ ──────────────────────────────────► │
│ POST /api/plugin/command-result │
│ ◄────────────────────────────────── │1. Pairing initial
Le pairing échange un token de courte durée (60s) contre des credentials permanents.
Génération du token (côté StormeoOS UI)
L'utilisateur génère un token de pairing depuis l'UI agence :
SitePilot → Mon site → Connecter le plugin- Token affiché 1 fois (60s TTL), à coller dans les réglages plugin
Endpoint d'échange
POST /api/plugin/pair
Content-Type: application/json
{
"pairingToken": "spt_<random hex>",
"siteUrl": "https://acme.fr",
"platform": "wordpress", // ou "prestashop"
"pluginVersion": "3.3.0",
"phpVersion": "8.1.0",
"platformVersion": "6.4.0" // version WP ou PS
}Réponse 200
{
"success": true,
"apiKey": "sak_<32 hex>",
"apiSecret": "ssa_<64 hex>",
"agencyId": 7,
"siteId": "uuid",
"connectorId": 42,
"platform": "wordpress",
"hmacRequired": false,
"instructions": "Copiez ces credentials dans les réglages du plugin. Ne les partagez jamais."
}Le
pairingTokenest consommé par cette requête (one-shot, supprimé après usage).
Stockage côté plugin
| Donnée | Stockage WP | Stockage PS |
|---|---|---|
apiKey | wp_options (chiffré AES-256-GCM at-rest) | ps_configuration (chiffré) |
apiSecret | idem | idem |
agencyId | idem | idem |
siteId | idem | idem |
Le plugin doit refuser de fonctionner si les credentials sont absents.
2. Heartbeat
Toutes les 5 minutes (configurable via cron WP / cron PS), le plugin envoie un ping :
POST /v1/ping
Authorization: Bearer <apiSecret>
X-Stormeo-Client-Id: <apiKey>Réponse :
{ "status": "ok", "timestamp": "2026-04-27T10:00:00.000Z", "latencyMs": 42 }Effet côté serveur : stormeo_api_configs.lastPing = now(), latencyMs updaté. Permet à l'UI agence d'afficher le statut connecté/déconnecté.
Pas de signature HMAC sur
/v1/ping— endpoint legacy, auth Bearer suffit.
3. Sync events (event-driven)
Au lieu de poll, le plugin pousse les events à mesure qu'ils surviennent (hooks WP / PS) :
| Hook WP | Endpoint StormeoOS | Type d'event |
|---|---|---|
save_post | /api/plugin/v2/security-event (type=content) | Création/modification post/page |
comment_post | /api/plugin/v2/security-event (type=comment) | Nouveau commentaire |
wp_login_failed | /api/plugin/v2/security-event (type=security) | Tentative login échouée |
woocommerce_new_order | /api/plugin/sync-content | Nouvelle commande WC |
cron daily | /api/plugin/v2/disk-usage | Métriques disque |
cron daily | /api/plugin/v2/file-integrity | Hash core files |
Voir events.md pour le catalogue complet.
Tous ces endpoints exigent HMAC au-delà du seuil version. Voir hmac-signature.md.
4. Pull commandes
Le plugin poll toutes les 60s une queue de commandes envoyées par StormeoOS :
GET /api/plugin/commands
X-Stormeo-API-Key: <apiKey>
X-Stormeo-Signature: sha256=...
X-Stormeo-Timestamp: 1730019660Réponse :
{
"commands": [
{ "id": 123, "type": "wp.update_plugin", "payload": { "plugin": "akismet", "version": "5.3" } },
{ "id": 124, "type": "wp.flush_cache", "payload": {} }
]
}Types de commandes supportés (extensible) :
wp.update_plugin,wp.update_theme,wp.update_corewp.flush_cache,wp.flush_object_cachewp.run_db_optimizeps.update_module,ps.regenerate_thumbnailsgeneric.execute_url_check
5. Push résultat
Après exécution d'une commande, le plugin renvoie le résultat :
POST /api/plugin/command-result
Content-Type: application/json
X-Stormeo-API-Key: <apiKey>
X-Stormeo-Signature: sha256=...
{
"commandId": 123,
"status": "success", // ou "error"
"result": { "updatedFrom": "5.2", "updatedTo": "5.3" },
"logs": "...",
"executedAt": "2026-04-27T10:05:00.000Z"
}Versioning et auto-rollout HMAC
Le plugin envoie sa version à chaque pairing + dans les heartbeats. Le serveur compare au seuil :
| Plugin version | Comportement HMAC |
|---|---|
< seuil (legacy) | OPTIONAL, accepté avec warning log |
>= seuil | REQUIRED automatiquement |
| Inconnue | OPTIONAL (heartbeat à venir mettra à jour) |
→ La mise à jour automatique du plugin vers une version >= seuil active HMAC sans intervention manuelle.
Pour rollback exceptionnel : variable env HMAC_THRESHOLD_<PLATFORM> côté serveur (ex: HMAC_THRESHOLD_WORDPRESS=99.0.0 désactive l'auto-rollout WP).
Kill-switch global
Côté StormeoOS, l'admin peut forcer HMAC sur tous les plugins en posant HMAC_REQUIRED=1 dans .env. Effet : tout plugin qui ne signe pas reçoit 401.
Inverse : HMAC_REQUIRED=0 (ou absent) revient à la cascade par défaut.
Désinstallation / révocation
Côté plugin
Supprimer les options apiKey / apiSecret (chiffrées) → le plugin cesse d'envoyer.
Côté StormeoOS
- UI :
SitePilot → Mon site → Déconnecter le plugin→ révoqueapiKey(le plugin recevra des401au prochain ping) - API admin :
DELETE /api/site-connectors/:id→ cascade, suppression des secrets
RGPD
Sur demande de suppression utilisateur :
POST /v1/gdpr/delete
Authorization: Bearer <apiSecret>
Content-Type: application/json
{
"platform": "wordpress",
"user_id": 42,
"user_data": { "email": "user@example.com" }
}Effet : log RGPD côté StormeoOS + anonymisation/suppression des references plateforme. Détails côté plugin (anonymisation users/comments WP, customer/addresses PS) dans la doc plugin.