Files
copymailrpi/web/includes/vision.php
2026-05-06 09:58:18 +02:00

109 lines
4.4 KiB
PHP

<?php
/**
* vision.php — Intégration Vision (licence)
* Cache SESSION : aucune requête réseau pendant 15 min après le dernier check.
* Le check HTTP n'a lieu qu'une fois par session toutes les 15 minutes.
*/
define('VISION_LICENSE_URL', 'https://vision.copydev.fr/api/license.php');
define('VISION_PRODUCT', 'copymail');
define('VISION_CACHE_TTL', 900); // 15 minutes
function vision_machine_id(): string {
$id = cfg('vision_machine_id', '');
if (!$id) {
$id = strtolower('copymail-' . bin2hex(random_bytes(6)));
cfg_set('vision_machine_id', $id);
}
return $id;
}
function vision_check(): array {
// 1. Cache session : si le résultat est frais, on retourne immédiatement
if (!empty($_SESSION['vision_result']) && !empty($_SESSION['vision_checked_at'])) {
if ((time() - $_SESSION['vision_checked_at']) < VISION_CACHE_TTL) {
return $_SESSION['vision_result'];
}
}
// 2. Clé non configurée
$key = cfg('vision_license_key', '');
if (!$key) {
$r = ['valid' => false, 'msg' => 'Licence non configurée.', 'unconfigured' => true];
$_SESSION['vision_result'] = $r;
$_SESSION['vision_checked_at'] = time();
return $r;
}
// 3. Appel Vision (max 3s timeout)
$url = VISION_LICENSE_URL . '?' . http_build_query([
'key' => $key,
'machine_id' => vision_machine_id(),
'hostname' => cfg('hostname', gethostname()),
]);
$ctx = stream_context_create(['http' => ['method' => 'GET', 'timeout' => 3, 'ignore_errors' => true]]);
$resp = @file_get_contents($url, false, $ctx);
if ($resp === false) {
// Vision injoignable — mode dégradé
$lastOk = (int)cfg('vision_last_ok', '0');
$timeout = (int)cfg('vision_offline_timeout', '72');
$elapsed = $lastOk ? (time() - $lastOk) / 3600 : PHP_INT_MAX;
$result = ($lastOk && $elapsed < $timeout)
? ['valid' => true, 'msg' => "Vision injoignable — mode dégradé ({$timeout}h max)", 'degraded' => true]
: ['valid' => false, 'msg' => 'Vision injoignable et délai hors-ligne dépassé.'];
} else {
$data = json_decode($resp, true);
if (!empty($data['valid'])) {
$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_offline_timeout', (string)($data['offline_timeout_hours'] ?? 72));
} else {
$result = ['valid' => false, 'msg' => $data['message'] ?? 'Licence invalide ou désactivée.'];
cfg_set('vision_last_ok', '0');
}
}
// 4. Stocke en session
$_SESSION['vision_result'] = $result;
$_SESSION['vision_checked_at'] = time();
return $result;
}
function vision_enforce(): void {
$result = vision_check();
if ($result['valid']) return;
$uri = $_SERVER['REQUEST_URI'] ?? '';
if (is_admin() && strpos($uri, '/admin/domain.php') !== false) return;
$msg = htmlspecialchars($result['msg'] ?? 'Licence invalide.');
$configLink = is_admin()
? '<a href="/admin/domain.php" class="btn btn-outline-light mt-3"><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;
}