feat: blocage si licence invalide/désactivée depuis Vision, cache 30min
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ function auth_check(): void {
|
||||
header('Location: /login.php');
|
||||
exit;
|
||||
}
|
||||
if (function_exists('vision_enforce')) vision_enforce();
|
||||
}
|
||||
|
||||
function admin_check(): void {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/vision.php';
|
||||
|
||||
function html_head(string $title): void {
|
||||
$domain = cfg('domain', 'copymail');
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
/**
|
||||
* vision.php — Intégration Vision (licence)
|
||||
* API : GET https://vision.copydev.fr/api/license.php?key=<key>&machine_id=<id>&hostname=<host>
|
||||
* Vérification toutes les 30 min, résultat mis en cache en BDD.
|
||||
*/
|
||||
|
||||
define('VISION_LICENSE_URL', 'https://vision.copydev.fr/api/license.php');
|
||||
define('VISION_PRODUCT', 'copymail');
|
||||
define('VISION_CACHE_TTL', 1800); // 30 minutes
|
||||
|
||||
function vision_machine_id(): string {
|
||||
$id = cfg('vision_machine_id', '');
|
||||
@@ -22,6 +24,14 @@ function vision_check(): array {
|
||||
return ['valid' => false, 'msg' => 'Licence non configurée.', 'unconfigured' => true];
|
||||
}
|
||||
|
||||
// Cache : si dernier check < 30 min et résultat valide, on ne re-vérifie pas
|
||||
$lastCheck = (int)cfg('vision_last_check', '0');
|
||||
$lastResult = cfg('vision_last_result', '');
|
||||
if ($lastResult && (time() - $lastCheck) < VISION_CACHE_TTL) {
|
||||
$cached = json_decode($lastResult, true);
|
||||
if ($cached) return $cached;
|
||||
}
|
||||
|
||||
$url = VISION_LICENSE_URL . '?' . http_build_query([
|
||||
'key' => $key,
|
||||
'machine_id' => vision_machine_id(),
|
||||
@@ -37,29 +47,77 @@ function vision_check(): array {
|
||||
$resp = @file_get_contents($url, false, $ctx);
|
||||
|
||||
if ($resp === false) {
|
||||
// Vision injoignable — on vérifie le délai offline autorisé
|
||||
// Vision injoignable — mode dégradé selon offline_timeout
|
||||
$lastOk = (int)cfg('vision_last_ok', '0');
|
||||
$timeout = (int)cfg('vision_offline_timeout', '72');
|
||||
$elapsed = (time() - $lastOk) / 3600;
|
||||
if ($lastOk && $elapsed < $timeout) {
|
||||
return ['valid' => true, 'msg' => "Vision injoignable (mode dégradé, {$timeout}h max)", 'degraded' => true];
|
||||
$result = ['valid' => true, 'msg' => "Vision injoignable — mode dégradé ({$timeout}h max)", 'degraded' => true];
|
||||
} else {
|
||||
$result = ['valid' => false, 'msg' => 'Vision injoignable et délai hors-ligne dépassé.'];
|
||||
}
|
||||
return ['valid' => false, 'msg' => 'Vision injoignable et délai offline dépassé.'];
|
||||
return $result;
|
||||
}
|
||||
|
||||
$data = json_decode($resp, true);
|
||||
|
||||
if (!empty($data['valid'])) {
|
||||
cfg_set('vision_last_ok', (string)time());
|
||||
cfg_set('vision_offline_timeout', (string)($data['offline_timeout_hours'] ?? 72));
|
||||
return [
|
||||
$result = [
|
||||
'valid' => true,
|
||||
'client' => $data['client'] ?? '',
|
||||
'product' => $data['product'] ?? '',
|
||||
'expires' => $data['expires_at'] ?? null,
|
||||
'devices' => $data['max_devices'] ?? 1,
|
||||
];
|
||||
cfg_set('vision_last_ok', (string)time());
|
||||
cfg_set('vision_last_check', (string)time());
|
||||
cfg_set('vision_last_result', json_encode($result));
|
||||
cfg_set('vision_offline_timeout', (string)($data['offline_timeout_hours'] ?? 72));
|
||||
return $result;
|
||||
}
|
||||
|
||||
return ['valid' => false, 'msg' => $data['message'] ?? 'Licence invalide.'];
|
||||
// Licence invalide / désactivée depuis Vision : invalide immédiatement le cache
|
||||
$result = ['valid' => false, 'msg' => $data['message'] ?? 'Licence invalide ou désactivée.'];
|
||||
cfg_set('vision_last_check', (string)time());
|
||||
cfg_set('vision_last_result', json_encode($result));
|
||||
cfg_set('vision_last_ok', '0'); // reset grace period
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie la licence et bloque si invalide.
|
||||
* À appeler sur toutes les pages.
|
||||
* Exception : la page de config (/admin/domain.php) reste accessible aux admins.
|
||||
*/
|
||||
function vision_enforce(): void {
|
||||
$result = vision_check();
|
||||
if ($result['valid']) return;
|
||||
|
||||
$uri = $_SERVER['REQUEST_URI'] ?? '';
|
||||
|
||||
// L'admin peut toujours accéder à la config pour saisir la clé
|
||||
if (is_admin() && strpos($uri, '/admin/domain.php') !== false) return;
|
||||
|
||||
// Bloque tout le reste
|
||||
$msg = htmlspecialchars($result['msg'] ?? 'Licence invalide.');
|
||||
$isAdmin = is_admin();
|
||||
$configLink = $isAdmin
|
||||
? '<a href="/admin/domain.php" class="btn btn-outline-light mt-2"><i class="bi bi-key me-1"></i>Configurer la licence</a>'
|
||||
: '';
|
||||
http_response_code(403);
|
||||
echo "<!DOCTYPE html><html lang='fr'><head><meta charset='UTF-8'>
|
||||
<meta name='viewport' content='width=device-width,initial-scale=1'>
|
||||
<title>Licence CopyMail</title>
|
||||
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css'>
|
||||
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css'>
|
||||
</head>
|
||||
<body class='bg-dark text-white d-flex align-items-center justify-content-center min-vh-100'>
|
||||
<div class='text-center p-5'>
|
||||
<i class='bi bi-shield-lock-fill text-danger' style='font-size:4rem'></i>
|
||||
<h2 class='mt-3 mb-2'>CopyMail — Accès bloqué</h2>
|
||||
<p class='text-secondary mb-4'>{$msg}</p>
|
||||
<p class='text-muted small'>Contactez <strong>CopyDev</strong> pour régulariser votre licence.</p>
|
||||
{$configLink}
|
||||
</div></body></html>";
|
||||
exit;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user