38471-vm/lib/LicenseService.php
2026-02-18 12:01:04 +00:00

138 lines
4.9 KiB
PHP

<?php
class LicenseService {
private static $remote_api_url = 'https://licensing.your-domain.com/api/v1'; // Replace with your server
/**
* Generates a unique fingerprint for this server environment.
*/
public static function getFingerprint() {
$data = [
php_uname(),
$_SERVER['SERVER_ADDR'] ?? '127.0.0.1',
$_SERVER['HTTP_HOST'] ?? 'localhost',
PHP_OS
];
return hash('sha256', implode('|', $data));
}
/**
* Checks if the system is currently activated.
*/
public static function isActivated() {
require_once __DIR__ . '/../db/config.php';
$stmt = db()->prepare("SELECT * FROM system_license WHERE status = 'active' LIMIT 1");
$stmt->execute();
$license = $stmt->fetch();
if (!$license) return false;
// 1. Verify fingerprint matches (Physical Protection)
if ($license['fingerprint'] !== self::getFingerprint()) {
return false;
}
// 2. Periodic Remote Validation (e.g., every 7 days)
// This ensures if you disable a key on your server, the client will stop working.
$last_check = strtotime($license['activated_at']); // In real use, store 'last_verified_at'
if (time() - $last_check > (7 * 24 * 60 * 60)) {
// It's been more than 7 days, let's re-verify
$res = self::callRemoteApi('/verify', [
'license_key' => $license['license_key'],
'fingerprint' => $license['fingerprint'],
'token' => $license['activation_token']
]);
if (!$res['success']) {
db()->exec("UPDATE system_license SET status = 'suspended'");
return false;
}
// Update last verified timestamp
db()->exec("UPDATE system_license SET activated_at = NOW()");
}
return true;
}
/**
* Attempts to activate the product online.
*/
public static function activate($license_key) {
$license_key = trim($license_key);
$fingerprint = self::getFingerprint();
// Call remote API for real validation
$response = self::callRemoteApi('/activate', [
'license_key' => $license_key,
'fingerprint' => $fingerprint,
'domain' => $_SERVER['HTTP_HOST'] ?? 'unknown',
'product' => 'Flatlogic Admin Panel'
]);
if (!$response['success']) {
return ['success' => false, 'error' => $response['error'] ?? 'Remote activation failed.'];
}
require_once __DIR__ . '/../db/config.php';
// Clear previous pending/failed attempts
db()->exec("DELETE FROM system_license");
$stmt = db()->prepare("INSERT INTO system_license (license_key, fingerprint, status, activated_at, activation_token) VALUES (?, ?, 'active', NOW(), ?)");
$token = $response['activation_token'] ?? bin2hex(random_bytes(32));
$stmt->execute([$license_key, $fingerprint, $token]);
return ['success' => true];
}
/**
* Remote API Caller
*/
private static function callRemoteApi($endpoint, $params) {
$url = self::$remote_api_url . $endpoint;
// Check if we are in local development / simulation mode
// If the URL is still the default placeholder, we use simulation
if (strpos(self::$remote_api_url, 'your-domain.com') !== false) {
return self::simulateApi($endpoint, $params);
}
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$resp = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code !== 200) {
return ['success' => false, 'error' => "Remote server returned error code $http_code."];
}
$data = json_decode($resp, true);
if (!$data) {
return ['success' => false, 'error' => "Invalid response from remote server."];
}
return $data;
}
/**
* Local Simulation for development purposes
*/
private static function simulateApi($endpoint, $params) {
$clean_key = strtoupper(trim($params['license_key'] ?? ''));
if (strpos($clean_key, 'FLAT-') === 0) {
if ($endpoint === '/verify') return ['success' => true];
return [
'success' => true,
'activation_token' => hash('sha256', $params['license_key'] . $params['fingerprint'] . 'DEBUG_SALT')
];
}
return ['success' => false, 'error' => 'License key invalid or expired (Simulation Mode).'];
}
}