202 lines
6.5 KiB
PHP
202 lines
6.5 KiB
PHP
<?php
|
|
/**
|
|
* LICENSE MANAGER SERVER (Standalone Module)
|
|
*
|
|
* This is the central authority that manages license keys and activations.
|
|
* It should be hosted on a secure, separate server.
|
|
*/
|
|
|
|
header('Content-Type: application/json');
|
|
require_once __DIR__ . '/config.php';
|
|
|
|
// Simple Router
|
|
$request_uri = $_SERVER['REQUEST_URI'] ?? '';
|
|
$endpoint = '';
|
|
|
|
if (strpos($request_uri, '/activate') !== false) $endpoint = 'activate';
|
|
if (strpos($request_uri, '/verify') !== false) $endpoint = 'verify';
|
|
if (strpos($request_uri, '/deactivate') !== false) $endpoint = 'deactivate';
|
|
if (strpos($request_uri, '/issue') !== false) $endpoint = 'issue';
|
|
if (strpos($request_uri, '/list') !== false) $endpoint = 'list';
|
|
|
|
$input = json_decode(file_get_contents('php://input'), true);
|
|
|
|
// If running as a simple script without proper URL rewriting
|
|
if (empty($endpoint)) {
|
|
$endpoint = $_GET['action'] ?? $input['action'] ?? '';
|
|
}
|
|
|
|
try {
|
|
$pdo = db_manager();
|
|
} catch (Exception $e) {
|
|
echo json_encode(['success' => false, 'error' => 'Database connection failed.']);
|
|
exit;
|
|
}
|
|
|
|
if ($endpoint === 'activate') {
|
|
$key = strtoupper(trim($input['license_key'] ?? ''));
|
|
$fingerprint = $input['fingerprint'] ?? '';
|
|
$domain = $input['domain'] ?? '';
|
|
$product = $input['product'] ?? '';
|
|
|
|
if (empty($key) || empty($fingerprint)) {
|
|
echo json_encode(['success' => false, 'error' => 'Missing required parameters.']);
|
|
exit;
|
|
}
|
|
|
|
// 1. Find License
|
|
$stmt = $pdo->prepare("SELECT * FROM licenses WHERE license_key = ? LIMIT 1");
|
|
$stmt->execute([$key]);
|
|
$license = $stmt->fetch();
|
|
|
|
if (!$license) {
|
|
echo json_encode(['success' => false, 'error' => 'Invalid license key.']);
|
|
exit;
|
|
}
|
|
|
|
if ($license['status'] !== 'active') {
|
|
echo json_encode(['success' => false, 'error' => 'License is ' . $license['status'] . '.']);
|
|
exit;
|
|
}
|
|
|
|
// 2. Check current activations
|
|
$stmt = $pdo->prepare("SELECT COUNT(*) FROM activations WHERE license_id = ?");
|
|
$stmt->execute([$license['id']]);
|
|
$current_activations = $stmt->fetchColumn();
|
|
|
|
// 3. Check if this machine is already activated
|
|
$stmt = $pdo->prepare("SELECT * FROM activations WHERE license_id = ? AND fingerprint = ?");
|
|
$stmt->execute([$license['id'], $fingerprint]);
|
|
$existing = $stmt->fetch();
|
|
|
|
if (!$existing) {
|
|
if ($current_activations >= $license['max_activations']) {
|
|
echo json_encode(['success' => false, 'error' => 'Maximum activation limit reached.']);
|
|
exit;
|
|
}
|
|
|
|
// Record new activation
|
|
$stmt = $pdo->prepare("INSERT INTO activations (license_id, fingerprint, domain, product) VALUES (?, ?, ?, ?)");
|
|
$stmt->execute([$license['id'], $fingerprint, $domain, $product]);
|
|
}
|
|
|
|
// Success: Return signed token
|
|
$token = hash_hmac('sha256', $key . $fingerprint, SERVER_SECRET);
|
|
echo json_encode([
|
|
'success' => true,
|
|
'activation_token' => $token
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
if ($endpoint === 'verify') {
|
|
$key = strtoupper(trim($input['license_key'] ?? ''));
|
|
$fingerprint = $input['fingerprint'] ?? '';
|
|
$token = $input['token'] ?? '';
|
|
|
|
// Simple validation: re-calculate token and check DB status
|
|
$expected_token = hash_hmac('sha256', $key . $fingerprint, SERVER_SECRET);
|
|
|
|
if ($token !== $expected_token) {
|
|
echo json_encode(['success' => false, 'error' => 'Invalid activation token.']);
|
|
exit;
|
|
}
|
|
|
|
$stmt = $pdo->prepare("SELECT status FROM licenses WHERE license_key = ?");
|
|
$stmt->execute([$key]);
|
|
$status = $stmt->fetchColumn();
|
|
|
|
if ($status === 'active') {
|
|
echo json_encode(['success' => true]);
|
|
} else {
|
|
echo json_encode(['success' => false, 'error' => 'License is no longer active.']);
|
|
}
|
|
exit;
|
|
}
|
|
|
|
if ($endpoint === 'deactivate') {
|
|
$key = strtoupper(trim($input['license_key'] ?? ''));
|
|
$fingerprint = $input['fingerprint'] ?? '';
|
|
|
|
// Deactivation should ideally require a token or signature, but for simplicity:
|
|
// We check if the license exists and the activation matches
|
|
|
|
// Find License ID
|
|
$stmt = $pdo->prepare("SELECT id FROM licenses WHERE license_key = ?");
|
|
$stmt->execute([$key]);
|
|
$licenseId = $stmt->fetchColumn();
|
|
|
|
if (!$licenseId) {
|
|
echo json_encode(['success' => false, 'error' => 'Invalid license key.']);
|
|
exit;
|
|
}
|
|
|
|
// Delete Activation
|
|
$stmt = $pdo->prepare("DELETE FROM activations WHERE license_id = ? AND fingerprint = ?");
|
|
$stmt->execute([$licenseId, $fingerprint]);
|
|
|
|
if ($stmt->rowCount() > 0) {
|
|
echo json_encode(['success' => true]);
|
|
} else {
|
|
echo json_encode(['success' => false, 'error' => 'Activation not found.']);
|
|
}
|
|
exit;
|
|
}
|
|
|
|
if ($endpoint === 'issue') {
|
|
$secret = $input['secret'] ?? '';
|
|
|
|
// Basic security check using the config constant
|
|
if ($secret !== SERVER_SECRET) {
|
|
echo json_encode(['success' => false, 'error' => 'Unauthorized. Invalid secret.']);
|
|
exit;
|
|
}
|
|
|
|
$max_activations = (int)($input['max_activations'] ?? 1);
|
|
$prefix = strtoupper(trim($input['prefix'] ?? 'FLAT'));
|
|
|
|
// Generate a formatted key: PREFIX-XXXX-XXXX
|
|
$key = $prefix . '-' . bin2hex(random_bytes(2)) . '-' . bin2hex(random_bytes(2));
|
|
$key = strtoupper($key);
|
|
|
|
try {
|
|
$stmt = $pdo->prepare("INSERT INTO licenses (license_key, max_activations) VALUES (?, ?)");
|
|
$stmt->execute([$key, $max_activations]);
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'license_key' => $key,
|
|
'max_activations' => $max_activations
|
|
]);
|
|
} catch (Exception $e) {
|
|
echo json_encode(['success' => false, 'error' => 'Failed to generate license.']);
|
|
}
|
|
exit;
|
|
}
|
|
|
|
if ($endpoint === 'list') {
|
|
// Basic security check (Optional: You can use the secret here too)
|
|
// For now, it fetches all licenses with their activation counts
|
|
try {
|
|
$stmt = $pdo->prepare("
|
|
SELECT l.*,
|
|
(SELECT COUNT(*) FROM activations a WHERE a.license_id = l.id) as activations_count,
|
|
(l.status = 'active') as is_active
|
|
FROM licenses l
|
|
ORDER BY l.created_at DESC
|
|
");
|
|
$stmt->execute();
|
|
$licenses = $stmt->fetchAll();
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'data' => $licenses
|
|
]);
|
|
} catch (Exception $e) {
|
|
echo json_encode(['success' => false, 'error' => 'Failed to fetch licenses: ' . $e->getMessage()]);
|
|
}
|
|
exit;
|
|
}
|
|
|
|
echo json_encode(['success' => false, 'error' => 'Invalid endpoint.']);
|