2026-02-20 15:20:10 +00:00

310 lines
17 KiB
PHP

<?php
/**
* LICENSE MANAGER ADMIN PANEL
*
* Secure page to manage licenses and activations.
*/
session_start();
require_once __DIR__ . '/config.php';
// SIMPLE PASSWORD PROTECTION
// Change this to a secure password or use a more robust auth system
$admin_password = "Meezan@2026";
if (isset($_GET['logout'])) {
session_destroy();
header("Location: manage.php");
exit;
}
if (!isset($_SESSION['license_admin_auth'])) {
if (isset($_POST['password']) && $_POST['password'] === $admin_password) {
$_SESSION['license_admin_auth'] = true;
header("Location: manage.php");
exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>License Admin Login</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body { background: #f4f7f6; display: flex; align-items: center; justify-content: center; height: 100vh; }
.login-card { width: 100%; max-width: 400px; padding: 2rem; border-radius: 1rem; box-shadow: 0 10px 25px rgba(0,0,0,0.05); background: white; }
</style>
</head>
<body>
<div class="login-card">
<h3 class="text-center mb-4">License Manager</h3>
<form method="POST">
<div class="mb-3">
<label class="form-label">Admin Password</label>
<input type="password" name="password" class="form-control" placeholder="Enter password" required autofocus>
</div>
<button type="submit" class="btn btn-primary w-100">Login</button>
</form>
<?php if (isset($_POST['password'])): ?>
<div class="alert alert-danger mt-3 py-2 small">Invalid password</div>
<?php endif; ?>
</div>
</body>
</html>
<?php
exit;
}
$pdo = db_manager();
$message = '';
// Handle Actions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
switch ($_POST['action']) {
case 'toggle_status':
$id = (int)$_POST['id'];
$new_status = $_POST['status'] === 'active' ? 'suspended' : 'active';
$stmt = $pdo->prepare("UPDATE licenses SET status = ? WHERE id = ?");
$stmt->execute([$new_status, $id]);
$message = "License status updated to $new_status.";
break;
case 'delete_license':
$id = (int)$_POST['id'];
$stmt = $pdo->prepare("DELETE FROM licenses WHERE id = ?");
$stmt->execute([$id]);
$message = "License deleted successfully.";
break;
case 'issue':
$prefix = strtoupper(trim($_POST['prefix'] ?? 'FLAT'));
$max_activations = (int)($_POST['max_activations'] ?? 1);
$max_counters = (int)($_POST['max_counters'] ?? 1);
$owner = trim($_POST['owner'] ?? '');
$address = trim($_POST['address'] ?? '');
$key = $prefix . '-' . strtoupper(bin2hex(random_bytes(2))) . '-' . strtoupper(bin2hex(random_bytes(2))) . '-' . strtoupper(bin2hex(random_bytes(2)));
$stmt = $pdo->prepare("INSERT INTO licenses (license_key, max_activations, max_counters, owner, address, status) VALUES (?, ?, ?, ?, ?, 'active')");
$stmt->execute([$key, $max_activations, $max_counters, $owner, $address]);
$message = "New license issued: $key";
break;
}
}
}
// Fetch Licenses
$licenses = $pdo->query("SELECT * FROM licenses ORDER BY created_at DESC")->fetchAll();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Manage Licenses</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<style>
body { background: #f1f5f9; font-family: 'Inter', system-ui, -apple-system, sans-serif; }
.navbar { background: #0f172a; padding: 1rem 0; box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1); }
.navbar-brand { font-weight: 700; letter-spacing: -0.025em; }
.card { border: none; border-radius: 0.75rem; box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); }
.card-header { background-color: #fff; border-bottom: 1px solid #e2e8f0; font-weight: 600; padding: 1.25rem; }
.form-label { font-weight: 500; color: #475569; font-size: 0.875rem; }
.form-control, .form-select { border-radius: 0.5rem; border: 1px solid #cbd5e1; padding: 0.625rem 0.875rem; }
.form-control:focus { border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); }
.btn-primary { background-color: #2563eb; border: none; padding: 0.625rem 1.25rem; font-weight: 600; border-radius: 0.5rem; transition: all 0.2s; }
.btn-primary:hover { background-color: #1d4ed8; transform: translateY(-1px); }
.status-active { background: #dcfce7; color: #166534; padding: 0.25rem 0.75rem; border-radius: 1rem; font-size: 0.75rem; font-weight: 600; }
.status-suspended { background: #fee2e2; color: #991b1b; padding: 0.25rem 0.75rem; border-radius: 1rem; font-size: 0.75rem; font-weight: 600; }
.table thead th { text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.05em; color: #64748b; background: #f8fafc; padding: 1rem; }
.table tbody td { padding: 1rem; vertical-align: middle; border-bottom: 1px solid #f1f5f9; }
code { background: #f1f5f9; color: #0f172a; padding: 0.25rem 0.5rem; border-radius: 0.375rem; font-weight: 500; }
.modal-content { border: none; border-radius: 1rem; }
.modal-header { border-bottom: 1px solid #f1f5f9; padding: 1.5rem; }
.modal-footer { border-top: 1px solid #f1f5f9; padding: 1.5rem; }
</style>
</head>
<body>
<nav class="navbar navbar-dark mb-4">
<div class="container">
<span class="navbar-brand mb-0 h1"><i class="bi bi-shield-lock me-2"></i> License Manager Admin</span>
<a href="?logout=1" class="btn btn-outline-light btn-sm">Logout</a>
</div>
</nav>
<div class="container pb-5">
<?php if ($message): ?>
<div class="alert alert-info alert-dismissible fade show" role="alert">
<?= htmlspecialchars($message) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<div class="row">
<!-- Issue License Card -->
<div class="col-lg-4 mb-4">
<div class="card p-4">
<h5 class="mb-4">Issue New License</h5>
<form method="POST">
<input type="hidden" name="action" value="issue">
<div class="mb-3">
<label class="form-label">Prefix</label>
<input type="text" name="prefix" class="form-control" value="FLAT" maxlength="10">
</div>
<div class="mb-3">
<label class="form-label">Machines Limit</label>
<input type="number" name="max_activations" class="form-control" value="1" min="1">
</div>
<div class="mb-3">
<label class="form-label">Counters Limit</label>
<input type="number" name="max_counters" class="form-control" value="1" min="1">
</div>
<div class="mb-3">
<label class="form-label">Owner Name</label>
<input type="text" name="owner" class="form-control" placeholder="Optional client name">
</div>
<div class="mb-3">
<label class="form-label">Address / Notes</label>
<textarea name="address" class="form-control" rows="2" placeholder="Optional details"></textarea>
</div>
<button type="submit" class="btn btn-primary w-100">Issue Key</button>
</form>
</div>
</div>
<!-- Licenses List -->
<div class="col-lg-8">
<div class="card overflow-hidden">
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center">
<h5 class="mb-0">Existing Licenses</h5>
<span class="badge bg-secondary"><?= count($licenses) ?> Total</span>
</div>
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead>
<tr>
<th>Key</th>
<th>Owner</th>
<th>Machines</th>
<th>Counters</th>
<th>Status</th>
<th>Created</th>
<th class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($licenses as $l): ?>
<tr>
<td><code><?= htmlspecialchars($l['license_key']) ?></code></td>
<td><span class="text-secondary small"><?= htmlspecialchars($l['owner'] ?: 'N/A') ?></span></td>
<td>
<?php
$stmt = $pdo->prepare("SELECT COUNT(*) FROM activations WHERE license_id = ?");
$stmt->execute([$l['id']]);
$count = $stmt->fetchColumn();
$percent = ($l['max_activations'] > 0) ? ($count / $l['max_activations']) * 100 : 0;
$bar_class = $percent >= 100 ? 'bg-danger' : ($percent >= 80 ? 'bg-warning' : 'bg-success');
?>
<div class="d-flex align-items-center">
<span class="me-2 fw-bold"><?= $count ?>/<?= $l['max_activations'] ?></span>
</div>
<div class="progress mt-1" style="height: 4px; width: 60px;">
<div class="progress-bar <?= $bar_class ?>" role="progressbar" style="width: <?= min(100, $percent) ?>%"></div>
</div>
</td>
<td>
<span class="badge bg-light text-dark border"><?= $l['max_counters'] ?? 0 ?></span>
</td>
<td>
<span class="status-<?= $l['status'] ?>">
<?= ucfirst($l['status']) ?>
</span>
</td>
<td class="small text-muted"><?= date('M d, y', strtotime($l['created_at'])) ?></td>
<td class="text-end">
<div class="btn-group">
<button type="button" class="btn btn-outline-info btn-sm" data-bs-toggle="modal" data-bs-target="#modal-<?= $l['id'] ?>" title="View Activations">
<i class="bi bi-laptop"></i>
</button>
<form method="POST" class="d-inline" onsubmit="return confirm('Change status?');">
<input type="hidden" name="action" value="toggle_status">
<input type="hidden" name="id" value="<?= $l['id'] ?>">
<input type="hidden" name="status" value="<?= $l['status'] ?>">
<button type="submit" class="btn btn-outline-secondary btn-sm" title="Toggle Status">
<i class="bi bi-power"></i>
</button>
</form>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure? This will also remove all activations.');">
<input type="hidden" name="action" value="delete_license">
<input type="hidden" name="id" value="<?= $l['id'] ?>">
<button type="submit" class="btn btn-outline-danger btn-sm" title="Delete">
<i class="bi bi-trash"></i>
</button>
</form>
</div>
</td>
</tr>
<!-- Activations Modal -->
<div class="modal fade" id="modal-<?= $l['id'] ?>" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Activations for <?= htmlspecialchars($l['license_key']) ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<?php
$stmt = $pdo->prepare("SELECT * FROM activations WHERE license_id = ? ORDER BY activated_at DESC");
$stmt->execute([$l['id']]);
$acts = $stmt->fetchAll();
if ($acts):
?>
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th>Fingerprint</th>
<th>Domain</th>
<th>Product</th>
<th>Activated At</th>
</tr>
</thead>
<tbody>
<?php foreach ($acts as $a): ?>
<tr>
<td><code><?= htmlspecialchars($a['fingerprint']) ?></code></td>
<td><?= htmlspecialchars($a['domain'] ?? '-') ?></td>
<td><?= htmlspecialchars($a['product'] ?? '-') ?></td>
<td><?= $a['activated_at'] ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php else: ?>
<p class="text-center text-muted my-3">No active machine activations found.</p>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
<?php if (empty($licenses)): ?>
<tr><td colspan="5" class="text-center py-4 text-muted">No licenses found.</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>